daily pastebin goal
47%
SHARE
TWEET

surveys Container

a guest Mar 22nd, 2019 56 Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  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)
RAW Paste Data
We use cookies for various purposes including analytics. By continuing to use Pastebin, you agree to our use of cookies as described in the Cookies Policy. OK, I Understand
 
Top