feat: enable custom entries and custom information requirements
This commit is contained in:
parent
e44e5012f1
commit
bd0701236c
9 changed files with 257 additions and 129 deletions
|
|
@ -993,6 +993,7 @@ function addCustomField (customerId, label, value) {
|
|||
}
|
||||
})
|
||||
)
|
||||
.then(res => !_.isNil(res))
|
||||
}
|
||||
|
||||
function saveCustomField (customerId, fieldId, newValue) {
|
||||
|
|
|
|||
|
|
@ -1,12 +1,6 @@
|
|||
const { gql } = require('apollo-server-express')
|
||||
|
||||
const typeDef = gql`
|
||||
type CustomerCustomField {
|
||||
id: ID
|
||||
label: String
|
||||
value: String
|
||||
}
|
||||
|
||||
type Customer {
|
||||
id: ID!
|
||||
authorizedOverride: String
|
||||
|
|
@ -86,6 +80,12 @@ const typeDef = gql`
|
|||
content: String
|
||||
}
|
||||
|
||||
type CustomerCustomField {
|
||||
id: ID
|
||||
label: String
|
||||
value: String
|
||||
}
|
||||
|
||||
type Query {
|
||||
customers(phone: String, name: String, address: String, id: String): [Customer] @auth
|
||||
customer(customerId: ID!): Customer @auth
|
||||
|
|
@ -94,9 +94,9 @@ const typeDef = gql`
|
|||
|
||||
type Mutation {
|
||||
setCustomer(customerId: ID!, customerInput: CustomerInput): Customer @auth
|
||||
addCustomField(customerId: ID!, label: String!, value: String!): CustomerCustomField @auth
|
||||
saveCustomField(customerId: ID!, fieldId: ID!, value: String!): CustomerCustomField @auth
|
||||
removeCustomField(customerId: ID!, fieldId: ID!): CustomerCustomField @auth
|
||||
addCustomField(customerId: ID!, label: String!, value: String!): Boolean @auth
|
||||
saveCustomField(customerId: ID!, fieldId: ID!, value: String!): Boolean @auth
|
||||
removeCustomField(customerId: ID!, fieldId: ID!): Boolean @auth
|
||||
editCustomer(customerId: ID!, customerEdit: CustomerEdit): Customer @auth
|
||||
deleteEditedData(customerId: ID!, customerEdit: CustomerEdit): Customer @auth
|
||||
replacePhoto(customerId: ID!, photoType: String, newPhoto: UploadGQL): Customer @auth
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
import Grid from '@material-ui/core/Grid'
|
||||
import { makeStyles } from '@material-ui/core/styles'
|
||||
import { parse, format, isValid } from 'date-fns/fp'
|
||||
import { parse, format } from 'date-fns/fp'
|
||||
import _ from 'lodash/fp'
|
||||
import * as R from 'ramda'
|
||||
import { useState, React } from 'react'
|
||||
|
|
@ -26,6 +26,7 @@ import { URI } from 'src/utils/apollo'
|
|||
|
||||
import styles from './CustomerData.styles.js'
|
||||
import { EditableCard } from './components'
|
||||
import { customerDataElements, customerDataschemas } from './helper.js'
|
||||
|
||||
const useStyles = makeStyles(styles)
|
||||
|
||||
|
|
@ -84,8 +85,8 @@ const CustomerData = ({
|
|||
R.compose(R.toLower, R.path(['customInfoRequest', 'customRequest', 'name']))
|
||||
)
|
||||
|
||||
const customEntries = null // get customer custom entries
|
||||
const customRequirements = [] // get customer custom requirements
|
||||
const customFields = []
|
||||
const customRequirements = []
|
||||
const customInfoRequests = sortByName(
|
||||
R.path(['customInfoRequests'])(customer) ?? []
|
||||
)
|
||||
|
|
@ -94,85 +95,6 @@ const CustomerData = ({
|
|||
|
||||
const getVisibleCards = _.filter(elem => elem.isAvailable)
|
||||
|
||||
const schemas = {
|
||||
idScan: Yup.object().shape({
|
||||
firstName: Yup.string().required(),
|
||||
lastName: Yup.string().required(),
|
||||
documentNumber: Yup.string().required(),
|
||||
dateOfBirth: Yup.string()
|
||||
.test({
|
||||
test: val => isValid(parse(new Date(), 'yyyy-MM-dd', val))
|
||||
})
|
||||
.required(),
|
||||
gender: Yup.string().required(),
|
||||
country: Yup.string().required(),
|
||||
expirationDate: Yup.string()
|
||||
.test({
|
||||
test: val => isValid(parse(new Date(), 'yyyy-MM-dd', val))
|
||||
})
|
||||
.required()
|
||||
}),
|
||||
usSsn: Yup.object().shape({
|
||||
usSsn: Yup.string().required()
|
||||
}),
|
||||
idCardPhoto: Yup.object().shape({
|
||||
idCardPhoto: Yup.mixed().required()
|
||||
}),
|
||||
frontCamera: Yup.object().shape({
|
||||
frontCamera: Yup.mixed().required()
|
||||
})
|
||||
}
|
||||
|
||||
const idScanElements = [
|
||||
{
|
||||
name: 'firstName',
|
||||
label: 'First name',
|
||||
component: TextInput
|
||||
},
|
||||
{
|
||||
name: 'documentNumber',
|
||||
label: 'ID number',
|
||||
component: TextInput
|
||||
},
|
||||
{
|
||||
name: 'dateOfBirth',
|
||||
label: 'Birthdate',
|
||||
component: TextInput
|
||||
},
|
||||
{
|
||||
name: 'gender',
|
||||
label: 'Gender',
|
||||
component: TextInput
|
||||
},
|
||||
{
|
||||
name: 'lastName',
|
||||
label: 'Last name',
|
||||
component: TextInput
|
||||
},
|
||||
{
|
||||
name: 'expirationDate',
|
||||
label: 'Expiration Date',
|
||||
component: TextInput
|
||||
},
|
||||
{
|
||||
name: 'country',
|
||||
label: 'Country',
|
||||
component: TextInput
|
||||
}
|
||||
]
|
||||
|
||||
const usSsnElements = [
|
||||
{
|
||||
name: 'usSsn',
|
||||
label: 'US SSN',
|
||||
component: TextInput,
|
||||
size: 190
|
||||
}
|
||||
]
|
||||
|
||||
const idCardPhotoElements = [{ name: 'idCardPhoto' }]
|
||||
const frontCameraElements = [{ name: 'frontCamera' }]
|
||||
|
||||
const initialValues = {
|
||||
idScan: {
|
||||
firstName: R.path(['firstName'])(idData) ?? '',
|
||||
|
|
@ -214,7 +136,7 @@ const CustomerData = ({
|
|||
|
||||
const cards = [
|
||||
{
|
||||
fields: idScanElements,
|
||||
fields: customerDataElements.idScanElements,
|
||||
title: 'ID Scan',
|
||||
titleIcon: <CardIcon className={classes.cardIcon} />,
|
||||
state: R.path(['idCardDataOverride'])(customer),
|
||||
|
|
@ -226,7 +148,7 @@ const CustomerData = ({
|
|||
editCustomer({
|
||||
idCardData: _.merge(idData, formatDates(values))
|
||||
}),
|
||||
validationSchema: schemas.idScan,
|
||||
validationSchema: customerDataschemas.idScan,
|
||||
initialValues: initialValues.idScan,
|
||||
isAvailable: !_.isNil(idData)
|
||||
},
|
||||
|
|
@ -257,7 +179,7 @@ const CustomerData = ({
|
|||
isAvailable: !_.isNil(sanctions)
|
||||
},
|
||||
{
|
||||
fields: frontCameraElements,
|
||||
fields: customerDataElements.frontCameraElements,
|
||||
title: 'Front facing camera',
|
||||
titleIcon: <EditIcon className={classes.editIcon} />,
|
||||
state: R.path(['frontCameraOverride'])(customer),
|
||||
|
|
@ -279,12 +201,12 @@ const CustomerData = ({
|
|||
/>
|
||||
) : null,
|
||||
hasImage: true,
|
||||
validationSchema: schemas.frontCamera,
|
||||
validationSchema: customerDataschemas.frontCamera,
|
||||
initialValues: initialValues.frontCamera,
|
||||
isAvailable: !_.isNil(customer.frontCameraPath)
|
||||
},
|
||||
{
|
||||
fields: idCardPhotoElements,
|
||||
fields: customerDataElements.idCardPhotoElements,
|
||||
title: 'ID card image',
|
||||
titleIcon: <EditIcon className={classes.editIcon} />,
|
||||
state: R.path(['idCardPhotoOverride'])(customer),
|
||||
|
|
@ -304,12 +226,12 @@ const CustomerData = ({
|
|||
/>
|
||||
) : null,
|
||||
hasImage: true,
|
||||
validationSchema: schemas.idCardPhoto,
|
||||
validationSchema: customerDataschemas.idCardPhoto,
|
||||
initialValues: initialValues.idCardPhoto,
|
||||
isAvailable: !_.isNil(customer.idCardPhotoPath)
|
||||
},
|
||||
{
|
||||
fields: usSsnElements,
|
||||
fields: customerDataElements.usSsnElements,
|
||||
title: 'US SSN',
|
||||
titleIcon: <CardIcon className={classes.cardIcon} />,
|
||||
state: R.path(['usSsnOverride'])(customer),
|
||||
|
|
@ -317,7 +239,7 @@ const CustomerData = ({
|
|||
reject: () => updateCustomer({ usSsnOverride: OVERRIDE_REJECTED }),
|
||||
save: values => editCustomer({ usSsn: values.usSsn }),
|
||||
deleteEditedData: () => deleteEditedData({ usSsn: null }),
|
||||
validationSchema: schemas.usSsn,
|
||||
validationSchema: customerDataschemas.usSsn,
|
||||
initialValues: initialValues.usSsn,
|
||||
isAvailable: !_.isNil(customer.usSsn)
|
||||
}
|
||||
|
|
@ -374,6 +296,29 @@ const CustomerData = ({
|
|||
})
|
||||
}, customInfoRequests)
|
||||
|
||||
R.forEach(it => {
|
||||
customFields.push({
|
||||
fields: [
|
||||
{
|
||||
name: it.label,
|
||||
label: it.label,
|
||||
value: it.value ?? '',
|
||||
component: TextInput
|
||||
}
|
||||
],
|
||||
title: it.label,
|
||||
titleIcon: <EditIcon className={classes.editIcon} />,
|
||||
save: () => {},
|
||||
deleteEditedData: () => {},
|
||||
validationSchema: Yup.object().shape({
|
||||
[it.label]: Yup.string()
|
||||
}),
|
||||
initialValues: {
|
||||
[it.label]: it.value ?? ''
|
||||
}
|
||||
})
|
||||
}, R.path(['customFields'])(customer) ?? [])
|
||||
|
||||
const editableCard = (
|
||||
{
|
||||
title,
|
||||
|
|
@ -444,9 +389,21 @@ const CustomerData = ({
|
|||
</Grid>
|
||||
</Grid>
|
||||
)}
|
||||
{customEntries && (
|
||||
{!_.isEmpty(customFields) && (
|
||||
<div className={classes.wrapper}>
|
||||
<span className={classes.separator}>Custom data entry</span>
|
||||
<Grid container>
|
||||
<Grid container direction="column" item xs={6}>
|
||||
{customFields.map((elem, idx) => {
|
||||
return isEven(idx) ? editableCard(elem, idx) : null
|
||||
})}
|
||||
</Grid>
|
||||
<Grid container direction="column" item xs={6}>
|
||||
{customFields.map((elem, idx) => {
|
||||
return !isEven(idx) ? editableCard(elem, idx) : null
|
||||
})}
|
||||
</Grid>
|
||||
</Grid>
|
||||
</div>
|
||||
)}
|
||||
{!R.isEmpty(customRequirements) && (
|
||||
|
|
|
|||
|
|
@ -236,6 +236,21 @@ const GET_DATA = gql`
|
|||
}
|
||||
`
|
||||
|
||||
const SET_CUSTOM_ENTRY = gql`
|
||||
mutation addCustomField($customerId: ID!, $label: String!, $value: String!) {
|
||||
addCustomField(customerId: $customerId, label: $label, value: $value)
|
||||
}
|
||||
`
|
||||
|
||||
const GET_ACTIVE_CUSTOM_REQUESTS = gql`
|
||||
query customInfoRequests($onlyEnabled: Boolean) {
|
||||
customInfoRequests(onlyEnabled: $onlyEnabled) {
|
||||
id
|
||||
customRequest
|
||||
}
|
||||
}
|
||||
`
|
||||
|
||||
const CustomerProfile = memo(() => {
|
||||
const history = useHistory()
|
||||
|
||||
|
|
@ -255,6 +270,16 @@ const CustomerProfile = memo(() => {
|
|||
|
||||
const { data: configResponse, loading: configLoading } = useQuery(GET_DATA)
|
||||
|
||||
const { data: activeCustomRequests } = useQuery(GET_ACTIVE_CUSTOM_REQUESTS, {
|
||||
variables: {
|
||||
onlyEnabled: true
|
||||
}
|
||||
})
|
||||
|
||||
const [setCustomEntry] = useMutation(SET_CUSTOM_ENTRY, {
|
||||
onCompleted: () => getCustomer()
|
||||
})
|
||||
|
||||
const [replaceCustomerPhoto] = useMutation(REPLACE_CUSTOMER_PHOTO, {
|
||||
onCompleted: () => getCustomer()
|
||||
})
|
||||
|
|
@ -294,6 +319,17 @@ const CustomerProfile = memo(() => {
|
|||
onCompleted: () => getCustomer()
|
||||
})
|
||||
|
||||
const saveCustomEntry = it => {
|
||||
setCustomEntry({
|
||||
variables: {
|
||||
customerId,
|
||||
label: it.title,
|
||||
value: it.data
|
||||
}
|
||||
})
|
||||
setWizard(null)
|
||||
}
|
||||
|
||||
const updateCustomer = it =>
|
||||
setCustomer({
|
||||
variables: {
|
||||
|
|
@ -385,6 +421,12 @@ const CustomerProfile = memo(() => {
|
|||
|
||||
const timezone = R.path(['config', 'locale_timezone'], configResponse)
|
||||
|
||||
const customRequirementOptions =
|
||||
activeCustomRequests?.customInfoRequests?.map(it => ({
|
||||
value: it.id,
|
||||
display: it.customRequest.name
|
||||
})) ?? []
|
||||
|
||||
const classes = useStyles()
|
||||
|
||||
return (
|
||||
|
|
@ -544,8 +586,11 @@ const CustomerProfile = memo(() => {
|
|||
{wizard && (
|
||||
<Wizard
|
||||
error={error?.message}
|
||||
save={() => {}}
|
||||
save={saveCustomEntry}
|
||||
addPhoto={replacePhoto}
|
||||
addCustomerData={editCustomer}
|
||||
onClose={() => setWizard(null)}
|
||||
customRequirementOptions={customRequirementOptions}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import { makeStyles } from '@material-ui/core'
|
||||
import { Form, Formik } from 'formik'
|
||||
import { Form, Formik, Field } from 'formik'
|
||||
import * as R from 'ramda'
|
||||
import React, { useState, Fragment } from 'react'
|
||||
|
||||
|
|
@ -7,6 +7,7 @@ import ErrorMessage from 'src/components/ErrorMessage'
|
|||
import Modal from 'src/components/Modal'
|
||||
import Stepper from 'src/components/Stepper'
|
||||
import { Button } from 'src/components/buttons'
|
||||
import { Dropdown } from 'src/components/inputs/formik'
|
||||
import { comet } from 'src/styling/variables'
|
||||
|
||||
import { entryType, customElements } from './helper'
|
||||
|
|
@ -41,6 +42,10 @@ const styles = {
|
|||
margin: [[0, 4, 0, 2]],
|
||||
borderBottom: `1px solid ${comet}`,
|
||||
display: 'inline-block'
|
||||
},
|
||||
dropdownField: {
|
||||
marginTop: 16,
|
||||
minWidth: 155
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -57,7 +62,14 @@ const getStep = (step, selectedValues) => {
|
|||
}
|
||||
}
|
||||
|
||||
const Wizard = ({ onClose, save, error }) => {
|
||||
const Wizard = ({
|
||||
onClose,
|
||||
save,
|
||||
error,
|
||||
customRequirementOptions,
|
||||
addCustomerData,
|
||||
addPhoto
|
||||
}) => {
|
||||
const classes = useStyles()
|
||||
|
||||
const [selectedValues, setSelectedValues] = useState(null)
|
||||
|
|
@ -66,6 +78,7 @@ const Wizard = ({ onClose, save, error }) => {
|
|||
step: 1
|
||||
})
|
||||
|
||||
const isCustom = values => values?.requirement === 'custom'
|
||||
const isLastStep = step === LAST_STEP
|
||||
const stepOptions = getStep(step, selectedValues)
|
||||
|
||||
|
|
@ -103,18 +116,34 @@ const Wizard = ({ onClose, save, error }) => {
|
|||
onSubmit={onContinue}
|
||||
initialValues={stepOptions.initialValues}
|
||||
validationSchema={stepOptions.schema}>
|
||||
<Form className={classes.form}>
|
||||
<stepOptions.Component
|
||||
selectedValues={selectedValues}
|
||||
{...stepOptions.props}
|
||||
/>
|
||||
<div className={classes.submit}>
|
||||
{error && <ErrorMessage>Failed to save</ErrorMessage>}
|
||||
<Button className={classes.button} type="submit">
|
||||
{isLastStep ? 'Add Data' : 'Next'}
|
||||
</Button>
|
||||
</div>
|
||||
</Form>
|
||||
{({ values }) => (
|
||||
<Form className={classes.form}>
|
||||
<stepOptions.Component
|
||||
selectedValues={selectedValues}
|
||||
hasCustomRequirementOptions={
|
||||
!R.isEmpty(customRequirementOptions)
|
||||
}
|
||||
{...stepOptions.props}
|
||||
/>
|
||||
{isCustom(values) && (
|
||||
<div>
|
||||
<Field
|
||||
className={classes.dropdownField}
|
||||
component={Dropdown}
|
||||
label="Available requests"
|
||||
name="requirement.customInfoRequestId"
|
||||
options={customRequirementOptions}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
<div className={classes.submit}>
|
||||
{error && <ErrorMessage>Failed to save</ErrorMessage>}
|
||||
<Button className={classes.button} type="submit">
|
||||
{isLastStep ? 'Add Data' : 'Next'}
|
||||
</Button>
|
||||
</div>
|
||||
</Form>
|
||||
)}
|
||||
</Formik>
|
||||
</Modal>
|
||||
</>
|
||||
|
|
|
|||
|
|
@ -150,7 +150,7 @@ const EditableCard = ({
|
|||
<H3 className={classes.cardTitle}>{title}</H3>
|
||||
<Tooltip width={304}></Tooltip>
|
||||
</div>
|
||||
{state && (
|
||||
{state && authorize && (
|
||||
<div className={classnames(label1ClassNames)}>
|
||||
<MainStatus statuses={[authorized]} />
|
||||
</div>
|
||||
|
|
@ -279,7 +279,7 @@ const EditableCard = ({
|
|||
Cancel
|
||||
</ActionButton>
|
||||
</div>
|
||||
{authorized.label !== 'Accepted' && (
|
||||
{authorize && authorized.label !== 'Accepted' && (
|
||||
<div className={classes.button}>
|
||||
<ActionButton
|
||||
color="spring"
|
||||
|
|
@ -291,7 +291,7 @@ const EditableCard = ({
|
|||
</ActionButton>
|
||||
</div>
|
||||
)}
|
||||
{authorized.label !== 'Rejected' && (
|
||||
{authorize && authorized.label !== 'Rejected' && (
|
||||
<ActionButton
|
||||
color="tomato"
|
||||
type="button"
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
import { makeStyles, Box } from '@material-ui/core'
|
||||
import classnames from 'classnames'
|
||||
import { parse, isValid } from 'date-fns/fp'
|
||||
import { Field, useFormikContext } from 'formik'
|
||||
import { parsePhoneNumberFromString } from 'libphonenumber-js'
|
||||
import * as R from 'ramda'
|
||||
|
|
@ -63,23 +64,25 @@ const getName = it => {
|
|||
) ?? ''}`.trim()
|
||||
}
|
||||
|
||||
// Manual Entry Wizard
|
||||
|
||||
const entryOptions = [
|
||||
{ display: 'Custom entry', code: 'custom' },
|
||||
{ display: 'Populate existing requirement', code: 'requirement' }
|
||||
]
|
||||
|
||||
const dataOptions = [
|
||||
{ display: 'Text', code: 'text' },
|
||||
{ display: 'File', code: 'file' },
|
||||
{ display: 'Image', code: 'image' }
|
||||
{ display: 'Text', code: 'text' }
|
||||
// TODO: Requires backend modifications to support File and Image
|
||||
// { display: 'File', code: 'file' },
|
||||
// { display: 'Image', code: 'image' }
|
||||
]
|
||||
|
||||
const requirementOptions = [
|
||||
{ display: 'Birthdate', code: 'birthdate' },
|
||||
{ display: 'ID card image', code: 'idCardPhoto' },
|
||||
{ display: 'ID data', code: 'idCardData' },
|
||||
{ display: 'Customer camera', code: 'facephoto' },
|
||||
{ display: 'US SSN', code: 'usSsn' }
|
||||
{ display: 'US SSN', code: 'usSsn' },
|
||||
{ display: 'Customer camera', code: 'facephoto' }
|
||||
]
|
||||
|
||||
const customTextOptions = [
|
||||
|
|
@ -108,7 +111,7 @@ const customTextSchema = Yup.object().shape({
|
|||
data: Yup.string().required()
|
||||
})
|
||||
|
||||
const EntryType = () => {
|
||||
const EntryType = ({ hasCustomRequirementOptions }) => {
|
||||
const classes = useStyles()
|
||||
const { values } = useFormikContext()
|
||||
|
||||
|
|
@ -154,7 +157,17 @@ const EntryType = () => {
|
|||
<Field
|
||||
component={RadioGroup}
|
||||
name="requirement"
|
||||
options={requirementOptions}
|
||||
options={
|
||||
hasCustomRequirementOptions
|
||||
? [
|
||||
{
|
||||
display: 'Custom information requirement',
|
||||
code: 'custom'
|
||||
},
|
||||
...requirementOptions
|
||||
]
|
||||
: requirementOptions
|
||||
}
|
||||
labelClassName={classes.label}
|
||||
radioClassName={classes.radio}
|
||||
className={classnames(classes.radioGroup, classes.specialGrid)}
|
||||
|
|
@ -209,6 +222,87 @@ const entryType = {
|
|||
initialValues: { entryType: '' }
|
||||
}
|
||||
|
||||
// Customer data
|
||||
|
||||
const customerDataElements = {
|
||||
idScanElements: [
|
||||
{
|
||||
name: 'firstName',
|
||||
label: 'First name',
|
||||
component: TextInput
|
||||
},
|
||||
{
|
||||
name: 'documentNumber',
|
||||
label: 'ID number',
|
||||
component: TextInput
|
||||
},
|
||||
{
|
||||
name: 'dateOfBirth',
|
||||
label: 'Birthdate',
|
||||
component: TextInput
|
||||
},
|
||||
{
|
||||
name: 'gender',
|
||||
label: 'Gender',
|
||||
component: TextInput
|
||||
},
|
||||
{
|
||||
name: 'lastName',
|
||||
label: 'Last name',
|
||||
component: TextInput
|
||||
},
|
||||
{
|
||||
name: 'expirationDate',
|
||||
label: 'Expiration Date',
|
||||
component: TextInput
|
||||
},
|
||||
{
|
||||
name: 'country',
|
||||
label: 'Country',
|
||||
component: TextInput
|
||||
}
|
||||
],
|
||||
usSsnElements: [
|
||||
{
|
||||
name: 'usSsn',
|
||||
label: 'US SSN',
|
||||
component: TextInput,
|
||||
size: 190
|
||||
}
|
||||
],
|
||||
idCardPhotoElements: [{ name: 'idCardPhoto' }],
|
||||
frontCameraElements: [{ name: 'frontCamera' }]
|
||||
}
|
||||
|
||||
const customerDataschemas = {
|
||||
idScan: Yup.object().shape({
|
||||
firstName: Yup.string().required(),
|
||||
lastName: Yup.string().required(),
|
||||
documentNumber: Yup.string().required(),
|
||||
dateOfBirth: Yup.string()
|
||||
.test({
|
||||
test: val => isValid(parse(new Date(), 'yyyy-MM-dd', val))
|
||||
})
|
||||
.required(),
|
||||
gender: Yup.string().required(),
|
||||
country: Yup.string().required(),
|
||||
expirationDate: Yup.string()
|
||||
.test({
|
||||
test: val => isValid(parse(new Date(), 'yyyy-MM-dd', val))
|
||||
})
|
||||
.required()
|
||||
}),
|
||||
usSsn: Yup.object().shape({
|
||||
usSsn: Yup.string().required()
|
||||
}),
|
||||
idCardPhoto: Yup.object().shape({
|
||||
idCardPhoto: Yup.mixed().required()
|
||||
}),
|
||||
frontCamera: Yup.object().shape({
|
||||
frontCamera: Yup.mixed().required()
|
||||
})
|
||||
}
|
||||
|
||||
const mapKeys = pair => {
|
||||
const [key, value] = pair
|
||||
if (key === 'txCustomerPhotoPath' || key === 'frontCameraPath') {
|
||||
|
|
@ -245,5 +339,7 @@ export {
|
|||
getName,
|
||||
entryType,
|
||||
customElements,
|
||||
formatPhotosData
|
||||
formatPhotosData,
|
||||
customerDataElements,
|
||||
customerDataschemas
|
||||
}
|
||||
|
|
|
|||
|
|
@ -62,7 +62,7 @@ const Graph = ({ data, timeFrame, timezone }) => {
|
|||
[]
|
||||
)
|
||||
|
||||
const filterDay = useMemo(
|
||||
const filterDay = useCallback(
|
||||
x => (timeFrame === 'day' ? x.getUTCHours() === 0 : x.getUTCDate() === 1),
|
||||
[timeFrame]
|
||||
)
|
||||
|
|
|
|||
|
|
@ -554,7 +554,7 @@ const Requirement = () => {
|
|||
}
|
||||
const options = enableCustomRequirement
|
||||
? [...requirementOptions, customInfoOption]
|
||||
: [...requirementOptions, { ...customInfoOption, disabled: true }]
|
||||
: [...requirementOptions]
|
||||
const titleClass = {
|
||||
[classes.error]:
|
||||
(!!errors.requirement && !isSuspend) || (isSuspend && hasRequirementError)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue