import { Form, Formik, useFormikContext } from 'formik' import * as R from 'ramda' import React, { useState, Fragment, useEffect } from 'react' import ErrorMessage from 'src/components/ErrorMessage' import Modal from 'src/components/Modal' import Stepper from 'src/components/Stepper' import { H5, Info3 } from 'src/components/typography' import { Button } from 'src/components/buttons' import { singularOrPlural } from 'src/utils/string' import { type, requirements } from './helper' const LAST_STEP = 2 const getStep = ( { step, config }, currency, customInfoRequests, complianceServices, emailAuth, triggers, ) => { switch (step) { // case 1: // return txDirection case 1: return type(currency) case 2: return requirements( config, triggers, customInfoRequests, complianceServices, emailAuth, ) default: return Fragment } } const getText = (step, config, currency) => { switch (step) { // case 1: // return `In ${getDirectionText(config)} transactions` case 1: return <>If the user {getTypeText(config, currency)} case 2: return <>the user will be {getRequirementText(config)}. default: return <> } } const orUnderline = value => { const blankSpaceEl = ( ) return R.isEmpty(value) || R.isNil(value) ? blankSpaceEl : value } // const getDirectionText = config => { // switch (config.direction) { // case 'both': // return 'both cash-in and cash-out' // case 'cashIn': // return 'cash-in' // case 'cashOut': // return 'cash-out' // default: // return orUnderline(null) // } // } const getTypeText = (config, currency) => { switch (config.triggerType) { case 'txAmount': return ( <> makes a single transaction over{' '} {orUnderline(config.threshold.threshold)} {currency} ) case 'txVolume': return ( <> makes more than {orUnderline(config.threshold.threshold)} {currency}{' '} worth of transactions within{' '} {orUnderline(config.threshold.thresholdDays)}{' '} {singularOrPlural(config.threshold.thresholdDays, 'day', 'days')} ) case 'txVelocity': return ( <> makes more than {orUnderline(config.threshold.threshold)}{' '} {singularOrPlural( config.threshold.threshold, 'transaction', 'transactions', )}{' '} in {orUnderline(config.threshold.thresholdDays)}{' '} {singularOrPlural(config.threshold.thresholdDays, 'day', 'days')} ) case 'consecutiveDays': return ( <> at least one transaction every day for{' '} {orUnderline(config.threshold.thresholdDays)}{' '} {singularOrPlural(config.threshold.thresholdDays, 'day', 'days')} ) default: return <> } } const getRequirementText = config => { switch (config.requirement?.requirement) { case 'email': return <>asked to enter code provided through email verification case 'sms': return <>asked to enter code provided through SMS verification case 'idCardPhoto': return <>asked to scan a ID with photo case 'idCardData': return <>asked to scan a ID case 'facephoto': return <>asked to have a photo taken case 'usSsn': return <>asked to input his social security number case 'sanctions': return <>matched against the OFAC sanctions list case 'superuser': return <> case 'suspend': return ( <> suspended for {orUnderline(config.requirement.suspensionDays)}{' '} {singularOrPlural(config.requirement.suspensionDays, 'day', 'days')} ) case 'block': return <>blocked case 'custom': return <>asked to fulfill a custom requirement case 'external': return <>redirected to an external verification process default: return orUnderline(null) } } const InfoPanel = ({ step, config = {}, liveValues = {}, currency }) => { const oldText = R.range(1, step).map((it, idx) => ( {getText(it, config, currency)} )) const newText = getText(step, liveValues, currency) const isLastStep = step === LAST_STEP return ( <>
Trigger overview so far
{oldText} {step !== 1 && ', '} {newText} {!isLastStep && '...'} ) } const GetValues = ({ setValues }) => { const { values } = useFormikContext() useEffect(() => { setValues && values && setValues(values) }, [setValues, values]) return null } const Wizard = ({ onClose, save, error, currency, customInfoRequests, complianceServices, emailAuth, triggers, }) => { const [liveValues, setLiveValues] = useState({}) const [{ step, config }, setState] = useState({ step: 1, }) const isLastStep = step === LAST_STEP const stepOptions = getStep( { step, config }, currency, customInfoRequests, complianceServices, emailAuth, triggers, ) const onContinue = async it => { const newConfig = R.merge(config, stepOptions.schema.cast(it)) if (isLastStep) { return save(newConfig) } setState({ step: step + 1, config: newConfig, }) } const createErrorMessage = (errors, touched, values) => { const triggerType = values?.triggerType const containsType = R.contains(triggerType) const isSuspend = values?.requirement?.requirement === 'suspend' const isCustom = values?.requirement?.requirement === 'custom' const hasRequirementError = requirements().hasRequirementError( errors, touched, values, ) const hasCustomRequirementError = requirements().hasCustomRequirementError( errors, touched, values, ) const hasAmountError = !!errors.threshold && !!touched.threshold?.threshold && !containsType(['consecutiveDays']) && (!values.threshold?.threshold || values.threshold?.threshold < 0) const hasDaysError = !!errors.threshold && !!touched.threshold?.thresholdDays && !containsType(['txAmount']) && (!values.threshold?.thresholdDays || values.threshold?.thresholdDays < 0) if (containsType(['txAmount', 'txVolume', 'txVelocity']) && hasAmountError) return errors.threshold if ( containsType(['txVolume', 'txVelocity', 'consecutiveDays']) && hasDaysError ) return errors.threshold if ( (isSuspend && hasRequirementError) || (isCustom && hasCustomRequirementError) ) return errors.requirement } return ( <> } infoPanelHeight={172} open={true}> {({ errors, touched, values }) => (
{error && Failed to save} {createErrorMessage(errors, touched, values) && ( {createErrorMessage(errors, touched, values)} )}
)}
) } export default Wizard