Skip to content

Commit

Permalink
[TRAH] Sergei / TRAH - 2831 / Citizenship selection modal (deriv-com#…
Browse files Browse the repository at this point in the history
…13641)

* feat: create useClientCountry hook

* feat: intermediate result

* feat: done with citizenship modal

* feat: move changes back for AppContent

* fix: sonarcloud issue

* feat: implement review comments

* feat: implement review comments #2
  • Loading branch information
sergei-deriv authored Feb 21, 2024
1 parent 4f4fe75 commit 6f53181
Show file tree
Hide file tree
Showing 11 changed files with 241 additions and 0 deletions.
56 changes: 56 additions & 0 deletions packages/api/src/hooks/__tests__/useCountryList.spec.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
import { renderHook } from '@testing-library/react-hooks';
import useQuery from '../../useQuery';
import useClientCountry from '../useClientCountry';

jest.mock('../../useQuery');

const mockUseQuery = useQuery as jest.MockedFunction<typeof useQuery<'website_status'>>;

describe('useClientCountry', () => {
it('should return an undefined', () => {
// @ts-expect-error need to come up with a way to mock the return type of useFetch
mockUseQuery.mockReturnValue({
data: {
website_status: undefined,
},
});
const { result } = renderHook(() => useClientCountry());

expect(result.current.data).toBeUndefined();
});

it('should return Indonesia country code', () => {
// @ts-expect-error need to come up with a way to mock the return type of useFetch
mockUseQuery.mockReturnValue({
data: {
website_status: {
api_call_limits: {
max_proposal_subscription: {
applies_to: '',
max: 0,
},
max_requestes_general: {
applies_to: '',
hourly: 0,
minutely: 0,
},
max_requests_outcome: {
applies_to: '',
hourly: 0,
minutely: 0,
},
max_requests_pricing: {
applies_to: '',
hourly: 0,
minutely: 0,
},
},
currencies_config: {},
clients_country: 'id',
},
},
});
const { result } = renderHook(() => useClientCountry());
expect(result.current.data).toBe('id');
});
});
1 change: 1 addition & 0 deletions packages/api/src/hooks/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -77,3 +77,4 @@ export { default as useResetVirtualBalance } from './useResetVirtualBalance';
export { default as useExchangeRates } from './useExchangeRates';
export { default as useIsDIELEnabled } from './useIsDIELEnabled';
export { default as useKycAuthStatus } from './useKycAuthStatus';
export { default as useClientCountry } from './useClientCountry';
20 changes: 20 additions & 0 deletions packages/api/src/hooks/useClientCountry.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import { useMemo } from 'react';
import useQuery from '../useQuery';

/** A custom hook that gets the client country. */
const useClientCountry = () => {
const { data, ...website_status_rest } = useQuery('website_status');

/** Modify the client country. */
const modified_client_country = useMemo(() => {
return data?.website_status?.clients_country;
}, [data]);

return {
/** The client's country */
data: modified_client_country,
...website_status_rest,
};
};

export default useClientCountry;
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
import React, { useEffect, useState } from 'react';
import { useFormikContext } from 'formik';
import { isCVMEnabled } from '@/helpers';
import { useClientCountry, useResidenceList } from '@deriv/api';
import { LabelPairedChevronDownMdRegularIcon } from '@deriv/quill-icons';
import { Button, Checkbox, Dropdown, Text } from '@deriv-com/ui';
import { TSignupFormValues } from '../SignupWrapper/SignupWrapper';

type TCitizenshipModal = {
onClickNext: VoidFunction;
};

