diff --git a/src/components/FixedFooter.tsx b/src/components/FixedFooter.tsx index 475de82fac35..34bce2133a89 100644 --- a/src/components/FixedFooter.tsx +++ b/src/components/FixedFooter.tsx @@ -7,12 +7,12 @@ type FixedFooterProps = { children: ReactNode; /** Styles to be assigned to Container */ - style?: StyleProp; + style: Array>; }; function FixedFooter({style = [], children}: FixedFooterProps) { const styles = useThemeStyles(); - return {children}; + return {children}; } FixedFooter.displayName = 'FixedFooter'; diff --git a/src/components/Form/FormWrapper.js b/src/components/Form/FormWrapper.js index 638b6e5f8d19..4f7346a94a2d 100644 --- a/src/components/Form/FormWrapper.js +++ b/src/components/Form/FormWrapper.js @@ -5,7 +5,6 @@ import {withOnyx} from 'react-native-onyx'; import _ from 'underscore'; import FormAlertWithSubmitButton from '@components/FormAlertWithSubmitButton'; import FormSubmit from '@components/FormSubmit'; -import refPropTypes from '@components/refPropTypes'; import SafeAreaConsumer from '@components/SafeAreaConsumer'; import ScrollViewWithContext from '@components/ScrollViewWithContext'; import * as ErrorUtils from '@libs/ErrorUtils'; @@ -65,7 +64,7 @@ const propTypes = { errors: errorsPropType.isRequired, - inputRefs: PropTypes.objectOf(refPropTypes).isRequired, + inputRefs: PropTypes.objectOf(PropTypes.oneOfType([PropTypes.func, PropTypes.object])).isRequired, }; const defaultProps = { diff --git a/src/components/RadioButtons.tsx b/src/components/RadioButtons.tsx index b83710bd85bf..f8f9b345f855 100644 --- a/src/components/RadioButtons.tsx +++ b/src/components/RadioButtons.tsx @@ -1,4 +1,5 @@ import React, {useState} from 'react'; +import {View} from 'react-native'; import useThemeStyles from '@styles/useThemeStyles'; import RadioButtonWithLabel from './RadioButtonWithLabel'; @@ -20,7 +21,7 @@ function RadioButtons({items, onPress}: RadioButtonsProps) { const [checkedValue, setCheckedValue] = useState(''); return ( - <> + {items.map((item) => ( ))} - + ); } RadioButtons.displayName = 'RadioButtons'; -export type {Choice}; export default RadioButtons; diff --git a/src/components/SingleChoiceQuestion.tsx b/src/components/SingleChoiceQuestion.tsx deleted file mode 100644 index 07d4dfe817dd..000000000000 --- a/src/components/SingleChoiceQuestion.tsx +++ /dev/null @@ -1,39 +0,0 @@ -import React, {ForwardedRef, forwardRef} from 'react'; -import {Text as RNText} from 'react-native'; -import useThemeStyles from '@styles/useThemeStyles'; -import FormHelpMessage from './FormHelpMessage'; -import RadioButtons, {Choice} from './RadioButtons'; -import Text from './Text'; - -type SingleChoiceQuestionProps = { - prompt: string; - errorText?: string | string[]; - possibleAnswers: Choice[]; - currentQuestionIndex: number; - onInputChange: (value: string) => void; -}; - -function SingleChoiceQuestion({prompt, errorText, possibleAnswers, currentQuestionIndex, onInputChange}: SingleChoiceQuestionProps, ref: ForwardedRef) { - const styles = useThemeStyles(); - - return ( - <> - - {prompt} - - - - - ); -} - -SingleChoiceQuestion.displayName = 'SingleChoiceQuestion'; - -export default forwardRef(SingleChoiceQuestion); diff --git a/src/pages/EnablePayments/IdologyQuestions.js b/src/pages/EnablePayments/IdologyQuestions.js index 569a6f9aa109..97c0f55f27c6 100644 --- a/src/pages/EnablePayments/IdologyQuestions.js +++ b/src/pages/EnablePayments/IdologyQuestions.js @@ -1,14 +1,17 @@ import PropTypes from 'prop-types'; -import React, {useState} from 'react'; +import React, {useRef, useState} from 'react'; import {View} from 'react-native'; import {withOnyx} from 'react-native-onyx'; import _ from 'underscore'; -import FormProvider from '@components/Form/FormProvider'; -import InputWrapper from '@components/Form/InputWrapper'; -import SingleChoiceQuestion from '@components/SingleChoiceQuestion'; +import FixedFooter from '@components/FixedFooter'; +import FormAlertWithSubmitButton from '@components/FormAlertWithSubmitButton'; +import FormScrollView from '@components/FormScrollView'; +import OfflineIndicator from '@components/OfflineIndicator'; +import RadioButtons from '@components/RadioButtons'; import Text from '@components/Text'; import TextLink from '@components/TextLink'; import useLocalize from '@hooks/useLocalize'; +import * as ErrorUtils from '@libs/ErrorUtils'; import useThemeStyles from '@styles/useThemeStyles'; import * as BankAccounts from '@userActions/BankAccounts'; import ONYXKEYS from '@src/ONYXKEYS'; @@ -48,13 +51,15 @@ const defaultProps = { walletAdditionalDetails: {}, }; -function IdologyQuestions({questions, idNumber}) { +function IdologyQuestions({questions, walletAdditionalDetails, idNumber}) { const styles = useThemeStyles(); + const formRef = useRef(); const {translate} = useLocalize(); const [currentQuestionIndex, setCurrentQuestionIndex] = useState(0); const [shouldHideSkipAnswer, setShouldHideSkipAnswer] = useState(false); const [userAnswers, setUserAnswers] = useState([]); + const [error, setError] = useState(''); const currentQuestion = questions[currentQuestionIndex] || {}; const possibleAnswers = _.filter( @@ -69,6 +74,7 @@ function IdologyQuestions({questions, idNumber}) { }; }), ); + const errorMessage = ErrorUtils.getLatestErrorMessage(walletAdditionalDetails) || error; /** * Put question answer in the state. @@ -80,6 +86,7 @@ function IdologyQuestions({questions, idNumber}) { tempAnswers[currentQuestionIndex] = {question: currentQuestion.type, answer}; setUserAnswers(tempAnswers); + setError(''); }; /** @@ -87,37 +94,30 @@ function IdologyQuestions({questions, idNumber}) { */ const submitAnswers = () => { if (!userAnswers[currentQuestionIndex]) { - return; - } - // Get the number of questions that were skipped by the user. - const skippedQuestionsCount = _.filter(userAnswers, (answer) => answer.answer === SKIP_QUESTION_TEXT).length; - - // We have enough answers, let's call expectID KBA to verify them - if (userAnswers.length - skippedQuestionsCount >= questions.length - MAX_SKIP) { - const tempAnswers = _.map(userAnswers, _.clone); - - // Auto skip any remaining questions - if (tempAnswers.length < questions.length) { - for (let i = tempAnswers.length; i < questions.length; i++) { - tempAnswers[i] = {question: questions[i].type, answer: SKIP_QUESTION_TEXT}; - } - } - - BankAccounts.answerQuestionsForWallet(tempAnswers, idNumber); - setUserAnswers(tempAnswers); + setError(translate('additionalDetailsStep.selectAnswer')); } else { - // Else, show next question - setCurrentQuestionIndex(currentQuestionIndex + 1); - setShouldHideSkipAnswer(skippedQuestionsCount >= MAX_SKIP); - } - }; + // Get the number of questions that were skipped by the user. + const skippedQuestionsCount = _.filter(userAnswers, (answer) => answer.answer === SKIP_QUESTION_TEXT).length; + + // We have enough answers, let's call expectID KBA to verify them + if (userAnswers.length - skippedQuestionsCount >= questions.length - MAX_SKIP) { + const tempAnswers = _.map(userAnswers, _.clone); + + // Auto skip any remaining questions + if (tempAnswers.length < questions.length) { + for (let i = tempAnswers.length; i < questions.length; i++) { + tempAnswers[i] = {question: questions[i].type, answer: SKIP_QUESTION_TEXT}; + } + } - const validate = (values) => { - const errors = {}; - if (!values.answer) { - errors.answer = translate('additionalDetailsStep.selectAnswer'); + BankAccounts.answerQuestionsForWallet(tempAnswers, idNumber); + setUserAnswers(tempAnswers); + } else { + // Else, show next question + setCurrentQuestionIndex(currentQuestionIndex + 1); + setShouldHideSkipAnswer(skippedQuestionsCount >= MAX_SKIP); + } } - return errors; }; return ( @@ -131,23 +131,33 @@ function IdologyQuestions({questions, idNumber}) { {translate('additionalDetailsStep.helpLink')} - - + + {currentQuestion.prompt} + + + + + { + formRef.current.scrollTo({y: 0, animated: true}); + }} + message={errorMessage} + isLoading={walletAdditionalDetails.isLoading} + buttonText={translate('common.saveAndContinue')} + containerStyles={[styles.mh0, styles.mv0, styles.mb0]} /> - + + ); }