Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -82,26 +82,22 @@ const WalletTextField = forwardRef(
)}
</div>
<div className='wallets-textfield__message-container'>
{!disabled && (
<>
{showMessage && !isInvalid && (
<HelperMessage
inputValue={value}
maxLength={maxLength}
message={message}
messageVariant={messageVariant}
/>
)}
{errorMessage && (isInvalid || (!isInvalid && shouldShowWarningMessage)) && (
<HelperMessage
inputValue={value}
isError={isInvalid}
maxLength={maxLength}
message={errorMessage as string}
messageVariant={isInvalid ? 'error' : 'warning'}
/>
)}
</>
{showMessage && !isInvalid && (
<HelperMessage
inputValue={value}
maxLength={maxLength}
message={message}
messageVariant={messageVariant}
/>
)}
{errorMessage && (isInvalid || (!isInvalid && shouldShowWarningMessage)) && (
<HelperMessage
inputValue={value}
isError={isInvalid}
maxLength={maxLength}
message={errorMessage as string}
messageVariant={isInvalid ? 'error' : 'warning'}
/>
)}
</div>
</div>
Expand Down
4 changes: 4 additions & 0 deletions packages/wallets/src/components/DatePicker/DatePicker.scss
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,10 @@ abbr[title] {
&__button {
all: unset;
cursor: pointer;

&:disabled {
filter: invert(92%) sepia(0%) saturate(112%) hue-rotate(253deg) brightness(106%) contrast(89%);
}
}

&__container {
Expand Down
3 changes: 3 additions & 0 deletions packages/wallets/src/components/DatePicker/DatePicker.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ interface TDatePickerProps extends TFlowFieldProps {

const DatePicker = ({
defaultValue,
disabled,
label,
maxDate,
message,
Expand Down Expand Up @@ -54,6 +55,7 @@ const DatePicker = ({
return (
<div className='wallets-datepicker' ref={datePickerRef}>
<FlowTextField
disabled={disabled}
label={label}
message={message}
name={name}
Expand All @@ -62,6 +64,7 @@ const DatePicker = ({
<button
className='wallets-datepicker__button'
data-testid='wallets_datepicker_button'
disabled={disabled}
onClick={toggleCalendar}
>
<CalendarIcon />
Expand Down
14 changes: 10 additions & 4 deletions packages/wallets/src/components/FlowField/FlowTextField.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import React, { forwardRef, Ref, useEffect, useState } from 'react';
import { Field, FieldProps } from 'formik';
import { Field, FieldProps, useFormikContext } from 'formik';
import * as Yup from 'yup';
import WalletTextField, { WalletTextFieldProps } from '../Base/WalletTextField/WalletTextField';
import { useFlow } from '../FlowProvider';
Expand All @@ -22,6 +22,7 @@ const FlowTextField = forwardRef(
) => {
const [hasTouched, setHasTouched] = useState(false);
const { setFormValues } = useFlow();
const { setFieldTouched } = useFormikContext();

const validateField = (value: unknown) => {
try {
Expand All @@ -34,9 +35,14 @@ const FlowTextField = forwardRef(
};

useEffect(() => {
if (defaultValue) {
setFormValues(name, defaultValue);
}
const setFormValuesAndTouch = async () => {
if (defaultValue) {
await setFormValues(name, defaultValue, true);
setFieldTouched(name, true, true);
}
};

setFormValuesAndTouch();
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ describe('FlowTextField', () => {
</FlowProvider>
);
expect(screen.getByDisplayValue('default')).toBeInTheDocument();
expect(mockUseFlow.setFormValues).toHaveBeenCalledWith('test', 'default');
expect(mockUseFlow.setFormValues).toHaveBeenCalledWith('test', 'default', true);
});

it('should set hasTouched value when user is on focus', () => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,9 @@ function FlowProvider<T extends TWalletScreens>({
enableReinitialize
initialValues={initialValues}
onSubmit={() => undefined}
validateOnBlur
validateOnChange
validateOnMount
validationSchema={validationSchema}
>
{({ errors, setFieldValue, values }) => {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
.wallets-idv-document-details {
border-radius: 0.8rem;
border: 0.1rem solid var(--system-light-5-active-background, #d6dadb);
margin-bottom: 2.4rem;
padding: 1.6rem;

&__body {
Expand All @@ -13,6 +14,42 @@
}
}

&__checkbox {
display: flex;
align-items: center;
gap: 0.8rem;
padding: 0.8rem 0 0 0.8rem;

& > * {
cursor: pointer;
}

input {
height: 1.6rem;
width: 1.6rem;
transition: 0.3s ease-in-out;
accent-color: #ff444f;
}

@include mobile {
padding-top: 1.6rem;
}

&--disabled {
input {
cursor: not-allowed;
accent-color: #999;
}

label {
span {
cursor: not-allowed;
color: #999;
}
}
}
}

&__content {
display: flex;
flex-direction: column;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
import React from 'react';
import React, { useEffect, useMemo } from 'react';
import classNames from 'classnames';
import { Field, useFormikContext } from 'formik';
import moment from 'moment';
import { useSettings } from '@deriv/api';
import { DatePicker, FlowTextField, InlineMessage, useFlow, WalletText } from '../../../../../../components';
Expand All @@ -9,14 +11,39 @@ import './IDVDocumentUploadDetails.scss';

const IDVDocumentUploadDetails = () => {
const { data: getSettings } = useSettings();
const { setFormValues } = useFlow();
const { errors, formValues, setFormValues } = useFlow();
const { validateForm } = useFormikContext();

const handleDateChange = (formattedDate: string | null) => {
setFormValues('dateOfBirth', formattedDate);
};

const dateOfBirth = getSettings?.date_of_birth || 0;
const formattedDateOfBirth = new Date(dateOfBirth * 1000);
const firstName = getSettings?.first_name;
const lastName = getSettings?.last_name;

useEffect(() => {
setFormValues('firstName', getSettings?.first_name);
setFormValues('lastName', getSettings?.last_name);
validateForm();
}, [getSettings?.first_name, getSettings?.last_name, setFormValues, validateForm]);

const isValid = useMemo(() => {
return (
getSettings?.first_name &&
getSettings?.last_name &&
getSettings?.date_of_birth &&
!(errors.firstName || errors.lastName || errors.dateOfBirth)
);
}, [
errors.dateOfBirth,
errors.firstName,
errors.lastName,
getSettings?.date_of_birth,
getSettings?.first_name,
getSettings?.last_name,
]);

return (
<div className='wallets-idv-document-details'>
Expand All @@ -29,7 +56,8 @@ const IDVDocumentUploadDetails = () => {
<div className='wallets-idv-document-details__body'>
<div className='wallets-idv-document-details__content'>
<FlowTextField
defaultValue={getSettings?.first_name}
defaultValue={firstName}
disabled={formValues.verifiedIdvDetails}
label='First name*'
message='Your first name as in your identity document'
name='firstName'
Expand All @@ -38,7 +66,8 @@ const IDVDocumentUploadDetails = () => {
/>

<FlowTextField
defaultValue={getSettings?.last_name}
defaultValue={lastName}
disabled={formValues.verifiedIdvDetails}
label='Last name*'
message='Your last name as in your identity document'
name='lastName'
Expand All @@ -47,6 +76,7 @@ const IDVDocumentUploadDetails = () => {
/>
<DatePicker
defaultValue={unixToDateString(formattedDateOfBirth)}
disabled={formValues.verifiedIdvDetails}
label='Date of birth*'
maxDate={moment().subtract(18, 'years').toDate()}
message='Your date of birth as in your identity document'
Expand All @@ -65,6 +95,18 @@ const IDVDocumentUploadDetails = () => {
<SideNote />
</div>
</div>
<div
className={classNames('wallets-idv-document-details__checkbox', {
'wallets-idv-document-details__checkbox--disabled': !isValid,
})}
>
<Field disabled={!isValid} id='idv-checkbox' name='verifiedIdvDetails' type='checkbox' />
<label htmlFor='idv-checkbox'>
<WalletText lineHeight='2xs' size='sm'>
I confirm that the name and date of birth above match my chosen identity document
</WalletText>
</label>
</div>
</div>
);
};
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
import React from 'react';
import moment from 'moment';
import { useSettings } from '@deriv/api';
import { fireEvent, render, screen } from '@testing-library/react';
import { FlowProvider, FlowTextField } from '../../../../../../../components';
import IDVDocumentUploadDetails from '../IDVDocumentUploadDetails';

jest.mock('@deriv/api', () => ({
useSettings: jest.fn(),
}));

describe('IDVDocumentUploadDetails', () => {
beforeEach(() => {
(useSettings as jest.Mock).mockReturnValue({
data: {
date_of_birth: 0,
first_name: 'John',
last_name: 'Doe',
},
});
});

test('should render component with default values', () => {
render(
<FlowProvider
initialValues={{
test: 'default',
}}
screens={{
test: <FlowTextField name='test' />,
}}
>
{() => {
return <IDVDocumentUploadDetails />;
}}
</FlowProvider>
);

expect(screen.getByLabelText('First name*')).toHaveValue('John');
expect(screen.getByLabelText('Last name*')).toHaveValue('Doe');
expect(screen.getByLabelText('Date of birth*')).toHaveValue('1970-01-01');
expect(
screen.getByLabelText(/I confirm that the name and date of birth above match my chosen identity document/)
).toBeInTheDocument();
});

test('should render component with date of birth if existing in getSettings', () => {
(useSettings as jest.Mock).mockReturnValue({
data: {
date_of_birth: moment().subtract(25, 'years').unix(),
first_name: 'John',
last_name: 'Doe',
},
});

render(
<FlowProvider
initialValues={{
test: 'default',
}}
screens={{
test: <FlowTextField name='test' />,
}}
>
{() => {
return <IDVDocumentUploadDetails />;
}}
</FlowProvider>
);

expect(screen.getByLabelText('First name*')).toHaveValue('John');
expect(screen.getByLabelText('Last name*')).toHaveValue('Doe');
expect(screen.getByLabelText('Date of birth*')).toHaveValue(
moment().subtract(25, 'years').format('YYYY-MM-DD')
);
expect(
screen.getByLabelText(/I confirm that the name and date of birth above match my chosen identity document/)
).toBeInTheDocument();
});

test('should handle checkbox and fields change correctly when checkbox is checked', () => {
render(
<FlowProvider
initialValues={{
test: 'default',
}}
screens={{
test: <FlowTextField name='test' />,
}}
>
{() => {
return <IDVDocumentUploadDetails />;
}}
</FlowProvider>
);

fireEvent.click(
screen.getByLabelText(/I confirm that the name and date of birth above match my chosen identity document/)
);

expect(screen.getByLabelText('First name*')).toBeDisabled();
expect(screen.getByLabelText('Last name*')).toBeDisabled();
expect(screen.getByLabelText('Date of birth*')).toBeDisabled();

fireEvent.click(
screen.getByLabelText(/I confirm that the name and date of birth above match my chosen identity document/)
);

expect(screen.getByLabelText('First name*')).toBeEnabled();
expect(screen.getByLabelText('Last name*')).toBeEnabled();
expect(screen.getByLabelText('Date of birth*')).toBeEnabled();
});
});
Loading