Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Utkarsha/refinement api token accounts #86

Merged
Show file tree
Hide file tree
Changes from 18 commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
faa5efa
refactor: refactored api-token index and test files
utkarsha-deriv Jul 26, 2023
065b3ab
Merge branch 'master' into utkarsha/refinement-api-token-accounts
utkarsha-deriv Jul 26, 2023
7fa5591
fix: added is_desktop to mocks also
utkarsha-deriv Jul 26, 2023
fb66efb
chore: remove comments
utkarsha-deriv Jul 26, 2023
6964dac
test: testcases for api-token.tsx
utkarsha-deriv Aug 8, 2023
3ec58a4
chore: remove isDesktop
utkarsha-deriv Aug 8, 2023
2443c1f
Merge branch 'master' into utkarsha/refinement-api-token-accounts
utkarsha-deriv Aug 8, 2023
33c711e
chore: api_token_title check improvement
utkarsha-deriv Aug 15, 2023
a1befbc
Revert "chore: api_token_title check improvement"
utkarsha-deriv Aug 17, 2023
260b006
fix: defaultCheckbox type added
utkarsha-deriv Aug 22, 2023
cc16344
fix: comments
utkarsha-deriv Aug 25, 2023
c5bd720
fix: clearTimeout
utkarsha-deriv Aug 25, 2023
c4fcbfc
fix: is_desktop
utkarsha-deriv Aug 30, 2023
d46925e
fix: is_desktop
utkarsha-deriv Aug 30, 2023
20729aa
chore: remove styles
utkarsha-deriv Aug 31, 2023
4c5fc86
Merge branch 'binary-com:master' into utkarsha/refinement-api-token-a…
utkarsha-deriv Aug 31, 2023
55a8a51
chore: Localize component
utkarsha-deriv Sep 1, 2023
7dd9b3a
Merge branch 'binary-com:master' into utkarsha/refinement-api-token-a…
utkarsha-deriv Sep 1, 2023
42716f0
Merge branch 'accounts_team/accounts_package_ts_migration/sprint_6' i…
utkarsha-deriv Sep 1, 2023
4d37aa0
chore: introduce loop for api token card
utkarsha-deriv Sep 1, 2023
2aec880
chore: refactor api token card
utkarsha-deriv Sep 1, 2023
69d0d47
feat: :art: incorporated hooks for API token
likhith-deriv Sep 5, 2023
13eb4ef
Merge branch 'accounts_team/accounts_package_ts_migration/sprint_6' i…
utkarsha-deriv Sep 11, 2023
ade390e
feat: :art: incorporated hooks
likhith-deriv Sep 11, 2023
b8b7324
fix: prop type
likhith-deriv Sep 11, 2023
08217cc
Merge pull request #8 from likhith-deriv/likhith/incorporated-hooks-t…
utkarsha-deriv Sep 11, 2023
0ff5b37
fix: :white_check_mark: fixed testcase
likhith-deriv Sep 11, 2023
f81c60b
feat: :art: migrated to Localize
likhith-deriv Sep 11, 2023
3208966
Merge pull request #9 from likhith-deriv/likhith/fix-testcase
utkarsha-deriv Sep 11, 2023
0d9a82b
fix: localize to Localize for Composite checkbox
utkarsha-deriv Sep 11, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view

Large diffs are not rendered by default.

40 changes: 14 additions & 26 deletions packages/account/src/Components/api-token/api-token-card.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,38 +3,26 @@ import { Field, FieldProps } from 'formik';
import { CompositeCheckbox } from '@deriv/components';

type TApiTokenCard = {
description: string;
description: JSX.Element;
utkarsha-deriv marked this conversation as resolved.
Show resolved Hide resolved
display_name: string;
name: string;
value: boolean;
setFieldValue: (name: string, value: boolean) => void;
};

