diff --git a/package-lock.json b/package-lock.json index 6a0cce5a4..a5b33fa07 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9,6 +9,7 @@ "version": "0.0.0", "dependencies": { "@deriv/deriv-api": "^1.0.11", + "@deriv/quill-icons": "^1.22.10", "@deriv/ui": "^0.8.0", "@docusaurus/core": "^3.3.2", "@docusaurus/plugin-client-redirects": "^3.3.2", @@ -2579,6 +2580,15 @@ "rxjs": "^7.8.1" } }, + "node_modules/@deriv/quill-icons": { + "version": "1.22.10", + "resolved": "https://registry.npmjs.org/@deriv/quill-icons/-/quill-icons-1.22.10.tgz", + "integrity": "sha512-BtyMfKln7iBcTcERiaj3t8ADMplCOfE3J184Asaa/9RnE42e5JtehkYw78lwinYTBTzr1sL5tK0GRNlziFNRKw==", + "peerDependencies": { + "react": ">= 16", + "react-dom": ">= 16" + } + }, "node_modules/@deriv/ui": { "version": "0.8.0", "resolved": "https://registry.npmjs.org/@deriv/ui/-/ui-0.8.0.tgz", diff --git a/package.json b/package.json index 90e3d03bd..075dce8c4 100644 --- a/package.json +++ b/package.json @@ -22,6 +22,7 @@ }, "dependencies": { "@deriv/deriv-api": "^1.0.11", + "@deriv/quill-icons": "^1.22.10", "@deriv/ui": "^0.8.0", "@docusaurus/core": "^3.3.2", "@docusaurus/plugin-client-redirects": "^3.3.2", diff --git a/src/contexts/api-token/api-token.context.tsx b/src/contexts/api-token/api-token.context.tsx index 9d55e38fc..994aa766a 100644 --- a/src/contexts/api-token/api-token.context.tsx +++ b/src/contexts/api-token/api-token.context.tsx @@ -6,6 +6,8 @@ export interface IApiTokenContext { isLoadingTokens: boolean; currentToken: TTokenType; updateCurrentToken: (token: TTokenType) => void; + lastTokenDisplayName: string; + setLastTokenDisplayName: (name: string) => void; } export const ApiTokenContext = React.createContext(null); diff --git a/src/contexts/api-token/api-token.provider.tsx b/src/contexts/api-token/api-token.provider.tsx index 19db6a81b..3ac9b34e3 100644 --- a/src/contexts/api-token/api-token.provider.tsx +++ b/src/contexts/api-token/api-token.provider.tsx @@ -11,6 +11,7 @@ type TTokenProviderProps = { const ApiTokenProvider = ({ children }: TTokenProviderProps) => { const [tokens, setTokens] = useState([]); const [currentToken, setCurrentToken] = useState(); + const [lastTokenDisplayName, setLastTokenDisplayName] = useState(''); const { send: getAllTokens, data, is_loading } = useWS('api_token'); const { is_authorized } = useAuthContext(); @@ -46,8 +47,18 @@ const ApiTokenProvider = ({ children }: TTokenProviderProps) => { currentToken, updateCurrentToken, updateTokens, + lastTokenDisplayName, + setLastTokenDisplayName, }; - }, [currentToken, is_loading, tokens, updateCurrentToken, updateTokens]); + }, [ + currentToken, + is_loading, + tokens, + updateCurrentToken, + updateTokens, + lastTokenDisplayName, + setLastTokenDisplayName, + ]); return {children}; }; diff --git a/src/features/dashboard/components/ApiTokenForm/CreateTokenField/index.tsx b/src/features/dashboard/components/ApiTokenForm/CreateTokenField/index.tsx index ac38aef27..e8b1b4b43 100644 --- a/src/features/dashboard/components/ApiTokenForm/CreateTokenField/index.tsx +++ b/src/features/dashboard/components/ApiTokenForm/CreateTokenField/index.tsx @@ -44,6 +44,7 @@ const CreateTokenField = ({ setFormIsCleared(false); } }, [form_is_cleared]); + const getTokenNames = useMemo(() => { const token_names = []; for (const token_object of tokens) { diff --git a/src/features/dashboard/components/ApiTokenForm/__tests__/api-token.form.test.tsx b/src/features/dashboard/components/ApiTokenForm/__tests__/api-token.form.test.tsx index 16a26c5b6..6bbff31e3 100644 --- a/src/features/dashboard/components/ApiTokenForm/__tests__/api-token.form.test.tsx +++ b/src/features/dashboard/components/ApiTokenForm/__tests__/api-token.form.test.tsx @@ -77,6 +77,7 @@ describe('Home Page', () => { valid_for_ip: '', }, ], + lastTokenDisplayName: '', })); render(); @@ -207,21 +208,6 @@ describe('Home Page', () => { expect(mockCreateToken).not.toHaveBeenCalled(); }); - it('Should open success dialog when token is created ', async () => { - const nameInput = screen.getByRole('textbox'); - await act(async () => { - await userEvent.type(nameInput, 'test create token'); - }); - - const submitButton = screen.getByRole('button', { name: /Create/i }); - - await act(async () => { - await userEvent.click(submitButton); - }); - - const modal = await screen.getByText('Your API token is ready to be used.'); - expect(modal).toBeVisible(); - }); it('Should have create button disabled in case of empty input or error message', async () => { const submitButton = screen.getByRole('button', { name: /Create/i }); diff --git a/src/features/dashboard/components/ApiTokenTable/CopyButton/__tests__/CopyButton.test.tsx b/src/features/dashboard/components/ApiTokenTable/CopyButton/__tests__/CopyButton.test.tsx index 961ed0c28..56409815c 100644 --- a/src/features/dashboard/components/ApiTokenTable/CopyButton/__tests__/CopyButton.test.tsx +++ b/src/features/dashboard/components/ApiTokenTable/CopyButton/__tests__/CopyButton.test.tsx @@ -14,7 +14,7 @@ describe('CopyButton', () => { jest.spyOn(navigator.clipboard, 'writeText'); it('should render the CopyButton', () => { - render(); + render(); const copy_button = screen.getByRole('button'); expect(copy_button).toBeInTheDocument(); @@ -79,7 +79,6 @@ describe('CopyButton', () => { expect(modal).not.toBeInTheDocument(); }); - it('should show a green check for 2 seconds when copied', async () => { const user = userEvent.setup({ delay: null }); jest.useFakeTimers(); diff --git a/src/features/dashboard/components/ApiTokenTable/CopyButton/index.tsx b/src/features/dashboard/components/ApiTokenTable/CopyButton/index.tsx index 6ab218ede..1d35c430f 100644 --- a/src/features/dashboard/components/ApiTokenTable/CopyButton/index.tsx +++ b/src/features/dashboard/components/ApiTokenTable/CopyButton/index.tsx @@ -1,6 +1,7 @@ import React, { useState } from 'react'; import CopyTokenDialog from '../CopyTokenDialog'; import styles from '../token-cell.module.scss'; +import { StandaloneCopyRegularIcon } from '@deriv/quill-icons'; type TCopyButton = { value: string; diff --git a/src/features/dashboard/components/ApiTokenTable/table.token.cell.tsx b/src/features/dashboard/components/ApiTokenTable/table.token.cell.tsx index 9c0d9acee..ce3d8fa39 100644 --- a/src/features/dashboard/components/ApiTokenTable/table.token.cell.tsx +++ b/src/features/dashboard/components/ApiTokenTable/table.token.cell.tsx @@ -2,7 +2,6 @@ import React, { useEffect, useState } from 'react'; import { TTokenType } from '@site/src/types'; import { CellProps } from 'react-table'; import styles from './token-cell.module.scss'; -import CopyButton from './CopyButton'; const ApiTokenCell = ({ cell }: React.PropsWithChildren>) => { const [is_hiding_token, setIsHidingToken] = useState(true); @@ -24,16 +23,7 @@ const ApiTokenCell = ({ cell }: React.PropsWithChildren -
{is_hiding_token ? : cell.value}
- - diff --git a/src/features/dashboard/components/Dialogs/TokenCreationDialogSuccess/token-creation-dialog-sucess.module.scss b/src/features/dashboard/components/Dialogs/TokenCreationDialogSuccess/token-creation-dialog-sucess.module.scss index 4967bf3fd..27e5203dc 100644 --- a/src/features/dashboard/components/Dialogs/TokenCreationDialogSuccess/token-creation-dialog-sucess.module.scss +++ b/src/features/dashboard/components/Dialogs/TokenCreationDialogSuccess/token-creation-dialog-sucess.module.scss @@ -1,29 +1,71 @@ @use 'src/styles/utility' as *; .wrapper { - width: rem(44); + width: rem(51.2); + height: rem(36); + padding: 0px 32px 32px 32px !important; +} + +.title { + color: var(--core-color-solid-slate-1400, #000); + text-align: center; + font-family: 'IBM Plex Sans'; + font-size: 16px; + font-style: normal; + font-weight: 700; + line-height: 24px; + top: 0px; + padding: 0px 0px !important; } .modal { + position: relative; + z-index: 310; display: flex; flex-direction: column; - gap: 8px; - padding: rem(0.8) rem(2.4) 0; - font-size: rem(1.4); - line-height: rem(2); - @media (max-width: 992px) { - padding: 0 0 0 rem(1.6); - } + overflow: auto; + color: var(--core-color-opacity-black-600, rgba(0, 0, 0, 0.72)); + font-family: 'IBM Plex Sans'; + font-size: 16px; + font-style: normal; + font-weight: 400; + margin-top: 32px; + line-height: 24px; + margin-bottom: 16px; + text-align: left; +} + +.textField { + display: flex; + justify-content: space-between; + align-items: center; + max-width: 448px; + text-align: left; + gap: 4px; + border-radius: 8px; + padding: 4px 16px; + border: 1px solid var(--core-color-opacity-black-100, rgba(0, 0, 0, 0.08)); + background: var(--core-color-solid-slate-50, #fff); } -.buttonWrapper { +.key { + font-size: 12px; + font-weight: 400; + line-height: 18px; +} +.button_wrapper { + width: 100%; display: flex; - justify-content: flex-end; - padding: rem(2.4); - gap: rem(0.8); + padding-top: 48px; + justify-content: center; +} - .btn { - padding: rem(1) rem(1.6); - border-radius: rem(1.5); - } +.btn { + display: flex; + width: 124px !important; + height: 24px; + padding: 0px 16px; + gap: 8px; + border-radius: 16px !important; + background: var(--core-color-solid-coral-700, #ff444f); } diff --git a/src/features/dashboard/components/Table/__tests__/Table.test.tsx b/src/features/dashboard/components/Table/__tests__/Table.test.tsx index 5b542aac0..b7c289184 100644 --- a/src/features/dashboard/components/Table/__tests__/Table.test.tsx +++ b/src/features/dashboard/components/Table/__tests__/Table.test.tsx @@ -80,13 +80,6 @@ describe('Table', () => { }); it('Should render token cells properly', () => { - const eyeButtons = screen.getAllByTestId('eye-button'); - expect(eyeButtons[0]).toBeInTheDocument(); - - eyeButtons.forEach((button) => { - fireEvent.click(button); - }); - const tokenCells = screen.getAllByTestId('token-cell'); expect(tokenCells.length).toBe(2); diff --git a/src/features/dashboard/hooks/__tests__/useCreateToken.test.tsx b/src/features/dashboard/hooks/__tests__/useCreateToken.test.tsx index 2dfcac271..c0e9aabdf 100644 --- a/src/features/dashboard/hooks/__tests__/useCreateToken.test.tsx +++ b/src/features/dashboard/hooks/__tests__/useCreateToken.test.tsx @@ -38,9 +38,12 @@ const mockUpdateTokens = jest.fn().mockImplementation((updatedTokens) => { tokens = updatedTokens; }); +const mockSetLastTokenDisplayName = jest.fn(); + mockUseApiToken.mockImplementation(() => ({ tokens, updateTokens: mockUpdateTokens, + setLastTokenDisplayName: mockSetLastTokenDisplayName, })); describe('Use Create Token', () => { @@ -84,6 +87,7 @@ describe('Use Create Token', () => { valid_for_ip: '', }, ], + setlastTokenDisplayName: '', }, echo_req: { api_token: 1, diff --git a/src/features/dashboard/hooks/useCreateToken/index.tsx b/src/features/dashboard/hooks/useCreateToken/index.tsx index 9b142090d..69d718e06 100644 --- a/src/features/dashboard/hooks/useCreateToken/index.tsx +++ b/src/features/dashboard/hooks/useCreateToken/index.tsx @@ -7,15 +7,16 @@ import { TTokenType } from '@site/src/types'; const useCreateToken = () => { const { send, data, is_loading, error } = useWS('api_token'); const { is_authorized } = useAuthContext(); - const { updateTokens } = useApiToken(); + const { updateTokens, setLastTokenDisplayName } = useApiToken(); const createToken = useCallback( (tokenName: string, scopes: TTokenType['scopes']) => { if (is_authorized) { send({ new_token: tokenName, new_token_scopes: scopes }); + setLastTokenDisplayName(tokenName); } }, - [is_authorized, send], + [is_authorized, send, setLastTokenDisplayName], ); useEffect(() => { diff --git a/static/img/copy.svg b/static/img/copy.svg index 0b99f2503..03cb6c4f2 100644 --- a/static/img/copy.svg +++ b/static/img/copy.svg @@ -1 +1,3 @@ - \ No newline at end of file + + +