daily pastebin goal
4%
SHARE
TWEET

Survey Container

a guest Jan 23rd, 2019 61 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 } 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(/active|inactive/) && appState === 'background') {
  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.   validatePageData (pageData, responses) {
  490.     const { items } = pageData
  491.     let isValid = true
  492.     let timburdenPreviousItemValue = null
  493.  
  494.     items.map(item => {
  495.       const { validation } = item
  496.       if (item.value) timburdenPreviousItemValue = item.value
  497.       // if an invalid response is found will skip the other checks
  498.       if (item.sliderInfo && (item.sliderInfo.min || item.sliderInfo.min === 0) &&
  499.         !(this.hasResponseData(responses[item.id]))) {
  500.         return this.addSliderDefalutResponse(item)
  501.       }
  502.       if (isValid && this.isRequiredItem(item) &&
  503.         (!(this.hasResponseData(responses[item.id]) || item.value || timburdenPreviousItemValue)) &&
  504.           !this.hasItemDependencies(item, responses)) {
  505.         if (validation === 'hours') {
  506.           this.setState({ error: Config.surveysGeneralConfig.errorMessages['hours'] })
  507.         } else this.setState({ error: Config.surveysGeneralConfig.errorMessages[item.input] })
  508.         isValid = false
  509.       }
  510.       if (isValid && validation && validation !== 'month') {
  511.         const value = (responses[item.id] && responses[item.id].value) || item.value
  512.         if (!value && !this.isRequiredItem(item)) return // if no value, and field is optional => no need for validations
  513.         if (validation === 'SSN') { // here should be added validation for popup if needed
  514.           isValid =  validateNHS(value) || validateSSN(value) //validate for UK and US
  515.           if (!isValid) this.setState({ error: Config.surveysGeneralConfig.errorMessages['nhs'] })
  516.         }
  517.       }
  518.     })
  519.     return isValid
  520.   }
  521.  
  522.   checkNextPage () {
  523.     const { pageOrder, pageCounter, surveyData, responses } = this.state
  524.     const currentPage = pageOrder[pageCounter - 1]
  525.     const nextPage = this.getNextPage(surveyData.pages[currentPage].nextPage, responses)
  526.  
  527.     this.setState({ nextPage, error: null })
  528.     return nextPage
  529.   }
  530.  
  531.   processString (string) { return string.replace(/\s/g, '').toLowerCase() }
  532.  
  533.   interpretAsyncResults = ({results, status}, callback, zipCode) => {
  534.     const { country } = this.props.localUser
  535.     let avCountriesZipcode = false
  536.     let zipCodeMatch = false
  537.  
  538.     let userCountry = country
  539.     if (country === 'UK') userCountry = 'GB'
  540.     if (status !== 'OK') return callback(status, 'zipCode')
  541.  
  542.     if (results[0] && results[0].address_components && (results[0].types[0] === 'postal_code')) {
  543.       results[0].address_components.map(({ types, short_name }) => {
  544.         if (types && (types[0] === 'postal_code') &&
  545.           (this.processString(short_name) === this.processString(zipCode))) {
  546.           zipCodeMatch = true
  547.         }
  548.         if (types && (types[0] === 'country') &&
  549.           (userCountry === short_name)) {
  550.           avCountriesZipcode = true
  551.         }
  552.       })
  553.       if (avCountriesZipcode && zipCodeMatch) return callback(null)
  554.     }
  555.     this.setState({ error: translate('surveyItemErrors', 'zipcode') })
  556.     return callback(status, 'zipCode')
  557.   }
  558.  
  559.   resolveValidationPromises = (promises, callback, zipCode) => {
  560.     let noAsyncValidation = false
  561.  
  562.     Promise.all(promises).then((results) => {
  563.       results.forEach((response, index) => {
  564.         if (response === 'noAsyncValidation') noAsyncValidation = true
  565.         else return this.interpretAsyncResults(response, callback, zipCode)
  566.  
  567.         if (noAsyncValidation && index === results.length - 1) {
  568.           return callback(null, 'no_async_validation')
  569.         }
  570.       })
  571.     })
  572.   }
  573.  
  574.   checkItemAsyncValidations = ({items}, responses, callback) => {
  575.     const promises = []
  576.     let zipCode = ''
  577.  
  578.     items.forEach(({id, value, field}) => {
  579.       const usedValue = (responses[id] && typeof responses[id].value === 'string')
  580.         ? responses[id].value
  581.         : value
  582.  
  583.       if (field === 'zipCode') {
  584.         const language = this.props.localUser.language
  585.         promises.push(GoogleapisService.checkZipcode({ zipCode: usedValue, language }))
  586.         zipCode = usedValue
  587.       } else promises.push('noAsyncValidation')
  588.     })
  589.     this.resolveValidationPromises(promises, callback, zipCode)
  590.   }
  591.  
  592.   onPressPrevious = () => {
  593.     const { pageOrder, pageCounter } = this.state
  594.     const currentPageNo = pageCounter
  595.  
  596.     pageOrder.pop()
  597.  
  598.     currentPageNo >= 1 && this.setState({
  599.       pageCounter: currentPageNo - 1,
  600.       pageOrder: pageOrder,
  601.       error: null
  602.     }, () => this.checkNextPage)
  603.   }
  604.  
  605.   onPressNext = () => {
  606.     const { pageOrder, pageCounter, surveyData, responses } = this.state
  607.     const currentPage = pageOrder[pageCounter - 1]
  608.     const pageData = surveyData.pages[currentPage]
  609.  
  610.     if (this.pageHasAsyncValidation(pageData)) {
  611.       return this.checkItemAsyncValidations(pageData, responses, (err, field) => {
  612.         if (err && field === 'zipCode') {
  613.           return this.setState({ error: translate('surveyItemErrors', 'zipcode') })
  614.         }
  615.         this.validateDataAndGetNextPage(pageData, responses)
  616.       })
  617.     }
  618.     this.validateDataAndGetNextPage(pageData, responses)
  619.   }
  620.  
  621.   pageHasAsyncValidation (pageData) {
  622.     const pageInputType = pageData.pageInputType || null
  623.     return pageInputType && pageInputType === 'hasAsyncValidations'
  624.   }
  625.  
  626.   leavePageCheckValidInput = (callback) => {
  627.     const { pageOrder, pageCounter, surveyData, responses } = this.state
  628.     const pageData = surveyData.pages[pageOrder[pageCounter - 1]]
  629.  
  630.     if (this.pageHasAsyncValidation(pageData)) {
  631.       return this.checkItemAsyncValidations(pageData, responses, (err, field) => {
  632.         if (err && field === 'zipCode') {
  633.           const { id, value } = pageData.items[0]
  634.           responses[id].value = value
  635.           this.setState({ responses })
  636.         }
  637.         callback()
  638.       })
  639.     }
  640.     callback()
  641.   }
  642.  
  643.   composeResponseData = intermediary => {
  644.     const {
  645.       pageOrder,
  646.       pageCounter,
  647.       surveyData,
  648.       responses,
  649.       surveyStartedAt,
  650.       multipleChoiceQuestions
  651.     } = this.state
  652.     const { title, version, expiresIn } = surveyData
  653.     const { surveyId, localUser } = this.props
  654.     const { timezoneOffset } = localUser
  655.     const currentPage = pageOrder[pageCounter - 1]
  656.  
  657.     const newData = {
  658.       title,
  659.       version: version || null,
  660.       expiresIn,
  661.       surveyId,
  662.       responses,
  663.       pageOrder,
  664.       timezoneOffset,
  665.       multipleChoiceQuestions,
  666.       multipleChoicesMainPages: this.multipleChoicesMainPages,
  667.       multipleChoicesMainPageAnswers: this.multipleChoicesMainPageAnswers,
  668.       startedAt: surveyStartedAt,
  669.       minPagesLeft: surveyData.pages[currentPage].minPages,
  670.       completionDate: !intermediary && Moment().format()
  671.     }
  672.  
  673.     return newData
  674.   }
  675.  
  676.   doNotCreadeOrUpdateSurveyAnswer (requestSource) {
  677.     const {
  678.       responses,
  679.       copyResponses,
  680.       showPopupDate
  681.     } = this.state
  682.     const {
  683.       createSurveyAnswerLoading,
  684.       updateSurveyAnswerLoading
  685.     } = this.props
  686.     const sameResponses = copyResponses === JSON.stringify(responses)
  687.     const responseIsEmpty = JSON.stringify(responses) === '{}'
  688.  
  689.     // Verify if not the same response, but if there is another call in progress
  690.     return ((sameResponses ||
  691.       responseIsEmpty ||
  692.       createSurveyAnswerLoading ||
  693.       updateSurveyAnswerLoading) &&
  694.       !showPopupDate &&
  695.       requestSource !== 'goBack' &&
  696.       requestSource !== 'endSurvey')
  697.   }
  698.  
  699.   resetErrorSubmit = () => this.setState({ errorSubmittingSurvey: false })
  700.  
  701.   update (...args) { this.props.updateSurveyAnswer(...args) }
  702.  
  703.   createOrUpdateSurveyAnswer (intermediary) {
  704.     const { surveyAnswerId, surveyWithAnswerData, updateDragDropModalValue } = this.state
  705.     const { createSurveyAnswer, answerId, data, localUser } = this.props
  706.  
  707.     const newData = this.composeResponseData(intermediary)
  708.  
  709.     if (updateDragDropModalValue) {
  710.       newData.showDragAndDropPopup = 'no'
  711.       this.setState({ updateDragDropModalValue: false })
  712.     }
  713.  
  714.     const surveyWithAnswerId = surveyWithAnswerData && surveyWithAnswerData.surveyAnswerId
  715.     const answerSurveysId = answerId || surveyAnswerId || surveyWithAnswerId
  716.     const { token, language } = localUser
  717.     const params = {params: {accessToken: token, language}}
  718.  
  719.     answerSurveysId && token && (data.status !== 'expired' ||
  720.       (surveyWithAnswerData && surveyWithAnswerData.status !== 'expired'))
  721.       ? this.update(answerSurveysId, newData, params)
  722.       : createSurveyAnswer(newData, params)
  723.   }
  724.  
  725.   createResponseData (intermediary, requestSource) {
  726.     const { surveyData } = this.state
  727.  
  728.     if (!surveyData) return
  729.  
  730.     if (requestSource === 'goBack') this.setState({goBack: true})
  731.     else this.setState({goBack: false})
  732.  
  733.     if (this.doNotCreadeOrUpdateSurveyAnswer(requestSource)) return
  734.  
  735.     this.createOrUpdateSurveyAnswer(intermediary)
  736.   }
  737.  
  738.   // HERE STARTS MULTIPLE CHOICE QUESTION LOGIC
  739.   deleteMultipleChoice = () => { // 'don't know' answer
  740.     const { noOfPages, multipleChoiceQuestions } = this.state
  741.     const lengthMultipleChoiceElements = multipleChoiceQuestions.length
  742.  
  743.     this.deleteDataMultipleChoice()
  744.     this.setState({
  745.       multipleChoiceQuestions: [],
  746.       noOfPages: noOfPages - lengthMultipleChoiceElements
  747.     })
  748.   }
  749.  
  750.   deleteDataMultipleChoice () {
  751.     const { surveyData, pageOrder, pageCounter } = this.state
  752.  
  753.     const currentPage = pageOrder[pageCounter - 1]
  754.     // temporary fix becauase it's called every time uncheck a box on any question
  755.     if (surveyData.pages[pageOrder[pageCounter - 1]].pageInputType === 'multipleChoices') {
  756.       this.multipleChoicesMainPages[currentPage] = {}
  757.       this.multipleChoicesMainPageAnswers = _.pickBy(this.multipleChoicesMainPageAnswers, value => value.mainPage !== currentPage)
  758.     }
  759.   }
  760.  
  761.   addReponseForMultipleChoice = (response, lengthMultipleChoiceElements) => {
  762.     const { pageOrder, pageCounter, responses, surveyData } = this.state
  763.     const currentPage = pageOrder[pageCounter - 1]
  764.  
  765.     const data = {
  766.       responses,
  767.       pageData: surveyData.pages[currentPage],
  768.       nextPage: surveyData.pages[pageOrder[pageCounter - 1]].nextPage,
  769.       lengthMultipleChoiceElements
  770.     }
  771.     const optionValues = surveyData.pages[pageOrder[pageCounter - 1]].items[0].values
  772.     const { multipleChoicePickedValues } =
  773.       this.getMultipleChoicePickedValues(data, response.value, optionValues, { isAddResponse: true })
  774.     return {
  775.       mQuestions: multipleChoicePickedValues,
  776.       lengthMultipleChoiceElements: response.value.length
  777.     }
  778.   }
  779.  
  780.   getLenghtMultipleChoiceOrMainArray = (multipleChoiceQuestions, mainPage, currentPage) => {
  781.     let lengthMultipleChoiceElements = multipleChoiceQuestions.length
  782.     let mainPageArray = Object.keys(mainPage)
  783.     const mainPageLength = mainPageArray.length
  784.     mainPageArray = mainPageArray.slice(mainPageArray.indexOf(currentPage) + 1, mainPageLength)
  785.     if (mainPageLength > 3) lengthMultipleChoiceElements = mainPageArray.length
  786.     return lengthMultipleChoiceElements
  787.   }
  788.  
  789.   updateStateAndCheckNextPage = (data) => this.setState(data, () => this.checkNextPage())
  790.  
  791.   getMultipleChoicePickedValues = (data, pickedValues, allPossibleValues, isAddResponse) => {
  792.     const { pageData } = data
  793.     const { pageOrder, pageCounter } = this.state
  794.  
  795.     const currentPage = pageOrder[pageCounter - 1]
  796.  
  797.     const multipleChoicePickedValues = []
  798.     allPossibleValues.map((allValue, index) => {
  799.       pickedValues.map(pickedValue => {
  800.         if (allValue === pickedValue) {
  801.           multipleChoicePickedValues.push(pageData.multipleChoiceQuestions[index])
  802.         }
  803.       })
  804.     })
  805.  
  806.     this.refreshMainPageAnswers(multipleChoicePickedValues, currentPage)
  807.     const isInPageOrder = pageOrder.findIndex(val => val === multipleChoicePickedValues[0])
  808.  
  809.     const newLength = multipleChoicePickedValues.length
  810.     if (isInPageOrder < 0 && !isAddResponse) {
  811.       pageOrder.push(multipleChoicePickedValues[0])
  812.       multipleChoicePickedValues.splice(0, 1)
  813.     }
  814.  
  815.     return { multipleChoicePickedValues, newLength }
  816.   }
  817.  
  818.   refreshMainPageAnswers (pickedValues, currentPage) {
  819.     this.multipleChoicesMainPages[currentPage] = {}
  820.     const newAnswers = {}
  821.     newAnswers[currentPage] = { nextPage: pickedValues[0] }
  822.     pickedValues.forEach((object, index) => {
  823.       newAnswers[object] = { nextPage: pickedValues[index + 1] }
  824.       if (!this.multipleChoicesMainPageAnswers[object]) {
  825.         this.multipleChoicesMainPageAnswers[object] = { mainPage: currentPage }
  826.       }
  827.     })
  828.     this.multipleChoicesMainPages[currentPage] = newAnswers
  829.   }
  830.  
  831.   updatePageProgressIfPickedValues = (data, pickedValues) => {
  832.     const { nextPage } = data
  833.     const { pageOrder, pageCounter, surveyData } = this.state
  834.     const allPossibleValues = surveyData.pages[pageOrder[pageCounter - 1]].items[0].values
  835.     const {
  836.       multipleChoicePickedValues,
  837.       newLength
  838.     } = this.getMultipleChoicePickedValues(data, pickedValues, allPossibleValues)
  839.  
  840.     const stateData = {
  841.       multipleChoiceQuestions: multipleChoicePickedValues,
  842.       pageCounter: pageCounter + 1,
  843.       pageOrder,
  844.       noOfPages: surveyData.pages[nextPage].minPages + pageCounter + newLength
  845.     }
  846.     this.updateStateAndCheckNextPage(stateData)
  847.   }
  848.  
  849.   updatePageProgressIfMultipleQuestion = (data) => {
  850.     const { responses, nextPage, lengthMultipleChoiceElements } = data
  851.     const { pageOrder, pageCounter } = this.state
  852.     const pickedValues = responses[pageOrder[pageCounter - 1] + '_item1'] &&
  853.       responses[pageOrder[pageCounter - 1] + '_item1'].value
  854.     if (!pickedValues) return this.updatePageProgressAnyQuestion(nextPage, lengthMultipleChoiceElements)
  855.     this.updatePageProgressIfPickedValues(data, pickedValues)
  856.   }
  857.  
  858.   updatePageProgressAnyQuestion = (nextPage, lengthMultipleChoiceElements) => {
  859.     const { pageOrder, pageCounter, surveyData } = this.state
  860.     pageOrder.push(nextPage)
  861.     const stateData = {
  862.       pageCounter: pageCounter + 1,
  863.       pageOrder,
  864.       noOfPages: surveyData.pages[nextPage].minPages + pageCounter + lengthMultipleChoiceElements
  865.     }
  866.     this.updateStateAndCheckNextPage(stateData)
  867.   }
  868.  
  869.   getLenghtAndUpdateMultipleChoice = (multipleChoiceQuestions, mainPage, currentPage) => {
  870.     multipleChoiceQuestions.splice(0, 1)
  871.     this.setState({ multipleChoiceQuestions })
  872.     let lengthMultipleChoiceElements = multipleChoiceQuestions.length
  873.     let mainPageArray = Object.keys(mainPage)
  874.     const mainPageLength = mainPageArray.length
  875.     mainPageArray = mainPageArray.slice(mainPageArray.indexOf(currentPage) + 2, mainPageLength)
  876.     if (mainPageLength > 3) lengthMultipleChoiceElements = mainPageArray.length
  877.     return lengthMultipleChoiceElements
  878.   }
  879.  
  880.   validateDataAndGetNextPage = (pageData, responses) => {
  881.     const { multipleChoiceQuestions, pageOrder, pageCounter } = this.state
  882.     const currentPage = pageOrder[pageCounter - 1]
  883.     let lengthMultipleChoiceElements = 0
  884.  
  885.     if (!this.validatePageData(pageData, responses)) return false
  886.     let nextPage = this.getNextPage(pageData.nextPage, responses)
  887.  
  888.     if (this.multipleChoicesMainPageAnswers[currentPage]) {
  889.       const mainPage = this.multipleChoicesMainPages[this.multipleChoicesMainPageAnswers[currentPage].mainPage]
  890.       if (mainPage[currentPage].nextPage) nextPage = mainPage[currentPage].nextPage
  891.       lengthMultipleChoiceElements = this.getLenghtAndUpdateMultipleChoice(multipleChoiceQuestions, mainPage, currentPage)
  892.     }
  893.  
  894.     if (pageData.pageInputType === 'multipleChoices') { // new multiple choice page
  895.       const data = { pageData, responses, nextPage, lengthMultipleChoiceElements }
  896.       return this.updatePageProgressIfMultipleQuestion(data)
  897.     }
  898.     if (nextPage) return this.updatePageProgressAnyQuestion(nextPage, lengthMultipleChoiceElements)
  899.     // the extra check of next page it's for not selecting any option yet
  900.     this.createResponseData(false, 'endSurvey')
  901.   }
  902.   // HERE ENDS MULTIPLE CHOICE QUESTION LOGIC
  903.  
  904.   renderHeader () {
  905.     const { eq5d, pageCounter, noOfPages, surveyData } = this.state
  906.     return (
  907.       <SurveyHeader
  908.         eq5d={eq5d}
  909.         pageCounter={pageCounter}
  910.         onBackPressed={this.onBackAndroid}
  911.         noOfPages={noOfPages}
  912.         surveyData={surveyData} />
  913.     )
  914.   }
  915.  
  916.   renderSurveyPages () {
  917.     const {
  918.       pageOrder,
  919.       pageCounter,
  920.       surveyData,
  921.       eq5d,
  922.       responses,
  923.       error,
  924.       leaveSurvey,
  925.       loading
  926.     } = this.state
  927.     const { navigate } = this.props
  928.     const currentPage = pageOrder[pageCounter - 1]
  929.     const firstPage = surveyData.firstPage
  930.     const pages = surveyData.pages
  931.     const pageData = currentPage && (pages[currentPage] || pages[firstPage] || {})
  932.  
  933.     return eq5d
  934.       ? <EQ5DSurvey
  935.         goBack={this.goBack}
  936.         leaveSurvey={leaveSurvey}
  937.         onSurveyModalPressed={this.onSurveyModalPressed}
  938.         addResponse={this.addResponse}
  939.         deleteResponse={this.deleteResponse}
  940.         id={currentPage}
  941.         pageOrder={pageOrder}
  942.         isLoading={loading}
  943.         page={pageData}
  944.         error={error}
  945.         responses={responses}
  946.         setError={this.setError} />
  947.       : <Survey
  948.         goBack={this.goBack}
  949.         toggleInfoPopup={this.toggleInfoPopup}
  950.         leaveSurvey={leaveSurvey}
  951.         onSurveyModalPressed={this.onSurveyModalPressed}
  952.         error={error}
  953.         addResponse={this.addResponse}
  954.         deleteResponse={this.deleteResponse}
  955.         id={currentPage}
  956.         pageOrder={pageOrder}
  957.         isLoading={loading}
  958.         navigate={navigate}
  959.         deleteMultipleChoice={this.deleteMultipleChoice}
  960.         page={pageData}
  961.         responses={responses}
  962.         setError={this.setError}
  963.         createTimeburdenSpecialAnswer={this.createTimeburdenSpecialAnswer} />
  964.   }
  965.  
  966.   renderBottomControls () {
  967.     const {
  968.       pageCounter,
  969.       surveyData,
  970.       eq5d,
  971.       nextPage,
  972.       noOfPages,
  973.       loading,
  974.       errorSubmittingSurvey
  975.     } = this.state
  976.     const isLastPage = pageCounter === noOfPages && typeof nextPage !== 'string'
  977.  
  978.     return eq5d
  979.       ? <EQ5DNavigationControl
  980.         eq5d={eq5d}
  981.         isFirstPage={ pageCounter < 2 }
  982.         isLastPage={isLastPage}
  983.         loading={loading}
  984.         errorSubmit={errorSubmittingSurvey}
  985.         buttonInfo={surveyData}
  986.         onPressNext={this.onPressNext}
  987.         onPressPrevious={this.onPressPrevious} />
  988.       : <SurveyNavigationControl
  989.         eq5d={eq5d}
  990.         isFirstPage={ pageCounter < 2 }
  991.         isLastPage={isLastPage}
  992.         loading={loading}
  993.         resetErrorSubmit={this.resetErrorSubmit}
  994.         errorSubmit={errorSubmittingSurvey}
  995.         buttonInfo={surveyData}
  996.         onPressNext={this.onPressNext}
  997.         onPressPrevious={this.onPressPrevious} />
  998.   }
  999.  
  1000.   renderLoadingSurveyData () {
  1001.     const { surveyLoading } = this.props
  1002.     const { getSurveyError } = this.state
  1003.     const { text, icon, error, button } = Config.loadingConfig.loading
  1004.     let loadingMessage = text
  1005.     if (getSurveyError) loadingMessage = error
  1006.     if (surveyLoading) loadingMessage = text
  1007.  
  1008.     return (
  1009.       <LoadingSurvey
  1010.         loadingImage={icon}
  1011.         loadingError={getSurveyError && !surveyLoading}
  1012.         button={button}
  1013.         onButtonPressed={() => this.getSurveyFromBackend()}
  1014.         message={loadingMessage} />
  1015.     )
  1016.   }
  1017.  
  1018.   renderSurveyStatus () {
  1019.     const { data, goBack, surveyError } = this.props
  1020.     const {
  1021.       pageCounter,
  1022.       noOfPages,
  1023.       surveyCompleted,
  1024.       surveyData,
  1025.       thankYouScreenData
  1026.     } = this.state
  1027.     const surveyDataInfo = Object.keys(data).length ? data : surveyData
  1028.     const { surveyLoading } = this.props
  1029.     console.log(this.state, { data })
  1030.     return (
  1031.       <SurveyStatus
  1032.         loadingData={surveyLoading}
  1033.         surveyError={surveyError}
  1034.         goToSurvey={this.setResumeSurveyValue}
  1035.         surveyCompleted={surveyCompleted}
  1036.         pageCounter={pageCounter}
  1037.         noOfPages={noOfPages}
  1038.         goBack={goBack}
  1039.         surveyData={surveyDataInfo}
  1040.         thankYouScreen={thankYouScreenData} />
  1041.     )
  1042.   }
  1043.  
  1044.   renderInfoPopup = () => {
  1045.     const { showInfoPopup, firstTimePopup } = this.state
  1046.  
  1047.     if (showInfoPopup) {
  1048.       return (
  1049.         <InfoPopup
  1050.           firstTimePopup={firstTimePopup}
  1051.           onCloseFirstTimePopup={this.onCloseFirstTimePopup}
  1052.           onPopupShown={this.toggleInfoPopup} />
  1053.       )
  1054.     }
  1055.   }
  1056.  
  1057.   renderOfflineNotifier () {
  1058.     return (
  1059.       <OfflineNotifier
  1060.         text={translate('general', 'noInternetConnection')}
  1061.       />
  1062.     )
  1063.   }
  1064.  
  1065.   renderSurveyContent () {
  1066.     const { surveyLoading, surveyError } = this.props
  1067.     const { eq5d, surveyData } = this.state
  1068.     const backgroundColor = eq5d
  1069.       ? Styles.mainColors.WHITE
  1070.       : Styles.mainColors.SCREEN_DEFAULT_BACKGROUND_COLOR
  1071.  
  1072.     return (
  1073.       <View style={{ height: screen.height, backgroundColor }}>
  1074.         {this.renderHeader()}
  1075.         {this.renderOfflineNotifier()}
  1076.         {(surveyLoading || surveyError || !surveyData) && this.renderLoadingSurveyData()}
  1077.         {!surveyLoading && surveyData && this.renderSurveyPages()}
  1078.         {this.renderInfoPopup()}
  1079.         {!surveyLoading && surveyData && this.renderBottomControls()}
  1080.       </View>
  1081.     )
  1082.   }
  1083.  
  1084.   render () {
  1085.     const { data } = this.props
  1086.     const { resumeSurvey, surveyCompleted, surveyAnswerId, surveyData } = this.state
  1087.     const answerSurveysId = (data && data.answerId) || surveyAnswerId
  1088.  
  1089.     if ((surveyAnswerId && surveyData && !resumeSurvey) ||
  1090.       (answerSurveysId && !resumeSurvey) || surveyCompleted) {
  1091.       return this.renderSurveyStatus()
  1092.     }
  1093.  
  1094.     return this.renderSurveyContent()
  1095.   }
  1096. }
  1097.  
  1098. const mapStateToProps = state => {
  1099.   return {
  1100.     ...getSelectors(surveySelector, 'surveySelector', state),
  1101.     ...getSelectors(createSurveyAnswerSelector, 'createSurveyAnswerSelector', state),
  1102.     ...getSelectors(updateSurveyAnswerSelector, 'updateSurveyAnswerSelector', state),
  1103.     ...getSelectors(surveyListSelector, 'surveyListSelector', state),
  1104.     localUser: userSelector(state) || {}
  1105.   }
  1106. }
  1107.  
  1108. const mapDispatchToProps = {
  1109.   getSurvey,
  1110.   getSurveyList,
  1111.   createSurveyAnswer,
  1112.   updateSurveyAnswer,
  1113.   deleteConsentData,
  1114.   setLocalUser,
  1115.   setUser
  1116. }
  1117.  
  1118. 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