Commit c33b2fd0 authored by tom goriunov's avatar tom goriunov Committed by GitHub

Merge pull request #69 from blockscout/chors

more eslint rules
parents a775d015 dd691ec8
......@@ -19,6 +19,7 @@ module.exports = {
'@typescript-eslint',
'react-hooks',
'jsx-a11y',
'eslint-plugin-import-helpers',
],
parser: '@typescript-eslint/parser',
parserOptions: {
......@@ -104,6 +105,7 @@ module.exports = {
'@typescript-eslint/no-use-before-define': 'off',
'@typescript-eslint/no-useless-constructor': [ 'error' ],
'@typescript-eslint/type-annotation-spacing': 'error',
'@typescript-eslint/no-explicit-any': [ 'error', { ignoreRestArgs: true } ],
// отключены в пользу @typescript-eslint
'brace-style': 'off',
......@@ -177,6 +179,21 @@ module.exports = {
'space-unary-ops': 'off',
'template-curly-spacing': [ 'error', 'always' ],
'wrap-iife': [ 'error', 'inside' ],
semi: [ 'error', 'always' ],
'import-helpers/order-imports': [
'error',
{
newlinesBetween: 'always',
groups: [
'module',
'/types/',
[ '/^data/', '/^icons/', '/^lib/', '/^pages/', '/^theme/', '/^ui/' ],
[ 'parent', 'sibling', 'index' ],
],
alphabetize: { order: 'asc', ignoreCase: true },
},
],
'react/jsx-key': 'error',
'react/jsx-no-bind': [ 'error', {
......
......@@ -5,6 +5,6 @@ module.exports = withReactSvg({
include: path.resolve(__dirname, 'icons'),
reactStrictMode: true,
webpack(config) {
return config
return config;
},
})
});
import React, { useState } from 'react';
import type { AppProps } from 'next/app';
import { ChakraProvider } from '@chakra-ui/react';
import theme from 'theme';
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
import type { AppProps } from 'next/app';
import React, { useState } from 'react';
import theme from 'theme';
function MyApp({ Component, pageProps }: AppProps) {
const [ queryClient ] = useState(() => new QueryClient({
......@@ -23,4 +23,4 @@ function MyApp({ Component, pageProps }: AppProps) {
);
}
export default MyApp
export default MyApp;
import React from 'react';
import Document, { Html, Head, Main, NextScript } from 'next/document'
import { ColorModeScript } from '@chakra-ui/react';
import theme from 'theme'
import Document, { Html, Head, Main, NextScript } from 'next/document';
import React from 'react';
import theme from 'theme';
class MyDocument extends Document {
render() {
......@@ -23,8 +24,8 @@ class MyDocument extends Document {
<NextScript/>
</body>
</Html>
)
);
}
}
export default MyDocument
export default MyDocument;
import React from 'react';
import type { NextPage } from 'next';
import Head from 'next/head'
import Head from 'next/head';
import React from 'react';
import ApiKeys from 'ui/pages/ApiKeys';
......@@ -11,6 +11,6 @@ const ApiKeysPage: NextPage = () => {
<ApiKeys/>
</>
);
}
};
export default ApiKeysPage
export default ApiKeysPage;
import type { NextApiRequest } from 'next'
import type { NextApiRequest } from 'next';
import handler from 'pages/api/utils/handler';
......@@ -7,10 +7,10 @@ const getUrl = (req: NextApiRequest) => {
if (req.method === 'PUT') {
const params = { address_hash: req.query.address_hash as string, name: req.query.name as string };
const searchParams = new URLSearchParams(params);
url += `?${ searchParams.toString() }`
url += `?${ searchParams.toString() }`;
}
return url;
}
};
const addressDeleteHandler = handler(getUrl, [ 'DELETE', 'PUT' ]);
......
import handler from 'pages/api/utils/handler';
import type { AddressTags } from 'pages/api/types/account';
import handler from 'pages/api/utils/handler';
const addressHandler = handler<AddressTags>(() => '/account/v1/user/tags/address', [ 'GET', 'POST' ]);
export default addressHandler;
import type { NextApiRequest } from 'next'
import type { NextApiRequest } from 'next';
import handler from 'pages/api/utils/handler';
......@@ -7,10 +7,10 @@ const getUrl = (req: NextApiRequest) => {
if (req.method === 'PUT') {
const params = { transaction_hash: req.query.transaction_hash as string, name: req.query.name as string };
const searchParams = new URLSearchParams(params);
url += `?${ searchParams.toString() }`
url += `?${ searchParams.toString() }`;
}
return url;
}
};
const transactionDeleteHandler = handler(getUrl, [ 'DELETE', 'PUT' ]);
......
import handler from 'pages/api/utils/handler';
import type { TransactionTags } from 'pages/api/types/account';
import handler from 'pages/api/utils/handler';
const transactionHandler = handler<TransactionTags>(() => '/account/v1/user/tags/transaction', [ 'GET', 'POST' ]);
export default transactionHandler;
......@@ -8,11 +8,11 @@ export default function fetch(path: string, init?: RequestInit): Promise<Respons
accept: 'application/json',
authorization: `Bearer ${ process.env.API_AUTHORIZATION_TOKEN }`,
'content-type': 'application/json',
}
};
const url = `https://${ process.env.API_HOST }${ process.env.API_BASE_PATH }${ path }`;
return nodeFetch(url, {
headers,
...init,
})
});
}
import type { NextApiRequest, NextApiResponse } from 'next'
import type { NextApiRequest, NextApiResponse } from 'next';
import fetch from './fetch';
......@@ -7,7 +7,7 @@ type Methods = 'GET' | 'POST' | 'PUT' | 'DELETE';
export default function handler<TRes>(getUrl: (_req: NextApiRequest) => string, allowedMethods: Array<Methods>) {
return async(_req: NextApiRequest, res: NextApiResponse<TRes>) => {
if (_req.method === 'GET' && allowedMethods.includes('GET')) {
const response = await fetch(getUrl(_req))
const response = await fetch(getUrl(_req));
const data = await response.json() as TRes;
res.status(200).json(data);
......@@ -15,17 +15,17 @@ export default function handler<TRes>(getUrl: (_req: NextApiRequest) => string,
const response = await fetch(getUrl(_req), {
method: 'POST',
body: _req.body,
})
});
const data = await response.json() as TRes;
res.status(200).json(data)
res.status(200).json(data);
} else if (allowedMethods.includes('PUT') && _req.method === 'PUT') {
const response = await fetch(getUrl(_req), {
method: 'PUT',
})
});
const data = await response.json() as TRes;
res.status(200).json(data)
res.status(200).json(data);
} else if (allowedMethods.includes('DELETE') && _req.method === 'DELETE') {
const response = await fetch(getUrl(_req), { method: 'DELETE' });
// FIXME: add error handlers
......@@ -35,8 +35,8 @@ export default function handler<TRes>(getUrl: (_req: NextApiRequest) => string,
}
res.status(200).end();
} else {
res.setHeader('Allow', allowedMethods)
res.status(405).end(`Method ${ _req.method } Not Allowed`)
res.setHeader('Allow', allowedMethods);
res.status(405).end(`Method ${ _req.method } Not Allowed`);
}
}
};
}
import React from 'react';
import type { NextPage } from 'next';
import { Center } from '@chakra-ui/react';
import type { NextPage } from 'next';
import React from 'react';
import Page from 'ui/shared/Page/Page';
const Home: NextPage = () => {
......@@ -13,4 +14,4 @@ const Home: NextPage = () => {
);
};
export default Home
export default Home;
import React, { useCallback, useState } from 'react';
import { useQuery } from '@tanstack/react-query';
import type { NextPage } from 'next';
import Head from 'next/head'
import { useQuery } from '@tanstack/react-query'
import Head from 'next/head';
import React, { useCallback, useState } from 'react';
import PrivateTags from 'ui/pages/PrivateTags';
......@@ -20,20 +19,20 @@ const PrivateTagsPage: NextPage = () => {
// FIXME: request data only for active tab and only once
// don't refetch after tab change
useQuery([ 'address' ], async() => {
const response = await fetch('/api/account/private-tags/address')
const response = await fetch('/api/account/private-tags/address');
if (!response.ok) {
throw new Error('Network response was not ok')
throw new Error('Network response was not ok');
}
return response.json()
})
return response.json();
});
useQuery([ 'transaction' ], async() => {
const response = await fetch('/api/account/private-tags/transaction')
const response = await fetch('/api/account/private-tags/transaction');
if (!response.ok) {
throw new Error('Network response was not ok')
throw new Error('Network response was not ok');
}
return response.json()
})
return response.json();
});
return (
<>
......@@ -41,6 +40,6 @@ const PrivateTagsPage: NextPage = () => {
<PrivateTags onChangeTab={ onChangeTab }/>
</>
);
}
};
export default PrivateTagsPage;
import React from 'react';
import type { NextPage } from 'next';
import Head from 'next/head'
import Head from 'next/head';
import React from 'react';
import PublicTags from 'ui/pages/PublicTags';
......@@ -11,6 +11,6 @@ const PublicTagsPage: NextPage = () => {
<PublicTags/>
</>
);
}
};
export default PublicTagsPage
export default PublicTagsPage;
import React from 'react';
import type { NextPage } from 'next';
import Head from 'next/head'
import Head from 'next/head';
import React from 'react';
import WatchList from 'ui/pages/Watchlist';
......@@ -11,6 +11,6 @@ const WatchListPage: NextPage = () => {
<WatchList/>
</>
);
}
};
export default WatchListPage
export default WatchListPage;
......@@ -15,7 +15,7 @@ const variantPrimary = {
_disabled: {
opacity: 0.2,
},
}
};
const variantSecondary = {
color: 'blue.600',
......@@ -29,7 +29,7 @@ const variantSecondary = {
_disabled: {
opacity: 0.2,
},
}
};
const variantIcon: SystemStyleFunction = (props) => {
return {
......@@ -37,8 +37,8 @@ const variantIcon: SystemStyleFunction = (props) => {
_hover: {
color: mode('blue.400', 'blue.200')(props),
},
}
}
};
};
const variantIconBorder = {
color: 'blue.600',
......@@ -51,14 +51,14 @@ const variantIconBorder = {
_disabled: {
opacity: 0.2,
},
}
};
const variants = {
primary: variantPrimary,
secondary: variantSecondary,
icon: variantIcon,
iconBorder: variantIconBorder,
}
};
const Button: ComponentStyleConfig = {
baseStyle: {
......@@ -91,6 +91,6 @@ const Button: ComponentStyleConfig = {
px: 2,
},
},
}
};
export default Button;
......@@ -3,12 +3,12 @@ import type { SystemStyleObject } from '@chakra-ui/theme-tools';
const baseStyleLabel: SystemStyleObject = {
_disabled: { opacity: 0.2 },
}
};
const Checkbox: ComponentStyleConfig = {
baseStyle: {
label: baseStyleLabel,
},
}
};
export default Checkbox;
......@@ -3,12 +3,13 @@ import type { ComponentStyleConfig } from '@chakra-ui/theme';
import { getColor, mode } from '@chakra-ui/theme-tools';
import type { StyleFunctionProps, PartsStyleFunction } from '@chakra-ui/theme-tools';
import type { Dict } from '@chakra-ui/utils';
import getDefaultFormColors from '../utils/getDefaultFormColors';
const activeInputStyles = {
paddingTop: '30px',
paddingBottom: '10px',
}
};
const getActiveLabelStyles = (theme: Dict, fc: string) => ({
color: getColor(theme, fc),
......@@ -78,13 +79,13 @@ const variantFloating: PartsStyleFunction<typeof parts> = (props: StyleFunctionP
marginStart: 0,
color: mode('gray.500', 'whiteAlpha.400')(props),
},
}
}
};
};
const Form: ComponentStyleConfig = {
variants: {
floating: variantFloating,
},
}
};
export default Form;
......@@ -3,7 +3,7 @@ import type { ComponentStyleConfig } from '@chakra-ui/theme';
const baseStyle = {
fontWeight: '500',
letterSpacing: '-0.5px',
}
};
// WIP
// designer promised to sync theme and page mock-ups
......@@ -13,11 +13,11 @@ const sizes = {
fontSize: '32px',
lineHeight: '40px',
},
}
};
const Heading: ComponentStyleConfig = {
sizes,
baseStyle,
}
};
export default Heading;
import type { inputAnatomy as parts } from '@chakra-ui/anatomy';
import { Input as InputComponent } from '@chakra-ui/react';
import type { ComponentStyleConfig } from '@chakra-ui/theme';
import type { PartsStyleFunction, SystemStyleObject } from '@chakra-ui/theme-tools';
import { mode } from '@chakra-ui/theme-tools';
import getDefaultTransitionProps from '../utils/getDefaultTransitionProps';
import getOutlinedFieldStyles from '../utils/getOutlinedFieldStyles';
import { Input as InputComponent } from '@chakra-ui/react';
const sizes: Record<string, SystemStyleObject> = {
md: {
fontSize: 'md',
......@@ -24,7 +24,7 @@ const sizes: Record<string, SystemStyleObject> = {
h: '80px',
borderRadius: 'base',
},
}
};
const variantOutline: PartsStyleFunction<typeof parts> = (props) => {
const transitionProps = getDefaultTransitionProps();
......@@ -37,8 +37,8 @@ const variantOutline: PartsStyleFunction<typeof parts> = (props) => {
bg: mode('gray.100', 'whiteAlpha.200')(props),
...transitionProps,
},
}
}
};
};
const Input: ComponentStyleConfig = {
sizes: {
......@@ -57,11 +57,11 @@ const Input: ComponentStyleConfig = {
variants: {
outline: variantOutline,
},
}
};
InputComponent.defaultProps = {
...InputComponent.defaultProps,
placeholder: ' ',
}
};
export default Input;
import type { ComponentStyleConfig } from '@chakra-ui/theme';
import { mode } from '@chakra-ui/theme-tools';
import type { SystemStyleFunction, SystemStyleInterpolation } from '@chakra-ui/theme-tools';
import getDefaultTransitionProps from '../utils/getDefaultTransitionProps';
const baseStyle: SystemStyleInterpolation = {
...getDefaultTransitionProps(),
}
};
const variantPrimary: SystemStyleFunction = (props) => {
return {
......@@ -13,8 +14,8 @@ const variantPrimary: SystemStyleFunction = (props) => {
_hover: {
color: mode('blue.400', 'blue.200')(props),
},
}
}
};
};
const variantSecondary: SystemStyleFunction = (props) => {
return {
......@@ -22,22 +23,22 @@ const variantSecondary: SystemStyleFunction = (props) => {
_hover: {
color: mode('gray.600', 'gray.400')(props),
},
}
}
};
};
const variants = {
primary: variantPrimary,
secondary: variantSecondary,
}
};
const defaultProps = {
variant: 'primary',
}
};
const Link: ComponentStyleConfig = {
variants,
defaultProps,
baseStyle,
}
};
export default Link;
import { modalAnatomy as parts } from '@chakra-ui/anatomy'
import type { PartsStyleFunction, SystemStyleFunction } from '@chakra-ui/theme-tools'
import { mode } from '@chakra-ui/theme-tools'
import { modalAnatomy as parts } from '@chakra-ui/anatomy';
import type { ComponentMultiStyleConfig } from '@chakra-ui/theme';
import type { PartsStyleFunction, SystemStyleFunction } from '@chakra-ui/theme-tools';
import { mode } from '@chakra-ui/theme-tools';
const baseStyleDialog: SystemStyleFunction = (props) => {
return {
padding: 8,
borderRadius: 'lg',
bg: mode('white', 'gray.800')(props),
}
}
};
};
const baseStyleHeader = {
padding: 0,
marginBottom: 8,
fontSize: '2xl',
lineHeight: 10,
}
};
const baseStyleBody = {
padding: 0,
marginBottom: 8,
}
};
const baseStyleFooter = {
padding: 0,
justifyContent: 'flex-start',
}
};
const baseStyleCloseButton: SystemStyleFunction = (props) => {
return {
......@@ -37,11 +37,11 @@ const baseStyleCloseButton: SystemStyleFunction = (props) => {
color: mode('gray.700', 'gray.600')(props),
_hover: { color: 'blue.400' },
_active: { bg: 'none' },
}
}
};
};
const baseStyleOverlay = {
bg: 'blackAlpha.800',
}
};
const baseStyle: PartsStyleFunction<typeof parts> = (props) => ({
dialog: baseStyleDialog(props),
......@@ -50,7 +50,7 @@ const baseStyle: PartsStyleFunction<typeof parts> = (props) => ({
footer: baseStyleFooter,
closeButton: baseStyleCloseButton(props),
overlay: baseStyleOverlay,
})
});
const sizes = {
md: {
......@@ -58,13 +58,13 @@ const sizes = {
maxW: '760px',
},
},
}
};
const Modal: ComponentMultiStyleConfig = {
parts: parts.keys,
sizes,
baseStyle,
}
};
Modal.defaultProps = { isCentered: true };
......
......@@ -3,12 +3,12 @@ import type { SystemStyleObject } from '@chakra-ui/theme-tools';
const baseStyleLabel: SystemStyleObject = {
_disabled: { opacity: 0.2 },
}
};
const Radio: ComponentStyleConfig = {
baseStyle: {
label: baseStyleLabel,
},
}
};
export default Radio;
......@@ -2,6 +2,7 @@ import type { tableAnatomy as parts } from '@chakra-ui/anatomy';
import type { ComponentMultiStyleConfig } from '@chakra-ui/theme';
import { mode } from '@chakra-ui/theme-tools';
import type { PartsStyleFunction } from '@chakra-ui/theme-tools';
import getDefaultTransitionProps from '../utils/getDefaultTransitionProps';
const variantSimple: PartsStyleFunction<typeof parts> = (props) => {
......@@ -21,8 +22,8 @@ const variantSimple: PartsStyleFunction<typeof parts> = (props) => {
borderColor: mode('gray.200', 'whiteAlpha.200')(props),
...transitionProps,
},
}
}
};
};
const Table: ComponentMultiStyleConfig = {
parts: [ 'th', 'td', 'table', 'thead' ],
......@@ -65,6 +66,6 @@ const Table: ComponentMultiStyleConfig = {
variants: {
simple: variantSimple,
},
}
};
export default Table;
import type { tabsAnatomy as parts } from '@chakra-ui/anatomy';
import type { ComponentStyleConfig } from '@chakra-ui/theme';
import type {
PartsStyleFunction,
} from '@chakra-ui/theme-tools'
import { getColor } from '@chakra-ui/theme-tools'
import type { tabsAnatomy as parts } from '@chakra-ui/anatomy'
} from '@chakra-ui/theme-tools';
import { getColor } from '@chakra-ui/theme-tools';
const variantSoftRounded: PartsStyleFunction<typeof parts> = (props) => {
const { colorScheme: c, theme } = props
const { colorScheme: c, theme } = props;
return {
tab: {
borderRadius: '12px',
......@@ -21,13 +20,13 @@ const variantSoftRounded: PartsStyleFunction<typeof parts> = (props) => {
color: getColor(theme, `${ c }.400`),
},
},
}
}
};
};
const Tabs: ComponentStyleConfig = {
variants: {
'soft-rounded': variantSoftRounded,
},
}
};
export default Tabs;
......@@ -2,6 +2,7 @@ import type { tagAnatomy as parts } from '@chakra-ui/anatomy';
import type { ComponentStyleConfig } from '@chakra-ui/theme';
import { mode } from '@chakra-ui/theme-tools';
import type { PartsStyleFunction } from '@chakra-ui/theme-tools';
import getDefaultTransitionProps from '../utils/getDefaultTransitionProps';
const variantGray: PartsStyleFunction<typeof parts> = (props) => {
......@@ -13,12 +14,12 @@ const variantGray: PartsStyleFunction<typeof parts> = (props) => {
color: mode('gray.600', 'gray.50')(props),
...transitionProps,
},
}
}
};
};
const variants = {
gray: variantGray,
}
};
const Tag: ComponentStyleConfig = {
baseStyle: {
......@@ -30,6 +31,6 @@ const Tag: ComponentStyleConfig = {
},
},
variants,
}
};
export default Tag;
import type { SystemStyleFunction } from '@chakra-ui/theme-tools';
import type { ComponentStyleConfig } from '@chakra-ui/theme';
import type { SystemStyleFunction } from '@chakra-ui/theme-tools';
import { mode } from '@chakra-ui/theme-tools';
const variantSecondary: SystemStyleFunction = (props) => ({
......@@ -10,6 +10,6 @@ const Text: ComponentStyleConfig = {
variants: {
secondary: variantSecondary,
},
}
};
export default Text;
import { Textarea as TextareaComponent } from '@chakra-ui/react';
import type { ComponentStyleConfig } from '@chakra-ui/theme';
import type {
SystemStyleObject,
} from '@chakra-ui/theme-tools'
} from '@chakra-ui/theme-tools';
import type { ComponentStyleConfig } from '@chakra-ui/theme';
import getOutlinedFieldStyles from '../utils/getOutlinedFieldStyles';
import { Textarea as TextareaComponent } from '@chakra-ui/react';
const sizes: Record<string, SystemStyleObject> = {
lg: {
fontSize: 'md',
......@@ -16,7 +15,7 @@ const sizes: Record<string, SystemStyleObject> = {
h: '160px',
borderRadius: 'base',
},
}
};
const Textarea: ComponentStyleConfig = {
sizes,
......@@ -27,11 +26,11 @@ const Textarea: ComponentStyleConfig = {
size: 'md',
variant: 'outline',
},
}
};
TextareaComponent.defaultProps = {
...TextareaComponent.defaultProps,
placeholder: ' ',
}
};
export default Textarea;
import type { ComponentStyleConfig } from '@chakra-ui/theme';
import { Tooltip as TooltipComponent } from '@chakra-ui/react';
import type { ComponentStyleConfig } from '@chakra-ui/theme';
const Tooltip: ComponentStyleConfig = {
baseStyle: {
maxWidth: 'unset',
},
}
};
TooltipComponent.defaultProps = { ...TooltipComponent.defaultProps, hasArrow: true }
TooltipComponent.defaultProps = { ...TooltipComponent.defaultProps, hasArrow: true };
export default Tooltip;
......@@ -28,6 +28,6 @@ const components = {
Text,
Textarea,
Tooltip,
}
};
export default components;
......@@ -4,6 +4,6 @@ const config: ThemeConfig = {
initialColorMode: 'system',
useSystemColorMode: false,
disableTransitionOnChange: false,
}
};
export default config;
......@@ -7,6 +7,6 @@ const borders = {
lg: '24px',
full: '9999px',
},
}
};
export default borders;
......@@ -46,6 +46,6 @@ const colors = {
'800': 'RGBA(16, 17, 18, 0.80)',
'900': 'RGBA(16, 17, 18, 0.92)',
},
}
};
export default colors;
......@@ -21,6 +21,6 @@ const typography = {
fontFamily: 'heading',
},
},
}
};
export default typography;
import type { StyleFunctionProps } from '@chakra-ui/theme-tools';
import { mode } from '@chakra-ui/theme-tools';
import getDefaultTransitionProps from './utils/getDefaultTransitionProps';
const global = (props: StyleFunctionProps) => ({
......@@ -7,6 +8,6 @@ const global = (props: StyleFunctionProps) => ({
bg: mode('white', 'black')(props),
...getDefaultTransitionProps(),
},
})
});
export default global;
import { extendTheme } from '@chakra-ui/react';
import typography from './foundations/typography';
import borders from './foundations/borders';
import colors from './foundations/colors';
import components from './components/index';
import config from './config';
import borders from './foundations/borders';
import colors from './foundations/colors';
import typography from './foundations/typography';
import global from './global';
const overrides = {
......@@ -16,6 +16,6 @@ const overrides = {
styles: {
global,
},
}
};
export default extendTheme(overrides);
......@@ -2,10 +2,10 @@ import type { StyleFunctionProps } from '@chakra-ui/theme-tools';
import { mode } from '@chakra-ui/theme-tools';
export default function getDefaultFormColors(props: StyleFunctionProps) {
const { focusBorderColor: fc, errorBorderColor: ec, filledBorderColor: flc } = props
const { focusBorderColor: fc, errorBorderColor: ec, filledBorderColor: flc } = props;
return {
focusColor: fc || mode('brand.700', 'brand.300')(props),
errorColor: ec || mode('red.400', 'red.300')(props),
filledColor: flc || mode('gray.300', 'gray.600')(props),
}
};
}
......@@ -3,5 +3,5 @@ export default function getDefaultTransitionProps() {
transitionProperty: 'background-color, color, border-color',
transitionDuration: 'normal',
transitionTimingFunction: 'ease',
}
};
}
import type { StyleFunctionProps } from '@chakra-ui/theme-tools';
import { mode, getColor } from '@chakra-ui/theme-tools';
import getDefaultFormColors from './getDefaultFormColors';
import getDefaultTransitionProps from './getDefaultTransitionProps';
export default function getOutlinedFieldStyles(props: StyleFunctionProps) {
const { theme } = props
const { theme } = props;
const { focusColor: fc, errorColor: ec, filledColor: flc } = getDefaultFormColors(props);
const transitionProps = getDefaultTransitionProps();
......@@ -39,5 +40,5 @@ export default function getOutlinedFieldStyles(props: StyleFunctionProps) {
':-webkit-autofill': { transition: 'background-color 5000s ease-in-out 0s' },
':-webkit-autofill:hover': { transition: 'background-color 5000s ease-in-out 0s' },
':-webkit-autofill:focus': { transition: 'background-color 5000s ease-in-out 0s' },
}
};
}
......@@ -17,8 +17,8 @@
"baseUrl": ".",
"paths": {
"~/*": ["./*"]
}
},
},
"include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", "additional.d.ts", "decs.d.ts"],
"exclude": ["node_modules"]
"exclude": ["node_modules"],
}
import React, { useCallback, useEffect } from 'react';
import type { SubmitHandler, ControllerRenderProps } from 'react-hook-form';
import { useForm, Controller } from 'react-hook-form';
import {
Box,
Button,
......@@ -9,6 +5,9 @@ import {
FormLabel,
Input,
} from '@chakra-ui/react';
import React, { useCallback, useEffect } from 'react';
import type { SubmitHandler, ControllerRenderProps } from 'react-hook-form';
import { useForm, Controller } from 'react-hook-form';
import type { TApiKeyItem } from 'data/apiKey';
......@@ -44,7 +43,7 @@ const ApiKeyForm: React.FC<Props> = ({ data }) => {
/>
<FormLabel>Auto-generated API key token</FormLabel>
</FormControl>
)
);
}, []);
const renderNameInput = useCallback(({ field }: {field: ControllerRenderProps<Inputs, 'name'>}) => {
......@@ -57,7 +56,7 @@ const ApiKeyForm: React.FC<Props> = ({ data }) => {
/>
<FormLabel>Application name for API key (e.g Web3 project)</FormLabel>
</FormControl>
)
);
}, [ errors ]);
return (
......@@ -92,7 +91,7 @@ const ApiKeyForm: React.FC<Props> = ({ data }) => {
</Button>
</Box>
</>
)
}
);
};
export default ApiKeyForm;
import React, { useCallback } from 'react';
import type { TApiKeyItem } from 'data/apiKey';
import FormModal from 'ui/shared/FormModal';
import ApiKeyForm from './ApiKeyForm';
import FormModal from 'ui/shared/FormModal';
type Props = {
isOpen: boolean;
......@@ -13,10 +13,10 @@ type Props = {
const AddressModal: React.FC<Props> = ({ isOpen, onClose, data }) => {
const title = data ? 'Edit API key' : 'New API key';
const text = 'Add an application name to identify your API key. Click the button below to auto-generate the associated key.'
const text = 'Add an application name to identify your API key. Click the button below to auto-generate the associated key.';
const renderForm = useCallback(() => {
return <ApiKeyForm data={ data }/>
return <ApiKeyForm data={ data }/>;
}, [ data ]);
return (
<FormModal<TApiKeyItem>
......@@ -27,7 +27,7 @@ const AddressModal: React.FC<Props> = ({ isOpen, onClose, data }) => {
data={ data }
renderForm={ renderForm }
/>
)
}
);
};
export default AddressModal;
import React from 'react';
import {
Table,
Thead,
......@@ -7,7 +5,8 @@ import {
Tr,
Th,
TableContainer,
} from '@chakra-ui/react'
} from '@chakra-ui/react';
import React from 'react';
import type { TApiKey, TApiKeyItem } from 'data/apiKey';
......
import React, { useCallback } from 'react';
import {
Tr,
Td,
HStack,
Text,
} from '@chakra-ui/react'
import EditButton from 'ui/shared/EditButton';
import DeleteButton from 'ui/shared/DeleteButton';
} from '@chakra-ui/react';
import React, { useCallback } from 'react';
import type { TApiKeyItem } from 'data/apiKey';
import CopyToClipboard from 'ui/shared/CopyToClipboard';
import DeleteButton from 'ui/shared/DeleteButton';
import EditButton from 'ui/shared/EditButton';
interface Props {
item: TApiKeyItem;
......@@ -45,7 +43,7 @@ const WatchlistTableItem = ({ item, onEditClick, onDeleteClick }: Props) => {
</HStack>
</Td>
</Tr>
)
);
};
export default WatchlistTableItem;
import React, { useCallback } from 'react';
import { Text } from '@chakra-ui/react';
import DeleteModal from 'ui/shared/DeleteModal'
import React, { useCallback } from 'react';
import DeleteModal from 'ui/shared/DeleteModal';
type Props = {
isOpen: boolean;
......@@ -17,7 +18,7 @@ const DeleteAddressModal: React.FC<Props> = ({ isOpen, onClose, name }) => {
const renderText = useCallback(() => {
return (
<Text display="flex">API key for<Text fontWeight="600" whiteSpace="pre">{ ` "${ name || 'name' }" ` }</Text>will be deleted</Text>
)
);
}, [ name ]);
return (
<DeleteModal
......@@ -27,7 +28,7 @@ const DeleteAddressModal: React.FC<Props> = ({ isOpen, onClose, name }) => {
title="Remove API key"
renderContent={ renderText }
/>
)
}
);
};
export default DeleteAddressModal;
import type { UseCheckboxProps } from '@chakra-ui/checkbox';
import { useCheckbox } from '@chakra-ui/checkbox'
import { useCheckbox } from '@chakra-ui/checkbox';
import { SunIcon } from '@chakra-ui/icons';
import { useColorMode, useColorModeValue, Icon } from '@chakra-ui/react';
import type {
SystemStyleObject,
ThemingProps,
......@@ -9,14 +11,12 @@ import {
chakra,
forwardRef,
omitThemingProps,
} from '@chakra-ui/system'
import { dataAttr, __DEV__ } from '@chakra-ui/utils'
import * as React from 'react'
import { SunIcon } from '@chakra-ui/icons'
import { useColorMode, useColorModeValue, Icon } from '@chakra-ui/react';
import getDefaultTransitionProps from '../../theme/utils/getDefaultTransitionProps';
import moonIcon from '../../icons/moon.svg';
} from '@chakra-ui/system';
import { dataAttr, __DEV__ } from '@chakra-ui/utils';
import * as React from 'react';
import moonIcon from '../../icons/moon.svg';
import getDefaultTransitionProps from '../../theme/utils/getDefaultTransitionProps';
import styles from './ColorModeToggler.module.css';
export interface ColorModeTogglerProps
......@@ -36,22 +36,22 @@ export const ColorModeToggler = forwardRef<ColorModeTogglerProps, 'input'>((prop
getRootProps,
} = useCheckbox({ ...ownProps, isChecked: colorMode === 'light' });
const trackBg = useColorModeValue('blackAlpha.100', 'whiteAlpha.200')
const thumbBg = useColorModeValue('white', 'black')
const trackBg = useColorModeValue('blackAlpha.100', 'whiteAlpha.200');
const thumbBg = useColorModeValue('white', 'black');
const transitionProps = getDefaultTransitionProps();
const trackStyles: SystemStyleObject = React.useMemo(() => ({
bg: trackBg,
...transitionProps,
transitionDuration: '500ms',
}), [ trackBg, transitionProps ])
}), [ trackBg, transitionProps ]);
const thumbStyles: SystemStyleObject = React.useMemo(() => ({
bg: thumbBg,
...transitionProps,
transitionProperty: 'background-color, transform',
transitionDuration: '500ms',
}), [ thumbBg, transitionProps ])
}), [ thumbBg, transitionProps ]);
return (
<chakra.label
......@@ -85,9 +85,9 @@ export const ColorModeToggler = forwardRef<ColorModeTogglerProps, 'input'>((prop
/>
</chakra.div>
</chakra.label>
)
})
);
});
if (__DEV__) {
ColorModeToggler.displayName = 'ColorModeToggler'
ColorModeToggler.displayName = 'ColorModeToggler';
}
import React from 'react';
import { SearchIcon } from '@chakra-ui/icons';
import { HStack, InputGroup, Input, InputLeftAddon, InputLeftElement, Center, useColorModeValue } from '@chakra-ui/react';
import { SearchIcon } from '@chakra-ui/icons'
import React from 'react';
import Identicon from 'react-identicons';
import { ColorModeToggler } from './ColorModeToggler';
import { ColorModeToggler } from './ColorModeToggler';
import styles from './Header.module.css';
const Header = () => {
......@@ -30,7 +30,7 @@ const Header = () => {
<Identicon className={ styles.identicon } string="randomness" size={ 96 }/>
</Center>
</HStack>
)
}
);
};
export default Header;
import React from 'react';
import { Link, Icon, Text, HStack } from '@chakra-ui/react';
import NextLink from 'next/link';
import { useRouter } from 'next/router';
import React from 'react';
import useColors from './useColors';
interface Props {
......@@ -35,7 +36,7 @@ const AccountNavLink = ({ text, pathname, icon }: Props) => {
</HStack>
</Link>
</NextLink>
)
}
);
};
export default AccountNavLink;
import React from 'react';
import { Box, VStack } from '@chakra-ui/react';
import AccountNavLink from './AccountNavLink';
import WatchlistIcon from 'icons/watchlist.svg'
import PrivateTagIcon from 'icons/privattags.svg'
import PublicTagIcon from 'icons/publictags.svg'
import ApiKeysIcon from 'icons/API.svg';
import React from 'react';
import ABIIcon from 'icons/ABI.svg';
import ApiKeysIcon from 'icons/API.svg';
import PrivateTagIcon from 'icons/privattags.svg';
import PublicTagIcon from 'icons/publictags.svg';
import WatchlistIcon from 'icons/watchlist.svg';
import AccountNavLink from './AccountNavLink';
const navItems = [
{ text: 'Watchlist', pathname: '/watchlist', icon: WatchlistIcon },
......@@ -13,7 +15,7 @@ const navItems = [
{ text: 'Public tags', pathname: '/public-tags', icon: PublicTagIcon },
{ text: 'API keys', pathname: '/api-keys', icon: ApiKeysIcon },
{ text: 'Custom ABI', pathname: '/custom-abi', icon: ABIIcon },
]
];
const AccountNavigation = () => {
return (
......@@ -22,7 +24,7 @@ const AccountNavigation = () => {
{ navItems.map((item) => <AccountNavLink key={ item.text } { ...item }/>) }
</VStack>
</Box>
)
}
);
};
export default AccountNavigation;
import React from 'react';
import { ChevronRightIcon } from '@chakra-ui/icons';
import { Link, Icon, Text, HStack } from '@chakra-ui/react';
import NextLink from 'next/link';
import { useRouter } from 'next/router';
import { ChevronRightIcon } from '@chakra-ui/icons'
import React from 'react';
import useColors from './useColors';
interface Props {
......@@ -39,7 +40,7 @@ const MainNavLink = ({ text, pathname, icon }: Props) => {
</HStack>
</Link>
</NextLink>
)
}
);
};
export default MainNavLink;
import React from 'react';
import { Box, VStack } from '@chakra-ui/react';
import MainNavLink from './MainNavLink';
import BlocksIcon from 'icons/block.svg'
import TransactionsIcon from 'icons/transactions.svg'
import TokensIcon from 'icons/token.svg'
import React from 'react';
import AppsIcon from 'icons/apps.svg';
import BlocksIcon from 'icons/block.svg';
import BlockscoutIcon from 'icons/blockscout.svg';
import TokensIcon from 'icons/token.svg';
import TransactionsIcon from 'icons/transactions.svg';
import MainNavLink from './MainNavLink';
const navItems = [
{ text: 'Blocks', pathname: '/blocks', icon: BlocksIcon },
......@@ -13,7 +15,7 @@ const navItems = [
{ text: 'Tokens', pathname: '/tokens', icon: TokensIcon },
{ text: 'Apps', pathname: '/apps', icon: AppsIcon },
{ text: 'Blockscout', pathname: '/blockscout', icon: BlockscoutIcon },
]
];
const MainNavigation = () => {
return (
......@@ -22,7 +24,7 @@ const MainNavigation = () => {
{ navItems.map((item) => <MainNavLink key={ item.text } { ...item }/>) }
</VStack>
</Box>
)
}
);
};
export default MainNavigation;
import React from 'react';
import { VStack, Text, HStack, Icon, Link, useColorModeValue } from '@chakra-ui/react';
import React from 'react';
import getDefaultTransitionProps from 'theme/utils/getDefaultTransitionProps';
import ghIcon from 'icons/social/git.svg';
import twIcon from 'icons/social/tweet.svg';
import tgIcon from 'icons/social/telega.svg';
import statsIcon from 'icons/social/stats.svg';
import tgIcon from 'icons/social/telega.svg';
import twIcon from 'icons/social/tweet.svg';
import getDefaultTransitionProps from 'theme/utils/getDefaultTransitionProps';
const SOCIAL_LINKS = [
{ link: '#gh', icon: ghIcon },
{ link: '#tw', icon: twIcon },
{ link: '#tg', icon: tgIcon },
{ link: '#stats', icon: statsIcon },
]
];
const NavFooter = () => {
return (
......@@ -35,7 +34,7 @@ const NavFooter = () => {
<Link href={ sl.link } key={ sl.link } variant="secondary">
<Icon as={ sl.icon } boxSize={ 5 }/>
</Link>
)
);
}) }
</HStack>
<Text>
......@@ -43,7 +42,7 @@ const NavFooter = () => {
</Text>
<Text>Version: <Link color="blue.500">v4.2.1-beta</Link></Text>
</VStack>
)
}
);
};
export default NavFooter;
import React from 'react';
import { VStack, HStack, Icon, useColorModeValue } from '@chakra-ui/react';
import AccountNavigation from './AccountNavigation';
import MainNavigation from './MainNavigation';
import NavFooter from './NavFooter'
import React from 'react';
import logoIcon from 'icons/logo.svg';
import networksIcon from 'icons/networks.svg';
import getDefaultTransitionProps from '../../theme/utils/getDefaultTransitionProps';
import AccountNavigation from './AccountNavigation';
import MainNavigation from './MainNavigation';
import NavFooter from './NavFooter';
const Navigation = () => {
return (
......@@ -42,7 +41,7 @@ const Navigation = () => {
<AccountNavigation/>
<NavFooter/>
</VStack>
)
}
);
};
export default Navigation;
......@@ -11,5 +11,5 @@ export default function useColors() {
'default': 'transparent',
active: useColorModeValue('blue.50', 'whiteAlpha.200'),
},
}
};
}
import React, { useCallback, useState } from 'react';
import { Box, Button, HStack, Link, Text, useDisclosure } from '@chakra-ui/react';
import Page from 'ui/shared/Page/Page';
import AccountPageHeader from 'ui/shared/AccountPageHeader';
import ApiKeyTable from 'ui/apiKey/ApiKeyTable/ApiKeyTable';
import ApiKeyModal from 'ui/apiKey/ApiKeyModal/ApiKeyModal';
import DeleteApiKeyModal from 'ui/apiKey/DeleteApiKeyModal';
import React, { useCallback, useState } from 'react';
import type { TApiKeyItem } from 'data/apiKey';
import { apiKey } from 'data/apiKey';
import { space } from 'lib/html-entities';
import ApiKeyModal from 'ui/apiKey/ApiKeyModal/ApiKeyModal';
import ApiKeyTable from 'ui/apiKey/ApiKeyTable/ApiKeyTable';
import DeleteApiKeyModal from 'ui/apiKey/DeleteApiKeyModal';
import AccountPageHeader from 'ui/shared/AccountPageHeader';
import Page from 'ui/shared/Page/Page';
const DATA_LIMIT = 3;
......@@ -25,7 +22,7 @@ const ApiKeys: React.FC = () => {
const onEditClick = useCallback((data: TApiKeyItem) => {
setApiKeyModalData(data);
apiKeyModalProps.onOpen();
}, [ apiKeyModalProps ])
}, [ apiKeyModalProps ]);
const onApiKeyModalClose = useCallback(() => {
setApiKeyModalData(undefined);
......@@ -35,14 +32,14 @@ const ApiKeys: React.FC = () => {
const onDeleteClick = useCallback((data: TApiKeyItem) => {
setDeleteModalData(data.name);
deleteModalProps.onOpen();
}, [ deleteModalProps ])
}, [ deleteModalProps ]);
const onDeleteModalClose = useCallback(() => {
setDeleteModalData(undefined);
deleteModalProps.onClose();
}, [ deleteModalProps ]);
const canAdd = apiKey.length < DATA_LIMIT
const canAdd = apiKey.length < DATA_LIMIT;
return (
<Page>
......@@ -82,4 +79,4 @@ const ApiKeys: React.FC = () => {
);
};
export default ApiKeys
export default ApiKeys;
import React, { useCallback } from 'react';
import { useQueryClient } from '@tanstack/react-query'
import type { AddressTags, TransactionTags } from 'types/api/account';
import {
Box,
Tab,
......@@ -11,11 +6,15 @@ import {
TabPanel,
TabPanels,
} from '@chakra-ui/react';
import { useQueryClient } from '@tanstack/react-query';
import React, { useCallback } from 'react';
import type { AddressTags, TransactionTags } from 'types/api/account';
import Page from 'ui/shared/Page/Page';
import AccountPageHeader from 'ui/shared/AccountPageHeader';
import PrivateAddressTags from 'ui/privateTags/PrivateAddressTags';
import PrivateTransactionTags from 'ui/privateTags/PrivateTransactionTags';
import AccountPageHeader from 'ui/shared/AccountPageHeader';
import Page from 'ui/shared/Page/Page';
type Props = {
onChangeTab: (index: number) => void;
......@@ -28,7 +27,7 @@ const PrivateTags = ({ onChangeTab: onChangeTabProps }: Props) => {
const onTabChange = useCallback((index: number) => {
onChangeTabProps(index);
}, [ onChangeTabProps ])
}, [ onChangeTabProps ]);
return (
<Page>
......@@ -53,4 +52,4 @@ const PrivateTags = ({ onChangeTab: onChangeTabProps }: Props) => {
);
};
export default PrivateTags
export default PrivateTags;
import React, { useCallback, useState } from 'react';
import { animateScroll } from 'react-scroll';
import {
Box,
useToast,
} from '@chakra-ui/react';
import React, { useCallback, useState } from 'react';
import { animateScroll } from 'react-scroll';
import Page from 'ui/shared/Page/Page';
import AccountPageHeader from 'ui/shared/AccountPageHeader';
import type { TPublicTagItem } from 'data/publicTags';
import PublicTagsData from 'ui/publicTags/PublicTagsData';
import PublicTagsForm from 'ui/publicTags/PublicTagsForm/PublicTagsForm';
import AccountPageHeader from 'ui/shared/AccountPageHeader';
import Page from 'ui/shared/Page/Page';
type TScreen = 'data' | 'form';
......@@ -22,9 +22,9 @@ const toastDescriptions = {
const PublicTags: React.FC = () => {
const [ screen, setScreen ] = useState<TScreen>('data');
const [ formData, setFormData ] = useState();
const [ formData, setFormData ] = useState<TPublicTagItem>();
const toast = useToast()
const toast = useToast();
const showToast = useCallback((action: TToastAction) => {
toast({
......@@ -39,7 +39,7 @@ const PublicTags: React.FC = () => {
});
}, [ toast ]);
const changeToFormScreen = useCallback((data: any) => {
const changeToFormScreen = useCallback((data?: TPublicTagItem) => {
setFormData(data);
setScreen('form');
animateScroll.scrollToTop({
......@@ -65,10 +65,10 @@ const PublicTags: React.FC = () => {
let header;
if (screen === 'data') {
content = <PublicTagsData changeToFormScreen={ changeToFormScreen } onTagDelete={ onTagDelete }/>
header = 'Public tags'
content = <PublicTagsData changeToFormScreen={ changeToFormScreen } onTagDelete={ onTagDelete }/>;
header = 'Public tags';
} else {
content = <PublicTagsForm changeToDataScreen={ changeToDataScreen } data={ formData }/>
content = <PublicTagsForm changeToDataScreen={ changeToDataScreen } data={ formData }/>;
header = formData ? 'Request to edit a public tag/label' : 'Request a public tag/label';
}
......
import React, { useCallback, useState } from 'react';
import { Box, Button, Text, useDisclosure } from '@chakra-ui/react';
import Page from 'ui/shared/Page/Page';
import AccountPageHeader from 'ui/shared/AccountPageHeader';
import WatchlistTable from 'ui/watchlist/WatchlistTable/WatchlistTable';
import AddressModal from 'ui/watchlist/AddressModal/AddressModal';
import React, { useCallback, useState } from 'react';
import type { TWatchlistItem } from 'data/watchlist';
import { watchlist } from 'data/watchlist';
import AccountPageHeader from 'ui/shared/AccountPageHeader';
import Page from 'ui/shared/Page/Page';
import AddressModal from 'ui/watchlist/AddressModal/AddressModal';
import DeleteAddressModal from 'ui/watchlist/DeleteAddressModal';
import WatchlistTable from 'ui/watchlist/WatchlistTable/WatchlistTable';
const WatchList: React.FC = () => {
const addressModalProps = useDisclosure();
......@@ -21,7 +19,7 @@ const WatchList: React.FC = () => {
const onEditClick = useCallback((data: TWatchlistItem) => {
setAddressModalData(data);
addressModalProps.onOpen();
}, [ addressModalProps ])
}, [ addressModalProps ]);
const onAddressModalClose = useCallback(() => {
setAddressModalData(undefined);
......@@ -31,7 +29,7 @@ const WatchList: React.FC = () => {
const onDeleteClick = useCallback((data: TWatchlistItem) => {
setDeleteModalData(data.address);
deleteModalProps.onOpen();
}, [ deleteModalProps ])
}, [ deleteModalProps ]);
const onDeleteModalClose = useCallback(() => {
setDeleteModalData(undefined);
......@@ -66,4 +64,4 @@ const WatchList: React.FC = () => {
);
};
export default WatchList
export default WatchList;
import React, { useCallback, useEffect, useState } from 'react';
import type { SubmitHandler, ControllerRenderProps } from 'react-hook-form';
import { useForm, Controller } from 'react-hook-form';
import { useMutation, useQueryClient } from '@tanstack/react-query';
import {
Box,
Button,
} from '@chakra-ui/react';
import { useMutation, useQueryClient } from '@tanstack/react-query';
import React, { useCallback, useEffect, useState } from 'react';
import type { SubmitHandler, ControllerRenderProps } from 'react-hook-form';
import { useForm, Controller } from 'react-hook-form';
import type { AddressTag } from 'types/api/account';
import AddressInput from 'ui/shared/AddressInput';
import TagInput from 'ui/shared/TagInput';
import type { AddressTag } from 'types/api/account';
const ADDRESS_LENGTH = 42;
const TAG_MAX_LENGTH = 35;
......@@ -42,14 +41,14 @@ const AddressForm: React.FC<Props> = ({ data, onClose }) => {
const requestParams = {
name: formData?.tag,
address_hash: formData?.address,
}
};
if (data) {
// edit tag
const params = new URLSearchParams(requestParams);
mutationFunction = () => fetch(`/api/account/private-tags/address/${ data.id }?${ params.toString() }`, { method: 'PUT' })
mutationFunction = () => fetch(`/api/account/private-tags/address/${ data.id }?${ params.toString() }`, { method: 'PUT' });
} else {
// add tag
mutationFunction = () => fetch('/api/account/private-tags/address', { method: 'POST', body: JSON.stringify(requestParams) })
mutationFunction = () => fetch('/api/account/private-tags/address', { method: 'POST', body: JSON.stringify(requestParams) });
}
return mutationFunction();
}, {
......@@ -71,11 +70,11 @@ const AddressForm: React.FC<Props> = ({ data, onClose }) => {
};
const renderAddressInput = useCallback(({ field }: {field: ControllerRenderProps<Inputs, 'address'>}) => {
return <AddressInput<Inputs, 'address'> field={ field } isInvalid={ Boolean(errors.address) }/>
return <AddressInput<Inputs, 'address'> field={ field } isInvalid={ Boolean(errors.address) }/>;
}, [ errors ]);
const renderTagInput = useCallback(({ field }: {field: ControllerRenderProps<Inputs, 'tag'>}) => {
return <TagInput field={ field } isInvalid={ Boolean(errors.tag) }/>
return <TagInput field={ field } isInvalid={ Boolean(errors.tag) }/>;
}, [ errors ]);
return (
......@@ -113,7 +112,7 @@ const AddressForm: React.FC<Props> = ({ data, onClose }) => {
</Button>
</Box>
</>
)
}
);
};
export default AddressForm;
......@@ -2,9 +2,10 @@ import React, { useCallback } from 'react';
import type { AddressTag } from 'types/api/account';
import AddressForm from './AddressForm';
import FormModal from 'ui/shared/FormModal';
import AddressForm from './AddressForm';
type Props = {
isOpen: boolean;
onClose: () => void;
......@@ -13,10 +14,10 @@ type Props = {
const AddressModal: React.FC<Props> = ({ isOpen, onClose, data }) => {
const title = data ? 'Edit address tag' : 'New address tag';
const text = 'Label any address with a private address tag (up to 35 chars) to customize your explorer experience.'
const text = 'Label any address with a private address tag (up to 35 chars) to customize your explorer experience.';
const renderForm = useCallback(() => {
return <AddressForm data={ data } onClose={ onClose }/>
return <AddressForm data={ data } onClose={ onClose }/>;
}, [ data, onClose ]);
return (
<FormModal<AddressTag>
......@@ -27,7 +28,7 @@ const AddressModal: React.FC<Props> = ({ isOpen, onClose, data }) => {
data={ data }
renderForm={ renderForm }
/>
)
}
);
};
export default AddressModal;
import React from 'react';
import {
Table,
Thead,
......@@ -7,7 +5,8 @@ import {
Tr,
Th,
TableContainer,
} from '@chakra-ui/react'
} from '@chakra-ui/react';
import React from 'react';
import type { AddressTags, AddressTag } from 'types/api/account';
......
import React, { useCallback } from 'react';
import {
Tag,
Tr,
Td,
HStack,
} from '@chakra-ui/react'
} from '@chakra-ui/react';
import React, { useCallback } from 'react';
import type { AddressTag } from 'types/api/account';
import AddressIcon from 'ui/shared/AddressIcon';
import AddressLinkWithTooltip from 'ui/shared/AddressLinkWithTooltip';
import type { AddressTag } from 'types/api/account';
import EditButton from 'ui/shared/EditButton';
import DeleteButton from 'ui/shared/DeleteButton';
import EditButton from 'ui/shared/EditButton';
import TruncatedTextTooltip from 'ui/shared/TruncatedTextTooltip';
interface Props {
......@@ -52,7 +51,7 @@ const AddressTagTableItem = ({ item, onEditClick, onDeleteClick }: Props) => {
</HStack>
</Td>
</Tr>
)
);
};
export default AddressTagTableItem;
import React, { useCallback, useState } from 'react';
import { Text } from '@chakra-ui/react';
import DeleteModal from 'ui/shared/DeleteModal'
import { useMutation, useQueryClient } from '@tanstack/react-query';
import React, { useCallback, useState } from 'react';
import type { AddressTag, TransactionTag } from 'types/api/account';
import DeleteModal from 'ui/shared/DeleteModal';
type Props = {
isOpen: boolean;
onClose: () => void;
......@@ -22,7 +22,7 @@ const DeletePrivateTagModal: React.FC<Props> = ({ isOpen, onClose, data, type })
const queryClient = useQueryClient();
const { mutate } = useMutation(() => {
return fetch(`/api/account/private-tags/${ type }/${ id }`, { method: 'DELETE' })
return fetch(`/api/account/private-tags/${ type }/${ id }`, { method: 'DELETE' });
}, {
onError: () => {
// eslint-disable-next-line no-console
......@@ -38,13 +38,13 @@ const DeletePrivateTagModal: React.FC<Props> = ({ isOpen, onClose, data, type })
const onDelete = useCallback(() => {
setPending(true);
mutate()
mutate();
}, [ mutate ]);
const renderText = useCallback(() => {
return (
<Text display="flex">Tag<Text fontWeight="600" whiteSpace="pre">{ ` "${ tag || 'tag' }" ` }</Text>will be deleted</Text>
)
);
}, [ tag ]);
return (
......@@ -56,7 +56,7 @@ const DeletePrivateTagModal: React.FC<Props> = ({ isOpen, onClose, data, type })
renderContent={ renderText }
pending={ pending }
/>
)
}
);
};
export default DeletePrivateTagModal;
import { Box, Button, Spinner, Text, useDisclosure } from '@chakra-ui/react';
import React, { useCallback, useState } from 'react';
import { Box, Button, Spinner, Text, useDisclosure } from '@chakra-ui/react';
import type { AddressTags, AddressTag } from 'types/api/account';
import AddressTagTable from './AddressTagTable/AddressTagTable';
import AddressModal from './AddressModal/AddressModal';
import AddressTagTable from './AddressTagTable/AddressTagTable';
import DeletePrivateTagModal from './DeletePrivateTagModal';
import type { AddressTags, AddressTag } from 'types/api/account';
type Props = {
addressTags: AddressTags;
......@@ -21,7 +21,7 @@ const PrivateAddressTags = ({ addressTags }: Props) => {
const onEditClick = useCallback((data: AddressTag) => {
setAddressModalData(data);
addressModalProps.onOpen();
}, [ addressModalProps ])
}, [ addressModalProps ]);
const onAddressModalClose = useCallback(() => {
setAddressModalData(undefined);
......@@ -31,7 +31,7 @@ const PrivateAddressTags = ({ addressTags }: Props) => {
const onDeleteClick = useCallback((data: AddressTag) => {
setDeleteModalData(data);
deleteModalProps.onOpen();
}, [ deleteModalProps ])
}, [ deleteModalProps ]);
const onDeleteModalClose = useCallback(() => {
setDeleteModalData(undefined);
......@@ -72,4 +72,4 @@ const PrivateAddressTags = ({ addressTags }: Props) => {
);
};
export default PrivateAddressTags
export default PrivateAddressTags;
import React, { useCallback, useState } from 'react';
import { Box, Button, Text, useDisclosure } from '@chakra-ui/react';
import React, { useCallback, useState } from 'react';
import type { TransactionTags, TransactionTag } from 'types/api/account';
import TransactionTagTable from './TransactionTagTable/TransactionTagTable';
import TransactionModal from './TransactionModal/TransactionModal';
import DeletePrivateTagModal from './DeletePrivateTagModal';
import TransactionModal from './TransactionModal/TransactionModal';
import TransactionTagTable from './TransactionTagTable/TransactionTagTable';
type Props = {
transactionTags: TransactionTags;
......@@ -23,7 +21,7 @@ const PrivateTransactionTags = ({ transactionTags }: Props) => {
const onEditClick = useCallback((data: TransactionTag) => {
setTransactionModalData(data);
transactionModalProps.onOpen();
}, [ transactionModalProps ])
}, [ transactionModalProps ]);
const onAddressModalClose = useCallback(() => {
setTransactionModalData(undefined);
......@@ -33,7 +31,7 @@ const PrivateTransactionTags = ({ transactionTags }: Props) => {
const onDeleteClick = useCallback((data: TransactionTag) => {
setDeleteModalData(data);
deleteModalProps.onOpen();
}, [ deleteModalProps ])
}, [ deleteModalProps ]);
const onDeleteModalClose = useCallback(() => {
setDeleteModalData(undefined);
......@@ -73,4 +71,4 @@ const PrivateTransactionTags = ({ transactionTags }: Props) => {
);
};
export default PrivateTransactionTags
export default PrivateTransactionTags;
import {
Box,
Button,
} from '@chakra-ui/react';
import { useMutation, useQueryClient } from '@tanstack/react-query';
import React, { useCallback, useEffect, useState } from 'react';
import type { SubmitHandler, ControllerRenderProps } from 'react-hook-form';
import { useForm, Controller } from 'react-hook-form';
import type { TransactionTag } from 'types/api/account';
import { useMutation, useQueryClient } from '@tanstack/react-query';
import {
Box,
Button,
} from '@chakra-ui/react';
import TransactionInput from 'ui/shared/TransactionInput';
import TagInput from 'ui/shared/TagInput';
import TransactionInput from 'ui/shared/TransactionInput';
const HASH_LENGTH = 66;
const TAG_MAX_LENGTH = 35;
......@@ -43,14 +41,14 @@ const TransactionForm: React.FC<Props> = ({ data, onClose }) => {
const requestParams = {
name: formData?.tag,
transaction_hash: formData?.transaction,
}
};
if (data) {
// edit tag
const params = new URLSearchParams(requestParams);
mutationFunction = () => fetch(`/api/account/private-tags/transaction/${ data.id }?${ params.toString() }`, { method: 'PUT' })
mutationFunction = () => fetch(`/api/account/private-tags/transaction/${ data.id }?${ params.toString() }`, { method: 'PUT' });
} else {
// add tag
mutationFunction = () => fetch('/api/account/private-tags/transaction', { method: 'POST', body: JSON.stringify(requestParams) })
mutationFunction = () => fetch('/api/account/private-tags/transaction', { method: 'POST', body: JSON.stringify(requestParams) });
}
return mutationFunction();
}, {
......@@ -69,15 +67,15 @@ const TransactionForm: React.FC<Props> = ({ data, onClose }) => {
const onSubmit: SubmitHandler<Inputs> = formData => {
setPending(true);
// api method for editing is not implemented now!!!
mutate(formData)
}
mutate(formData);
};
const renderTransactionInput = useCallback(({ field }: {field: ControllerRenderProps<Inputs, 'transaction'>}) => {
return <TransactionInput field={ field } isInvalid={ Boolean(errors.transaction) }/>
return <TransactionInput field={ field } isInvalid={ Boolean(errors.transaction) }/>;
}, [ errors ]);
const renderTagInput = useCallback(({ field }: {field: ControllerRenderProps<Inputs, 'tag'>}) => {
return <TagInput field={ field } isInvalid={ Boolean(errors.tag) }/>
return <TagInput field={ field } isInvalid={ Boolean(errors.tag) }/>;
}, [ errors ]);
return (
......@@ -115,7 +113,7 @@ const TransactionForm: React.FC<Props> = ({ data, onClose }) => {
</Button>
</Box>
</>
)
}
);
};
export default TransactionForm;
......@@ -2,9 +2,10 @@ import React, { useCallback } from 'react';
import type { TransactionTag } from 'types/api/account';
import TransactionForm from './TransactionForm';
import FormModal from 'ui/shared/FormModal';
import TransactionForm from './TransactionForm';
type Props = {
isOpen: boolean;
onClose: () => void;
......@@ -13,10 +14,10 @@ type Props = {
const AddressModal: React.FC<Props> = ({ isOpen, onClose, data }) => {
const title = data ? 'Edit transaction tag' : 'New transaction tag';
const text = 'Label any transaction with a private transaction tag (up to 35 chars) to customize your explorer experience.'
const text = 'Label any transaction with a private transaction tag (up to 35 chars) to customize your explorer experience.';
const renderForm = useCallback(() => {
return <TransactionForm data={ data } onClose={ onClose }/>
return <TransactionForm data={ data } onClose={ onClose }/>;
}, [ data, onClose ]);
return (
<FormModal<TransactionTag>
......@@ -27,7 +28,7 @@ const AddressModal: React.FC<Props> = ({ isOpen, onClose, data }) => {
data={ data }
renderForm={ renderForm }
/>
)
}
);
};
export default AddressModal;
import React from 'react';
import type { TransactionTags, TransactionTag } from 'types/api/account';
import {
Table,
Thead,
......@@ -9,7 +5,10 @@ import {
Tr,
Th,
TableContainer,
} from '@chakra-ui/react'
} from '@chakra-ui/react';
import React from 'react';
import type { TransactionTags, TransactionTag } from 'types/api/account';
import TransactionTagTableItem from './TransactionTagTableItem';
......
import React, { useCallback } from 'react';
import {
Tag,
Tr,
Td,
HStack,
Tooltip,
} from '@chakra-ui/react'
} from '@chakra-ui/react';
import React, { useCallback } from 'react';
import EditButton from 'ui/shared/EditButton';
import DeleteButton from 'ui/shared/DeleteButton';
import type { TransactionTag } from 'types/api/account';
import AddressLinkWithTooltip from 'ui/shared/AddressLinkWithTooltip';
import type { TransactionTag } from 'types/api/account';
import DeleteButton from 'ui/shared/DeleteButton';
import EditButton from 'ui/shared/EditButton';
interface Props {
item: TransactionTag;
......@@ -49,7 +47,7 @@ const AddressTagTableItem = ({ item, onEditClick, onDeleteClick }: Props) => {
</HStack>
</Td>
</Tr>
)
);
};
export default AddressTagTableItem;
import { Flex, Text, FormControl, FormLabel, Textarea } from '@chakra-ui/react';
import React, { useCallback, useState } from 'react';
import type { ChangeEvent } from 'react';
import { Flex, Text, FormControl, FormLabel, Textarea } from '@chakra-ui/react';
import DeleteModal from 'ui/shared/DeleteModal';
import type { TPublicTag } from 'data/publicTags';
import DeleteModal from 'ui/shared/DeleteModal';
type Props = {
isOpen: boolean;
......@@ -35,7 +34,7 @@ const DeletePublicTagModal: React.FC<Props> = ({ isOpen, onClose, tags = [], onD
<Text fontWeight="600" whiteSpace="pre">{ ` "${ tags[0].name }" ` }</Text>
<Text>will be removed.</Text>
</>
)
);
}
if (tags.length > 1) {
const tagsText: Array<JSX.Element | string> = [];
......@@ -51,12 +50,12 @@ const DeletePublicTagModal: React.FC<Props> = ({ isOpen, onClose, tags = [], onD
if (index === tags.length - 1) {
tagsText.push(<Text fontWeight="600" whiteSpace="pre">{ ` "${ tag.name }" ` }</Text>);
}
})
});
text = (
<>
<Text>Public tags</Text>{ tagsText }<Text>will be removed.</Text>
</>
)
);
}
return (
<>
......@@ -72,7 +71,7 @@ const DeletePublicTagModal: React.FC<Props> = ({ isOpen, onClose, tags = [], onD
<FormLabel>Why do you want to remove tags?</FormLabel>
</FormControl>
</>
)
);
}, [ tags, reason, onFieldChange ]);
return (
......@@ -83,7 +82,7 @@ const DeletePublicTagModal: React.FC<Props> = ({ isOpen, onClose, tags = [], onD
title="Request to remove a public tag"
renderContent={ renderContent }
/>
)
}
);
};
export default DeletePublicTagModal;
import React from 'react';
import {
Table,
Thead,
......@@ -7,7 +5,8 @@ import {
Tr,
Th,
TableContainer,
} from '@chakra-ui/react'
} from '@chakra-ui/react';
import React from 'react';
import type { TPublicTagItem, TPublicTags } from 'data/publicTags';
......
import React, { useCallback } from 'react';
import {
Box,
Tag,
......@@ -9,15 +7,15 @@ import {
HStack,
VStack,
useColorModeValue,
} from '@chakra-ui/react'
} from '@chakra-ui/react';
import React, { useCallback } from 'react';
import type { TPublicTagItem, TPublicTagAddress, TPublicTag } from 'data/publicTags';
import AddressIcon from 'ui/shared/AddressIcon';
import AddressLinkWithTooltip from 'ui/shared/AddressLinkWithTooltip';
import TruncatedTextTooltip from 'ui/shared/TruncatedTextTooltip';
import type { TPublicTagItem, TPublicTagAddress, TPublicTag } from 'data/publicTags';
import EditButton from 'ui/shared/EditButton';
import DeleteButton from 'ui/shared/DeleteButton';
import EditButton from 'ui/shared/EditButton';
import TruncatedTextTooltip from 'ui/shared/TruncatedTextTooltip';
interface Props {
item: TPublicTagItem;
......@@ -49,7 +47,7 @@ const PublicTagTableItem = ({ item, onEditClick, onDeleteClick }: Props) => {
{ adr.addressName && <Text fontSize="sm" color={ secondaryColor } mt={ 0.5 }>{ adr.addressName }</Text> }
</Box>
</HStack>
)
);
}) }
</VStack>
</Td>
......@@ -62,7 +60,7 @@ const PublicTagTableItem = ({ item, onEditClick, onDeleteClick }: Props) => {
{ tag.name }
</Tag>
</TruncatedTextTooltip>
)
);
}) }
</VStack>
</Td>
......@@ -76,7 +74,7 @@ const PublicTagTableItem = ({ item, onEditClick, onDeleteClick }: Props) => {
</HStack>
</Td>
</Tr>
)
);
};
export default PublicTagTableItem;
......@@ -3,11 +3,12 @@ import React, { useCallback, useState } from 'react';
import type { TPublicTagItem, TPublicTag } from 'data/publicTags';
import { publicTags } from 'data/publicTags';
import DeletePublicTagModal from './DeletePublicTagModal';
import PublicTagTable from './PublicTagTable/PublicTagTable';
import DeletePublicTagModal from './DeletePublicTagModal'
type Props = {
changeToFormScreen: (data?: any) => void;
changeToFormScreen: (data?: TPublicTagItem) => void;
onTagDelete: () => void;
}
......@@ -26,7 +27,7 @@ const PublicTagsData = ({ changeToFormScreen, onTagDelete }: Props) => {
const onItemEditClick = useCallback((item: TPublicTagItem) => {
changeToFormScreen(item);
}, [ changeToFormScreen ])
}, [ changeToFormScreen ]);
const onItemDeleteClick = useCallback((item: TPublicTagItem) => {
setDeleteModalData(item.tags);
......@@ -58,7 +59,7 @@ const PublicTagsData = ({ changeToFormScreen, onTagDelete }: Props) => {
onDeleteSuccess={ onTagDelete }
/>
</>
)
}
);
};
export default PublicTagsData;
import { RadioGroup, Radio, Stack } from '@chakra-ui/react';
import React, { useCallback } from 'react';
import type { ControllerRenderProps, Control } from 'react-hook-form';
import { RadioGroup, Radio, Stack } from '@chakra-ui/react';
import { Controller } from 'react-hook-form';
import type { Inputs } from './PublicTagsForm';
interface Props {
......@@ -22,8 +23,8 @@ export default function PublicTagFormAction({ control, canReport }: Props) {
</Radio>
</Stack>
</RadioGroup>
)
}, [ canReport ])
);
}, [ canReport ]);
return (
<Controller
......@@ -31,5 +32,5 @@ export default function PublicTagFormAction({ control, canReport }: Props) {
control={ control }
render={ renderRadioGroup }
/>
)
);
}
import { IconButton, Icon } from '@chakra-ui/react';
import React, { useCallback } from 'react';
import type { ControllerRenderProps, Control } from 'react-hook-form';
import { IconButton, Icon } from '@chakra-ui/react';
import { Controller } from 'react-hook-form';
import type { Inputs } from './PublicTagsForm';
import AddressInput from 'ui/shared/AddressInput';
import PlusIcon from 'icons/plus.svg';
import MinusIcon from 'icons/minus.svg';
import PlusIcon from 'icons/plus.svg';
import AddressInput from 'ui/shared/AddressInput';
import type { Inputs } from './PublicTagsForm';
interface Props {
control: Control<Inputs>;
......@@ -28,7 +29,7 @@ export default function PublicTagFormAction({ control, index, fieldsLength, hasE
size="lg"
placeholder="Smart contract / Address (0x...)"
/>
)
);
}, [ hasError ]);
return (
......@@ -64,5 +65,5 @@ export default function PublicTagFormAction({ control, index, fieldsLength, hasE
top="25px"
/>
) }</>
)
);
}
import { FormControl, FormLabel, Textarea } from '@chakra-ui/react';
import React, { useCallback } from 'react';
import type { ControllerRenderProps, Control } from 'react-hook-form';
import { FormControl, FormLabel, Textarea } from '@chakra-ui/react';
import { Controller } from 'react-hook-form';
import type { Inputs } from './PublicTagsForm';
interface Props {
......@@ -18,8 +19,8 @@ export default function PublicTagFormComment({ control }: Props) {
/>
<FormLabel>Specify the reason for adding tags and color preference(s).</FormLabel>
</FormControl>
)
}, [])
);
}, []);
return (
<Controller
......@@ -27,5 +28,5 @@ export default function PublicTagFormComment({ control }: Props) {
control={ control }
render={ renderComment }
/>
)
);
}
......@@ -7,16 +7,15 @@ import {
HStack,
} from '@chakra-ui/react';
import React, { useCallback } from 'react';
import type { TPublicTagItem, TPublicTag, TPublicTagAddress } from 'data/publicTags';
import type { Path } from 'react-hook-form';
import { useForm, useFieldArray } from 'react-hook-form';
import type { TPublicTagItem, TPublicTag, TPublicTagAddress } from 'data/publicTags';
import PublicTagFormAction from './PublicTagFormAction';
import PublicTagFormAddressInput from './PublicTagFormAddressInput';
import PublicTagFormComment from './PublicTagFormComment';
import PublicTagsFormInput from './PublicTagsFormInput';
import PublicTagFormAddressInput from './PublicTagFormAddressInput';
type Props = {
changeToDataScreen: (success?: boolean) => void;
......@@ -110,7 +109,7 @@ const PublicTagsForm = ({ changeToDataScreen, data }: Props) => {
onRemoveFieldClick={ onRemoveFieldClick }
/>
</Box>
)
);
}) }
<Box marginBottom={ 8 }>
<PublicTagFormComment control={ control }/>
......@@ -133,7 +132,7 @@ const PublicTagsForm = ({ changeToDataScreen, data }: Props) => {
</Button>
</HStack>
</Box>
)
}
);
};
export default PublicTagsForm;
import { FormControl, FormLabel, Input } from '@chakra-ui/react';
import React, { useCallback } from 'react';
import type { ControllerRenderProps, FieldValues, Path, Control } from 'react-hook-form';
import { FormControl, FormLabel, Input } from '@chakra-ui/react';
import { Controller } from 'react-hook-form';
interface Props<TInputs extends FieldValues> {
......@@ -21,7 +21,7 @@ export default function PublicTagsFormInput<Inputs extends FieldValues>({ label,
/>
<FormLabel>{ label }</FormLabel>
</FormControl>
)
);
}, [ label, required ]);
return (
<Controller
......@@ -29,5 +29,5 @@ export default function PublicTagsFormInput<Inputs extends FieldValues>({ label,
control={ control }
render={ renderInput }
/>
)
);
}
import React from 'react';
import { Heading } from '@chakra-ui/react';
import React from 'react';
const PageHeader = ({ text }: {text: string}) => {
return (
<Heading as="h1" size="lg" marginBottom={ 8 }>{ text }</Heading>
)
}
);
};
export default PageHeader;
import { Box } from '@chakra-ui/react';
import React from 'react';
import Jazzicon, { jsNumberForAddress } from 'react-jazzicon';
import { Box } from '@chakra-ui/react';
const AddressIcon = ({ address }: {address: string}) => {
return (
......
import React from 'react'
import type { ControllerRenderProps, FieldValues, Path } from 'react-hook-form';
import {
Input,
FormControl,
FormLabel,
} from '@chakra-ui/react';
import React from 'react';
import type { ControllerRenderProps, FieldValues, Path } from 'react-hook-form';
const ADDRESS_LENGTH = 42;
......@@ -33,5 +32,5 @@ export default function AddressInput<Inputs extends FieldValues, Name extends Pa
/>
<FormLabel>{ placeholder }</FormLabel>
</FormControl>
)
);
}
import React from 'react';
import { HStack, Link } from '@chakra-ui/react';
import React from 'react';
import AddressWithDots from './AddressWithDots';
import CopyToClipboard from './CopyToClipboard';
......@@ -20,7 +19,7 @@ const AddressLinkWithTooltip = ({ address }: {address: string}) => {
</Link>
<CopyToClipboard text={ address }/>
</HStack>
)
}
);
};
export default React.memo(AddressLinkWithTooltip);
......@@ -8,11 +8,12 @@
// so i did it with js
import React, { useCallback, useEffect, useRef } from 'react';
import { Tooltip } from '@chakra-ui/react'
import { Tooltip } from '@chakra-ui/react';
import _debounce from 'lodash/debounce';
import React, { useCallback, useEffect, useRef } from 'react';
import type { FontFace } from 'use-font-face-observer';
import useFontFaceObserver from 'use-font-face-observer';
import { BODY_TYPEFACE } from 'theme/foundations/typography';
const TAIL_LENGTH = 4;
......@@ -65,13 +66,13 @@ const AddressWithDots = ({ address, fontWeight }: {address: string; fontWeight:
// that's why there are separate useEffect hooks
useEffect(() => {
calculateString();
}, [ calculateString, isFontFaceLoaded ])
}, [ calculateString, isFontFaceLoaded ]);
useEffect(() => {
const resizeHandler = _debounce(calculateString, 50)
window.addEventListener('resize', resizeHandler)
const resizeHandler = _debounce(calculateString, 50);
window.addEventListener('resize', resizeHandler);
return function cleanup() {
window.removeEventListener('resize', resizeHandler)
window.removeEventListener('resize', resizeHandler);
};
}, [ calculateString ]);
......@@ -81,11 +82,11 @@ const AddressWithDots = ({ address, fontWeight }: {address: string; fontWeight:
if (isTruncated) {
return (
<Tooltip label={ address }>{ content }</Tooltip>
)
);
}
return content;
}
};
function getWidth(el: HTMLElement) {
return el.getBoundingClientRect().width;
......
import { IconButton, Tooltip, useClipboard } from '@chakra-ui/react';
import React, { useEffect, useState } from 'react';
import { IconButton, Tooltip, useClipboard } from '@chakra-ui/react';
import CopyIcon from 'icons/copy.svg';
const CopyToClipboard = ({ text }: {text: string}) => {
......@@ -27,6 +27,6 @@ const CopyToClipboard = ({ text }: {text: string}) => {
/>
</Tooltip>
);
}
};
export default CopyToClipboard;
import React, { useCallback } from 'react';
import { Tooltip, IconButton, Icon } from '@chakra-ui/react';
import React, { useCallback } from 'react';
import DeleteIcon from 'icons/delete.svg';
......@@ -9,7 +8,7 @@ type Props = {
}
const DeleteButton = ({ onClick }: Props) => {
const onFocusCapture = useCallback((e: React.SyntheticEvent) => e.stopPropagation(), [])
const onFocusCapture = useCallback((e: React.SyntheticEvent) => e.stopPropagation(), []);
return (
<Tooltip label="Delete">
<IconButton
......@@ -22,7 +21,7 @@ const DeleteButton = ({ onClick }: Props) => {
onFocusCapture={ onFocusCapture }
/>
</Tooltip>
)
}
);
};
export default DeleteButton;
import React, { useCallback } from 'react';
import {
Button,
Modal,
......@@ -10,6 +8,7 @@ import {
ModalBody,
ModalCloseButton,
} from '@chakra-ui/react';
import React, { useCallback } from 'react';
type Props = {
isOpen: boolean;
......@@ -49,7 +48,7 @@ const DeleteModal: React.FC<Props> = ({ isOpen, onClose, onDelete, title, render
</ModalFooter>
</ModalContent>
</Modal>
)
}
);
};
export default DeleteModal;
import React, { useCallback } from 'react';
import { Tooltip, IconButton, Icon } from '@chakra-ui/react';
import React, { useCallback } from 'react';
import EditIcon from 'icons/edit.svg';
......@@ -9,7 +8,7 @@ type Props = {
}
const EditButton = ({ onClick }: Props) => {
const onFocusCapture = useCallback((e: React.SyntheticEvent) => e.stopPropagation(), [])
const onFocusCapture = useCallback((e: React.SyntheticEvent) => e.stopPropagation(), []);
return (
<Tooltip label="Edit">
<IconButton
......@@ -22,7 +21,7 @@ const EditButton = ({ onClick }: Props) => {
onFocusCapture={ onFocusCapture }
/>
</Tooltip>
)
}
);
};
export default EditButton;
import React from 'react';
import {
Modal,
ModalOverlay,
......@@ -9,6 +7,7 @@ import {
ModalCloseButton,
Text,
} from '@chakra-ui/react';
import React from 'react';
interface Props<TData> {
isOpen: boolean;
......@@ -36,5 +35,5 @@ export default function FormModal<TData>({ isOpen, onClose, data, title, text, r
</ModalBody>
</ModalContent>
</Modal>
)
);
}
import React from 'react';
import { Box, HStack, VStack } from '@chakra-ui/react';
import React from 'react';
import Navigation from 'ui/navigation/Navigation';
import Header from 'ui/header/Header';
import Navigation from 'ui/navigation/Navigation';
interface Props {
children: React.ReactNode;
......@@ -34,4 +34,4 @@ const Page = ({ children }: Props) => {
);
};
export default Page
export default Page;
import React from 'react';
import type { ControllerRenderProps } from 'react-hook-form';
import {
Input,
FormControl,
FormLabel,
} from '@chakra-ui/react';
import React from 'react';
import type { ControllerRenderProps, FieldValues } from 'react-hook-form';
const TAG_MAX_LENGTH = 35;
type Props = {
field: ControllerRenderProps<any, 'tag'>;
type Props<Field> = {
field: Field;
isInvalid: boolean;
}
const TagInput: React.FC<Props> = ({ field, isInvalid }) => {
function TagInput<Field extends Partial<ControllerRenderProps<FieldValues, 'tag'>>>({ field, isInvalid }: Props<Field>) {
return (
<FormControl variant="floating" id="tag" isRequired>
<Input
......@@ -25,7 +23,7 @@ const TagInput: React.FC<Props> = ({ field, isInvalid }) => {
/>
<FormLabel>Private tag (max 35 characters)</FormLabel>
</FormControl>
)
);
}
export default TagInput;
import React from 'react'
import type { ControllerRenderProps } from 'react-hook-form';
import {
Input,
FormControl,
FormLabel,
} from '@chakra-ui/react';
import React from 'react';
import type { ControllerRenderProps, FieldValues } from 'react-hook-form';
const HASH_LENGTH = 66;
type Props = {
field: ControllerRenderProps<any, 'transaction'>;
type Props<Field> = {
field: Field;
isInvalid: boolean;
}
const AddressInput: React.FC<Props> = ({ field, isInvalid }) => {
function AddressInput<Field extends Partial<ControllerRenderProps<FieldValues, 'transaction'>>>({ field, isInvalid }: Props<Field>) {
return (
<FormControl variant="floating" id="transaction" isRequired>
<Input
......@@ -24,7 +23,7 @@ const AddressInput: React.FC<Props> = ({ field, isInvalid }) => {
/>
<FormLabel>Transaction hash (0x...)</FormLabel>
</FormControl>
)
);
}
export default AddressInput
export default AddressInput;
import React from 'react';
import { Tooltip } from '@chakra-ui/react'
import { Tooltip } from '@chakra-ui/react';
import debounce from 'lodash/debounce';
import React from 'react';
import useFontFaceObserver from 'use-font-face-observer';
import { BODY_TYPEFACE } from 'theme/foundations/typography';
interface Props {
......@@ -33,18 +34,18 @@ const TruncatedTextTooltip = ({ children, label }: Props) => {
// FIXME: that should be useLayoutEffect, but it keeps complaining about SSR
// let's keep it as it is until the first issue
React.useEffect(() => {
updatedTruncateState()
updatedTruncateState();
}, [ updatedTruncateState, isFontFaceLoaded ]);
// we want to do recalculation when isFontFaceLoaded flag is changed
// but we don't want to create more resize event listeners
// that's why there are separate useEffect hooks
React.useEffect(() => {
const handleResize = debounce(updatedTruncateState, 1000)
window.addEventListener('resize', handleResize)
const handleResize = debounce(updatedTruncateState, 1000);
window.addEventListener('resize', handleResize);
return function cleanup() {
window.removeEventListener('resize', handleResize)
window.removeEventListener('resize', handleResize);
};
}, [ updatedTruncateState ]);
......@@ -52,7 +53,7 @@ const TruncatedTextTooltip = ({ children, label }: Props) => {
// and it is not cleared how to manage case with two or more children
const child = React.Children.only(children) as React.ReactElement & {
ref?: React.Ref<React.ReactNode>;
}
};
const modifiedChildren = React.cloneElement(
child,
{ ref: childRef },
......
import React, { useCallback, useEffect } from 'react';
import type { SubmitHandler, ControllerRenderProps } from 'react-hook-form';
import { useForm, Controller } from 'react-hook-form';
import {
Box,
Button,
......@@ -10,12 +6,14 @@ import {
Grid,
GridItem,
} from '@chakra-ui/react';
import React, { useCallback, useEffect } from 'react';
import type { SubmitHandler, ControllerRenderProps } from 'react-hook-form';
import { useForm, Controller } from 'react-hook-form';
import type { TWatchlistItem } from 'data/watchlist';
import AddressInput from 'ui/shared/AddressInput';
import TagInput from 'ui/shared/TagInput';
import type { TWatchlistItem } from 'data/watchlist';
const NOTIFICATIONS = [ 'xDAI', 'ERC-20', 'ERC-721, ERC-1155 (NFT)' ];
const ADDRESS_LENGTH = 42;
const TAG_MAX_LENGTH = 35;
......@@ -43,11 +41,11 @@ const AddressForm: React.FC<Props> = ({ data }) => {
const onSubmit: SubmitHandler<Inputs> = data => console.log(data);
const renderAddressInput = useCallback(({ field }: {field: ControllerRenderProps<Inputs, 'address'>}) => {
return <AddressInput<Inputs, 'address'> field={ field } isInvalid={ Boolean(errors.address) }/>
return <AddressInput<Inputs, 'address'> field={ field } isInvalid={ Boolean(errors.address) }/>;
}, [ errors ]);
const renderTagInput = useCallback(({ field }: {field: ControllerRenderProps<Inputs, 'tag'>}) => {
return <TagInput field={ field } isInvalid={ Boolean(errors.tag) }/>
return <TagInput field={ field } isInvalid={ Boolean(errors.tag) }/>;
}, [ errors ]);
const renderCheckbox = useCallback(({ field }: {field: ControllerRenderProps<Inputs, 'notification'>}) => (
......@@ -98,7 +96,7 @@ const AddressForm: React.FC<Props> = ({ data }) => {
<GridItem><Checkbox colorScheme="blue" size="lg">Incoming</Checkbox></GridItem>
<GridItem><Checkbox colorScheme="blue" size="lg">Outgoing</Checkbox></GridItem>
</React.Fragment>
)
);
}) }
</Grid>
</Box>
......@@ -119,7 +117,7 @@ const AddressForm: React.FC<Props> = ({ data }) => {
</Button>
</Box>
</>
)
}
);
};
export default AddressForm;
import React, { useCallback } from 'react';
import type { TWatchlistItem } from 'data/watchlist';
import FormModal from 'ui/shared/FormModal';
import AddressForm from './AddressForm';
import FormModal from 'ui/shared/FormModal';
type Props = {
isOpen: boolean;
......@@ -13,10 +13,10 @@ type Props = {
const AddressModal: React.FC<Props> = ({ isOpen, onClose, data }) => {
const title = data ? 'Edit watch list address' : 'New address to watch list';
const text = 'An email notification can be sent to you when an address on your watch list sends or receives any transactions.'
const text = 'An email notification can be sent to you when an address on your watch list sends or receives any transactions.';
const renderForm = useCallback(() => {
return <AddressForm data={ data }/>
return <AddressForm data={ data }/>;
}, [ data ]);
return (
<FormModal<TWatchlistItem>
......@@ -27,7 +27,7 @@ const AddressModal: React.FC<Props> = ({ isOpen, onClose, data }) => {
data={ data }
renderForm={ renderForm }
/>
)
}
);
};
export default AddressModal;
import React, { useCallback } from 'react';
import { Text } from '@chakra-ui/react';
import DeleteModal from 'ui/shared/DeleteModal'
import React, { useCallback } from 'react';
import DeleteModal from 'ui/shared/DeleteModal';
type Props = {
isOpen: boolean;
......@@ -17,7 +18,7 @@ const DeleteAddressModal: React.FC<Props> = ({ isOpen, onClose, address }) => {
const renderText = useCallback(() => {
return (
<Text display="flex">Address <Text fontWeight="600" whiteSpace="pre"> { address || 'address' } </Text> will be deleted</Text>
)
);
}, [ address ]);
return (
......@@ -28,7 +29,7 @@ const DeleteAddressModal: React.FC<Props> = ({ isOpen, onClose, address }) => {
title="Remove address from watch list"
renderContent={ renderText }
/>
)
}
);
};
export default DeleteAddressModal;
import React from 'react';
import { Link, HStack, VStack, Image, Text, Icon, useColorModeValue } from '@chakra-ui/react';
import React from 'react';
import AddressIcon from 'ui/shared/AddressIcon';
import AddressLinkWithTooltip from 'ui/shared/AddressLinkWithTooltip';
import type { TWatchlistItem } from 'data/watchlist';
import { nbsp } from 'lib/html-entities';
import TokensIcon from 'icons/tokens.svg';
import WalletIcon from 'icons/wallet.svg';
import { nbsp } from 'lib/html-entities';
import AddressIcon from 'ui/shared/AddressIcon';
import AddressLinkWithTooltip from 'ui/shared/AddressLinkWithTooltip';
const WatchListAddressItem = ({ item }: {item: TWatchlistItem}) => {
const mainTextColor = useColorModeValue('gray.700', 'gray.50');
......@@ -40,7 +39,7 @@ const WatchListAddressItem = ({ item }: {item: TWatchlistItem}) => {
) }
</VStack>
</HStack>
)
}
);
};
export default WatchListAddressItem;
import React, { useCallback } from 'react';
import {
Tag,
Tr,
Td,
Switch,
HStack,
} from '@chakra-ui/react'
} from '@chakra-ui/react';
import React, { useCallback } from 'react';
import EditButton from 'ui/shared/EditButton';
import type { TWatchlistItem } from 'data/watchlist';
import DeleteButton from 'ui/shared/DeleteButton';
import EditButton from 'ui/shared/EditButton';
import TruncatedTextTooltip from 'ui/shared/TruncatedTextTooltip';
import type { TWatchlistItem } from 'data/watchlist';
import WatchListAddressItem from './WatchListAddressItem';
interface Props {
......@@ -49,7 +47,7 @@ const WatchlistTableItem = ({ item, onEditClick, onDeleteClick }: Props) => {
</HStack>
</Td>
</Tr>
)
);
};
export default WatchlistTableItem;
import React from 'react';
import {
Table,
Thead,
......@@ -7,7 +5,8 @@ import {
Tr,
Th,
TableContainer,
} from '@chakra-ui/react'
} from '@chakra-ui/react';
import React from 'react';
import type { TWatchlist, TWatchlistItem } from 'data/watchlist';
......
......@@ -1625,6 +1625,11 @@ eslint-plugin-es5@^1.5.0:
resolved "https://registry.yarnpkg.com/eslint-plugin-es5/-/eslint-plugin-es5-1.5.0.tgz#aab19af3d4798f7924bba309bc4f87087280fbba"
integrity sha512-Qxmfo7v2B7SGAEURJo0dpBweFf+JU15kSyALfiB2rXWcBuJ96r6X9kFHXFnhdopPHCaHjoQs1xQPUJVbGMb1AA==
eslint-plugin-import-helpers@^1.2.1:
version "1.2.1"
resolved "https://registry.yarnpkg.com/eslint-plugin-import-helpers/-/eslint-plugin-import-helpers-1.2.1.tgz#22c7ac66c964e8257b2a6fb4aff8a51b35cbdc6d"
integrity sha512-BSqLlCnyX4tWGlvPUTpBgUoaFiWxXSztpk9SozZVW4TZU1ygZuF0Lrfn9CO5xx1XT+PVAR9yroP9JPRyB4rAjQ==
eslint-plugin-import@^2.26.0:
version "2.26.0"
resolved "https://registry.yarnpkg.com/eslint-plugin-import/-/eslint-plugin-import-2.26.0.tgz#f812dc47be4f2b72b478a021605a59fc6fe8b88b"
......
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