const ApiTokenCard = ({
name,
value,
display_name,
description,
setFieldValue,
children,
}: React.PropsWithChildren<TApiTokenCard>) => {
const ApiTokenCard = ({ name, display_name, description, children }: React.PropsWithChildren<TApiTokenCard>) => {
return (
<Field name={name}>
{({ field }: FieldProps<string | boolean>) => {
return (
<CompositeCheckbox
{...field}
onChange={() => setFieldValue(name, !value)}
value={value}
className='api-token__checkbox'
defaultChecked={value}
label={display_name}
description={description}
>
{children}
</CompositeCheckbox>
);
}}
{({ field, form: { setFieldValue } }: FieldProps<boolean>) => (
<CompositeCheckbox
{...field}
// Used to set the checkbox value when clicked on the encased region
onChange={() => setFieldValue(name, !field.value)}
className='api-token__checkbox'
label={display_name}
description={description}
>
{children}
</CompositeCheckbox>
)}
</Field>
);
};
Expand Down
21 changes: 0 additions & 21 deletions packages/account/src/Components/api-token/api-token-footer.tsx

This file was deleted.

31 changes: 0 additions & 31 deletions packages/account/src/Components/api-token/api-token-overlay.tsx

This file was deleted.

6 changes: 0 additions & 6 deletions packages/account/src/Components/api-token/api-token.scss
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,6 @@
max-height: 100%;
width: 100%;

@include tablet-up {
&--app-settings {
padding: 2.4rem;
}
}

& .dc-timeline__container {
width: 100%;
}
Expand Down
135 changes: 56 additions & 79 deletions packages/account/src/Components/api-token/api-token.tsx
Original file line number Diff line number Diff line change
@@ -1,15 +1,13 @@
import React from 'react';
import classNames from 'classnames';
import { Formik, Form, Field, FormikValues, FormikErrors, FieldProps } from 'formik';
import { Formik, Form, Field, FormikErrors, FieldProps, FormikHelpers } from 'formik';
import { Timeline, Input, Button, ThemedScrollbars, Loading } from '@deriv/components';
import InlineNoteWithIcon from '../inline-note-with-icon';
import { isDesktop, isMobile, getPropertyValue, useIsMounted, WS } from '@deriv/shared';
import { localize } from '@deriv/translations';
import { getPropertyValue, useIsMounted, WS } from '@deriv/shared';
import { Localize, localize } from '@deriv/translations';
import LoadErrorMessage from 'Components/load-error-message';
import ApiTokenArticle from './api-token-article';
import ApiTokenCard from './api-token-card';
import ApiTokenFooter from './api-token-footer';
import ApiTokenOverlay from './api-token-overlay';
import ApiTokenTable from './api-token-table';
import ApiTokenContext from './api-token-context';
import { TToken } from 'Types';
Expand All @@ -30,22 +28,19 @@ type AptTokenState = {
is_delete_success: boolean;
};

export type TApiToken = {
footer_ref: Element | DocumentFragment | undefined;
is_app_settings: boolean;
overlay_ref:
| undefined
| ((...args: unknown[]) => unknown)
| import('prop-types').InferProps<{
current: import('prop-types').Requireable<unknown>;
}>;
setIsOverlayShown: (is_overlay_shown: boolean | undefined) => void;
// eslint-disable-next-line @typescript-eslint/no-explicit-any
type TApiTokenForm = {
token_name: string;
read: boolean;
trade: boolean;
payments: boolean;
trading_information: boolean;
admin: boolean;
};

const ApiToken = ({ footer_ref, is_app_settings, overlay_ref, setIsOverlayShown }: TApiToken) => {
const { client } = useStore();
const ApiToken = () => {
const { client, ui } = useStore();
const { is_switching } = client;
const { is_desktop, is_mobile } = ui;
const isMounted = useIsMounted();
const prev_is_switching = React.useRef(is_switching);
const [state, setState] = React.useReducer(
Expand All @@ -65,11 +60,15 @@ const ApiToken = ({ footer_ref, is_app_settings, overlay_ref, setIsOverlayShown
is_delete_success: false,
}
);
const timeout_ref = React.useRef<NodeJS.Timeout | undefined>();

React.useEffect(() => {
getApiTokens();

return () => setState({ dispose_token: '' });
return () => {
setState({ dispose_token: '' });
clearTimeout(timeout_ref.current);
};
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);

Expand All @@ -81,12 +80,6 @@ const ApiToken = ({ footer_ref, is_app_settings, overlay_ref, setIsOverlayShown
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [is_switching]);

React.useEffect(() => {
if (typeof setIsOverlayShown === 'function') {
setIsOverlayShown(state.is_overlay_shown);
}
}, [state.is_overlay_shown, setIsOverlayShown]);

const initial_form = {
token_name: '',
read: false,
Expand All @@ -96,10 +89,8 @@ const ApiToken = ({ footer_ref, is_app_settings, overlay_ref, setIsOverlayShown
admin: false,
};

const toggleOverlay = () => setState({ is_overlay_shown: !state.is_overlay_shown });

const validateFields = (values: FormikValues) => {
const errors: FormikErrors<FormikValues> = {};
const validateFields = (values: TApiTokenForm) => {
const errors: FormikErrors<TApiTokenForm> = {};
const token_name = values.token_name && values.token_name.trim();

if (!token_name) {
Expand All @@ -121,15 +112,18 @@ const ApiToken = ({ footer_ref, is_app_settings, overlay_ref, setIsOverlayShown
return errors;
};

const selectedTokenScope = (values: FormikValues) =>
Object.keys(values).filter(item => item !== 'token_name' && values[item]);
const handleSubmit = async (values: FormikValues, { setSubmitting, setFieldError, resetForm }: any) => {
const selectedTokenScope = (values: TApiTokenForm) =>
Object.keys(values).filter(item => item !== 'token_name' && Boolean(values[item as keyof TApiTokenForm]));

const handleSubmit = async (
values: TApiTokenForm,
{ setSubmitting, setFieldError, resetForm }: FormikHelpers<TApiTokenForm>
) => {
const token_response = await WS.apiToken({
api_token: 1,
new_token: values.token_name,
new_token_scopes: selectedTokenScope(values),
});

if (token_response.error) {
setFieldError('token_name', token_response.error.message);
} else if (isMounted()) {
Expand All @@ -141,7 +135,6 @@ const ApiToken = ({ footer_ref, is_app_settings, overlay_ref, setIsOverlayShown
if (isMounted()) setState({ is_success: false });
}, 500);
}

resetForm();
setSubmitting(false);
};
Expand Down Expand Up @@ -176,12 +169,12 @@ const ApiToken = ({ footer_ref, is_app_settings, overlay_ref, setIsOverlayShown

if (isMounted()) setState({ is_delete_loading: false, is_delete_success: true });

setTimeout(() => {
timeout_ref.current = setTimeout(() => {
if (isMounted()) setState({ is_delete_success: false });
}, 500);
};

const { api_tokens, is_loading, is_success, error_message, is_overlay_shown } = state;
const { api_tokens, is_loading, is_success, error_message } = state;

if (is_loading || is_switching) {
return <Loading is_fullscreen={false} className='account__initial-loader' />;
Expand All @@ -193,23 +186,16 @@ const ApiToken = ({ footer_ref, is_app_settings, overlay_ref, setIsOverlayShown

const context_value = {
api_tokens,
toggleOverlay,
deleteToken,
footer_ref,
overlay_ref,
};

return (
<React.Fragment>
<ApiTokenContext.Provider value={context_value}>
<section
className={classNames('da-api-token', {
'da-api-token--app-settings': is_app_settings,
})}
>
<section className='da-api-token'>
<div className='da-api-token__wrapper'>
<ThemedScrollbars className='da-api-token__scrollbars' is_bypassed={isMobile()}>
{!is_app_settings && isMobile() && <ApiTokenArticle />}
<ThemedScrollbars className='da-api-token__scrollbars' is_bypassed={is_mobile}>
{is_mobile && <ApiTokenArticle />}
<Formik initialValues={initial_form} onSubmit={handleSubmit} validate={validateFields}>
{({
values,
Expand All @@ -220,7 +206,6 @@ const ApiToken = ({ footer_ref, is_app_settings, overlay_ref, setIsOverlayShown
handleChange,
handleBlur,
isSubmitting,
setFieldValue,
setFieldTouched,
}) => (
<Form noValidate>
Expand All @@ -231,54 +216,44 @@ const ApiToken = ({ footer_ref, is_app_settings, overlay_ref, setIsOverlayShown
<div className='da-api-token__checkbox-wrapper'>
<ApiTokenCard
name='read'
value={values.read}
setFieldValue={setFieldValue}
display_name={localize('Read')}
description={localize(
'This scope will allow third-party apps to view your account activity, settings, limits, balance sheets, trade purchase history, and more.'
)}
description={
<Localize i18n_default_text='This scope will allow third-party apps to view your account activity, settings, limits, balance sheets, trade purchase history, and more.' />
}
/>
<ApiTokenCard
name='trade'
value={values.trade}
display_name={localize('Trade')}
setFieldValue={setFieldValue}
description={localize(
'This scope will allow third-party apps to buy and sell contracts for you, renew your expired purchases, and top up your demo accounts.'
)}
description={
<Localize i18n_default_text='This scope will allow third-party apps to buy and sell contracts for you, renew your expired purchases, and top up your demo accounts.' />
}
/>
<ApiTokenCard
name='payments'
value={values.payments}
display_name={localize('Payments')}
setFieldValue={setFieldValue}
description={localize(
'This scope will allow third-party apps to withdraw to payment agents and make inter-account transfers for you.'
)}
description={
<Localize i18n_default_text='This scope will allow third-party apps to withdraw to payment agents and make inter-account transfers for you.' />
}
/>
<ApiTokenCard
name='trading_information'
value={values.trading_information}
display_name={localize('Trading information')}
setFieldValue={setFieldValue}
description={localize(
'This scope will allow third-party apps to view your trading history.'
)}
description={
<Localize i18n_default_text='This scope will allow third-party apps to view your trading history.' />
}
utkarsha-deriv marked this conversation as resolved.
Show resolved Hide resolved
/>
<ApiTokenCard
name='admin'
value={values.admin}
display_name={localize('Admin')}
setFieldValue={setFieldValue}
description={localize(
'This scope will allow third-party apps to open accounts for you, manage your settings and token usage, and more. '
)}
description={
<Localize i18n_default_text='This scope will allow third-party apps to open accounts for you, manage your settings and token usage, and more. ' />
}
>
<InlineNoteWithIcon
icon='IcAlertWarning'
message={localize(
'To avoid loss of funds, do not share tokens with the Admin scope with unauthorised parties.'
)}
message={
<Localize i18n_default_text='To avoid loss of funds, do not share tokens with the Admin scope with unauthorised parties.' />
}
title={localize('Note')}
/>
</ApiTokenCard>
Expand Down Expand Up @@ -308,7 +283,11 @@ const ApiToken = ({ footer_ref, is_app_settings, overlay_ref, setIsOverlayShown
'Length of token name must be between 2 and 32 characters.'
)}
required
error={touched.token_name && errors.token_name}
error={
touched.token_name && errors.token_name
? errors.token_name
: undefined
}
/>
)}
</Field>
Expand Down Expand Up @@ -346,11 +325,9 @@ const ApiToken = ({ footer_ref, is_app_settings, overlay_ref, setIsOverlayShown
)}
</Formik>
</ThemedScrollbars>
{!is_app_settings && isDesktop() && <ApiTokenArticle />}
{is_desktop && <ApiTokenArticle />}
</div>
</section>
{footer_ref && <ApiTokenFooter />}
{overlay_ref && is_overlay_shown && <ApiTokenOverlay />}
</ApiTokenContext.Provider>
</React.Fragment>
);
Expand Down
Loading