Advertisement
Guest User

surveys Container

a guest
Mar 22nd, 2019
106
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 38.22 KB | None | 0 0
  1. import React from 'react'
  2. import {
  3. View,
  4. Dimensions,
  5. BackHandler,
  6. Platform
  7. } from 'react-native'
  8. import PropTypes from 'prop-types'
  9. import { connect } from 'react-redux'
  10. import Moment from 'moment'
  11. import _ from 'lodash'
  12. import { Styles } from '../../styles'
  13. import {
  14. getSurvey,
  15. createSurveyAnswer,
  16. getSurveyList,
  17. updateSurveyAnswer
  18. } from './store/actions'
  19. import {
  20. surveySelector,
  21. createSurveyAnswerSelector,
  22. updateSurveyAnswerSelector,
  23. surveyListSelector
  24. } from './store/selectors'
  25. import { OfflineNotifier, LoadingSurvey } from './components'
  26. import { SurveyHeader, SurveyStatus, InfoPopup } from './surveyComponents'
  27. import { validateNHS, validateSSN, validateNumberGermany, validateNumberItaly, validateDNI } from './regex'
  28. import {
  29. Survey,
  30. EQ5DSurvey,
  31. SurveyNavigationControl,
  32. EQ5DNavigationControl
  33. } from './'
  34. import translate from '../../content-config/content/main'
  35. import { getSelectors, validatePropsData } from '../../lib/store/dataHelpers'
  36. import { setLocalUser, setUser } from '../../store/common/actions'
  37. import { userSelector } from '../../store/common/selectors'
  38. import { deleteConsentData } from '../consent/store/actions'
  39. import Config from './config'
  40. import ErrorHandling from '../../utils/ErrorHandling'
  41. import { validateConditions } from './validateConditions'
  42. import { GoogleapisServiceProvider } from '../../lib/api/googleapis'
  43. import { isTokenError } from '../../utils'
  44.  
  45. const GoogleapisService = GoogleapisServiceProvider()
  46.  
  47. const screen = Dimensions.get('window')
  48. const dateFormat = 'YYYY-MM-DD HH:mm:ss'
  49. const defaultState = {
  50. surveyData: null,
  51. surveyStartedAt: null,
  52. tooltip: true,
  53. nextPage: null,
  54. pageCounter: 1,
  55. noOfPages: null,
  56. eq5d: null,
  57. loading: false,
  58. pageOrder: [],
  59. responses: {},
  60. resumeSurvey: false,
  61. error: null,
  62. surveyCompleted: false,
  63. leaveSurvey: false,
  64. goBack: false,
  65. errorSubmittingSurvey: false,
  66. getSurveyError: null,
  67. surveyId: null,
  68. thankYouScreenData: {},
  69. errorCode: null,
  70. multipleChoiceQuestions: [],
  71. showUnselectDragDropPopup: null
  72. }
  73.  
  74. const isLoadingProps = (props, state) => {
  75. const { surveyLoading, createSurveyAnswerLoading,
  76. surveyListLoading, updateSurveyAnswerLoading } = props
  77. const { goBack, loading } = state
  78.  
  79. // SurveyListLoading && goBack, need to be theer so that we check if the lsit
  80. // is loading only when we press the goback button, and not when we open a survey
  81. return !loading && (surveyLoading || createSurveyAnswerLoading || updateSurveyAnswerLoading ||
  82. !props.localUser.token || (surveyListLoading && goBack))
  83. }
  84.  
  85. class SurveyContainer extends ErrorHandling {
  86. constructor (props) {
  87. super(props)
  88. this.state = { ...defaultState }
  89. this.multipleChoicesMainPages = {}
  90. this.multipleChoicesMainPageAnswers = {}
  91. }
  92.  
  93. componentDidMount () {
  94. this.getSurveyFromBackend()
  95.  
  96. if (Platform.OS === 'android') {
  97. BackHandler.addEventListener('hardwareBackPress', this.onBackAndroid)
  98. }
  99. }
  100.  
  101. componentWillUnmount () {
  102. BackHandler.removeEventListener('hardwareBackPress', this.onBackAndroid)
  103. }
  104.  
  105. static getDerivedStateFromProps (props, state) {
  106. const { surveySuccess, createSurveyAnswerError, updateSurveyAnswerError, surveyError } = props
  107.  
  108. if (isLoadingProps(props, state)) return { loading: true }
  109.  
  110. if (surveySuccess && state.error) return { error: false, loading: false }
  111.  
  112. if ((createSurveyAnswerError || updateSurveyAnswerError) &&
  113. !isTokenError(createSurveyAnswerError) && !isTokenError(updateSurveyAnswerError))
  114. {
  115. return {
  116. loading: false,
  117. leaveSurvey: false,
  118. errorCode: null,
  119. errorSubmittingSurvey: true
  120. }
  121. }
  122. // if we retry call (token expired) we don't want to set loading to false
  123. if (surveyError && !isTokenError(surveyError)) return { loading: false, getSurveyError: true }
  124.  
  125. return null
  126. }
  127.  
  128. componentDidUpdate (prevProps, prevState) {
  129. const {
  130. surveySuccess,
  131. surveyError,
  132. appState
  133. } = this.props
  134.  
  135. if (prevProps.appState.match(/background|inactive/) && appState === 'active') {
  136. this.createResponseData(true)
  137. }
  138.  
  139. if (surveySuccess && validatePropsData('success', 'survey', prevProps, this.props)) {
  140. return this.onSurveySuccess(surveySuccess)
  141. }
  142.  
  143. if (surveySuccess &&
  144. (validatePropsData('success', 'createSurveyAnswer', prevProps, this.props) ||
  145. (validatePropsData('success', 'updateSurveyAnswer', prevProps, this.props)))) {
  146. this.onSurveyAnswerSuccess()
  147. }
  148.  
  149. if (surveyError && validatePropsData('error', 'survey', prevProps, this.props)) {
  150. return this.checkTokenError(surveyError, () => this.getSurveyFromBackend(), true)
  151. }
  152.  
  153. if ((validatePropsData('error', 'createSurveyAnswer', prevProps, this.props)) ||
  154. (validatePropsData('error', 'updateSurveyAnswer', prevProps, this.props))) {
  155. const { createSurveyAnswerError, updateSurveyAnswerError } = this.props
  156. return this.checkTokenError(createSurveyAnswerError || updateSurveyAnswerError,
  157. () => this.createOrUpdateSurveyAnswer(), false)
  158. }
  159.  
  160. this.onValidatePropsDataSurveysList(prevProps)
  161. }
  162.  
  163. checkTokenError (error, callback, surveyError) {
  164. if (isTokenError(error)) {
  165. if (this.retryCounter > 0) {
  166. this.retryCounter = 0
  167.  
  168. return this.setState({
  169. loading: false,
  170. getSurveyError: surveyError,
  171. errorSubmittingSurvey: true,
  172. errorCode: null,
  173. leaveSurvey: false
  174. })
  175. }
  176. this.refreshTokenAndRetry(() => callback()) // method found in ErrorHandling
  177. }
  178. }
  179.  
  180. onSurveyAnswerSuccess () {
  181. const surveyAnswerResponse = this.getSurveyAnswerResponse()
  182.  
  183. this.setState(prevState => ({
  184. loading: false,
  185. copyResponses: JSON.stringify(prevState.responses),
  186. surveyWithAnswerData: surveyAnswerResponse
  187. }))
  188.  
  189. // If survey completed
  190. if (surveyAnswerResponse.status === 'completed') this.onSurveyCompleted(surveyAnswerResponse)
  191.  
  192. // When navigating back or or putting survey in background
  193. if (this.state.goBack) this.retrieveSurveysList()
  194.  
  195. // call doesn't end when putting app in background
  196. // this.setState({ appState: AppState.currentState }) // TODO: ????
  197. }
  198.  
  199. getSurveyAnswerResponse () {
  200. const { createSurveyAnswerTimestamp, updateSurveyAnswerTimestamp,
  201. createSurveyAnswerSuccess, updateSurveyAnswerSuccess
  202. } = this.props
  203.  
  204. return createSurveyAnswerTimestamp > updateSurveyAnswerTimestamp
  205. ? createSurveyAnswerSuccess
  206. : updateSurveyAnswerSuccess
  207. }
  208.  
  209. onSurveyCompleted (surveyAnswerResponse) {
  210. this.retrieveSurveysList()
  211. this.setCompletedSurveyValue(surveyAnswerResponse)
  212. }
  213.  
  214. getSurveyFromBackend = () => {
  215. const { surveyId, localUser, getSurvey } = this.props
  216.  
  217. if (localUser && surveyId) {
  218. const { token, language } = localUser
  219. getSurvey(surveyId, {
  220. params: {
  221. accessToken: token,
  222. language
  223. }
  224. })
  225. }
  226. }
  227.  
  228. onValidatePropsDataSurveysList (prevProps) {
  229. const { goBack } = this.state
  230.  
  231. if ((validatePropsData('success', 'surveyList', prevProps, this.props) && goBack) ||
  232. validatePropsData('error', 'surveyList', prevProps, this.props)) {
  233. this.goToEdiary()
  234. }
  235. }
  236.  
  237. goToEdiary () { this.setState({ leaveSurvey: false }, () => this.props.goBack()) }
  238.  
  239. isResumeOrExpiredScreenShown = () => {
  240. const { data } = this.props
  241. const { resumeSurvey, surveyAnswerId, surveyData } = this.state
  242. const answerSurveysId = (data && data.answerId) || surveyAnswerId
  243.  
  244. return (surveyAnswerId && surveyData && !resumeSurvey) ||
  245. (answerSurveysId && !resumeSurvey)
  246. }
  247.  
  248. onBackAndroid = () => {
  249. const { surveyLoading, goBack } = this.props
  250. const { leaveSurvey } = this.state
  251. if (leaveSurvey || surveyLoading || this.isResumeOrExpiredScreenShown()) goBack()
  252. else this.onSurveyModalPressed(true)
  253. return true
  254. }
  255.  
  256. goBack = () => {
  257. const { responses, showPopupDate } = this.state
  258. const { fromNotifier, goToDashboard, goBack } = this.props
  259.  
  260. if (Object.keys(responses).length > 0 || showPopupDate) {
  261. this.leavePageCheckValidInput(() => this.createResponseData(true, 'goBack'))
  262. return
  263. }
  264. if (fromNotifier) return goToDashboard()
  265. goBack()
  266. }
  267.  
  268. toggleInfoPopup = (value, firstTime) => {
  269. const { surveyData } = this.state
  270.  
  271. if (firstTime && surveyData.showDragAndDropPopup === 'no') return
  272.  
  273. if (firstTime && surveyData.showDragAndDropPopup === 'yes') {
  274. return this.setState({ showInfoPopup: value, firstTimePopup: true, updateDragDropModalValue: true })
  275. }
  276. this.setState({ showInfoPopup: value })
  277. }
  278.  
  279. onCloseFirstTimePopup = () => {
  280. this.setState({ showInfoPopup: false, firstTimePopup: false })
  281. }
  282.  
  283. retrieveSurveysList () {
  284. const { localUser, getSurveyList } = this.props
  285. const { token, language } = localUser
  286.  
  287. getSurveyList({
  288. params: {
  289. accessToken: token,
  290. language
  291. }
  292. })
  293. }
  294.  
  295. setResumeSurveyValue = () => {
  296. this.setState({
  297. resumeSurvey: true,
  298. // We reset startedAt when we start again, an expired response
  299. surveyStartedAt: Moment().format(dateFormat)
  300. })
  301. }
  302.  
  303. setCompletedSurveyValue = surveyAnswerResponse => {
  304. this.setState({
  305. surveyCompleted: true,
  306. thankYouScreenData: surveyAnswerResponse
  307. })
  308. }
  309.  
  310. setError = value => this.setState({ error: value })
  311.  
  312. addResponse = (id, response, callback) => {
  313. const { pageOrder, pageCounter, responses, surveyData, multipleChoiceQuestions } = this.state
  314. const currentPage = pageOrder[pageCounter - 1]
  315. response.page = currentPage
  316. responses[id] = response
  317. const minPages = surveyData.pages[currentPage].minPages
  318. const pageInputType = surveyData.pages[pageOrder[pageCounter - 1]].pageInputType
  319. let lengthMultipleChoiceElements = 0
  320. if (this.multipleChoicesMainPageAnswers[currentPage]) {
  321. const mainPage = this.multipleChoicesMainPages[this.multipleChoicesMainPageAnswers[currentPage].mainPage]
  322. lengthMultipleChoiceElements = this.getLenghtMultipleChoiceOrMainArray(multipleChoiceQuestions, mainPage, currentPage)
  323. }
  324.  
  325. let mQuestions = multipleChoiceQuestions
  326. // Case multiple choice, and exclude multiple choice and radio types of answers
  327. if (pageInputType === 'multipleChoices' && typeof response.value === 'object') {
  328. const result = this.addReponseForMultipleChoice(response, lengthMultipleChoiceElements)
  329. mQuestions = result.mQuestions
  330. lengthMultipleChoiceElements = result.lengthMultipleChoiceElements
  331. }
  332.  
  333. this.setState({
  334. responses,
  335. multipleChoiceQuestions: mQuestions,
  336. noOfPages: minPages + pageCounter - 1 + lengthMultipleChoiceElements
  337. }, () => {
  338. if (callback) return callback()
  339. this.checkNextPage()
  340. })
  341. }
  342.  
  343. deleteSurveyConsentData = () => this.props.deleteConsentData('surveys_consent')
  344.  
  345. deleteResponse = id => { // uncheck answer
  346. const { responses, noOfPages, surveyData, pageOrder, pageCounter } = this.state
  347. const pageInputType = surveyData.pages[pageOrder[pageCounter - 1]].pageInputType
  348. delete responses[id]
  349. // Case multiple choice answers
  350. if (pageInputType === 'multipleChoices') {
  351. this.deleteDataMultipleChoice()
  352. return this.setState({
  353. responses,
  354. noOfPages: noOfPages - 1,
  355. multipleChoiceQuestions: []
  356. }, this.checkNextPage)
  357. }
  358. this.checkNextPage()
  359. }
  360.  
  361. setSurveyWithAnswers (survey, surveyAnswer) {
  362. const { responses, minPagesLeft, pageOrder, id, multipleChoiceQuestions = [],
  363. multipleChoicesMainPageAnswers, multipleChoicesMainPages } = surveyAnswer
  364. const length = pageOrder.length
  365. const { variablePrefix } = survey
  366. const multipleChoiceQuestionsLength = multipleChoiceQuestions.length > 0
  367. ? multipleChoiceQuestions.length : 0
  368.  
  369. this.multipleChoicesMainPageAnswers = multipleChoicesMainPageAnswers || []
  370. this.multipleChoicesMainPages = multipleChoicesMainPages || []
  371.  
  372. this.setState({
  373. surveyAnswerId: id,
  374. surveyData: survey,
  375. pageOrder,
  376. responses,
  377. multipleChoiceQuestions,
  378. noOfPages: length + minPagesLeft - 1 + multipleChoiceQuestionsLength,
  379. pageCounter: length,
  380. eq5d: variablePrefix === 'eq_5d',
  381. loading: false,
  382. copyResponses: JSON.stringify(responses),
  383. errorCode: null
  384. }, this.checkNextPage)
  385. }
  386.  
  387. setSurvey (survey) {
  388. const { pageOrder } = this.state
  389. const { pages, firstPage, variablePrefix } = survey
  390. pageOrder.length = 0
  391. pageOrder.push(survey.firstPage)
  392.  
  393. this.setState({
  394. surveyData: survey,
  395. surveyStartedAt: Moment().format(dateFormat),
  396. noOfPages: pages[firstPage].minPages,
  397. eq5d: variablePrefix === 'eq_5d',
  398. loading: false,
  399. nextPage: survey.firstPage,
  400. errorCode: null,
  401. responses: {},
  402. pageCounter: 1
  403. })
  404. }
  405.  
  406. onSurveySuccess (surveyResponse) {
  407. const { survey, surveyAnswer } = surveyResponse
  408. const expired = surveyAnswer && surveyAnswer.status === 'expired'
  409.  
  410. if (surveyAnswer && !expired) return this.setSurveyWithAnswers(survey, surveyAnswer)
  411. this.setSurvey(survey)
  412. }
  413.  
  414. onSurveyModalPressed = value => {
  415. const { surveyError } = this.props
  416.  
  417. if (surveyError) return this.props.goBack()
  418. this.setState({ leaveSurvey: value })
  419. }
  420.  
  421. swithThroughConditions (conditions, responses) {
  422. let conditionsPassed = true
  423. conditions.map(block => {
  424. // skip the other validations if there is a failed condition
  425. if (conditionsPassed) {
  426. const response = responses[block.inputId]
  427. conditionsPassed = validateConditions[block.condition](block, response)
  428. }
  429. })
  430. return conditionsPassed
  431. }
  432.  
  433. getNextPage (nextPage, responses) {
  434. let result = null
  435. let conditions = null
  436. const conditionals = nextPage.if ? nextPage.if : null
  437.  
  438. if (conditionals) {
  439. conditionals.map(cond => {
  440. // skip the other conditionals if a result has been found
  441. if (!result) {
  442. conditions = cond.conditions
  443. if (this.swithThroughConditions(conditions, responses)) result = cond
  444. }
  445. })
  446. if (result) return result.page
  447. if (nextPage.else) return nextPage.else
  448. return nextPage.page
  449. }
  450. return nextPage.page
  451. }
  452.  
  453. hasResponseData (data) {
  454. if (!data) return false
  455. return data.value !== null && data.value !== undefined && data.value !== ''
  456. }
  457.  
  458. hasItemDependencies (item, responses) {
  459. const { disableDependency } = item
  460.  
  461. if (!disableDependency) return false
  462.  
  463. let hasData = true
  464. disableDependency.map(dependency => {
  465. // if there is an undefined response the other dependencies are skipped
  466. if (hasData) {
  467. hasData = this.hasResponseData(responses[dependency])
  468. }
  469. })
  470. return hasData
  471. }
  472.  
  473. isRequiredItem (item) { return item.input && (item.required === 1) }
  474.  
  475. addSliderDefalutResponse (item) {
  476. const { id, field, parents, sliderInfo } = item
  477. const defaultVal = (sliderInfo && (sliderInfo.min || sliderInfo.min === 0)) ? sliderInfo.min : ''
  478. const response = {
  479. field: field,
  480. value: defaultVal,
  481. parents: parents,
  482. disabled: false
  483. }
  484. this.addResponse(id, response, () => {
  485. return true
  486. })
  487. }
  488.  
  489. validateSecurityHealthNumber (value) {
  490. const { country } = this.props.localUser
  491.  
  492. const validations = {
  493. UK: () => validateNHS(value),
  494. US: () => validateSSN(value),
  495. IT: () => validateNumberItaly(value),
  496. DE: () => validateNumberGermany(value),
  497. ES: () => validateDNI(value)
  498. }
  499. return validations[country]()
  500. }
  501.  
  502. validatePageData (pageData, responses) {
  503. const { items } = pageData
  504. let isValid = true
  505. let timburdenPreviousItemValue = null
  506.  
  507. items.map(item => {
  508. const { validation } = item
  509. if (item.value) timburdenPreviousItemValue = item.value
  510. // if an invalid response is found will skip the other checks
  511. if (item.sliderInfo && (item.sliderInfo.min || item.sliderInfo.min === 0) &&
  512. !(this.hasResponseData(responses[item.id]))) {
  513. return this.addSliderDefalutResponse(item)
  514. }
  515. if (isValid && this.isRequiredItem(item) &&
  516. (!(this.hasResponseData(responses[item.id]) || item.value || timburdenPreviousItemValue)) &&
  517. !this.hasItemDependencies(item, responses)) {
  518. if (validation === 'hours') {
  519. this.setState({ error: Config.surveysGeneralConfig.errorMessages['hours'] })
  520. } else this.setState({ error: Config.surveysGeneralConfig.errorMessages[item.input] })
  521. isValid = false
  522. }
  523. if (isValid && validation && validation !== 'month') {
  524. const value = (responses[item.id] && responses[item.id].value) || item.value
  525. if (!value && !this.isRequiredItem(item)) return // if no value, and field is optional => no need for validations
  526. if (validation === 'SSN') { // here should be added validation for popup if needed
  527. isValid = this.validateSecurityHealthNumber(value)
  528. if (!isValid) this.setState({ error: Config.surveysGeneralConfig.errorMessages['nhs'] })
  529. }
  530. }
  531. })
  532. return isValid
  533. }
  534.  
  535. checkNextPage () {
  536. const { pageOrder, pageCounter, surveyData, responses } = this.state
  537. const currentPage = pageOrder[pageCounter - 1]
  538. const nextPage = this.getNextPage(surveyData.pages[currentPage].nextPage, responses)
  539.  
  540. this.setState({ nextPage, error: null })
  541. return nextPage
  542. }
  543.  
  544. processString (string) { return string.replace(/\s/g, '').toLowerCase() }
  545.  
  546. interpretAsyncResults = ({results, status}, callback, zipCode) => {
  547. const { country } = this.props.localUser
  548. let avCountriesZipcode = false
  549. let zipCodeMatch = false
  550.  
  551. if (status !== 'OK') return callback(status, 'zipCode')
  552. let found = false
  553.  
  554. let userCountry = country
  555. if (country === 'UK') userCountry = 'GB'
  556.  
  557. results.forEach(result => {
  558. if (result && result.address_components && (result.types[0] === 'postal_code')) {
  559. result.address_components.map(({ types, short_name }) => {
  560. if (types && (types[0] === 'postal_code') &&
  561. (this.processString(short_name) === this.processString(zipCode))) {
  562. zipCodeMatch = true
  563. }
  564.  
  565. if (types && (types[0] === 'country') &&
  566. (userCountry === short_name)) {
  567. avCountriesZipcode = true
  568. }
  569. })
  570. if (avCountriesZipcode && zipCodeMatch) found = true
  571. }
  572. })
  573.  
  574. if (found) return callback(null)
  575.  
  576. this.setState({ error: translate('surveyItemErrors', 'zipcode') })
  577. return callback(status, 'zipCode')
  578. }
  579.  
  580. resolveValidationPromises = (promises, callback, zipCode) => {
  581. let noAsyncValidation = false
  582.  
  583. Promise.all(promises).then((results) => {
  584. results.forEach((response, index) => {
  585. if (response === 'noAsyncValidation') noAsyncValidation = true
  586. else return this.interpretAsyncResults(response, callback, zipCode)
  587.  
  588. if (noAsyncValidation && index === results.length - 1) {
  589. return callback(null, 'no_async_validation')
  590. }
  591. })
  592. })
  593. }
  594.  
  595. checkItemAsyncValidations = ({items}, responses, callback) => {
  596. const promises = []
  597. let zipCode = ''
  598.  
  599. items.forEach(({id, value, field}) => {
  600. const usedValue = (responses[id] && typeof responses[id].value === 'string')
  601. ? responses[id].value
  602. : value
  603.  
  604. if (field === 'zipCode') {
  605. const region = this.props.localUser.country
  606. promises.push(GoogleapisService.checkZipcode({ zipCode: usedValue, region }))
  607. zipCode = usedValue
  608. } else promises.push('noAsyncValidation')
  609. })
  610. this.resolveValidationPromises(promises, callback, zipCode)
  611. }
  612.  
  613. onPressPrevious = () => {
  614. const { pageOrder, pageCounter } = this.state
  615. const currentPageNo = pageCounter
  616.  
  617. pageOrder.pop()
  618.  
  619. currentPageNo >= 1 && this.setState({
  620. pageCounter: currentPageNo - 1,
  621. pageOrder: pageOrder,
  622. error: null
  623. }, () => this.checkNextPage)
  624. }
  625.  
  626. onPressNext = () => {
  627. const { pageOrder, pageCounter, surveyData, responses } = this.state
  628. const currentPage = pageOrder[pageCounter - 1]
  629. const pageData = surveyData.pages[currentPage]
  630.  
  631. if (this.pageHasAsyncValidation(pageData)) {
  632. return this.checkItemAsyncValidations(pageData, responses, (err, field) => {
  633. if (err && field === 'zipCode') {
  634. return this.setState({ error: translate('surveyItemErrors', 'zipcode') })
  635. }
  636. this.validateDataAndGetNextPage(pageData, responses)
  637. })
  638. }
  639. this.validateDataAndGetNextPage(pageData, responses)
  640. }
  641.  
  642. pageHasAsyncValidation (pageData) {
  643. const pageInputType = pageData.pageInputType || null
  644. return pageInputType && pageInputType === 'hasAsyncValidations'
  645. }
  646.  
  647. leavePageCheckValidInput = (callback) => {
  648. const { pageOrder, pageCounter, surveyData, responses } = this.state
  649. const pageData = surveyData.pages[pageOrder[pageCounter - 1]]
  650.  
  651. if (this.pageHasAsyncValidation(pageData)) {
  652. return this.checkItemAsyncValidations(pageData, responses, (err, field) => {
  653. if (err && field === 'zipCode') {
  654. const { id, value } = pageData.items[0]
  655. responses[id].value = value
  656. this.setState({ responses })
  657. }
  658. callback()
  659. })
  660. }
  661. callback()
  662. }
  663.  
  664. composeResponseData = intermediary => {
  665. const {
  666. pageOrder,
  667. pageCounter,
  668. surveyData,
  669. responses,
  670. surveyStartedAt,
  671. multipleChoiceQuestions
  672. } = this.state
  673. const { title, version, expiresIn } = surveyData
  674. const { surveyId, localUser } = this.props
  675. const { timezoneOffset } = localUser
  676. const currentPage = pageOrder[pageCounter - 1]
  677.  
  678. const newData = {
  679. title,
  680. version: version || null,
  681. expiresIn,
  682. surveyId,
  683. responses,
  684. pageOrder,
  685. timezoneOffset,
  686. multipleChoiceQuestions,
  687. multipleChoicesMainPages: this.multipleChoicesMainPages,
  688. multipleChoicesMainPageAnswers: this.multipleChoicesMainPageAnswers,
  689. startedAt: surveyStartedAt,
  690. minPagesLeft: surveyData.pages[currentPage].minPages,
  691. completionDate: !intermediary && Moment().format()
  692. }
  693.  
  694. return newData
  695. }
  696.  
  697. doNotCreadeOrUpdateSurveyAnswer (requestSource) {
  698. const {
  699. responses,
  700. copyResponses,
  701. showPopupDate
  702. } = this.state
  703. const {
  704. createSurveyAnswerLoading,
  705. updateSurveyAnswerLoading
  706. } = this.props
  707. const sameResponses = copyResponses === JSON.stringify(responses)
  708. const responseIsEmpty = JSON.stringify(responses) === '{}'
  709.  
  710. // Verify if not the same response, but if there is another call in progress
  711. return ((sameResponses ||
  712. responseIsEmpty ||
  713. createSurveyAnswerLoading ||
  714. updateSurveyAnswerLoading) &&
  715. !showPopupDate &&
  716. requestSource !== 'goBack' &&
  717. requestSource !== 'endSurvey')
  718. }
  719.  
  720. resetErrorSubmit = () => this.setState({ errorSubmittingSurvey: false })
  721.  
  722. update (...args) { this.props.updateSurveyAnswer(...args) }
  723.  
  724. createOrUpdateSurveyAnswer (intermediary) {
  725. const { surveyAnswerId, surveyWithAnswerData, updateDragDropModalValue } = this.state
  726. const { createSurveyAnswer, answerId, data, localUser } = this.props
  727.  
  728. const newData = this.composeResponseData(intermediary)
  729. if (updateDragDropModalValue) {
  730. newData.showDragAndDropPopup = 'no'
  731. this.setState({ updateDragDropModalValue: false })
  732. }
  733.  
  734. const surveyWithAnswerId = surveyWithAnswerData && surveyWithAnswerData.surveyAnswerId
  735. const answerSurveysId = answerId || surveyAnswerId || surveyWithAnswerId
  736. const { token, language } = localUser
  737. const params = {params: {accessToken: token, language}}
  738.  
  739. this.resetErrorSubmit()
  740. answerSurveysId && token && (data.status !== 'expired' ||
  741. (surveyWithAnswerData && surveyWithAnswerData.status !== 'expired'))
  742. ? this.update(answerSurveysId, newData, params)
  743. : createSurveyAnswer(newData, params)
  744. }
  745.  
  746. createResponseData (intermediary, requestSource) {
  747. const { surveyData } = this.state
  748.  
  749. if (!surveyData) return
  750.  
  751. if (requestSource === 'goBack') this.setState({goBack: true})
  752. else this.setState({goBack: false})
  753.  
  754. if (this.doNotCreadeOrUpdateSurveyAnswer(requestSource)) return
  755.  
  756. this.createOrUpdateSurveyAnswer(intermediary)
  757. }
  758.  
  759. // HERE STARTS MULTIPLE CHOICE QUESTION LOGIC
  760. deleteMultipleChoice = () => { // 'don't know' answer
  761. const { noOfPages, multipleChoiceQuestions } = this.state
  762. const lengthMultipleChoiceElements = multipleChoiceQuestions.length
  763.  
  764. this.deleteDataMultipleChoice()
  765. this.setState({
  766. multipleChoiceQuestions: [],
  767. noOfPages: noOfPages - lengthMultipleChoiceElements
  768. })
  769. }
  770.  
  771. deleteDataMultipleChoice () {
  772. const { surveyData, pageOrder, pageCounter } = this.state
  773.  
  774. const currentPage = pageOrder[pageCounter - 1]
  775. // temporary fix becauase it's called every time uncheck a box on any question
  776. if (surveyData.pages[pageOrder[pageCounter - 1]].pageInputType === 'multipleChoices') {
  777. this.multipleChoicesMainPages[currentPage] = {}
  778. this.multipleChoicesMainPageAnswers = _.pickBy(this.multipleChoicesMainPageAnswers, value => value.mainPage !== currentPage)
  779. }
  780. }
  781.  
  782. addReponseForMultipleChoice = (response, lengthMultipleChoiceElements) => {
  783. const { pageOrder, pageCounter, responses, surveyData } = this.state
  784. const currentPage = pageOrder[pageCounter - 1]
  785.  
  786. const data = {
  787. responses,
  788. pageData: surveyData.pages[currentPage],
  789. nextPage: surveyData.pages[pageOrder[pageCounter - 1]].nextPage,
  790. lengthMultipleChoiceElements
  791. }
  792. const optionValues = surveyData.pages[pageOrder[pageCounter - 1]].items[0].values
  793. const { multipleChoicePickedValues } =
  794. this.getMultipleChoicePickedValues(data, response.value, optionValues, { isAddResponse: true })
  795. return {
  796. mQuestions: multipleChoicePickedValues,
  797. lengthMultipleChoiceElements: response.value.length
  798. }
  799. }
  800.  
  801. getLenghtMultipleChoiceOrMainArray = (multipleChoiceQuestions, mainPage, currentPage) => {
  802. let lengthMultipleChoiceElements = multipleChoiceQuestions.length
  803. let mainPageArray = Object.keys(mainPage)
  804. const mainPageLength = mainPageArray.length
  805. mainPageArray = mainPageArray.slice(mainPageArray.indexOf(currentPage) + 1, mainPageLength)
  806. if (mainPageLength > 3) lengthMultipleChoiceElements = mainPageArray.length
  807. return lengthMultipleChoiceElements
  808. }
  809.  
  810. updateStateAndCheckNextPage = (data) => this.setState(data, () => this.checkNextPage())
  811.  
  812. getMultipleChoicePickedValues = (data, pickedValues, allPossibleValues, isAddResponse) => {
  813. const { pageData } = data
  814. const { pageOrder, pageCounter } = this.state
  815.  
  816. const currentPage = pageOrder[pageCounter - 1]
  817.  
  818. const multipleChoicePickedValues = []
  819. allPossibleValues.map((allValue, index) => {
  820. pickedValues.map(pickedValue => {
  821. if (allValue === pickedValue) {
  822. multipleChoicePickedValues.push(pageData.multipleChoiceQuestions[index])
  823. }
  824. })
  825. })
  826.  
  827. this.refreshMainPageAnswers(multipleChoicePickedValues, currentPage)
  828. const isInPageOrder = pageOrder.findIndex(val => val === multipleChoicePickedValues[0])
  829.  
  830. const newLength = multipleChoicePickedValues.length
  831. if (isInPageOrder < 0 && !isAddResponse) {
  832. pageOrder.push(multipleChoicePickedValues[0])
  833. multipleChoicePickedValues.splice(0, 1)
  834. }
  835.  
  836. return { multipleChoicePickedValues, newLength }
  837. }
  838.  
  839. refreshMainPageAnswers (pickedValues, currentPage) {
  840. this.multipleChoicesMainPages[currentPage] = {}
  841. const newAnswers = {}
  842. newAnswers[currentPage] = { nextPage: pickedValues[0] }
  843. pickedValues.forEach((object, index) => {
  844. newAnswers[object] = { nextPage: pickedValues[index + 1] }
  845. if (!this.multipleChoicesMainPageAnswers[object]) {
  846. this.multipleChoicesMainPageAnswers[object] = { mainPage: currentPage }
  847. }
  848. })
  849. this.multipleChoicesMainPages[currentPage] = newAnswers
  850. }
  851.  
  852. updatePageProgressIfPickedValues = (data, pickedValues) => {
  853. const { nextPage } = data
  854. const { pageOrder, pageCounter, surveyData } = this.state
  855. const allPossibleValues = surveyData.pages[pageOrder[pageCounter - 1]].items[0].values
  856. const {
  857. multipleChoicePickedValues,
  858. newLength
  859. } = this.getMultipleChoicePickedValues(data, pickedValues, allPossibleValues)
  860.  
  861. const stateData = {
  862. multipleChoiceQuestions: multipleChoicePickedValues,
  863. pageCounter: pageCounter + 1,
  864. pageOrder,
  865. noOfPages: surveyData.pages[nextPage].minPages + pageCounter + newLength
  866. }
  867. this.updateStateAndCheckNextPage(stateData)
  868. }
  869.  
  870. updatePageProgressIfMultipleQuestion = (data) => {
  871. const { responses, nextPage, lengthMultipleChoiceElements } = data
  872. const { pageOrder, pageCounter } = this.state
  873. const pickedValues = responses[pageOrder[pageCounter - 1] + '_item1'] &&
  874. responses[pageOrder[pageCounter - 1] + '_item1'].value
  875. if (!pickedValues) return this.updatePageProgressAnyQuestion(nextPage, lengthMultipleChoiceElements)
  876. this.updatePageProgressIfPickedValues(data, pickedValues)
  877. }
  878.  
  879. updatePageProgressAnyQuestion = (nextPage, lengthMultipleChoiceElements) => {
  880. const { pageOrder, pageCounter, surveyData } = this.state
  881. pageOrder.push(nextPage)
  882. const stateData = {
  883. pageCounter: pageCounter + 1,
  884. pageOrder,
  885. noOfPages: surveyData.pages[nextPage].minPages + pageCounter + lengthMultipleChoiceElements
  886. }
  887. this.updateStateAndCheckNextPage(stateData)
  888. }
  889.  
  890. getLenghtAndUpdateMultipleChoice = (multipleChoiceQuestions, mainPage, currentPage) => {
  891. multipleChoiceQuestions.splice(0, 1)
  892. this.setState({ multipleChoiceQuestions })
  893. let lengthMultipleChoiceElements = multipleChoiceQuestions.length
  894. let mainPageArray = Object.keys(mainPage)
  895. const mainPageLength = mainPageArray.length
  896. mainPageArray = mainPageArray.slice(mainPageArray.indexOf(currentPage) + 2, mainPageLength)
  897. if (mainPageLength > 3) lengthMultipleChoiceElements = mainPageArray.length
  898. return lengthMultipleChoiceElements
  899. }
  900.  
  901. validateDataAndGetNextPage = (pageData, responses) => {
  902. const { multipleChoiceQuestions, pageOrder, pageCounter } = this.state
  903. const currentPage = pageOrder[pageCounter - 1]
  904. let lengthMultipleChoiceElements = 0
  905.  
  906. if (!this.validatePageData(pageData, responses)) return false
  907. let nextPage = this.getNextPage(pageData.nextPage, responses)
  908.  
  909. if (this.multipleChoicesMainPageAnswers[currentPage]) {
  910. const mainPage = this.multipleChoicesMainPages[this.multipleChoicesMainPageAnswers[currentPage].mainPage]
  911. if (mainPage[currentPage].nextPage) nextPage = mainPage[currentPage].nextPage
  912. lengthMultipleChoiceElements = this.getLenghtAndUpdateMultipleChoice(multipleChoiceQuestions, mainPage, currentPage)
  913. }
  914.  
  915. if (pageData.pageInputType === 'multipleChoices') { // new multiple choice page
  916. const data = { pageData, responses, nextPage, lengthMultipleChoiceElements }
  917. return this.updatePageProgressIfMultipleQuestion(data)
  918. }
  919. if (nextPage) return this.updatePageProgressAnyQuestion(nextPage, lengthMultipleChoiceElements)
  920. // the extra check of next page it's for not selecting any option yet
  921. this.createResponseData(false, 'endSurvey')
  922. }
  923. // HERE ENDS MULTIPLE CHOICE QUESTION LOGIC
  924.  
  925. renderHeader () {
  926. const { eq5d, pageCounter, noOfPages, surveyData, loading } = this.state
  927. return (
  928. <SurveyHeader
  929. eq5d={eq5d}
  930. backButtonDisabled={loading}
  931. pageCounter={pageCounter}
  932. onBackPressed={this.onBackAndroid}
  933. noOfPages={noOfPages}
  934. surveyData={surveyData} />
  935. )
  936. }
  937.  
  938. renderSurveyPages () {
  939. const {
  940. pageOrder,
  941. pageCounter,
  942. surveyData,
  943. eq5d,
  944. responses,
  945. error,
  946. leaveSurvey,
  947. loading
  948. } = this.state
  949. const { navigate } = this.props
  950. const currentPage = pageOrder[pageCounter - 1]
  951. const firstPage = surveyData.firstPage
  952. const pages = surveyData.pages
  953. const pageData = currentPage && (pages[currentPage] || pages[firstPage] || {})
  954.  
  955. return eq5d
  956. ? <EQ5DSurvey
  957. goBack={this.goBack}
  958. leaveSurvey={leaveSurvey}
  959. onSurveyModalPressed={this.onSurveyModalPressed}
  960. addResponse={this.addResponse}
  961. deleteResponse={this.deleteResponse}
  962. id={currentPage}
  963. pageOrder={pageOrder}
  964. isLoading={loading}
  965. page={pageData}
  966. error={error}
  967. responses={responses}
  968. setError={this.setError} />
  969. : <Survey
  970. goBack={this.goBack}
  971. toggleInfoPopup={this.toggleInfoPopup}
  972. leaveSurvey={leaveSurvey}
  973. onSurveyModalPressed={this.onSurveyModalPressed}
  974. error={error}
  975. addResponse={this.addResponse}
  976. deleteResponse={this.deleteResponse}
  977. id={currentPage}
  978. pageOrder={pageOrder}
  979. isLoading={loading}
  980. navigate={navigate}
  981. deleteMultipleChoice={this.deleteMultipleChoice}
  982. page={pageData}
  983. responses={responses}
  984. setError={this.setError}
  985. createTimeburdenSpecialAnswer={this.createTimeburdenSpecialAnswer} />
  986. }
  987.  
  988. renderBottomControls () {
  989. const {
  990. pageCounter,
  991. surveyData,
  992. eq5d,
  993. nextPage,
  994. noOfPages,
  995. loading,
  996. errorSubmittingSurvey
  997. } = this.state
  998. const isLastPage = pageCounter === noOfPages && typeof nextPage !== 'string'
  999.  
  1000. return eq5d
  1001. ? <EQ5DNavigationControl
  1002. eq5d={eq5d}
  1003. isFirstPage={ pageCounter < 2 }
  1004. isLastPage={isLastPage}
  1005. loading={loading}
  1006. errorSubmit={errorSubmittingSurvey}
  1007. buttonInfo={surveyData}
  1008. onPressNext={this.onPressNext}
  1009. onPressPrevious={this.onPressPrevious} />
  1010. : <SurveyNavigationControl
  1011. eq5d={eq5d}
  1012. isFirstPage={ pageCounter < 2 }
  1013. isLastPage={isLastPage}
  1014. loading={loading}
  1015. resetErrorSubmit={this.resetErrorSubmit}
  1016. errorSubmit={errorSubmittingSurvey}
  1017. buttonInfo={surveyData}
  1018. onPressNext={this.onPressNext}
  1019. onPressPrevious={this.onPressPrevious} />
  1020. }
  1021.  
  1022. renderLoadingSurveyData () {
  1023. const { surveyLoading } = this.props
  1024. const { getSurveyError } = this.state
  1025. const { text, icon, error, button } = Config.loadingConfig.loading
  1026. let loadingMessage = text
  1027. if (getSurveyError) loadingMessage = error
  1028. if (surveyLoading) loadingMessage = text
  1029.  
  1030. return (
  1031. <LoadingSurvey
  1032. loadingImage={icon}
  1033. loadingError={getSurveyError && !surveyLoading}
  1034. button={button}
  1035. onButtonPressed={() => this.getSurveyFromBackend()}
  1036. message={loadingMessage} />
  1037. )
  1038. }
  1039.  
  1040. renderSurveyStatus () {
  1041. const {
  1042. data,
  1043. goBack,
  1044. surveyError,
  1045. surveyLoading,
  1046. localUser,
  1047. surveyId
  1048. } = this.props
  1049. const {
  1050. pageCounter,
  1051. noOfPages,
  1052. surveyCompleted,
  1053. surveyData,
  1054. thankYouScreenData
  1055. } = this.state
  1056. const surveyDataInfo = Object.keys(data).length ? data : surveyData
  1057.  
  1058. if (!surveyDataInfo.status) {
  1059. surveyDataInfo.status = localUser.surveys[surveyId]
  1060. ? localUser.surveys[surveyId].lastAnswerStatus
  1061. : ''
  1062. }
  1063.  
  1064. return (
  1065. <SurveyStatus
  1066. loadingData={surveyLoading}
  1067. surveyError={surveyError}
  1068. goToSurvey={this.setResumeSurveyValue}
  1069. surveyCompleted={surveyCompleted}
  1070. pageCounter={pageCounter}
  1071. noOfPages={noOfPages}
  1072. goBack={goBack}
  1073. surveyData={surveyDataInfo}
  1074. thankYouScreen={thankYouScreenData} />
  1075. )
  1076. }
  1077.  
  1078. renderInfoPopup = () => {
  1079. const { showInfoPopup, firstTimePopup } = this.state
  1080.  
  1081. if (showInfoPopup) {
  1082. return (
  1083. <InfoPopup
  1084. firstTimePopup={firstTimePopup}
  1085. onCloseFirstTimePopup={this.onCloseFirstTimePopup}
  1086. onPopupShown={this.toggleInfoPopup} />
  1087. )
  1088. }
  1089. }
  1090.  
  1091. renderOfflineNotifier () {
  1092. return (
  1093. <OfflineNotifier
  1094. text={translate('general', 'noInternetConnection')}
  1095. />
  1096. )
  1097. }
  1098.  
  1099. renderSurveyContent () {
  1100. const { surveyLoading, surveyError } = this.props
  1101. const { eq5d, surveyData } = this.state
  1102. const backgroundColor = eq5d
  1103. ? Styles.mainColors.WHITE
  1104. : Styles.mainColors.SCREEN_DEFAULT_BACKGROUND_COLOR
  1105.  
  1106. return (
  1107. <View style={{ height: screen.height, backgroundColor }}>
  1108. {this.renderHeader()}
  1109. {this.renderOfflineNotifier()}
  1110. {(surveyLoading || surveyError || !surveyData) && this.renderLoadingSurveyData()}
  1111. {!surveyLoading && surveyData && this.renderSurveyPages()}
  1112. {this.renderInfoPopup()}
  1113. {!surveyLoading && surveyData && this.renderBottomControls()}
  1114. </View>
  1115. )
  1116. }
  1117.  
  1118. render () {
  1119. const { data } = this.props
  1120. const { resumeSurvey, surveyCompleted, surveyAnswerId, surveyData } = this.state
  1121. const answerSurveysId = (data && data.answerId) || surveyAnswerId
  1122.  
  1123. if ((surveyAnswerId && surveyData && !resumeSurvey) ||
  1124. (answerSurveysId && !resumeSurvey) || surveyCompleted) {
  1125. return this.renderSurveyStatus()
  1126. }
  1127.  
  1128. return this.renderSurveyContent()
  1129. }
  1130. }
  1131.  
  1132. const mapStateToProps = state => {
  1133. return {
  1134. ...getSelectors(surveySelector, 'surveySelector', state),
  1135. ...getSelectors(createSurveyAnswerSelector, 'createSurveyAnswerSelector', state),
  1136. ...getSelectors(updateSurveyAnswerSelector, 'updateSurveyAnswerSelector', state),
  1137. ...getSelectors(surveyListSelector, 'surveyListSelector', state),
  1138. localUser: userSelector(state) || {}
  1139. }
  1140. }
  1141.  
  1142. const mapDispatchToProps = {
  1143. getSurvey,
  1144. getSurveyList,
  1145. createSurveyAnswer,
  1146. updateSurveyAnswer,
  1147. deleteConsentData,
  1148. setLocalUser,
  1149. setUser
  1150. }
  1151.  
  1152. export default connect(mapStateToProps, mapDispatchToProps)(SurveyContainer)
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement