Skip to content

Commit

Permalink
[Cashier-V2] george / FEQ-1955 / Implement Payment Agent Withdrawal c…
Browse files Browse the repository at this point in the history
…omponents (binary-com#14284)

* feat(cashier-v2): ✨ add Payment agent withdarwal components

* refactor(cashier-v2): 🎨 chore refactoring
  • Loading branch information
heorhi-deriv committed Mar 22, 2024
1 parent a40f052 commit 1d2e59c
Show file tree
Hide file tree
Showing 27 changed files with 475 additions and 26 deletions.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions packages/cashier-v2/src/assets/images/ic-website.svg
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Expand Up @@ -4,6 +4,10 @@
justify-content: space-between;
}

.main {
width: 100%;
}

.icon-wrapper {
width: 1.6rem;
height: 1.6rem;
Expand Down
Expand Up @@ -15,7 +15,7 @@ const ExpansionPanel: React.FC<TProps> = ({ content, header }) => {

return (
<div className={styles.container}>
<div>
<div className={styles.main}>
{header}
{isOpen && content}
</div>
Expand Down
@@ -1,7 +1,11 @@
import React from 'react';
import { ExpansionPanel } from '../../../../components';
import type { THooks } from '../../../../hooks/types';
import { PaymentAgentCardDescription, PaymentAgentCardDetails } from './components';
import {
PaymentAgentCardDepositDetails,
PaymentAgentCardDescription,
PaymentAgentCardWithdrawalForm,
} from './components';
import styles from './PaymentAgentCard.module.scss';

type TProps = {
Expand All @@ -13,7 +17,13 @@ const PaymentAgentCard: React.FC<TProps> = ({ isDeposit, paymentAgent }) => {
return (
<div className={styles.container} data-testid='dt_payment_agent_deposit_card'>
<ExpansionPanel
content={isDeposit ? <PaymentAgentCardDetails paymentAgent={paymentAgent} /> : <></>}
content={
isDeposit ? (
<PaymentAgentCardDepositDetails paymentAgent={paymentAgent} />
) : (
<PaymentAgentCardWithdrawalForm paymentAgent={paymentAgent} />
)
}
header={<PaymentAgentCardDescription paymentAgent={paymentAgent} />}
/>
</div>
Expand Down
Expand Up @@ -5,31 +5,31 @@ import TransferLimitIcon from '../../../../../../assets/images/ic-account-transf
import DepositIcon from '../../../../../../assets/images/ic-cashier-add.svg';
import WithdrawalIcon from '../../../../../../assets/images/ic-cashier-minus.svg';
import PhoneIcon from '../../../../../../assets/images/ic-phone.svg';
import { THooks } from '../../../../../../hooks/types';
import type { THooks } from '../../../../../../hooks/types';
import { TCurrency } from '../../../../../../types';
import { PaymentAgentCardDetail } from '../PaymentAgentCardDetail';
import styles from './PaymentAgentCardDetails.module.scss';
import styles from './PaymentAgentCardDepositDetails.module.scss';

type TPaymentAgentCardDetailsProps = {
type TPaymentAgentCardDepositDetailsProps = {
paymentAgent: THooks.PaymentAgentList[number];
};

type TPaymentAgentPhoneDetailsProps = {
phoneNumbers: TPaymentAgentCardDetailsProps['paymentAgent']['phone_numbers'];
phoneNumbers: THooks.PaymentAgentList[number]['phone_numbers'];
};

type TPaymentAgentTransferLimitDetailsProps = {
currency: TCurrency;
maxWithdrawal: TPaymentAgentCardDetailsProps['paymentAgent']['max_withdrawal'];
minWithdrawal: TPaymentAgentCardDetailsProps['paymentAgent']['min_withdrawal'];
maxWithdrawal: THooks.PaymentAgentList[number]['max_withdrawal'];
minWithdrawal: THooks.PaymentAgentList[number]['min_withdrawal'];
};

type TPaymentAgentDepositCommissionDetailsProps = {
depositCommission: TPaymentAgentCardDetailsProps['paymentAgent']['deposit_commission'];
depositCommission: THooks.PaymentAgentList[number]['deposit_commission'];
};

type TPaymentAgentWithdrawalCommissionDetailsProps = {
withdrawalCommission: TPaymentAgentCardDetailsProps['paymentAgent']['withdrawal_commission'];
withdrawalCommission: THooks.PaymentAgentList[number]['withdrawal_commission'];
};

const PaymentAgentPhoneDetails: React.FC<TPaymentAgentPhoneDetailsProps> = ({ phoneNumbers }) => {
Expand Down Expand Up @@ -77,7 +77,7 @@ const PaymentAgentWithdrawalCommissionDetails: React.FC<TPaymentAgentWithdrawalC
);
};

const PaymentAgentCardDetails: React.FC<TPaymentAgentCardDetailsProps> = ({ paymentAgent }) => {
const PaymentAgentCardDepositDetails: React.FC<TPaymentAgentCardDepositDetailsProps> = ({ paymentAgent }) => {
const {
currencies: currency,
deposit_commission: depositCommission,
Expand Down Expand Up @@ -105,4 +105,4 @@ const PaymentAgentCardDetails: React.FC<TPaymentAgentCardDetailsProps> = ({ paym
);
};

export default PaymentAgentCardDetails;
export default PaymentAgentCardDepositDetails;
@@ -1,14 +1,14 @@
import React from 'react';
import { render, screen } from '@testing-library/react';
import PaymentAgentCardDetails from '../PaymentAgentCardDetails';
import PaymentAgentCardDepositDetails from '../PaymentAgentCardDepositDetails';

jest.mock('@deriv-com/ui', () => ({
...jest.requireActual('@deriv-com/ui'),
useDevice: jest.fn(() => ({ isMobile: false })),
}));

describe('PaymentAgentCardDetails', () => {
let mockedProps: React.ComponentProps<typeof PaymentAgentCardDetails>;
describe('PaymentAgentCardDepositDetails', () => {
let mockedProps: React.ComponentProps<typeof PaymentAgentCardDepositDetails>;

beforeEach(() => {
mockedProps = {
Expand All @@ -25,7 +25,7 @@ describe('PaymentAgentCardDetails', () => {
});

it('should render proper payment agent details', () => {
render(<PaymentAgentCardDetails {...mockedProps} />);
render(<PaymentAgentCardDepositDetails {...mockedProps} />);

expect(screen.getByText('Phone number')).toBeInTheDocument();
expect(screen.getByText(/375291234567/)).toBeInTheDocument();
Expand Down
@@ -0,0 +1 @@
export { default as PaymentAgentCardDepositDetails } from './PaymentAgentCardDepositDetails';

This file was deleted.

@@ -0,0 +1,15 @@
.container {
display: flex;
flex-direction: column;
gap: 1.6rem;
padding-top: 3.2rem;
}

.form {
display: flex;

@include mobile-cashier-v2 {
flex-direction: column;
gap: 1.6rem;
}
}
@@ -0,0 +1,90 @@
import React from 'react';
import { Field, FieldProps, Form, Formik } from 'formik';
import { Button, Input, Text } from '@deriv-com/ui';
import { FormatUtils } from '@deriv-com/utils';
import type { THooks } from '../../../../../../hooks/types';
import type { TCurrency } from '../../../../../../types';
import styles from './PaymentAgentCardWithdrawalForm.module.scss';

type TPaymentAgentCardWithdrawalFormProps = {
paymentAgent: THooks.PaymentAgentList[number];
};

type TWithdrawalLimitsProps = {
currency: TCurrency;
maxWithdrawalLimit: THooks.PaymentAgentList[number]['max_withdrawal'];
minWithdrawalLimit: THooks.PaymentAgentList[number]['min_withdrawal'];
};

const WithdrawalLimits: React.FC<TWithdrawalLimitsProps> = ({ currency, maxWithdrawalLimit, minWithdrawalLimit }) => {
const minLimit = `${FormatUtils.formatMoney(Number(minWithdrawalLimit), { currency })} ${currency}`;
const maxLimit = `${FormatUtils.formatMoney(Number(maxWithdrawalLimit), { currency })} ${currency}`;

return (
<Text color='less-prominent' size='xs'>
Withdrawal limits: {minLimit}-{maxLimit}
</Text>
);
};

const PaymentAgentCardWithdrawalForm: React.FC<TPaymentAgentCardWithdrawalFormProps> = ({ paymentAgent }) => {
const { currencies, max_withdrawal: maxWithdrawalLimit, min_withdrawal: minWithdrawalLimit } = paymentAgent;
const onSubmitHandler = () => undefined;

return (
<div className={styles.container}>
<Text as='p' size='sm' weight='bold'>
Withdrawal amount
</Text>
<Formik
initialValues={{
amount: '',
}}
onSubmit={onSubmitHandler}
>
{({ errors, isSubmitting, isValid, touched, values }) => {
return (
<Form className={styles.form} noValidate>
<Field name='amount'>
{({ field }: FieldProps) => (
<Input
{...field}
autoComplete='off'
error={touched.amount && Boolean(errors.amount)}
isFullWidth
label='Enter amount'
maxLength={30}
message={
<WithdrawalLimits
currency={currencies as TCurrency}
maxWithdrawalLimit={maxWithdrawalLimit}
minWithdrawalLimit={minWithdrawalLimit}
/>
}
required
rightPlaceholder={
<Text as='span' size='sm'>
{paymentAgent.currencies}
</Text>
}
type='text'
/>
)}
</Field>
<Button
disabled={!isValid || isSubmitting || !values.amount}
size='lg'
textSize='sm'
type='submit'
>
Continue
</Button>
</Form>
);
}}
</Formik>
</div>
);
};

export default PaymentAgentCardWithdrawalForm;
@@ -0,0 +1 @@
export { default as PaymentAgentCardWithdrawalForm } from './PaymentAgentCardWithdrawalForm';
@@ -1,4 +1,5 @@
import { PaymentAgentCardDepositDetails } from './PaymentAgentCardDepositDetails';
import { PaymentAgentCardDescription } from './PaymentAgentCardDescription';
import { PaymentAgentCardDetails } from './PaymentAgentCardDetails';
import { PaymentAgentCardWithdrawalForm } from './PaymentAgentCardWithdrawalForm';

export { PaymentAgentCardDescription, PaymentAgentCardDetails };
export { PaymentAgentCardDepositDetails, PaymentAgentCardDescription, PaymentAgentCardWithdrawalForm };
@@ -0,0 +1,28 @@
.container {
display: flex;
flex-direction: column;
gap: 2.4rem;
width: 100%;
max-width: 58.8rem;
margin: 0 auto;
}

.back-section {
display: flex;
align-items: center;
}

.form {
display: flex;
flex-direction: column;
gap: 2.4rem;
}

.amount-input {
display: flex;

@include mobile-cashier-v2 {
flex-direction: column;
gap: 1.6rem;
}
}
@@ -0,0 +1,94 @@
import React from 'react';
import { Field, FieldProps, Form, Formik } from 'formik';
import { useActiveAccount } from '@deriv/api-v2';
import { LabelPairedCircleXmarkMdFillIcon, StandaloneArrowLeftBoldIcon } from '@deriv/quill-icons';
import { Button, Input, Text } from '@deriv-com/ui';
import styles from './PaymentAgentUnlistedWithdrawalForm.module.scss';

const PaymentAgentUnlistedWithdrawalForm = () => {
const { data: activeAccount } = useActiveAccount();
const onSubmitHandler = () => undefined;

return (
<div className={styles.container}>
<div className={styles['back-section']}>
<StandaloneArrowLeftBoldIcon data-testid='dt-back-arrow-icon' iconSize='md' />
<Text size='sm' weight='bold'>
Back to list
</Text>
</div>
<Formik
initialValues={{
accountNumber: '',
amount: '',
}}
onSubmit={onSubmitHandler}
>
{({ errors, isSubmitting, isValid, setFieldValue, touched, values }) => {
const isFormEmpty = !Object.values(values).some(Boolean);

return (
<Form className={styles.form}>
<Field name='account_number'>
{({ field }: FieldProps) => (
<Input
{...field}
autoComplete='off'
error={touched.accountNumber && Boolean(errors.accountNumber)}
isFullWidth
label='Enter the payment agent account number'
maxLength={30}
message='Example: CR123456789'
required
rightPlaceholder={
errors.accountNumber ? (
<LabelPairedCircleXmarkMdFillIcon
onClick={() => setFieldValue('accountNumber', '')}
/>
) : null
}
type='text'
/>
)}
</Field>
<div className={styles['amount-input']}>
<Field name='amount'>
{({ field }: FieldProps) => (
<Input
{...field}
autoComplete='off'
error={touched.amount && Boolean(errors.amount)}
isFullWidth
label='Enter amount'
maxLength={30}
required
rightPlaceholder={
<Text as='span' size='sm'>
{activeAccount?.currency_config?.display_code}
</Text>
}
type='text'
/>
)}
</Field>
<Button
disabled={!isValid || isSubmitting || isFormEmpty}
size='lg'
textSize='sm'
type='submit'
>
Continue
</Button>
</div>
</Form>
);
}}
</Formik>
<Text as='p' color='less-prominent' size='xs'>
Note: Deriv does not charge any transfer fees.
</Text>
</div>
);
};

export default PaymentAgentUnlistedWithdrawalForm;
@@ -0,0 +1 @@
export { default as PaymentAgentUnlistedWithdrawalForm } from './PaymentAgentUnlistedWithdrawalForm';
@@ -0,0 +1,13 @@
.container {
display: flex;
align-items: center;
gap: 0.4rem;
flex-basis: 0;
}

.icon-wrapper {
display: flex;
align-items: center;
width: 1.6rem;
height: 1.6rem;
}

0 comments on commit 1d2e59c

Please sign in to comment.