Commit 4681f509 authored by tom's avatar tom

add comment field and show application rejection reason

parent 1481ef31
......@@ -181,6 +181,7 @@ export interface TokenInfoApplicationConfig {
}
export interface TokenInfoApplication {
adminComments?: string;
coinGeckoTicker?: string;
coinMarketCapTicker?: string;
comment?: string;
......
......@@ -7,7 +7,7 @@ import buildApiUrl from 'playwright/utils/buildApiUrl';
import AddressVerificationStepAddress from './AddressVerificationStepAddress';
const CHECK_ADDRESS_URL = buildApiUrl('address_verification', { chainId: '99', type: ':prepare' }, true);
const CHECK_ADDRESS_URL = buildApiUrl('address_verification', { chainId: '1', type: ':prepare' });
test('base view', async({ mount, page }) => {
await page.route(CHECK_ADDRESS_URL, (route) => route.fulfill({
......
......@@ -7,7 +7,7 @@ import buildApiUrl from 'playwright/utils/buildApiUrl';
import AddressVerificationStepSignature from './AddressVerificationStepSignature';
const VERIFY_ADDRESS_URL = buildApiUrl('address_verification', { chainId: '99', type: ':verify' }, true);
const VERIFY_ADDRESS_URL = buildApiUrl('address_verification', { chainId: '1', type: ':verify' });
test('base view', async({ mount, page }) => {
await page.route(VERIFY_ADDRESS_URL, (route) => route.fulfill({
......
......@@ -72,7 +72,7 @@ test('base view', async({ mount, page, createSocket }) => {
});
test('with verified info', async({ mount, page, createSocket }) => {
const VERIFIED_INFO_URL = buildApiUrl('token_verified_info', { chainId: '99', hash: '1' }, true);
const VERIFIED_INFO_URL = buildApiUrl('token_verified_info', { chainId: '1', hash: '1' });
await page.route(VERIFIED_INFO_URL, (route) => route.fulfill({
body: JSON.stringify(verifiedAddressesMocks.TOKEN_INFO_APPLICATION.APPROVED),
}));
......@@ -113,7 +113,7 @@ test.describe('mobile', () => {
});
test('with verified info', async({ mount, page, createSocket }) => {
const VERIFIED_INFO_URL = buildApiUrl('token_verified_info', { chainId: '99', hash: '1' }, true);
const VERIFIED_INFO_URL = buildApiUrl('token_verified_info', { chainId: '1', hash: '1' });
await page.route(VERIFIED_INFO_URL, (route) => route.fulfill({
body: JSON.stringify(verifiedAddressesMocks.TOKEN_INFO_APPLICATION.APPROVED),
}));
......
......@@ -7,8 +7,8 @@ import buildApiUrl from 'playwright/utils/buildApiUrl';
import VerifiedAddresses from './VerifiedAddresses';
const VERIFIED_ADDRESS_URL = buildApiUrl('verified_addresses', { chainId: '99' }, true);
const TOKEN_INFO_APPLICATIONS_URL = buildApiUrl('token_info_applications', { chainId: '99', id: undefined }, true);
const VERIFIED_ADDRESS_URL = buildApiUrl('verified_addresses', { chainId: '1' });
const TOKEN_INFO_APPLICATIONS_URL = buildApiUrl('token_info_applications', { chainId: '1', id: undefined });
test.beforeEach(async({ context }) => {
await context.route(mocks.TOKEN_INFO_APPLICATION_BASE.iconUrl, (route) => {
......@@ -38,8 +38,8 @@ test('base view +@mobile', async({ mount, page }) => {
});
test('address verification flow', async({ mount, page }) => {
const CHECK_ADDRESS_URL = buildApiUrl('address_verification', { chainId: '99', type: ':prepare' }, true);
const VERIFY_ADDRESS_URL = buildApiUrl('address_verification', { chainId: '99', type: ':verify' }, true);
const CHECK_ADDRESS_URL = buildApiUrl('address_verification', { chainId: '1', type: ':prepare' });
const VERIFY_ADDRESS_URL = buildApiUrl('address_verification', { chainId: '1', type: ':verify' });
await page.route(VERIFIED_ADDRESS_URL, (route) => route.fulfill({
body: JSON.stringify(mocks.VERIFIED_ADDRESS_RESPONSE.DEFAULT),
......@@ -87,8 +87,8 @@ test('address verification flow', async({ mount, page }) => {
});
test('application update flow', async({ mount, page }) => {
const TOKEN_INFO_APPLICATION_URL = buildApiUrl('token_info_applications', { chainId: '99', id: mocks.TOKEN_INFO_APPLICATION.UPDATED_ITEM.id }, true);
const FORM_CONFIG_URL = buildApiUrl('token_info_applications_config', { chainId: '99' }, true);
const TOKEN_INFO_APPLICATION_URL = buildApiUrl('token_info_applications', { chainId: '1', id: mocks.TOKEN_INFO_APPLICATION.UPDATED_ITEM.id });
const FORM_CONFIG_URL = buildApiUrl('token_info_applications_config', { chainId: '1' });
await page.route(VERIFIED_ADDRESS_URL, (route) => route.fulfill({
body: JSON.stringify(mocks.VERIFIED_ADDRESS_RESPONSE.DEFAULT),
......
......@@ -7,7 +7,7 @@ import buildApiUrl from 'playwright/utils/buildApiUrl';
import TokenInfoForm from './TokenInfoForm';
const FORM_CONFIG_URL = buildApiUrl('token_info_applications_config', { chainId: '99' }, true);
const FORM_CONFIG_URL = buildApiUrl('token_info_applications_config', { chainId: '1' });
test('base view +@mobile +@dark-mode', async({ mount, page }) => {
await page.route(mocks.TOKEN_INFO_APPLICATION_BASE.iconUrl, (route) => {
......@@ -36,3 +36,31 @@ test('base view +@mobile +@dark-mode', async({ mount, page }) => {
await expect(component).toHaveScreenshot();
});
test('status IN_PROCESS', async({ mount, page }) => {
await page.route(mocks.TOKEN_INFO_APPLICATION_BASE.iconUrl, (route) => {
return route.fulfill({
status: 200,
path: './playwright/image_md.jpg',
});
});
await page.route(FORM_CONFIG_URL, (route) => route.fulfill({
body: JSON.stringify(mocks.TOKEN_INFO_FORM_CONFIG),
}));
const props = {
address: mocks.VERIFIED_ADDRESS.ITEM_1.contractAddress,
tokenName: 'Test Token (TT)',
application: mocks.TOKEN_INFO_APPLICATION.IN_PROCESS,
onSubmit: () => {},
};
const component = await mount(
<TestApp>
<TokenInfoForm { ...props }/>
</TestApp>,
);
await expect(component).toHaveScreenshot();
});
import { Alert, Button, Grid, GridItem } from '@chakra-ui/react';
import { Button, Grid, GridItem } from '@chakra-ui/react';
import React from 'react';
import type { SubmitHandler } from 'react-hook-form';
import { useForm } from 'react-hook-form';
......@@ -16,6 +16,7 @@ import ContentLoader from 'ui/shared/ContentLoader';
import DataFetchAlert from 'ui/shared/DataFetchAlert';
import TokenInfoFieldAddress from './fields/TokenInfoFieldAddress';
import TokenInfoFieldComment from './fields/TokenInfoFieldComment';
import TokenInfoFieldDocs from './fields/TokenInfoFieldDocs';
import TokenInfoFieldIconUrl from './fields/TokenInfoFieldIconUrl';
import TokenInfoFieldPriceTicker from './fields/TokenInfoFieldPriceTicker';
......@@ -30,6 +31,7 @@ import TokenInfoFieldSocialLink from './fields/TokenInfoFieldSocialLink';
import TokenInfoFieldSupport from './fields/TokenInfoFieldSupport';
import TokenInfoFieldTokenName from './fields/TokenInfoFieldTokenName';
import TokenInfoFormSectionHeader from './TokenInfoFormSectionHeader';
import TokenInfoFormStatusText from './TokenInfoFormStatusText';
import { getFormDefaultValues, prepareRequestBody } from './utils';
interface Props {
......@@ -104,13 +106,11 @@ const TokenInfoForm = ({ address, tokenName, application, onSubmit }: Props) =>
return (
<form noValidate onSubmit={ handleSubmit(onFormSubmit) } autoComplete="off" ref={ containerRef }>
<div>Requests are sent to a moderator for review and approval. This process can take several days.</div>
{ application?.status === 'IN_PROCESS' &&
<Alert status="warning" mt={ 6 }>Request in progress. Once an admin approves your request you can edit token info.</Alert> }
<TokenInfoFormStatusText application={ application }/>
<Grid mt={ 8 } gridTemplateColumns={{ base: '1fr', lg: '1fr 1fr' }} columnGap={ 5 } rowGap={ 5 }>
<TokenInfoFieldAddress { ...fieldProps }/>
<TokenInfoFieldTokenName { ...fieldProps }/>
<TokenInfoFieldAddress { ...fieldProps }/>
<TokenInfoFieldRequesterName { ...fieldProps }/>
<TokenInfoFieldRequesterEmail { ...fieldProps }/>
......@@ -146,6 +146,10 @@ const TokenInfoForm = ({ address, tokenName, application, onSubmit }: Props) =>
<GridItem colSpan={{ base: 1, lg: 2 }}>
<TokenInfoFieldPriceTicker { ...fieldProps } name="ticker_defi_llama" label="DefiLlama URL "/>
</GridItem>
<GridItem colSpan={{ base: 1, lg: 2 }}>
<TokenInfoFieldComment { ...fieldProps }/>
</GridItem>
</Grid>
<Button
type="submit"
......
import { Alert } from '@chakra-ui/react';
import React from 'react';
import type { TokenInfoApplication } from 'types/api/account';
interface Props {
application?: TokenInfoApplication;
}
const TokenInfoFormStatusText = ({ application }: Props) => {
if (!application) {
return null;
}
switch (application.status) {
case 'IN_PROCESS': {
return (
<div>
<div>Requests are sent to a moderator for review and approval. This process can take several days.</div>
<Alert status="warning" mt={ 6 }>Request in progress. Once an admin approves your request you can edit token info.</Alert>
</div>
);
}
case 'UPDATE_REQUIRED': {
return (
<div>
{ application.adminComments && <Alert status="warning" mt={ 6 }>{ application.adminComments }</Alert> }
</div>
);
}
case 'REJECTED': {
return (
<div>
{ application.adminComments && <Alert status="warning" mt={ 6 }>{ application.adminComments }</Alert> }
</div>
);
}
default:
return null;
}
};
export default React.memo(TokenInfoFormStatusText);
import { FormControl, Textarea } from '@chakra-ui/react';
import React from 'react';
import type { Control, ControllerProps } from 'react-hook-form';
import { Controller } from 'react-hook-form';
import type { Fields } from '../types';
import InputPlaceholder from 'ui/shared/InputPlaceholder';
interface Props {
control: Control<Fields>;
isReadOnly?: boolean;
}
const TokenInfoFieldComment = ({ control, isReadOnly }: Props) => {
const renderControl: ControllerProps<Fields, 'comment'>['render'] = React.useCallback(({ field, fieldState, formState }) => {
return (
<FormControl variant="floating" id={ field.name } size={{ base: 'md', lg: 'lg' }}>
<Textarea
{ ...field }
isInvalid={ Boolean(fieldState.error) }
isDisabled={ formState.isSubmitting || isReadOnly }
autoComplete="off"
maxH="160px"
maxLength={ 300 }
/>
<InputPlaceholder text="Comment" error={ fieldState.error }/>
</FormControl>
);
}, [ isReadOnly ]);
return (
<Controller
name="comment"
control={ control }
render={ renderControl }
rules={{ maxLength: 300 }}
/>
);
};
export default React.memo(TokenInfoFieldComment);
......@@ -13,6 +13,7 @@ export interface Fields extends SocialLinkFields, TickerUrlFields {
docs?: string;
support?: string;
icon_url: string;
comment?: string;
}
export interface TickerUrlFields {
......
......@@ -32,6 +32,7 @@ export function getFormDefaultValues(address: string, tokenName: string, applica
facebook: application.facebook || '',
medium: application.medium || '',
reddit: application.reddit || '',
comment: application.comment || '',
};
}
......@@ -61,5 +62,6 @@ export function prepareRequestBody(data: Fields): Omit<TokenInfoApplication, 'id
telegram: data.telegram,
tokenAddress: data.address,
twitter: data.twitter,
comment: data.comment,
};
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment