forked from deriv-com/deriv-app
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[account-v2]/likhith/coj-707/Incorporated POO Form (deriv-com#14813)
* chore: updated Deriv-ui * feat: incorporated File upload field * fix: incorporated File upload component * feat: added POO form * feat: added POO form * feat: added POO form * fix: incorporated review comments * fix: incorporated review comment * fix: incorporated code reviews * fix: incorporated review comments
- Loading branch information
1 parent
19f55ba
commit 7ea9c90
Showing
26 changed files
with
671 additions
and
63 deletions.
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
import React, { ComponentProps } from 'react'; | ||
import { Text } from '@deriv-com/ui'; | ||
|
||
export const LinkText = ({ children, ...rest }: ComponentProps<typeof Text>) => ( | ||
<Text as='a' color='red' rel='noreferrer' size='sm' target='_blank' {...rest}> | ||
{children} | ||
</Text> | ||
); |
11 changes: 11 additions & 0 deletions
11
packages/account-v2/src/components/LinkText/__tests__/LinkText.spec.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
import React from 'react'; | ||
import { render, screen } from '@testing-library/react'; | ||
import { LinkText } from '../LinkText'; | ||
|
||
describe('LinkText', () => { | ||
it('should render a link text', () => { | ||
render(<LinkText href='link_text'>Link Text</LinkText>); | ||
const linkText = screen.getByRole('link', { name: /Link Text/i }); | ||
expect(linkText).toBeInTheDocument(); | ||
}); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
151 changes: 151 additions & 0 deletions
151
packages/account-v2/src/containers/POOForm/FileUploadField.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,151 @@ | ||
import React, { ChangeEvent, MouseEvent, SyntheticEvent, useRef, useState } from 'react'; | ||
import clsx from 'clsx'; | ||
import { Field, FormikErrors, useFormikContext } from 'formik'; | ||
import { StandaloneXmarkRegularIcon } from '@deriv/quill-icons'; | ||
import { Button, Input } from '@deriv-com/ui'; | ||
import { TPaymentMethod, TProofOfOwnershipFormValue } from 'src/types'; | ||
import { compressImageFiles, TFile } from 'src/utils'; | ||
|
||
type TFileUploadFieldProps = { | ||
methodId: number; | ||
paymentMethod: TPaymentMethod; | ||
subIndex: number; | ||
}; | ||
|
||
export const FileUploaderField = ({ methodId, paymentMethod, subIndex }: TFileUploadFieldProps) => { | ||
const formik = useFormikContext<TProofOfOwnershipFormValue>(); | ||
const { errors, setFieldError, setFieldValue, values } = formik; | ||
const [showBrowseButton, setShowBrowseButton] = useState( | ||
!values[paymentMethod]?.[methodId]?.files?.[subIndex]?.name | ||
); | ||
|
||
if (!formik) { | ||
throw new Error('FileUploaderField must be used within a Formik component'); | ||
} | ||
|
||
// Create a reference to the hidden file input element | ||
const hiddenInputFieldRef = useRef<HTMLInputElement>(null); | ||
|
||
const preventEventBubble = (e: SyntheticEvent) => { | ||
e.nativeEvent.preventDefault(); | ||
e.nativeEvent.stopPropagation(); | ||
e.nativeEvent.stopImmediatePropagation(); | ||
}; | ||
|
||
const handleChange = async (event: ChangeEvent<HTMLInputElement>) => { | ||
preventEventBubble(event); | ||
// Check if files exist before proceeding | ||
if (!event.target.files || event.target.files.length === 0) { | ||
return; | ||
} | ||
const fileToUpload = await compressImageFiles([event.target.files[0]]); | ||
const paymentFileData = [...(values[paymentMethod]?.[methodId]?.files ?? [])]; | ||
paymentFileData[subIndex] = fileToUpload[0] as TFile; | ||
const selectedPaymentMethod = values?.[paymentMethod]; | ||
if (!selectedPaymentMethod) { | ||
return; | ||
} | ||
selectedPaymentMethod[methodId] = { | ||
...selectedPaymentMethod[methodId], | ||
files: paymentFileData ?? [], | ||
}; | ||
await setFieldValue(paymentMethod, { ...selectedPaymentMethod }); | ||
setShowBrowseButton(!fileToUpload[0]); | ||
}; | ||
|
||
const handleClick = (event: MouseEvent) => { | ||
preventEventBubble(event); | ||
hiddenInputFieldRef?.current?.click(); | ||
}; | ||
|
||
const updateError = () => { | ||
const paymentMethodError = errors?.[paymentMethod] ?? {}; | ||
const paymentMethodFileError = (paymentMethodError?.[methodId]?.files as FormikErrors<TFile>[]) ?? {}; | ||
|
||
delete paymentMethodFileError?.[subIndex]; | ||
paymentMethodError[methodId] = { | ||
...(paymentMethodError[methodId] ?? {}), | ||
files: paymentMethodFileError, | ||
}; | ||
|
||
// [TODO] - Need to check the logic for removing the paymentMethodIdentifier | ||
if (Object.keys(paymentMethodError[methodId]?.files as object).length === 0) { | ||
delete paymentMethodError[methodId]?.paymentMethodIdentifier; | ||
} | ||
// @ts-expect-error Error is an array | ||
setFieldError(paymentMethod, { ...paymentMethodFileError }); | ||
}; | ||
|
||
const handleIconClick = async (e: React.MouseEvent) => { | ||
e.nativeEvent.preventDefault(); | ||
e.nativeEvent.stopPropagation(); | ||
e.nativeEvent.stopImmediatePropagation(); | ||
|
||
if (hiddenInputFieldRef.current && 'value' in hiddenInputFieldRef.current) { | ||
hiddenInputFieldRef.current.value = ''; | ||
} | ||
const paymentFileData = values[paymentMethod]?.[methodId]?.files ?? []; | ||
const filteredFileData = paymentFileData.filter((_, i) => i !== subIndex); | ||
const selectedPaymentMethod = values?.[paymentMethod]; | ||
if (!selectedPaymentMethod) { | ||
return; | ||
} | ||
selectedPaymentMethod[methodId] = { | ||
...selectedPaymentMethod[methodId], | ||
files: filteredFileData, | ||
}; | ||
await setFieldValue(paymentMethod, { ...selectedPaymentMethod }); | ||
setShowBrowseButton(prevState => !prevState); | ||
updateError(); | ||
}; | ||
|
||
return ( | ||
<Field name={paymentMethod}> | ||
{() => { | ||
const errorMessage = errors?.[paymentMethod]?.[methodId]?.files?.[subIndex]; | ||
return ( | ||
<div className='flex gap-8'> | ||
<input | ||
accept='image/png, image/jpeg, image/jpg, application/pdf' | ||
className='hidden' | ||
name={paymentMethod} | ||
onChange={handleChange} | ||
ref={hiddenInputFieldRef} | ||
type='file' | ||
/> | ||
<Input | ||
error={Boolean(errorMessage)} | ||
isFullWidth | ||
label='Choose a photo' | ||
maxLength={255} | ||
message={ | ||
errorMessage | ||
? errorMessage?.toString() | ||
: 'Accepted formats: pdf, jpeg, jpg, and png. Max file size: 8MB' | ||
} | ||
name='cardImgName' | ||
readOnly | ||
rightPlaceholder={ | ||
<Button | ||
className={clsx({ hidden: showBrowseButton })} | ||
color='white' | ||
onClick={handleIconClick} | ||
size='md' | ||
type='button' | ||
variant='ghost' | ||
> | ||
<StandaloneXmarkRegularIcon height={20} width={20} /> | ||
</Button> | ||
} | ||
type='text' | ||
value={values[paymentMethod]?.[methodId]?.files?.[subIndex]?.name ?? ''} | ||
/> | ||
<Button onClick={handleClick} size='lg' type='button'> | ||
Browse | ||
</Button> | ||
</div> | ||
); | ||
}} | ||
</Field> | ||
); | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,66 @@ | ||
import React, { useEffect, useRef } from 'react'; | ||
import { Form, Formik, FormikProps } from 'formik'; | ||
import { useSettings } from '@deriv/api-v2'; | ||
import { Accordion, Button, Divider, Loader } from '@deriv-com/ui'; | ||
import { Timeline } from 'src/components/Timeline'; | ||
import { TPaymentMethod, TPaymentMethodData, TProofOfOwnershipFormValue } from 'src/types'; | ||
import { generatePOOInitialValues } from 'src/utils'; | ||
import { PaymentMethodForm, PaymentMethodTitle } from '../PaymentMethods'; | ||
|
||
type TPOOFormProps = { | ||
paymentMethodData: TPaymentMethodData; | ||
}; | ||
|
||
export const POOForm = ({ paymentMethodData }: TPOOFormProps) => { | ||
const { isLoading } = useSettings(); | ||
const formRef = useRef<FormikProps<TProofOfOwnershipFormValue>>(null); | ||
const paymentMethods = Object.keys(paymentMethodData) as TPaymentMethod[]; | ||
|
||
useEffect(() => { | ||
if (formRef.current) { | ||
formRef.current.resetForm(); | ||
} | ||
}, [paymentMethods]); | ||
|
||
if (isLoading) { | ||
return <Loader isFullScreen />; | ||
} | ||
|
||
const initialFormValues = generatePOOInitialValues(paymentMethodData); | ||
|
||
return ( | ||
<Formik | ||
enableReinitialize | ||
initialValues={initialFormValues} | ||
innerRef={formRef} | ||
onSubmit={() => { | ||
//TODO: Implement onSubmit | ||
}} | ||
> | ||
{({ dirty, isSubmitting, isValid }) => ( | ||
<Form className='grid h-full'> | ||
<Timeline className='pt-0 px-14 pb-16 m-12 w-full text-lg'> | ||
{paymentMethods.map((type, index) => ( | ||
<Timeline.Item key={`${type}_${index}`}> | ||
<Accordion | ||
title={<PaymentMethodTitle paymentMethod={paymentMethodData[type].paymentMethod} />} | ||
variant='bordered' | ||
> | ||
<PaymentMethodForm paymentMethodDetail={paymentMethodData[type]} /> | ||
</Accordion> | ||
</Timeline.Item> | ||
))} | ||
</Timeline> | ||
<section className='flex gap-8 flex-col justify-end'> | ||
<Divider /> | ||
<div className='flex gap-8 justify-end'> | ||
<Button disabled={!isValid || isSubmitting || !dirty} rounded='sm' size='lg' type='submit'> | ||
Submit | ||
</Button> | ||
</div> | ||
</section> | ||
</Form> | ||
)} | ||
</Formik> | ||
); | ||
}; |
Oops, something went wrong.