From 4fed72e3867d83fdfc37fc629c1b9a660c3912ea Mon Sep 17 00:00:00 2001 From: Kamil Owczarz Date: Wed, 29 Nov 2023 15:24:37 +0100 Subject: [PATCH 1/2] Revert "Revert "[Form Provider Refactor] IdologyQuestions"" This reverts commit 89967723d516f4684345170c4523a5e08c0ccc86. --- src/components/FixedFooter.tsx | 4 +- src/components/Form/FormWrapper.js | 3 +- src/components/RadioButtons.tsx | 6 +- src/components/SingleChoiceQuestion.tsx | 39 +++++++ src/pages/EnablePayments/IdologyQuestions.js | 108 +++++++++---------- 5 files changed, 95 insertions(+), 65 deletions(-) create mode 100644 src/components/SingleChoiceQuestion.tsx diff --git a/src/components/FixedFooter.tsx b/src/components/FixedFooter.tsx index 34bce2133a89..475de82fac35 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: Array>; + style?: StyleProp; }; 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 4f7346a94a2d..638b6e5f8d19 100644 --- a/src/components/Form/FormWrapper.js +++ b/src/components/Form/FormWrapper.js @@ -5,6 +5,7 @@ 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'; @@ -64,7 +65,7 @@ const propTypes = { errors: errorsPropType.isRequired, - inputRefs: PropTypes.objectOf(PropTypes.oneOfType([PropTypes.func, PropTypes.object])).isRequired, + inputRefs: PropTypes.objectOf(refPropTypes).isRequired, }; const defaultProps = { diff --git a/src/components/RadioButtons.tsx b/src/components/RadioButtons.tsx index f8f9b345f855..b83710bd85bf 100644 --- a/src/components/RadioButtons.tsx +++ b/src/components/RadioButtons.tsx @@ -1,5 +1,4 @@ import React, {useState} from 'react'; -import {View} from 'react-native'; import useThemeStyles from '@styles/useThemeStyles'; import RadioButtonWithLabel from './RadioButtonWithLabel'; @@ -21,7 +20,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 new file mode 100644 index 000000000000..07d4dfe817dd --- /dev/null +++ b/src/components/SingleChoiceQuestion.tsx @@ -0,0 +1,39 @@ +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 97c0f55f27c6..569a6f9aa109 100644 --- a/src/pages/EnablePayments/IdologyQuestions.js +++ b/src/pages/EnablePayments/IdologyQuestions.js @@ -1,17 +1,14 @@ import PropTypes from 'prop-types'; -import React, {useRef, useState} from 'react'; +import React, {useState} from 'react'; import {View} from 'react-native'; import {withOnyx} from 'react-native-onyx'; import _ from 'underscore'; -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 FormProvider from '@components/Form/FormProvider'; +import InputWrapper from '@components/Form/InputWrapper'; +import SingleChoiceQuestion from '@components/SingleChoiceQuestion'; 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'; @@ -51,15 +48,13 @@ const defaultProps = { walletAdditionalDetails: {}, }; -function IdologyQuestions({questions, walletAdditionalDetails, idNumber}) { +function IdologyQuestions({questions, 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( @@ -74,7 +69,6 @@ function IdologyQuestions({questions, walletAdditionalDetails, idNumber}) { }; }), ); - const errorMessage = ErrorUtils.getLatestErrorMessage(walletAdditionalDetails) || error; /** * Put question answer in the state. @@ -86,7 +80,6 @@ function IdologyQuestions({questions, walletAdditionalDetails, idNumber}) { tempAnswers[currentQuestionIndex] = {question: currentQuestion.type, answer}; setUserAnswers(tempAnswers); - setError(''); }; /** @@ -94,32 +87,39 @@ function IdologyQuestions({questions, walletAdditionalDetails, idNumber}) { */ const submitAnswers = () => { if (!userAnswers[currentQuestionIndex]) { - setError(translate('additionalDetailsStep.selectAnswer')); - } else { - // 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}; - } - } + return; + } + // Get the number of questions that were skipped by the user. + const skippedQuestionsCount = _.filter(userAnswers, (answer) => answer.answer === SKIP_QUESTION_TEXT).length; - BankAccounts.answerQuestionsForWallet(tempAnswers, idNumber); - setUserAnswers(tempAnswers); - } else { - // Else, show next question - setCurrentQuestionIndex(currentQuestionIndex + 1); - setShouldHideSkipAnswer(skippedQuestionsCount >= MAX_SKIP); + // 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); + } else { + // Else, show next question + setCurrentQuestionIndex(currentQuestionIndex + 1); + setShouldHideSkipAnswer(skippedQuestionsCount >= MAX_SKIP); } }; + const validate = (values) => { + const errors = {}; + if (!values.answer) { + errors.answer = translate('additionalDetailsStep.selectAnswer'); + } + return errors; + }; + return ( @@ -131,33 +131,23 @@ function IdologyQuestions({questions, walletAdditionalDetails, 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]} + + - - + ); } From 92fcded92c2efcbffe9294b20eed85c3a1eabf42 Mon Sep 17 00:00:00 2001 From: Kamil Owczarz Date: Wed, 29 Nov 2023 17:21:52 +0100 Subject: [PATCH 2/2] Fix no error message if press Save&Continue without fill anything in 2 & next idology question --- src/pages/EnablePayments/IdologyQuestions.js | 1 + 1 file changed, 1 insertion(+) diff --git a/src/pages/EnablePayments/IdologyQuestions.js b/src/pages/EnablePayments/IdologyQuestions.js index 569a6f9aa109..9e4f9d697fca 100644 --- a/src/pages/EnablePayments/IdologyQuestions.js +++ b/src/pages/EnablePayments/IdologyQuestions.js @@ -134,6 +134,7 @@ function IdologyQuestions({questions, idNumber}) {