import { FiatAccountType } from '@fiatconnect/fiatconnect-types' import { NativeStackScreenProps } from '@react-navigation/native-stack' import React, { useEffect, useLayoutEffect, useMemo, useRef, useState } from 'react' import { useTranslation } from 'react-i18next' import { ActivityIndicator, Image, StyleSheet, Text, TouchableOpacity, View } from 'react-native' import PickerSelect from 'react-native-picker-select' import { SafeAreaView } from 'react-native-safe-area-context' import AppAnalytics from 'src/analytics/AppAnalytics' import { FiatExchangeEvents } from 'src/analytics/Events' import BackButton from 'src/components/BackButton' import Button, { BtnSizes } from 'src/components/Button' import CancelButton from 'src/components/CancelButton' import Dialog from 'src/components/Dialog' import KeyboardAwareScrollView from 'src/components/KeyboardAwareScrollView' import KeyboardSpacer from 'src/components/KeyboardSpacer' import TextInput, { LINE_HEIGHT } from 'src/components/TextInput' import { getSchema, isComputedParam, isFormFieldParam, isImplicitParam, } from 'src/fiatconnect/fiatAccountSchemas' import { FormFieldParam } from 'src/fiatconnect/fiatAccountSchemas/types' import { schemaCountryOverridesSelector, sendingFiatAccountStatusSelector, } from 'src/fiatconnect/selectors' import { SendingFiatAccountStatus, submitFiatAccount } from 'src/fiatconnect/slice' import Checkmark from 'src/icons/Checkmark' import InfoIcon from 'src/icons/InfoIcon' import { styles as headerStyles } from 'src/navigator/Headers' import { navigateHome } from 'src/navigator/NavigationService' import { Screens } from 'src/navigator/Screens' import { StackParamList } from 'src/navigator/types' import { userLocationDataSelector } from 'src/networkInfo/selectors' import { useDispatch, useSelector } from 'src/redux/hooks' import colors from 'src/styles/colors' import { typeScale } from 'src/styles/fonts' import variables from 'src/styles/variables' export const TAG = 'FIATCONNECT/FiatDetailsScreen' type ScreenProps = NativeStackScreenProps type Props = ScreenProps const SHOW_ERROR_DELAY_MS = 1500 const FiatDetailsScreen = ({ route, navigation }: Props) => { const { t } = useTranslation() const { flow, quote } = route.params const sendingFiatAccountStatus = useSelector(sendingFiatAccountStatusSelector) const [validInputs, setValidInputs] = useState(false) const [errors, setErrors] = useState(new Map()) const fieldNamesToValues = useRef>({}) const { countryCodeAlpha2 } = useSelector(userLocationDataSelector) const dispatch = useDispatch() const schemaCountryOverrides = useSelector(schemaCountryOverridesSelector) const fiatAccountSchema = quote.getFiatAccountSchema() const fiatAccountType = quote.getFiatAccountType() const headerTitle = useMemo(() => { switch (fiatAccountType) { case FiatAccountType.BankAccount: return t('fiatDetailsScreen.headerBankAccount') case FiatAccountType.MobileMoney: return t('fiatDetailsScreen.headerMobileMoney') default: // should never happen throw new Error('Unsupported account type') } }, [fiatAccountType]) useLayoutEffect(() => { navigation.setOptions({ headerTitle: () => ( {headerTitle} {t('fiatDetailsScreen.headerSubTitle', { provider: quote.getProviderName() })} ), headerLeft: () => ( ), headerRight: () => ( { AppAnalytics.track(FiatExchangeEvents.cico_fiat_details_cancel, { flow: flow, provider: quote.getProviderId(), fiatAccountSchema, }) navigateHome() }} style={styles.cancelBtn} /> ), }) }, [navigation]) const schema = useMemo( () => getSchema({ fiatAccountSchema, country: countryCodeAlpha2, schemaCountryOverrides, fiatAccountType: quote.getFiatAccountType(), }), [fiatAccountSchema] ) const formFields = useMemo(() => { const fields = Object.values(schema).filter(isFormFieldParam) fields.forEach((field) => (fieldNamesToValues.current[field.name] = '')) return fields }, [fiatAccountSchema]) const implicitParameters = useMemo(() => { return Object.values(schema).filter(isImplicitParam) }, [fiatAccountSchema]) const computedParameters = useMemo(() => { return Object.values(schema).filter(isComputedParam) }, [fiatAccountSchema]) const onPressSubmit = async () => { validateInput() if (validInputs) { const body: Record = {} formFields.forEach((formField) => { body[formField.name] = fieldNamesToValues.current[formField.name] }) implicitParameters.forEach((param) => { body[param.name] = param.value }) computedParameters.forEach((param) => { body[param.name] = param.computeValue(body) }) dispatch( submitFiatAccount({ flow, quote, fiatAccountData: body, }) ) } } const validateInput = () => { setValidInputs(false) const newErrorMap = new Map() formFields.forEach((field) => { if (field.format) { fieldNamesToValues.current[field.name] = field.format( fieldNamesToValues.current[field.name] ) } const { isValid, errorMessage } = field.validate( fieldNamesToValues.current[field.name]?.trim(), fieldNamesToValues.current ) if (!isValid) { newErrorMap.set(field.name, errorMessage) } }) setErrors(newErrorMap) setValidInputs(newErrorMap.size === 0) } const setInputValue = ({ fieldName, value }: { fieldName: string; value: string }) => { fieldNamesToValues.current[fieldName] = value validateInput() } switch (sendingFiatAccountStatus) { case SendingFiatAccountStatus.Sending: return ( ) case SendingFiatAccountStatus.KycApproved: return ( ) case SendingFiatAccountStatus.NotSending: default: return ( {formFields.map((field) => ( { setInputValue({ fieldName, value }) }} allowedValues={quote.getFiatAccountSchemaAllowedValues(field.name)} isVisible={field.isVisible?.(fieldNamesToValues.current) ?? true} /> ))}