Skip to content
This repository was archived by the owner on May 13, 2024. It is now read-only.

Commit 7159f71

Browse files
authored
Merge pull request #187 from utkarsha-deriv/utkarsha/display-popup-upon-token-creation
2 parents a5cbcd1 + 39ac8e4 commit 7159f71

File tree

6 files changed

+161
-0
lines changed

6 files changed

+161
-0
lines changed

src/features/dashboard/components/ApiTokenForm/CreateTokenField/index.tsx

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import { Text, Button } from '@deriv/ui';
33
import styles from '../api-token.form.module.scss';
44
import useApiToken from '@site/src/hooks/useApiToken';
55
import { FieldErrorsImpl, UseFormRegisterReturn } from 'react-hook-form';
6+
import TokenCreationDialogSuccess from '../../Dialogs/TokenCreationDialogSuccess';
67

78
type TCreateTokenField = {
89
register: UseFormRegisterReturn;
@@ -18,13 +19,17 @@ type TCreateTokenField = {
1819
>;
1920
form_is_cleared: boolean;
2021
setFormIsCleared: Dispatch<SetStateAction<boolean>>;
22+
is_toggle: boolean;
23+
setToggleModal: Dispatch<SetStateAction<boolean>>;
2124
};
2225

2326
const CreateTokenField = ({
2427
errors,
2528
register,
2629
form_is_cleared,
2730
setFormIsCleared,
31+
is_toggle,
32+
setToggleModal,
2833
}: TCreateTokenField) => {
2934
const { tokens } = useApiToken();
3035
const [input_value, setInputValue] = useState('');
@@ -72,6 +77,7 @@ const CreateTokenField = ({
7277
<Button disabled={disable_button} type='submit'>
7378
Create
7479
</Button>
80+
{is_toggle && <TokenCreationDialogSuccess setToggleModal={setToggleModal} />}
7581
</div>
7682
{errors && errors.name && (
7783
<Text as='span' type='paragraph-1' className='error-message'>

src/features/dashboard/components/ApiTokenForm/__tests__/api-token.form.test.tsx

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,7 @@ const scopes = [
7575
label: 'Admin',
7676
},
7777
];
78+
const preventDefault = jest.fn();
7879

7980
describe('Home Page', () => {
8081
beforeEach(() => {
@@ -147,4 +148,29 @@ describe('Home Page', () => {
147148

148149
expect(mockCreateToken).not.toHaveBeenCalled();
149150
});
151+
152+
it('Should open success dialog when token is created ', async () => {
153+
const nameInput = screen.getByRole('textbox');
154+
155+
await userEvent.type(nameInput, 'test create token');
156+
157+
const submitButton = screen.getByRole('button', { name: /Create/i });
158+
await userEvent.click(submitButton);
159+
160+
const modal = await screen.getByText('Your API token is ready to be used.');
161+
expect(modal).toBeVisible();
162+
});
163+
164+
it('Should have create button disabled in case of empty input or error message', async () => {
165+
const submitButton = screen.getByRole('button', { name: /Create/i });
166+
expect(submitButton).toBeDisabled();
167+
168+
const nameInput = screen.getByRole('textbox');
169+
170+
await userEvent.type(nameInput, 'token-text');
171+
expect(submitButton).toBeDisabled();
172+
173+
await userEvent.clear(nameInput);
174+
expect(submitButton).toBeDisabled();
175+
});
150176
});

src/features/dashboard/components/ApiTokenForm/api-token.form.tsx

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,7 @@ const scopes: TScope[] = [
8080
const ApiTokenForm = (props: HTMLAttributes<HTMLFormElement>) => {
8181
const { createToken, isCreatingToken } = useCreateToken();
8282
const [form_is_cleared, setFormIsCleared] = useState(false);
83+
const [is_toggle, setToggleModal] = useState(false);
8384

8485
const {
8586
handleSubmit,
@@ -105,6 +106,7 @@ const ApiTokenForm = (props: HTMLAttributes<HTMLFormElement>) => {
105106
});
106107
createToken(name, selectedTokenScope);
107108
setFormIsCleared(true);
109+
setToggleModal((prev) => !prev);
108110
reset();
109111
},
110112
[createToken, reset],
@@ -157,6 +159,8 @@ const ApiTokenForm = (props: HTMLAttributes<HTMLFormElement>) => {
157159
errors={errors}
158160
form_is_cleared={form_is_cleared}
159161
setFormIsCleared={setFormIsCleared}
162+
is_toggle={is_toggle}
163+
setToggleModal={setToggleModal}
160164
/>
161165
<div className={styles.step_title}>
162166
<div className={`${styles.third_step} ${styles.step}`}>
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
import React from 'react';
2+
import TokenCreationDialogSuccess from '..';
3+
import { screen, render } from '@testing-library/react';
4+
import userEvent from '@testing-library/user-event';
5+
6+
describe('Token Creation Dialog', () => {
7+
it('Should display correct title on the modal', () => {
8+
render(<TokenCreationDialogSuccess setToggleModal={jest.fn()} />);
9+
10+
const title = screen.getByText(/Token created successfully/i);
11+
expect(title).toHaveTextContent('Token created successfully');
12+
});
13+
14+
it('Should display correct content on the modal', () => {
15+
render(<TokenCreationDialogSuccess setToggleModal={jest.fn()} />);
16+
17+
const textContent = screen.getByText(/Your API token is ready to be used./i);
18+
expect(textContent).toHaveTextContent('Your API token is ready to be used.');
19+
});
20+
21+
it('Should close the modal on OK button click', async () => {
22+
const mockOnClose = jest.fn();
23+
24+
render(<TokenCreationDialogSuccess setToggleModal={mockOnClose} />);
25+
26+
const okButton = screen.getByRole('button', { name: /OK/i });
27+
expect(okButton).toBeInTheDocument();
28+
29+
await userEvent.click(okButton);
30+
31+
expect(mockOnClose).toHaveBeenCalledTimes(1);
32+
});
33+
34+
it('Should close the modal on cross button click', async () => {
35+
const mockOnClose = jest.fn();
36+
37+
render(<TokenCreationDialogSuccess setToggleModal={mockOnClose} />);
38+
const modal = screen.getByText('Your API token is ready to be used.');
39+
40+
const crossButton = screen.getByTestId('close-button');
41+
await userEvent.click(crossButton);
42+
43+
expect(modal).not.toBeInTheDocument();
44+
expect(mockOnClose).toHaveBeenCalled();
45+
});
46+
});
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
import React, { useCallback } from 'react';
2+
import { Button, Modal } from '@deriv/ui';
3+
import styles from './token-creation-dialog-sucess.module.scss';
4+
5+
type ITokenCreationDialogSuccessProps = {
6+
setToggleModal: React.Dispatch<React.SetStateAction<boolean>>;
7+
};
8+
9+
export const TokenCreationDialogSuccess = ({
10+
setToggleModal,
11+
}: ITokenCreationDialogSuccessProps) => {
12+
const onOpenChange = useCallback(
13+
(open: boolean) => {
14+
if (!open) {
15+
setToggleModal(false);
16+
}
17+
},
18+
[setToggleModal],
19+
);
20+
const handleToggle = () => {
21+
setToggleModal(false);
22+
};
23+
24+
return (
25+
<Modal defaultOpen onOpenChange={onOpenChange}>
26+
<Modal.Portal>
27+
<div className='modal-overlay'>
28+
<Modal.Overlay />
29+
<Modal.PageContent
30+
title={'Token created successfully'}
31+
has_close_button
32+
className={styles.wrapper}
33+
>
34+
<div className={styles.modal}>
35+
<p>Your API token is ready to be used.</p>
36+
</div>
37+
38+
<div className={styles.buttonWrapper}>
39+
<Button color='primary' onClick={handleToggle} className={styles.btn}>
40+
OK
41+
</Button>
42+
</div>
43+
</Modal.PageContent>
44+
</div>
45+
</Modal.Portal>
46+
</Modal>
47+
);
48+
};
49+
50+
export default TokenCreationDialogSuccess;
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
@use 'src/styles/utility' as *;
2+
3+
.wrapper {
4+
width: rem(44);
5+
}
6+
7+
.modal {
8+
display: flex;
9+
flex-direction: column;
10+
gap: 8px;
11+
padding: rem(0.8) rem(2.4) 0;
12+
font-size: rem(1.4);
13+
line-height: rem(2);
14+
@media (max-width: 992px) {
15+
padding: 0 0 0 rem(1.6);
16+
}
17+
}
18+
19+
.buttonWrapper {
20+
display: flex;
21+
justify-content: flex-end;
22+
padding: rem(2.4);
23+
gap: rem(0.8);
24+
25+
.btn {
26+
padding: rem(1) rem(1.6);
27+
border-radius: rem(1.5);
28+
}
29+
}

0 commit comments

Comments
 (0)