Nelze vybrat více než 25 témat Téma musí začínat písmenem nebo číslem, může obsahovat pomlčky („-“) a může být dlouhé až 35 znaků.

OnboardingView.vue 11KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317
  1. <template lang="pug">
  2. main.view--onboarding
  3. article(
  4. style='display: flex; flex-direction: column; align-items: center'
  5. v-if='currentStep !== survey.steps.length'
  6. )
  7. .answers(v-for='(value, key) in answered')
  8. span(v-if='key == "name" && value && currentStep == 2') Hi {{ value }}!
  9. br
  10. .step(v-for='(step, i) in survey.steps')
  11. component(
  12. :is='step.component'
  13. :question='step'
  14. :answered='answered'
  15. :responses='responses'
  16. :survey='survey'
  17. :currentStep='currentStep'
  18. :surveyStepsCount='survey.steps.length'
  19. @handle-submit='onSubmit'
  20. @update-answers='updateAnswers'
  21. v-if='step && currentStep == i'
  22. )
  23. .invalidResponseMessage(
  24. style='text-align: center'
  25. v-if='invalidResponse'
  26. )
  27. p {{ survey.steps[currentStep].invalidInputPrompt }}
  28. footer
  29. p(v-if='currentStep != 0') You have completed: {{ currentStep }} / {{ survey.steps.length }} survey steps
  30. article(v-else)
  31. SurveyCompleteView(:answers='answered' :surveySteps='survey.steps' :currentProfileId='currentProfileId')
  32. </template>
  33. <script>
  34. import { Authenticator } from '../services/auth.service.js'
  35. import { surveyFactory } from '@/utils'
  36. import { currentProfile } from '../services/'
  37. import stepViews from '@/components/onboarding'
  38. import SurveyCompleteView from './SurveyCompleteView.vue'
  39. // import savesurveybyprofileid - call it on submit
  40. // paginate to save every steps answers
  41. export default {
  42. name: 'OnboardingView',
  43. components: {
  44. ...stepViews,
  45. SurveyCompleteView,
  46. },
  47. data: () => ({
  48. answered: {},
  49. aspectQuestions: [],
  50. responses: [],
  51. currentStep: 0,
  52. survey: null,
  53. currentProfileId: null,
  54. invalidResponse: false,
  55. authenticator: {},
  56. sessionToken: '',
  57. accessToken: '',
  58. }),
  59. computed: {
  60. cP() {
  61. return currentProfile ? currentProfile : null
  62. },
  63. },
  64. async created() {
  65. this.survey = await surveyFactory.createSurvey()
  66. this.authenticator = new Authenticator()
  67. if (document.cookie.length) {
  68. // TODO: Heavy Refactor needed, obvious code smells
  69. // BUG: NEEDS BROWSER REFRESH AFTER VERIFYING EMAIL AND REDIRECT BACK TO ONBOARDING
  70. // BUG: CURRENT IMPLEMENTATION HAS COOKIES THAT NEVER EXPIRE
  71. const siimeeAnswered = this.grabCookie('siimee_answered')
  72. const myCurrentStep = this.grabCookie('siimee_current_step')
  73. const myCurrentAnswers = this.grabCookie('siimee_cache_answered')
  74. const myCurrentResponses = this.grabCookie('siimee_cache_responses')
  75. this.sessionToken = this.grabCookie('siimee_session') || ''
  76. // TODO: START REFACTOR HERE...
  77. if (siimeeAnswered) {
  78. const siimeeAnswers = JSON.parse(siimeeAnswered)
  79. const sessionTokenIsValid =
  80. await this.authenticator.validateJwt(this.sessionToken)
  81. this.accessToken = this.grabCookie('siimee_access')
  82. if (sessionTokenIsValid.isValid) {
  83. this.answered = {
  84. name: siimeeAnswers.name,
  85. email: siimeeAnswers.email,
  86. seeking: siimeeAnswers.seeking,
  87. }
  88. this.currentProfileId = siimeeAnswers.profile_id
  89. this.responses = [
  90. { response_key_id: 8, val: siimeeAnswers.email },
  91. { response_key_id: 7, val: siimeeAnswers.name },
  92. { response_key_id: 11, val: siimeeAnswers.seeking },
  93. ]
  94. document.cookie = `siimee_current_step=${this.currentStep}; max-age=600 ; path=/onboarding ; secure`
  95. document.cookie = `siimee_cache_answered=${JSON.stringify(
  96. this.answered,
  97. )}; max-age=600 ; path=/onboarding ; secure`
  98. document.cookie = `siimee_cache_responses=${JSON.stringify(
  99. this.responses,
  100. )}; max-age=600 ; path=/onboarding ; secure`
  101. document.cookie = 'siimee_answered='
  102. this.currentStep = 6
  103. this.goToStep(this.currentStep)
  104. }
  105. } else if (myCurrentStep) {
  106. this.answered = JSON.parse(myCurrentAnswers)
  107. this.responses = JSON.parse(myCurrentResponses)
  108. this.currentStep = myCurrentStep
  109. this.goToStep(Number(myCurrentStep) + 1)
  110. } else {
  111. this.currentStep = 0
  112. this.goToStep(this.currentStep)
  113. }
  114. }
  115. },
  116. methods: {
  117. onSubmit() {
  118. console.log(JSON.stringify(this.answered))
  119. },
  120. async goToStep(num, maxAge) {
  121. maxAge = 600 // temp measure
  122. document.cookie = `siimee_current_step=${Number(
  123. this.currentStep,
  124. )}; max-age=${maxAge} ; path=/onboarding ; secure`
  125. document.cookie = `siimee_cache_answered=${JSON.stringify(
  126. this.answered,
  127. )}; max-age=${maxAge} ; path=/onboarding ; secure`
  128. document.cookie = `siimee_cache_responses=${JSON.stringify(
  129. this.responses,
  130. )}; max-age=${maxAge} ; path=/onboarding ; secure`
  131. if (num > 6) {
  132. this.validateAccessToken()
  133. }
  134. this.currentStep = num
  135. },
  136. // TODO: Refactor to use cookie's max-age attribute instead of network call for jwt auth
  137. async validateAccessToken() {
  138. const validatedAccessToken = await this.authenticator.validateJwt(
  139. this.accessToken,
  140. )
  141. if (!validatedAccessToken || !validatedAccessToken.isValid) {
  142. const sessionTokenIsValid = await this.validateSessionToken()
  143. if (!sessionTokenIsValid) {
  144. this.goToStep(0)
  145. }
  146. }
  147. },
  148. async validateSessionToken() {
  149. const validatedSessionToken = await this.authenticator.validateJwt(
  150. this.sessionToken,
  151. )
  152. if (!validatedSessionToken || validatedSessionToken.isValid) {
  153. this.accessToken = await this.authenticator.generateJwt({
  154. ...this.answered,
  155. expiration: 60 * 3,
  156. })
  157. return true
  158. } else return false
  159. },
  160. grabCookie(cookieKey) {
  161. const cookies = document.cookie
  162. .split('; ')
  163. .reduce((prev, current) => {
  164. const [name, ...value] = current.split('=')
  165. prev[name] = value.join('=')
  166. return prev
  167. }, {})
  168. const cookieVal =
  169. cookieKey in cookies ? cookies[`${cookieKey}`] : undefined
  170. return cookieVal
  171. },
  172. async updateAnswers(payload) {
  173. if (payload) {
  174. // this.invalidResponse = false
  175. const k = payload.question.survey_stage
  176. this.answered[k] = payload.input
  177. if (!this.survey.validateAnswer(payload)) {
  178. this.invalidResponse = true
  179. return
  180. }
  181. // once validated, don't log password in answered object
  182. this.answered[k] = k === 'password' ? undefined : payload.input
  183. // formats initial responses for response table
  184. const response = {}
  185. response.response_key_id = payload.question.response_key_id
  186. response.val = payload.input
  187. this.responses.push(response)
  188. // sends latest survey response to db
  189. if (this.currentProfileId) {
  190. surveyFactory.addNewSurveyAnswer(
  191. this.responses[this.responses.length - 1],
  192. this.currentProfileId,
  193. )
  194. }
  195. if (k === 'aspects') return
  196. }
  197. if (this.currentStep > this.survey.steps.length) {
  198. this.onSubmit(this.answered)
  199. } else {
  200. this.goToStep(this.currentStep + 1)
  201. }
  202. },
  203. },
  204. }
  205. </script>
  206. <style lang="sass">
  207. .view--onboarding
  208. width: 100%
  209. max-width: 428px
  210. background-color: #fff
  211. color: #1F2024
  212. font-family: Century Gothic,CenturyGothic,AppleGothic,sans-serif
  213. margin: 0 auto
  214. article
  215. height: 100vh
  216. .answers
  217. text-align: center
  218. .w-button
  219. display: flex
  220. width: 315px
  221. height: 60px
  222. border-radius: 6
  223. background-color: #D5D5D5
  224. color: #1F2024
  225. margin: 11px auto
  226. font-weight: bold
  227. font-size: 16px
  228. text-transform: uppercase
  229. &.next-btn
  230. border-radius: 6px
  231. background-color: #5BA626
  232. color: #1F2024
  233. height: 50px
  234. width: 315px
  235. font-size: 18px
  236. padding: 7px
  237. .w-card
  238. background-color: #1F2024
  239. justify-content: center
  240. align-items: center
  241. width: 100%
  242. h3
  243. text-transform: uppercase
  244. text-align: center
  245. font-size: 28px
  246. font-weight: bold
  247. color: white
  248. margin-top: 88px
  249. p
  250. color: white
  251. font-size: 18px
  252. padding: 11px
  253. text-align: center
  254. margin: 22px auto
  255. font-weight: bold
  256. input
  257. display: flex
  258. width: 315px
  259. height: 60px
  260. padding: 11px
  261. border-radius: 6
  262. background-color: #D5D5D5
  263. color: #1F2024
  264. margin: 11px auto
  265. font-weight: bold
  266. font-size: 16px
  267. .w-select
  268. padding: 11px
  269. color: #1F2024
  270. .search-type
  271. color: #1F2024
  272. height: 50px
  273. &.question
  274. p
  275. font-size: 18px
  276. text-align: left
  277. margin: 7px auto
  278. font-weight: normal
  279. section
  280. p
  281. margin: 0
  282. font-weight: bold
  283. text-transform: capitalize
  284. .w-radio__input
  285. &.primary
  286. background-color: #FFFFFF
  287. border: #BCC5D3 1px solid
  288. .w-card__content
  289. .w-button
  290. height: 50px
  291. background-color: #5BA626
  292. </style>