diff --git a/src/features/dashboard/components/ApiTokenForm/CreateTokenField/index.tsx b/src/features/dashboard/components/ApiTokenForm/CreateTokenField/index.tsx index 72987d5ef..bc727ebeb 100644 --- a/src/features/dashboard/components/ApiTokenForm/CreateTokenField/index.tsx +++ b/src/features/dashboard/components/ApiTokenForm/CreateTokenField/index.tsx @@ -19,6 +19,7 @@ type TCreateTokenField = { >; form_is_cleared: boolean; setFormIsCleared: Dispatch>; + setHideRestriction: Dispatch>; is_toggle: boolean; setToggleModal: Dispatch>; }; @@ -28,6 +29,7 @@ const CreateTokenField = ({ register, form_is_cleared, setFormIsCleared, + setHideRestriction, is_toggle, setToggleModal, }: TCreateTokenField) => { @@ -54,6 +56,11 @@ const CreateTokenField = ({ const disable_button = token_name_exists || Object.keys(errors).length > 0 || input_value === ''; const error_border_active = token_name_exists || errors.name; + useEffect(() => { + if (error_border_active) { + setHideRestriction(true); + } + }, [error_border_active, setHideRestriction]); return (
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 3c5bc2470..420d27f6c 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 @@ -4,6 +4,7 @@ import userEvent from '@testing-library/user-event'; import ApiTokenForm from '../api-token.form'; import useCreateToken from '../../../hooks/useCreateToken'; import useApiToken from '@site/src/hooks/useApiToken'; +import TokenNameRestrictions from '../../TokenNameRestrictions/TokenNameRestrictions'; jest.mock('@site/src/hooks/useApiToken'); @@ -139,6 +140,14 @@ describe('Home Page', () => { expect(error).toBeVisible; }); + it('should hide restrictions if error is present', async () => { + const nameInput = screen.getByRole('textbox'); + const restrictions = screen.getByRole('list'); + expect(restrictions).toBeVisible(); + await userEvent.type(nameInput, 'testtoken1'); + expect(restrictions).not.toBeVisible(); + }); + it('Should not create token when name input is empty', async () => { const nameInput = screen.getByRole('textbox'); diff --git a/src/features/dashboard/components/ApiTokenForm/api-token.form.module.scss b/src/features/dashboard/components/ApiTokenForm/api-token.form.module.scss index 4571be415..865d41bbb 100644 --- a/src/features/dashboard/components/ApiTokenForm/api-token.form.module.scss +++ b/src/features/dashboard/components/ApiTokenForm/api-token.form.module.scss @@ -55,7 +55,6 @@ form { display: flex; position: relative; box-sizing: border-box; - margin: rem(1) 0; &:hover { border: 1px solid var(--colors-greyLight600); } diff --git a/src/features/dashboard/components/ApiTokenForm/api-token.form.tsx b/src/features/dashboard/components/ApiTokenForm/api-token.form.tsx index 8ad9594d6..36b9d5917 100644 --- a/src/features/dashboard/components/ApiTokenForm/api-token.form.tsx +++ b/src/features/dashboard/components/ApiTokenForm/api-token.form.tsx @@ -1,4 +1,4 @@ -import React, { HTMLAttributes, useCallback, useState } from 'react'; +import React, { HTMLAttributes, useCallback, useEffect, useState } from 'react'; import { Text } from '@deriv/ui'; import { useForm } from 'react-hook-form'; import { Circles } from 'react-loader-spinner'; @@ -8,6 +8,7 @@ import ApiTokenCard from '../ApiTokenCard'; import useCreateToken from '@site/src/features/dashboard/hooks/useCreateToken'; import * as yup from 'yup'; import styles from './api-token.form.module.scss'; +import TokenNameRestrictions from '../TokenNameRestrictions/TokenNameRestrictions'; import CreateTokenField from './CreateTokenField'; const schema = yup @@ -79,6 +80,7 @@ const scopes: TScope[] = [ const ApiTokenForm = (props: HTMLAttributes) => { const { createToken, isCreatingToken } = useCreateToken(); + const [hiderestrictions, setHideRestrictions] = useState(false); const [form_is_cleared, setFormIsCleared] = useState(false); const [is_toggle, setToggleModal] = useState(false); @@ -93,7 +95,6 @@ const ApiTokenForm = (props: HTMLAttributes) => { resolver: yupResolver(schema), mode: 'all', }); - const onSubmit = useCallback( (data: TApiTokenForm) => { const { name } = data; @@ -120,6 +121,10 @@ const ApiTokenForm = (props: HTMLAttributes) => { [getValues, setValue], ); + useEffect(() => { + errors.name?.message ? setHideRestrictions(true) : setHideRestrictions(false); + }, [errors.name?.message]); + return (
@@ -159,9 +164,11 @@ const ApiTokenForm = (props: HTMLAttributes) => { errors={errors} form_is_cleared={form_is_cleared} setFormIsCleared={setFormIsCleared} + setHideRestriction={setHideRestrictions} is_toggle={is_toggle} setToggleModal={setToggleModal} /> + {!hiderestrictions && }
diff --git a/src/features/dashboard/components/TokenNameRestrictions/TokenNameRestrictions.module.scss b/src/features/dashboard/components/TokenNameRestrictions/TokenNameRestrictions.module.scss new file mode 100644 index 000000000..56a1aa36d --- /dev/null +++ b/src/features/dashboard/components/TokenNameRestrictions/TokenNameRestrictions.module.scss @@ -0,0 +1,10 @@ +@use 'src/styles/utility' as *; + +.tokenrestrictions { + font-size: rem(1.4); + font-weight: 400; + line-height: 18px; + padding-left: rem(2.8); + margin-top: rem(1); + color: var(--colors-greyLight600); +} diff --git a/src/features/dashboard/components/TokenNameRestrictions/TokenNameRestrictions.tsx b/src/features/dashboard/components/TokenNameRestrictions/TokenNameRestrictions.tsx new file mode 100644 index 000000000..2c882c6f0 --- /dev/null +++ b/src/features/dashboard/components/TokenNameRestrictions/TokenNameRestrictions.tsx @@ -0,0 +1,19 @@ +import React from 'react'; +import styles from './TokenNameRestrictions.module.scss'; + +const TokenNameRestrictions = () => { + return ( +
    +
  1. Only alphanumeric characters with spaces and underscores are allowed.
  2. +
  3. Only 2-32 characters are allowed
  4. +
  5. No duplicate token names are allowed for the same account.
  6. +
  7. + { + 'No keywords "deriv" or "binary" or words that look similar, e.g. "_binary_" or "d3eriv" are allowed.' + } +
  8. +
+ ); +}; + +export default TokenNameRestrictions; diff --git a/src/features/dashboard/components/TokenNameRestrictions/__tests__/TokenNameRestrictions.test.tsx b/src/features/dashboard/components/TokenNameRestrictions/__tests__/TokenNameRestrictions.test.tsx new file mode 100644 index 000000000..834f55919 --- /dev/null +++ b/src/features/dashboard/components/TokenNameRestrictions/__tests__/TokenNameRestrictions.test.tsx @@ -0,0 +1,31 @@ +import React from 'react'; +import { render, screen } from '@site/src/test-utils'; +import TokenNameRestrictions from '../TokenNameRestrictions'; + +describe('Restrictions for App name', () => { + beforeEach(() => { + render(); + }); + it('Should render the list', () => { + const RestrictonList = screen.getByRole('list'); + expect(RestrictonList).toBeInTheDocument(); + }); + + it('Should display correct content inside list items', () => { + const listItem1 = screen.getByText( + 'Only alphanumeric characters with spaces and underscores are allowed.', + ); + const listItem2 = screen.getByText('Only 2-32 characters are allowed'); + const listItem3 = screen.getByText( + 'No duplicate token names are allowed for the same account.', + ); + const listItem4 = screen.getByText( + 'No keywords "deriv" or "binary" or words that look similar, e.g. "_binary_" or "d3eriv" are allowed.', + ); + + expect(listItem1).toBeInTheDocument(); + expect(listItem2).toBeInTheDocument(); + expect(listItem3).toBeInTheDocument(); + expect(listItem4).toBeInTheDocument(); + }); +});