const CitizenshipModal = ({ onClickNext }: TCitizenshipModal) => {
const { data: residenceList, isLoading: residenceListLoading } = useResidenceList();
const { data: clientCountry, isLoading: clientCountryLoading } = useClientCountry();
const [isCheckBoxChecked, setIsCheckBoxChecked] = useState(false);
const { values, setFieldValue } = useFormikContext<TSignupFormValues>();
const isCheckboxVisible = isCVMEnabled(values.country);

useEffect(() => {
if (residenceList?.length && clientCountry && values.country === '') {
setFieldValue('country', clientCountry);
}
}, [clientCountry, setFieldValue, residenceList, values.country]);

// Add <Loading /> here later when it's created
if (clientCountryLoading && residenceListLoading) return null;

return (
<div className='h-full rounded-default max-w-[328px] lg:max-w-[440px] bg-system-light-primary-background'>
<div className='flex flex-col p-16 space-y-16 lg:space-y-24 lg:p-24'>
<Text weight='bold'>Select your country and citizenship:</Text>
<Dropdown
dropdownIcon={<LabelPairedChevronDownMdRegularIcon />}
errorMessage='Country of residence is where you currently live.'
label='Country of residence'
list={residenceList}
name='country'
onSelect={selectedItem => {
setFieldValue('country', selectedItem);
}}
value={values.country}
variant='comboBox'
/>
<Dropdown
dropdownIcon={<LabelPairedChevronDownMdRegularIcon />}
errorMessage='Select your citizenship/nationality as it appears on your passport or other government-issued ID.'
label='Citizenship'
list={residenceList}
name='citizenship'
onSelect={selectedItem => {
setFieldValue('citizenship', selectedItem);
}}
value={values.citizenship}
variant='comboBox'
/>
{isCheckboxVisible && (
<Checkbox
checked={isCheckBoxChecked}
label={
<Text size='sm'>
I hereby confirm that my request for opening an account with Deriv to trade OTC products
issued and offered exclusively outside Brazil was initiated by me. I fully understand
that Deriv is not regulated by CVM and by approaching Deriv I intend to set up a
relation with a foreign company.
</Text>
}
labelClassName='flex-1'
onChange={(event: React.ChangeEvent<HTMLInputElement>) =>
setIsCheckBoxChecked(event.target.checked)
}
wrapperClassName='w-auto'
/>
)}
<Button
className='w-full lg:self-end lg:w-fit'
disabled={Boolean(
!values.country || !values.citizenship || (isCheckboxVisible && !isCheckBoxChecked)
)}
onClick={onClickNext}
>
Next
</Button>
</div>
</div>
);
};

export default CitizenshipModal;
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { default as CitizenshipModal } from './CitizenshipModal';
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import React, { Dispatch } from 'react';
import { CitizenshipModal } from '../CitizenshipModal';

type TSignupScreens = {
setStep: Dispatch<React.SetStateAction<number>>;
step: number;
};

const SignupScreens = ({ step, setStep }: TSignupScreens) => {
switch (step) {
case 1:
return <CitizenshipModal onClickNext={() => setStep(prev => prev + 1)} />;
case 2:
return (
<div className='max-w-[328px] lg:max-w-[440px] bg-system-light-primary-background rounded-default p-16 space-y-16 lg:space-y-24 lg:p-24'>
Screen 2
</div>
);
default:
return null;
}
};

export default SignupScreens;
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { default as SignupScreens } from './SignupScreens';
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
import React, { useEffect, useState } from 'react';
import { Form, Formik } from 'formik';
import ReactModal from 'react-modal';
import { CUSTOM_STYLES } from '@/helpers';
import { SignupScreens } from '../SignupScreens';

export type TSignupFormValues = {
citizenship: string;
country: string;
password: string;
};

const SignupWrapper = () => {
// setIsOpen will be added later when flow is completed
const [isOpen] = useState(false);
const [step, setStep] = useState(1);

const initialValues = {
country: '',
citizenship: '',
password: '',
};

const handleSubmit = () => {
// will be added later
};

useEffect(() => {
ReactModal.setAppElement('#v2_modal_root');
}, []);

return (
<ReactModal isOpen={isOpen} shouldCloseOnOverlayClick={false} style={CUSTOM_STYLES}>
<Formik initialValues={initialValues} onSubmit={handleSubmit}>
<Form>
<SignupScreens setStep={setStep} step={step} />
</Form>
</Formik>
</ReactModal>
);
};

export default SignupWrapper;
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { default as SignupWrapper } from './SignupWrapper';
3 changes: 3 additions & 0 deletions packages/tradershub/src/flows/Signup/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
import { SignupWrapper as Signup } from './SignupWrapper';

export default Signup;
2 changes: 2 additions & 0 deletions packages/tradershub/src/helpers/signupModalHelpers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,3 +27,5 @@ export const CUSTOM_STYLES: TCustomStyles = {
zIndex: 9999,
},
};

export const isCVMEnabled = (countryCode: string) => countryCode === 'br';

0 comments on commit 6f53181

Please sign in to comment.