You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

OnboardingView.vue 7.5KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246
  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. :answered='answered'
  13. :currentStep='currentStep'
  14. :is='step.component'
  15. :question='step'
  16. :responses='responses'
  17. :survey='survey'
  18. @handle-submit='onSubmit'
  19. @update-answers='updateAnswers'
  20. v-if='step && currentStep == i'
  21. )
  22. .invalidResponseMessage(
  23. style='text-align: center'
  24. v-if='invalidResponse'
  25. )
  26. p {{ survey.steps[currentStep].invalidInputPrompt }}
  27. footer
  28. p(v-if='currentStep != 0') You have completed: {{ currentStep }} / {{ survey?.steps?.length }} survey steps
  29. article(v-else)
  30. SurveyCompleteView(:answers='answered' :surveySteps='survey?.steps')
  31. </template>
  32. <script>
  33. import { Authenticator } from '../services/auth.service.js'
  34. import { surveyFactory } from '@/utils'
  35. import stepViews from '@/components/onboarding'
  36. import SurveyCompleteView from './SurveyCompleteView.vue'
  37. let hashedAccessToken = null
  38. let currentProfileId = null
  39. export default {
  40. name: 'OnboardingView',
  41. components: {
  42. ...stepViews,
  43. SurveyCompleteView,
  44. },
  45. data: () => ({
  46. answered: {},
  47. aspectQuestions: [],
  48. responses: [],
  49. currentStep: 0,
  50. survey: null,
  51. invalidResponse: false,
  52. authenticator: {},
  53. }),
  54. async created() {
  55. this.survey = await surveyFactory.createSurvey()
  56. this.authenticator = new Authenticator()
  57. hashedAccessToken = this.grabStoredCookie('siimee_access')
  58. try {
  59. const sessionData = await this.validateSession(hashedAccessToken)
  60. currentProfileId = sessionData.profileId
  61. this.responses = sessionData.responses
  62. this.currentStep = this.responses.length + 3
  63. this.goToStep(this.currentStep)
  64. } catch (err) {
  65. console.error('ERROR :=>', err)
  66. this.goToStep(0)
  67. }
  68. },
  69. methods: {
  70. onSubmit() {
  71. console.log(JSON.stringify(this.answered))
  72. },
  73. async goToStep(num) {
  74. this.currentStep = num
  75. },
  76. grabStoredCookie(cookieKey) {
  77. const cookies = document.cookie
  78. .split('; ')
  79. .reduce((prev, current) => {
  80. const [name, ...value] = current.split('=')
  81. prev[name] = value.join('=')
  82. return prev
  83. }, {})
  84. const cookieVal =
  85. cookieKey in cookies ? cookies[`${cookieKey}`] : undefined
  86. return cookieVal
  87. },
  88. async validateSession(hashedAccessToken) {
  89. if (!hashedAccessToken)
  90. return console.warn('WARNING :=> accessToken is not defined')
  91. const validatedToken = await this.authenticator.validateSession(
  92. hashedAccessToken,
  93. )
  94. if (validatedToken.error) {
  95. throw new Error(validatedToken.error)
  96. } else {
  97. return validatedToken
  98. }
  99. },
  100. async updateAnswers(payload) {
  101. if (payload) {
  102. const k = payload.question.survey_stage
  103. this.answered[k] = payload.input
  104. // Once validated, don't log password in answered object
  105. this.answered[k] = k === 'password' ? undefined : payload.input
  106. // Hacky WorkAround for Validating Answers
  107. if (!this.survey.validateAnswer(payload)) {
  108. this.invalidResponse = true
  109. return
  110. }
  111. // Formats initial responses for response table
  112. const response = {}
  113. response.response_key_id = payload.question.response_key_id
  114. response.val = payload.input
  115. this.responses.push(response)
  116. if (k === 'aspects') return
  117. }
  118. // NOTE: If user has finished minimum profile creation,
  119. // Adds survey answers to responses table and verifies tokens on each step
  120. if (currentProfileId) {
  121. await surveyFactory.addNewSurveyAnswer(
  122. this.responses[this.responses.length - 1],
  123. currentProfileId,
  124. )
  125. try {
  126. await this.validateSession(hashedAccessToken)
  127. } catch (err) {
  128. this.currentStep = 0
  129. this.goToStep(this.currentStep)
  130. throw new Error(err)
  131. }
  132. }
  133. if (this.currentStep > this.survey.steps.length) {
  134. this.onSubmit(this.answered)
  135. } else {
  136. this.goToStep(this.currentStep + 1)
  137. }
  138. },
  139. },
  140. }
  141. </script>
  142. <style lang="sass">
  143. .view--onboarding
  144. width: 100%
  145. max-width: 428px
  146. background-color: #fff
  147. color: #1F2024
  148. font-family: Century Gothic,CenturyGothic,AppleGothic,sans-serif
  149. margin: 0 auto
  150. article
  151. height: 100vh
  152. .answers
  153. text-align: center
  154. .w-button
  155. display: flex
  156. width: 315px
  157. height: 60px
  158. border-radius: 6
  159. background-color: #D5D5D5
  160. color: #1F2024
  161. margin: 11px auto
  162. font-weight: bold
  163. font-size: 16px
  164. text-transform: uppercase
  165. &.next-btn
  166. border-radius: 6px
  167. background-color: #5BA626
  168. color: #1F2024
  169. height: 50px
  170. width: 315px
  171. font-size: 18px
  172. padding: 7px
  173. .w-card
  174. background-color: #1F2024
  175. justify-content: center
  176. align-items: center
  177. width: 100%
  178. h3
  179. text-transform: uppercase
  180. text-align: center
  181. font-size: 28px
  182. font-weight: bold
  183. color: white
  184. margin-top: 88px
  185. p
  186. color: white
  187. font-size: 18px
  188. padding: 11px
  189. text-align: center
  190. margin: 22px auto
  191. font-weight: bold
  192. input
  193. display: flex
  194. width: 315px
  195. height: 60px
  196. padding: 11px
  197. border-radius: 6
  198. background-color: #D5D5D5
  199. color: #1F2024
  200. margin: 11px auto
  201. font-weight: bold
  202. font-size: 16px
  203. .w-select
  204. padding: 11px
  205. color: #1F2024
  206. .search-type
  207. color: #1F2024
  208. height: 50px
  209. &.question
  210. p
  211. font-size: 18px
  212. text-align: left
  213. margin: 7px auto
  214. font-weight: normal
  215. section
  216. p
  217. margin: 0
  218. font-weight: bold
  219. text-transform: capitalize
  220. .w-radio__input
  221. &.primary
  222. background-color: #FFFFFF
  223. border: #BCC5D3 1px solid
  224. .w-card__content
  225. .w-button
  226. height: 50px
  227. background-color: #5BA626
  228. </style>