diff --git a/apps/stats-dapp/src/provider/stats-provider.tsx b/apps/stats-dapp/src/provider/stats-provider.tsx index ff5e40e21a..e4c4545631 100644 --- a/apps/stats-dapp/src/provider/stats-provider.tsx +++ b/apps/stats-dapp/src/provider/stats-provider.tsx @@ -265,7 +265,10 @@ export const StatsProvider: React.FC< useEffect(() => { const getPromiseApi = async (): Promise => { const wsProvider = new WsProvider(props.polkadotEndpoint); - const apiPromise = await ApiPromise.create({ provider: wsProvider }); + const apiPromise = await ApiPromise.create({ + provider: wsProvider, + noInitWarn: true, + }); setApi(apiPromise); // Get session height from Polkadot API diff --git a/apps/tangle-dapp/.eslintrc.json b/apps/tangle-dapp/.eslintrc.json index 38ebb785b4..faf8216565 100644 --- a/apps/tangle-dapp/.eslintrc.json +++ b/apps/tangle-dapp/.eslintrc.json @@ -3,8 +3,11 @@ "plugin:@nx/react-typescript", "next", "next/core-web-vitals", - "../../.eslintrc.json" + "../../.eslintrc.json", + "eslint:recommended" ], + "plugins": ["unused-imports", "simple-import-sort"], + "parser": "@typescript-eslint/parser", "ignorePatterns": ["!**/*", ".next/**/*"], "overrides": [ { @@ -23,7 +26,10 @@ } ], "rules": { - "@next/next/no-html-link-for-pages": "off" + "@next/next/no-html-link-for-pages": "off", + "simple-import-sort/imports": "error", + "simple-import-sort/exports": "error", + "no-unused-vars": "off" }, "env": { "jest": true diff --git a/apps/tangle-dapp/app/api/hello/route.ts b/apps/tangle-dapp/app/api/hello/route.ts index de70bac64e..3bbf325cbf 100644 --- a/apps/tangle-dapp/app/api/hello/route.ts +++ b/apps/tangle-dapp/app/api/hello/route.ts @@ -1,3 +1,3 @@ -export async function GET(request: Request) { +export async function GET() { return new Response('Hello, from API!'); } diff --git a/apps/tangle-dapp/app/layout.tsx b/apps/tangle-dapp/app/layout.tsx index 7577fbca36..dd0d592b1e 100644 --- a/apps/tangle-dapp/app/layout.tsx +++ b/apps/tangle-dapp/app/layout.tsx @@ -1,8 +1,11 @@ import '@webb-tools/webb-ui-components/tailwind.css'; -import { Metadata } from 'next'; + +import NextThemeProvider from '@webb-tools/api-provider-environment/NextThemeProvider'; import { TANGLE_DAPP_URL } from '@webb-tools/webb-ui-components/constants'; +import { Metadata } from 'next'; +import type React from 'react'; + import { Layout } from '../containers'; -import NextThemeProvider from '@webb-tools/api-provider-environment/NextThemeProvider'; export const metadata: Metadata = { title: { diff --git a/apps/tangle-dapp/app/page.tsx b/apps/tangle-dapp/app/page.tsx index 8eebe5f7a7..10486e829e 100644 --- a/apps/tangle-dapp/app/page.tsx +++ b/apps/tangle-dapp/app/page.tsx @@ -1,4 +1,5 @@ import { Typography } from '@webb-tools/webb-ui-components'; + import { HeaderChipsContainer, KeyMetricsTableContainer } from '../containers'; export default async function Index() { diff --git a/apps/tangle-dapp/components/Breadcrumbs/Breadcrumbs.tsx b/apps/tangle-dapp/components/Breadcrumbs/Breadcrumbs.tsx index db4f150ee6..4a07a5decb 100644 --- a/apps/tangle-dapp/components/Breadcrumbs/Breadcrumbs.tsx +++ b/apps/tangle-dapp/components/Breadcrumbs/Breadcrumbs.tsx @@ -1,21 +1,18 @@ 'use client'; import { FundsLine } from '@webb-tools/icons'; +import { getIconSizeInPixel } from '@webb-tools/icons/utils'; import { Breadcrumbs as BreadcrumbsCmp, BreadcrumbsItem, } from '@webb-tools/webb-ui-components'; import cx from 'classnames'; import Link from 'next/link'; -import { usePathname, useRouter } from 'next/navigation'; -import { type FC, useMemo, useEffect } from 'react'; +import { type FC, useMemo } from 'react'; + import { BreadcrumbType } from './types'; -import { getIconSizeInPixel } from '@webb-tools/icons/utils'; const Breadcrumbs: FC = () => { - const router = useRouter(); - const pathname = usePathname(); - const breadCrumbs = useMemo(() => { const md = getIconSizeInPixel('md'); const lg = getIconSizeInPixel('lg'); diff --git a/apps/tangle-dapp/components/Breadcrumbs/types.ts b/apps/tangle-dapp/components/Breadcrumbs/types.ts index 47053b33b9..74a819f073 100644 --- a/apps/tangle-dapp/components/Breadcrumbs/types.ts +++ b/apps/tangle-dapp/components/Breadcrumbs/types.ts @@ -1,7 +1,10 @@ +import type { IconBase } from '@webb-tools/icons/types'; +import type React from 'react'; + export type BreadcrumbType = { label: string; isLast: boolean; - icon: JSX.Element; + icon: React.ReactElement; href: string; className?: string; }; diff --git a/apps/tangle-dapp/components/HeaderChip/ChipValueClient.tsx b/apps/tangle-dapp/components/HeaderChip/ChipValueClient.tsx new file mode 100644 index 0000000000..ddf46595c6 --- /dev/null +++ b/apps/tangle-dapp/components/HeaderChip/ChipValueClient.tsx @@ -0,0 +1,14 @@ +'use client'; + +import getRoundedDownNumberWith2Decimals from '../../utils/getRoundedDownNumberWith2Decimals'; +import dataHooks from './dataHooks'; +import { ChipType } from './types'; + +export default function ChipValueClient(props: { + type: ChipType; + value?: number; +}) { + const era = dataHooks[props.type](props.value); + + return <>{getRoundedDownNumberWith2Decimals(era)}; +} diff --git a/apps/tangle-dapp/components/HeaderChip/HeaderChip.tsx b/apps/tangle-dapp/components/HeaderChip/HeaderChip.tsx index b16c31ce47..687415d84e 100644 --- a/apps/tangle-dapp/components/HeaderChip/HeaderChip.tsx +++ b/apps/tangle-dapp/components/HeaderChip/HeaderChip.tsx @@ -1,14 +1,15 @@ -import { Suspense, type FC, useMemo } from 'react'; import { Chip, + SkeletonLoader, Tooltip, TooltipBody, TooltipTrigger, Typography, - SkeletonLoader, } from '@webb-tools/webb-ui-components'; +import { type FC, Suspense, useMemo } from 'react'; + +import ChipValueClient from './ChipValueClient'; import { HeaderChipItemProps } from './types'; -import { getRoundedDownNumberWith2Decimals } from '../../utils'; export const HeaderChip: FC = ({ Icon, @@ -23,7 +24,7 @@ export const HeaderChip: FC = ({ {label}:{' '} }> - + ), @@ -46,8 +47,9 @@ export const HeaderChip: FC = ({ const HeaderChipValue = async ({ dataFetcher, -}: Pick) => { + label, +}: Pick) => { const value = await dataFetcher(); - return <>{getRoundedDownNumberWith2Decimals(value)}; + return ; }; diff --git a/apps/tangle-dapp/components/HeaderChip/dataHooks.ts b/apps/tangle-dapp/components/HeaderChip/dataHooks.ts new file mode 100644 index 0000000000..f2067521bf --- /dev/null +++ b/apps/tangle-dapp/components/HeaderChip/dataHooks.ts @@ -0,0 +1,9 @@ +import useEraCountSubscription from '../../data/HeaderChips/useEraCountSubscription'; +import useSessionCountSubscription from '../../data/HeaderChips/useSessionCountSubscription'; + +const dataHooks = { + ERA: useEraCountSubscription, + Session: useSessionCountSubscription, +} as const; + +export default dataHooks; diff --git a/apps/tangle-dapp/components/HeaderChip/types.ts b/apps/tangle-dapp/components/HeaderChip/types.ts index 6d4c8e7a09..522b969029 100644 --- a/apps/tangle-dapp/components/HeaderChip/types.ts +++ b/apps/tangle-dapp/components/HeaderChip/types.ts @@ -1,8 +1,11 @@ -import { type IconBase } from '@webb-tools/icons/types'; +import type { IconBase } from '@webb-tools/icons/types'; +import type React from 'react'; + +export type ChipType = 'ERA' | 'Session'; export interface HeaderChipItemProps { - Icon: (props: IconBase) => JSX.Element; - label: string; + Icon: (props: IconBase) => React.JSX.Element; + label: ChipType; hasTooltip?: boolean; tooltipContent?: string; dataFetcher: () => Promise; diff --git a/apps/tangle-dapp/components/InfoIconWithTooltip/InfoIconWithTooltip.tsx b/apps/tangle-dapp/components/InfoIconWithTooltip/InfoIconWithTooltip.tsx index 082465cbc4..5bb39ae753 100644 --- a/apps/tangle-dapp/components/InfoIconWithTooltip/InfoIconWithTooltip.tsx +++ b/apps/tangle-dapp/components/InfoIconWithTooltip/InfoIconWithTooltip.tsx @@ -1,6 +1,6 @@ -import { FC } from 'react'; -import { IconWithTooltip } from '@webb-tools/webb-ui-components'; import { InformationLine } from '@webb-tools/icons'; +import { IconWithTooltip } from '@webb-tools/webb-ui-components'; +import { FC } from 'react'; import { InfoIconWithTooltipProps } from './types'; diff --git a/apps/tangle-dapp/components/KeyMetricItem/KeyMetricItem.tsx b/apps/tangle-dapp/components/KeyMetricItem/KeyMetricItem.tsx index e9b2bc5339..609c595529 100644 --- a/apps/tangle-dapp/components/KeyMetricItem/KeyMetricItem.tsx +++ b/apps/tangle-dapp/components/KeyMetricItem/KeyMetricItem.tsx @@ -1,9 +1,10 @@ +import { SkeletonLoader, Typography } from '@webb-tools/webb-ui-components'; import { FC, Suspense } from 'react'; -import { Typography, SkeletonLoader } from '@webb-tools/webb-ui-components'; +import { twMerge } from 'tailwind-merge'; + import { InfoIconWithTooltip } from '..'; -import { getRoundedDownNumberWith2Decimals } from '../../utils'; +import KeyMetricItemValueClient from './KeyMetricItemValueClient'; import { MetricItemProps } from './types'; -import { twMerge } from 'tailwind-merge'; export const KeyMetricItem: FC = ({ title, @@ -21,42 +22,24 @@ export const KeyMetricItem: FC = ({ }> - + ); }; -const KeyMetricItemValue = async ( - props: Omit -) => { - const { dataFetcher, prefix, suffix } = props; +const KeyMetricItemValue = async (props: Omit) => { + const { dataFetcher, prefix, suffix, title } = props; const { value1, value2 } = await dataFetcher(); return ( -
-
- - {typeof value1 === 'number' && (prefix ?? '')} - {getRoundedDownNumberWith2Decimals(value1)} - {value2 && <> / {getRoundedDownNumberWith2Decimals(value2)}} - - - {typeof value1 === 'number' && suffix && ( - - {suffix} - - )} -
-
+ ); }; diff --git a/apps/tangle-dapp/components/KeyMetricItem/KeyMetricItemValueClient.tsx b/apps/tangle-dapp/components/KeyMetricItem/KeyMetricItemValueClient.tsx new file mode 100644 index 0000000000..2a0a64fe82 --- /dev/null +++ b/apps/tangle-dapp/components/KeyMetricItem/KeyMetricItemValueClient.tsx @@ -0,0 +1,44 @@ +'use client'; + +import { Typography } from '@webb-tools/webb-ui-components/typography/Typography'; + +import type { MetricReturnType } from '../../types'; +import getRoundedDownNumberWith2Decimals from '../../utils/getRoundedDownNumberWith2Decimals'; +import dataHooks, { defaultHook } from './dataHooks'; +import type { MetricItemProps } from './types'; + +function KeyMetricItemValueClient( + props: Pick & MetricReturnType +) { + const { title, prefix, suffix, value1: value1_, value2: value2_ } = props; + const dataHook = dataHooks[title] ?? defaultHook; + const { value1, value2 } = dataHook({ value1: value1_, value2: value2_ }); + + return ( +
+
+ + {typeof value1 === 'number' && (prefix ?? '')} + {getRoundedDownNumberWith2Decimals(value1)} + {value2 && <> / {getRoundedDownNumberWith2Decimals(value2)}} + + + {typeof value1 === 'number' && suffix && ( + + {suffix} + + )} +
+
+ ); +} + +export default KeyMetricItemValueClient; diff --git a/apps/tangle-dapp/components/KeyMetricItem/dataHooks.ts b/apps/tangle-dapp/components/KeyMetricItem/dataHooks.ts new file mode 100644 index 0000000000..8369f00ab7 --- /dev/null +++ b/apps/tangle-dapp/components/KeyMetricItem/dataHooks.ts @@ -0,0 +1,19 @@ +import { + useActiveAndDelegationCountSubscription, + useValidatorsCountSubscription, + useWaitingCountSubscription, +} from '../../data'; +import type { MetricReturnType } from '../../types'; + +const dataHooks: { + [key: string]: (defaultValue?: MetricReturnType) => MetricReturnType; +} = { + Validators: useValidatorsCountSubscription, + Waiting: useWaitingCountSubscription, + 'Active/Delegation': useActiveAndDelegationCountSubscription, +} as const; + +export default dataHooks; + +export const defaultHook = (defaultValue: MetricReturnType = {}) => + defaultValue; diff --git a/apps/tangle-dapp/components/index.ts b/apps/tangle-dapp/components/index.ts index e98436e559..4d91dae4ec 100644 --- a/apps/tangle-dapp/components/index.ts +++ b/apps/tangle-dapp/components/index.ts @@ -1,5 +1,5 @@ -export * from './sideBar'; export * from './Breadcrumbs'; export * from './HeaderChip'; export * from './InfoIconWithTooltip'; export * from './KeyMetricItem'; +export * from './sideBar'; diff --git a/apps/tangle-dapp/components/sideBar/SideBar.tsx b/apps/tangle-dapp/components/sideBar/SideBar.tsx index c26e07de19..413c6e44fc 100644 --- a/apps/tangle-dapp/components/sideBar/SideBar.tsx +++ b/apps/tangle-dapp/components/sideBar/SideBar.tsx @@ -1,8 +1,9 @@ 'use client'; -import { type FC } from 'react'; import { SideBar as SideBarCmp } from '@webb-tools/webb-ui-components'; import { setSideBarCookieOnToggle } from '@webb-tools/webb-ui-components/next-utils'; +import { type FC } from 'react'; + import sideBarProps from './sideBarProps'; interface SideBarProps { diff --git a/apps/tangle-dapp/components/sideBar/SideBarMenu.tsx b/apps/tangle-dapp/components/sideBar/SideBarMenu.tsx index eacd69e530..6cb4752771 100644 --- a/apps/tangle-dapp/components/sideBar/SideBarMenu.tsx +++ b/apps/tangle-dapp/components/sideBar/SideBarMenu.tsx @@ -1,7 +1,7 @@ 'use client'; -import { FC } from 'react'; import { SideBarMenu as SideBarMenuCmp } from '@webb-tools/webb-ui-components'; +import { FC } from 'react'; import sideBarProps from './sideBarProps'; diff --git a/apps/tangle-dapp/components/sideBar/sideBarProps.ts b/apps/tangle-dapp/components/sideBar/sideBarProps.ts index 158f2b22fb..aa2cd68457 100644 --- a/apps/tangle-dapp/components/sideBar/sideBarProps.ts +++ b/apps/tangle-dapp/components/sideBar/sideBarProps.ts @@ -2,9 +2,9 @@ import { AppsLine, DocumentationIcon, FaucetIcon, + FundsLine, GlobalLine, KeyIcon, - FundsLine, } from '@webb-tools/icons'; import { type SideBarFooterType, @@ -20,8 +20,8 @@ import { TANGLE_MKT_URL, TANGLE_STANDALONE_EXPLORER_URL, TANGLE_TESTNET_EXPLORER_URL, - WEBB_TANGLE_DOCS_URL, WEBB_FAUCET_URL, + WEBB_TANGLE_DOCS_URL, } from '@webb-tools/webb-ui-components/constants'; const sideBarItems: SideBarItemProps[] = [ diff --git a/apps/tangle-dapp/constants/polkadot.ts b/apps/tangle-dapp/constants/polkadot.ts index 17e53346b6..edda9237ce 100644 --- a/apps/tangle-dapp/constants/polkadot.ts +++ b/apps/tangle-dapp/constants/polkadot.ts @@ -1,16 +1,52 @@ -import { ApiPromise, WsProvider } from '@polkadot/api'; +import { ApiPromise, ApiRx, WsProvider } from '@polkadot/api'; import { TANGLE_RPC_ENDPOINT } from '@webb-tools/webb-ui-components/constants'; +import { firstValueFrom } from 'rxjs'; -export const getPolkadotApi = async ( +const apiPromiseCache = new Map(); + +export const getPolkadotApiPromise = async ( endpoint: string = TANGLE_RPC_ENDPOINT ): Promise => { + if (apiPromiseCache.has(endpoint)) { + return apiPromiseCache.get(endpoint); + } + try { const wsProvider = new WsProvider(endpoint); - const apiPromise = await ApiPromise.create({ provider: wsProvider }); + const apiPromise = await ApiPromise.create({ + provider: wsProvider, + noInitWarn: true, + }); + + apiPromiseCache.set(endpoint, apiPromise); return apiPromise; } catch (e) { console.error(e); - return undefined; + } +}; + +const apiRxCache = new Map(); + +export const getPolkadotApiRx = async ( + endpoint: string = TANGLE_RPC_ENDPOINT +): Promise => { + if (apiRxCache.has(endpoint)) { + return apiRxCache.get(endpoint); + } + + try { + const provider = new WsProvider(endpoint); + const api = new ApiRx({ + provider, + noInitWarn: true, + }); + + const apiRx = await firstValueFrom(api.isReady); + apiRxCache.set(endpoint, apiRx); + + return apiRx; + } catch (error) { + console.error(error); } }; diff --git a/apps/tangle-dapp/containers/HeaderChipsContainer/HeaderChipsContainer.tsx b/apps/tangle-dapp/containers/HeaderChipsContainer/HeaderChipsContainer.tsx index 4754148e24..ba1375906f 100644 --- a/apps/tangle-dapp/containers/HeaderChipsContainer/HeaderChipsContainer.tsx +++ b/apps/tangle-dapp/containers/HeaderChipsContainer/HeaderChipsContainer.tsx @@ -1,4 +1,5 @@ import { BlockIcon } from '@webb-tools/icons'; + import { HeaderChip } from '../../components'; import { getEraCount, getSessionCount } from '../../data'; diff --git a/apps/tangle-dapp/containers/KeyMetricsTableContainer/KeyMetricsTableContainer.tsx b/apps/tangle-dapp/containers/KeyMetricsTableContainer/KeyMetricsTableContainer.tsx index 02ce1ce964..7c2e59e7fb 100644 --- a/apps/tangle-dapp/containers/KeyMetricsTableContainer/KeyMetricsTableContainer.tsx +++ b/apps/tangle-dapp/containers/KeyMetricsTableContainer/KeyMetricsTableContainer.tsx @@ -1,12 +1,13 @@ import cx from 'classnames'; import { cache } from 'react'; + import { KeyMetricItem } from '../../components/KeyMetricItem'; import { - getValidatorsCount, - getWaitingCount, getActiveAndDelegationCount, getIdealStakedPercentage, getInflationPercentage, + getValidatorsCount, + getWaitingCount, } from '../../data'; const getValidatorsCountData = cache(getValidatorsCount); diff --git a/apps/tangle-dapp/containers/Layout/Layout.tsx b/apps/tangle-dapp/containers/Layout/Layout.tsx index 0d9f712670..b1ed16e059 100644 --- a/apps/tangle-dapp/containers/Layout/Layout.tsx +++ b/apps/tangle-dapp/containers/Layout/Layout.tsx @@ -1,7 +1,8 @@ -import React, { type PropsWithChildren, type FC } from 'react'; import { Footer } from '@webb-tools/webb-ui-components'; import { getSideBarStateFromCookie } from '@webb-tools/webb-ui-components/next-utils'; -import { SideBar, SideBarMenu, Breadcrumbs } from '../../components'; +import React, { type FC, type PropsWithChildren } from 'react'; + +import { Breadcrumbs, SideBar, SideBarMenu } from '../../components'; const Layout: FC = ({ children }) => { const isSideBarInitiallyExpanded = getSideBarStateFromCookie(); diff --git a/apps/tangle-dapp/containers/index.ts b/apps/tangle-dapp/containers/index.ts index 023ce56eb6..b477883eb0 100644 --- a/apps/tangle-dapp/containers/index.ts +++ b/apps/tangle-dapp/containers/index.ts @@ -1,3 +1,3 @@ -export { Layout } from './Layout'; -export * from './KeyMetricsTableContainer'; export * from './HeaderChipsContainer'; +export * from './KeyMetricsTableContainer'; +export { Layout } from './Layout'; diff --git a/apps/tangle-dapp/data/HeaderChips/getEraCount.ts b/apps/tangle-dapp/data/HeaderChips/getEraCount.ts index d79865d2cf..1ec2887fb0 100644 --- a/apps/tangle-dapp/data/HeaderChips/getEraCount.ts +++ b/apps/tangle-dapp/data/HeaderChips/getEraCount.ts @@ -1,16 +1,19 @@ -import { getPolkadotApi } from '../../constants'; +import { getPolkadotApiPromise } from '../../constants'; export const getEraCount = async (): Promise => { - const api = await getPolkadotApi(); + const api = await getPolkadotApiPromise(); if (!api) return NaN; try { - let activeEra = await api.query.staking.activeEra(); - activeEra = JSON.parse(JSON.stringify(activeEra)).index; + const activeEra = await api.query.staking.activeEra(); + const value = activeEra.unwrapOr(null); + if (value == null) { + return NaN; + } - return Number(activeEra.toString()); - } catch (e: any) { + return value.index.toNumber(); + } catch (e) { console.error(e); return NaN; diff --git a/apps/tangle-dapp/data/HeaderChips/getSessionCount.ts b/apps/tangle-dapp/data/HeaderChips/getSessionCount.ts index f728d7354b..9a1cdf4d16 100644 --- a/apps/tangle-dapp/data/HeaderChips/getSessionCount.ts +++ b/apps/tangle-dapp/data/HeaderChips/getSessionCount.ts @@ -1,18 +1,17 @@ -import { getPolkadotApi } from '../../constants'; +import { getPolkadotApiPromise } from '../../constants'; export const getSessionCount = async (): Promise => { - const api = await getPolkadotApi(); + const api = await getPolkadotApiPromise(); if (!api) return NaN; try { - const currentDKGPublicKey: any = await api.query.dkg.dkgPublicKey(); + const currentDKGPublicKey = await api.query.dkg.dkgPublicKey(); const currentSessionNumber = currentDKGPublicKey[0]; - return Number(currentSessionNumber.toString()); - } catch (e: any) { + return currentSessionNumber.toNumber(); + } catch (e) { console.error(e); - return NaN; } }; diff --git a/apps/tangle-dapp/data/HeaderChips/useEraCountSubscription.ts b/apps/tangle-dapp/data/HeaderChips/useEraCountSubscription.ts new file mode 100644 index 0000000000..10a497a149 --- /dev/null +++ b/apps/tangle-dapp/data/HeaderChips/useEraCountSubscription.ts @@ -0,0 +1,43 @@ +'use client'; + +import { useEffect, useState } from 'react'; +import type { Subscription } from 'rxjs'; + +import { getPolkadotApiRx } from '../../constants/polkadot'; + +export default function useEraCountSubscription(defaultValue?: number) { + const [era, setEra] = useState(() => defaultValue); + + useEffect(() => { + let isMounted = true; + let sub: Subscription | null = null; + + const apiRx = getPolkadotApiRx(); + + apiRx.then((api) => { + if (!api) { + return; + } + + sub = api.query.staking.activeEra().subscribe((nextEra) => { + const activeEra = nextEra.unwrapOr(null); + if (activeEra == null) { + return; + } + + const idx = activeEra.index.toNumber(); + + if (isMounted) { + setEra(idx); + } + }); + }); + + return () => { + isMounted = false; + sub?.unsubscribe(); + }; + }, []); + + return era; +} diff --git a/apps/tangle-dapp/data/HeaderChips/useSessionCountSubscription.ts b/apps/tangle-dapp/data/HeaderChips/useSessionCountSubscription.ts new file mode 100644 index 0000000000..318653938d --- /dev/null +++ b/apps/tangle-dapp/data/HeaderChips/useSessionCountSubscription.ts @@ -0,0 +1,40 @@ +'use client'; + +import { useEffect, useState } from 'react'; +import type { Subscription } from 'rxjs'; + +import { getPolkadotApiRx } from '../../constants/polkadot'; + +function useSessionCountSubscription(defaultValue = NaN) { + const [session, setSession] = useState(defaultValue); + + useEffect(() => { + let isMounted = true; + let sub: Subscription | null = null; + + const apiRx = getPolkadotApiRx(); + + apiRx.then((api) => { + if (!api) { + return; + } + + sub = api.query.dkg.dkgPublicKey().subscribe((currentDKGPublicKey) => { + const currentSessionNumber = currentDKGPublicKey[0]; + + if (isMounted) { + setSession(currentSessionNumber.toNumber()); + } + }); + }); + + return () => { + isMounted = false; + sub?.unsubscribe(); + }; + }, []); + + return session; +} + +export default useSessionCountSubscription; diff --git a/apps/tangle-dapp/data/TopLevelStats/getActiveAndDelegationCount.ts b/apps/tangle-dapp/data/TopLevelStats/getActiveAndDelegationCount.ts index 843de72a24..bbe9e7dd67 100644 --- a/apps/tangle-dapp/data/TopLevelStats/getActiveAndDelegationCount.ts +++ b/apps/tangle-dapp/data/TopLevelStats/getActiveAndDelegationCount.ts @@ -1,9 +1,9 @@ -import { getPolkadotApi } from '../../constants'; +import { getPolkadotApiPromise } from '../../constants'; import { MetricReturnType } from '../../types'; export const getActiveAndDelegationCount = async (): Promise => { - const api = await getPolkadotApi(); + const api = await getPolkadotApiPromise(); if (!api) return { value1: NaN, value2: NaN }; @@ -19,7 +19,7 @@ export const getActiveAndDelegationCount = const currentValidators = await api.query.session.validators(); // Collection of unique nominator addresses - Set is used to avoid duplicates, as a nominator can nominate multiple validators - const activeNominators = new Set(); + const activeNominators = new Set(); // For each validator, get their nominators for (const validator of currentValidators) { @@ -36,9 +36,9 @@ export const getActiveAndDelegationCount = return { value1: activeNominatorsCount, - value2: Number(totalNominatorCount.toString()), + value2: totalNominatorCount.toNumber(), }; - } catch (e: any) { + } catch (e) { console.error(e); return { value1: NaN, value2: NaN }; diff --git a/apps/tangle-dapp/data/TopLevelStats/getIdealStakedPercentage.ts b/apps/tangle-dapp/data/TopLevelStats/getIdealStakedPercentage.ts index 7e162f68cf..16d96737b4 100644 --- a/apps/tangle-dapp/data/TopLevelStats/getIdealStakedPercentage.ts +++ b/apps/tangle-dapp/data/TopLevelStats/getIdealStakedPercentage.ts @@ -1,10 +1,11 @@ -import { getPolkadotApi } from '../../constants'; import { BN_ZERO } from '@polkadot/util'; -import { calculateInflation } from '../../utils'; + +import { getPolkadotApiPromise } from '../../constants'; import { MetricReturnType } from '../../types'; +import { calculateInflation } from '../../utils'; export const getIdealStakedPercentage = async (): Promise => { - const api = await getPolkadotApi(); + const api = await getPolkadotApiPromise(); if (!api) return { @@ -19,7 +20,7 @@ export const getIdealStakedPercentage = async (): Promise => { return { value1: idealStakePercentage, }; - } catch (e: any) { + } catch (e) { console.error(e); return { diff --git a/apps/tangle-dapp/data/TopLevelStats/getInflationPercentage.ts b/apps/tangle-dapp/data/TopLevelStats/getInflationPercentage.ts index f51c4047f6..423be9cae7 100644 --- a/apps/tangle-dapp/data/TopLevelStats/getInflationPercentage.ts +++ b/apps/tangle-dapp/data/TopLevelStats/getInflationPercentage.ts @@ -1,10 +1,11 @@ -import { getPolkadotApi } from '../../constants'; import { BN_ZERO } from '@polkadot/util'; -import { calculateInflation } from '../../utils'; + +import { getPolkadotApiPromise } from '../../constants'; import { MetricReturnType } from '../../types'; +import { calculateInflation } from '../../utils'; export const getInflationPercentage = async (): Promise => { - const api = await getPolkadotApi(); + const api = await getPolkadotApiPromise(); if (!api) return { @@ -19,7 +20,7 @@ export const getInflationPercentage = async (): Promise => { return { value1: inflationPercentage, }; - } catch (e: any) { + } catch (e) { console.error(e); return { diff --git a/apps/tangle-dapp/data/TopLevelStats/getValidatorsCount.ts b/apps/tangle-dapp/data/TopLevelStats/getValidatorsCount.ts index 73bb04b38a..44ae21a611 100644 --- a/apps/tangle-dapp/data/TopLevelStats/getValidatorsCount.ts +++ b/apps/tangle-dapp/data/TopLevelStats/getValidatorsCount.ts @@ -1,8 +1,8 @@ -import { getPolkadotApi } from '../../constants'; +import { getPolkadotApiPromise } from '../../constants'; import { MetricReturnType } from '../../types'; export const getValidatorsCount = async (): Promise => { - const api = await getPolkadotApi(); + const api = await getPolkadotApiPromise(); if (!api) return { @@ -19,9 +19,9 @@ export const getValidatorsCount = async (): Promise => { return { value1: activeValidatorsCount, - value2: Number(totalValidatorsCount.toString()), + value2: totalValidatorsCount.toNumber(), }; - } catch (e: any) { + } catch (e) { console.error(e); return { diff --git a/apps/tangle-dapp/data/TopLevelStats/getWaitingCount.ts b/apps/tangle-dapp/data/TopLevelStats/getWaitingCount.ts index a42bc17008..a5177a6c99 100644 --- a/apps/tangle-dapp/data/TopLevelStats/getWaitingCount.ts +++ b/apps/tangle-dapp/data/TopLevelStats/getWaitingCount.ts @@ -1,8 +1,8 @@ -import { getPolkadotApi } from '../../constants'; +import { getPolkadotApiPromise } from '../../constants'; import { MetricReturnType } from '../../types'; export const getWaitingCount = async (): Promise => { - const api = await getPolkadotApi(); + const api = await getPolkadotApiPromise(); if (!api) return { @@ -13,9 +13,9 @@ export const getWaitingCount = async (): Promise => { const waitingInfo = await api.derive.staking.waitingInfo(); return { - value1: Number(waitingInfo.waiting.length.toString()), + value1: waitingInfo.waiting.length, }; - } catch (e: any) { + } catch (e) { console.error(e); return { diff --git a/apps/tangle-dapp/data/TopLevelStats/index.ts b/apps/tangle-dapp/data/TopLevelStats/index.ts index 19202ff420..6496cb52c4 100644 --- a/apps/tangle-dapp/data/TopLevelStats/index.ts +++ b/apps/tangle-dapp/data/TopLevelStats/index.ts @@ -1,5 +1,8 @@ -export * from './getValidatorsCount'; export * from './getActiveAndDelegationCount'; -export * from './getWaitingCount'; export * from './getIdealStakedPercentage'; export * from './getInflationPercentage'; +export * from './getValidatorsCount'; +export * from './getWaitingCount'; +export { default as useActiveAndDelegationCountSubscription } from './useActiveAndDelegationCountSubscription'; +export { default as useValidatorsCountSubscription } from './useValidatorsCountSubscription'; +export { default as useWaitingCountSubscription } from './useWaitingCountSubscription'; diff --git a/apps/tangle-dapp/data/TopLevelStats/useActiveAndDelegationCountSubscription.ts b/apps/tangle-dapp/data/TopLevelStats/useActiveAndDelegationCountSubscription.ts new file mode 100644 index 0000000000..c0097101e9 --- /dev/null +++ b/apps/tangle-dapp/data/TopLevelStats/useActiveAndDelegationCountSubscription.ts @@ -0,0 +1,78 @@ +'use client'; + +import { useEffect, useState } from 'react'; +import { firstValueFrom, type Subscription } from 'rxjs'; + +import { getPolkadotApiRx } from '../../constants/polkadot'; +import { MetricReturnType } from '../../types'; + +function useActiveAndDelegationCountSubscription( + defaultValue: MetricReturnType = {} +): MetricReturnType { + const [value1, setValue1] = useState(defaultValue.value1); + const [value2, setValue2] = useState(defaultValue.value2); + + useEffect(() => { + let isMounted = true; + let sub: Subscription | null = null; + + const apiRx = getPolkadotApiRx(); + + apiRx.then((api) => { + if (!api) { + return; + } + + sub = api.query.session.validators().subscribe(async (validators) => { + try { + const [totalNominator, activeEraRes] = await Promise.all([ + firstValueFrom(api.query.staking.counterForNominators()), + firstValueFrom(api.query.staking.activeEra()), + ] as const); + + const activeEra = activeEraRes.unwrapOr(null); + if (activeEra == null) { + console.warn('activeEra is null'); + return; + } + + const currentEra = activeEra.index; + + // Collection of unique nominator addresses - Set is used to avoid duplicates, as a nominator can nominate multiple validators + const activeNominators = new Set(); + + for (const validator of validators) { + const exposure = await firstValueFrom( + api.query.staking.erasStakers(currentEra, validator) + ); + + exposure.others.forEach((nominator) => { + activeNominators.add(nominator.who.toString()); + }); + } + + if (!isMounted) { + return; + } + + setValue1(activeNominators.size); + setValue2(totalNominator.toNumber()); + } catch (error) { + console.error(error); + } + }); + }); + + return () => { + isMounted = false; + sub?.unsubscribe(); + }; + }, []); + + return { + value1, + value2, + }; +} + +export default useActiveAndDelegationCountSubscription; diff --git a/apps/tangle-dapp/data/TopLevelStats/useValidatorsCountSubscription.ts b/apps/tangle-dapp/data/TopLevelStats/useValidatorsCountSubscription.ts new file mode 100644 index 0000000000..0fb5312542 --- /dev/null +++ b/apps/tangle-dapp/data/TopLevelStats/useValidatorsCountSubscription.ts @@ -0,0 +1,55 @@ +'use client'; + +import { useEffect, useState } from 'react'; +import { firstValueFrom, type Subscription } from 'rxjs'; + +import { getPolkadotApiRx } from '../../constants/polkadot'; +import { MetricReturnType } from '../../types'; + +function useValidatorCountSubscription( + defaultValue: MetricReturnType = {} +): MetricReturnType { + const [value1, setValue1] = useState(defaultValue.value1); + const [value2, setValue2] = useState(defaultValue.value2); + + useEffect(() => { + let isMounted = true; + let sub: Subscription | null = null; + + const apiRx = getPolkadotApiRx(); + + apiRx.then((api) => { + if (!api) { + return; + } + + sub = api.query.session.validators().subscribe(async (validators) => { + try { + const overview = await firstValueFrom(api.derive.staking.overview()); + const totalValidatorsCount = overview.validatorCount; + + if (!isMounted) { + return; + } + + setValue1(validators.length); + setValue2(totalValidatorsCount.toNumber()); + } catch (error) { + console.error(error); + } + }); + }); + + return () => { + isMounted = false; + sub?.unsubscribe(); + }; + }, []); + + return { + value1, + value2, + }; +} + +export default useValidatorCountSubscription; diff --git a/apps/tangle-dapp/data/TopLevelStats/useWaitingCountSubscription.ts b/apps/tangle-dapp/data/TopLevelStats/useWaitingCountSubscription.ts new file mode 100644 index 0000000000..d00248eb35 --- /dev/null +++ b/apps/tangle-dapp/data/TopLevelStats/useWaitingCountSubscription.ts @@ -0,0 +1,45 @@ +'use client'; + +import { useEffect, useState } from 'react'; +import { type Subscription } from 'rxjs'; + +import { getPolkadotApiRx } from '../../constants/polkadot'; +import { MetricReturnType } from '../../types'; + +function useWaitingCountSubscription( + defaultValue: MetricReturnType = {} +): MetricReturnType { + const [value1, setValue1] = useState(defaultValue.value1); + + useEffect(() => { + let isMounted = true; + let sub: Subscription | null = null; + + const apiRx = getPolkadotApiRx(); + + apiRx.then((api) => { + if (!api) { + return; + } + + sub = api.derive.staking.waitingInfo().subscribe((waitingInfo) => { + if (!isMounted) { + return; + } + + setValue1(waitingInfo.waiting.length); + }); + }); + + return () => { + isMounted = false; + sub?.unsubscribe(); + }; + }, []); + + return { + value1, + }; +} + +export default useWaitingCountSubscription; diff --git a/apps/tangle-dapp/next.config.js b/apps/tangle-dapp/next.config.js index 33a52c6887..8289d06f2f 100644 --- a/apps/tangle-dapp/next.config.js +++ b/apps/tangle-dapp/next.config.js @@ -9,6 +9,8 @@ const nextConfigBase = require('../../next.config.js'); const nextConfig = { ...nextConfigBase, + reactStrictMode: true, + // at default environment variable is only accessible by the server, resulting in hydration mismatch // make environment variable accessible by both the server and client env: {}, diff --git a/apps/tangle-dapp/public/favicon.ico b/apps/tangle-dapp/public/favicon.ico deleted file mode 100644 index 317ebcb233..0000000000 Binary files a/apps/tangle-dapp/public/favicon.ico and /dev/null differ diff --git a/apps/tangle-dapp/public/favicon.png b/apps/tangle-dapp/public/favicon.png new file mode 100644 index 0000000000..055e8634fd Binary files /dev/null and b/apps/tangle-dapp/public/favicon.png differ diff --git a/apps/tangle-dapp/tsconfig.json b/apps/tangle-dapp/tsconfig.json index ed471941f8..5357d0b7ee 100644 --- a/apps/tangle-dapp/tsconfig.json +++ b/apps/tangle-dapp/tsconfig.json @@ -6,6 +6,8 @@ "esModuleInterop": true, "allowSyntheticDefaultImports": true, "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, "forceConsistentCasingInFileNames": true, "noEmit": true, "resolveJsonModule": true, diff --git a/apps/tangle-dapp/utils/calculateInflation.ts b/apps/tangle-dapp/utils/calculateInflation.ts index 208d6cfc35..3c7710ae59 100644 --- a/apps/tangle-dapp/utils/calculateInflation.ts +++ b/apps/tangle-dapp/utils/calculateInflation.ts @@ -1,6 +1,6 @@ import { ApiPromise } from '@polkadot/api'; -import { BN, BN_MILLION } from '@polkadot/util'; import { getInflationParams } from '@polkadot/apps-config'; +import { BN, BN_MILLION } from '@polkadot/util'; // Source - https://github.com/polkadot-js/apps/blob/80759592b9f01996e67175e5dd4bdd89b58322ad/packages/react-hooks/src/useInflation.ts#L19C50-L19C50 export const calculateInflation = ( diff --git a/apps/tangle-dapp/utils/getRoundedDownNumberWith2Decimals.ts b/apps/tangle-dapp/utils/getRoundedDownNumberWith2Decimals.ts index 0ee668d562..3cf9d628a9 100644 --- a/apps/tangle-dapp/utils/getRoundedDownNumberWith2Decimals.ts +++ b/apps/tangle-dapp/utils/getRoundedDownNumberWith2Decimals.ts @@ -1,10 +1,10 @@ import { getRoundedAmountString } from '@webb-tools/webb-ui-components/utils'; -export const getRoundedDownNumberWith2Decimals: ( - number: number | undefined -) => string = (number: number | undefined) => { +const getRoundedDownNumberWith2Decimals = (number: number | undefined) => { return getRoundedAmountString(number, 2, { roundingFunction: Math.floor, totalLength: 0, }); }; + +export default getRoundedDownNumberWith2Decimals; diff --git a/apps/tangle-dapp/utils/index.ts b/apps/tangle-dapp/utils/index.ts index 1d9aaba742..55d5636dd7 100644 --- a/apps/tangle-dapp/utils/index.ts +++ b/apps/tangle-dapp/utils/index.ts @@ -1,2 +1,2 @@ export * from './calculateInflation'; -export * from './getRoundedDownNumberWith2Decimals'; +export { default as getRoundedDownNumberWith2Decimals } from './getRoundedDownNumberWith2Decimals'; diff --git a/libs/dapp-config/src/on-chain-config/substrate/on-chain-config.ts b/libs/dapp-config/src/on-chain-config/substrate/on-chain-config.ts index 12ba3f7683..79214759de 100644 --- a/libs/dapp-config/src/on-chain-config/substrate/on-chain-config.ts +++ b/libs/dapp-config/src/on-chain-config/substrate/on-chain-config.ts @@ -1,30 +1,26 @@ import '@webb-tools/protocol-substrate-types'; +import '@webb-tools/tangle-substrate-types'; -import { ApiPromise } from '@polkadot/api'; -import { Option } from '@polkadot/types'; +import type { ApiPromise } from '@polkadot/api'; +import type { Option } from '@polkadot/types'; import { PalletAssetRegistryAssetDetails, PalletAssetRegistryAssetMetadata, } from '@polkadot/types/lookup'; import { ChainType, parseTypedChainId } from '@webb-tools/sdk-core'; - -import { ChainAddressConfig } from '../../anchors'; +import type { ChainAddressConfig } from '../../anchors'; import { chainsConfig } from '../../chains'; import { DEFAULT_DECIMALS, DEFAULT_NATIVE_INDEX } from '../../constants'; import { CurrencyConfig } from '../../currencies'; -import { ICurrency } from '../../types'; -import { CurrencyResponse, OnChainConfigBase } from '../on-chain-config-base'; +import type { ICurrency } from '../../types'; +import { + OnChainConfigBase, + type CurrencyResponse, +} from '../on-chain-config-base'; // the singleton instance of the EVM on-chain config with lazy initialization let SubstrateOnChainConfigInstance: SubstrateOnChainConfig; -// Cache the currencies config -let cachedCurrenciesConfig: { - currenciesConfig: Record; - fungibleToWrappableMap: Map>>; - anchorConfig: Record; -}; - export class SubstrateOnChainConfig extends OnChainConfigBase { private constructor() { super(); @@ -338,7 +334,7 @@ export class SubstrateOnChainConfig extends OnChainConfigBase { existedFungibleToWrappableMap, existedAnchorConfig ); - cachedCurrenciesConfig = config; + return config; } } diff --git a/libs/polkadot-api-provider/src/ext-provider/polkadot-provider.ts b/libs/polkadot-api-provider/src/ext-provider/polkadot-provider.ts index 08908c4b79..6d4aaf861a 100644 --- a/libs/polkadot-api-provider/src/ext-provider/polkadot-provider.ts +++ b/libs/polkadot-api-provider/src/ext-provider/polkadot-provider.ts @@ -2,7 +2,7 @@ // SPDX-License-Identifier: Apache-2.0 /* eslint-disable @typescript-eslint/ban-ts-comment */ -import '@webb-tools/protocol-substrate-types'; +import '@webb-tools/tangle-substrate-types'; import { ApiPromise, WsProvider } from '@polkadot/api'; import { diff --git a/libs/polkadot-api-provider/src/mt-utils.ts b/libs/polkadot-api-provider/src/mt-utils.ts index 9616758045..bb4cd085f9 100644 --- a/libs/polkadot-api-provider/src/mt-utils.ts +++ b/libs/polkadot-api-provider/src/mt-utils.ts @@ -1,7 +1,4 @@ -import '@webb-tools/protocol-substrate-types'; - import { Note } from '@webb-tools/sdk-core'; - import { ApiPromise } from '@polkadot/api'; import { hexToU8a, u8aToHex } from '@polkadot/util'; diff --git a/libs/polkadot-api-provider/src/webb-provider.ts b/libs/polkadot-api-provider/src/webb-provider.ts index 2c33cf7b1b..5c3da4fd03 100644 --- a/libs/polkadot-api-provider/src/webb-provider.ts +++ b/libs/polkadot-api-provider/src/webb-provider.ts @@ -1,7 +1,7 @@ // Copyright 2022 @webb-tools/ // SPDX-License-Identifier: Apache-2.0 import '@webb-tools/api-derive'; -import '@webb-tools/protocol-substrate-types'; +import '@webb-tools/tangle-substrate-types'; import { ApiInitHandler, diff --git a/libs/polkadot-api-provider/src/webb-provider/bridge-api.ts b/libs/polkadot-api-provider/src/webb-provider/bridge-api.ts index 9d2563355b..c059fc785d 100644 --- a/libs/polkadot-api-provider/src/webb-provider/bridge-api.ts +++ b/libs/polkadot-api-provider/src/webb-provider/bridge-api.ts @@ -2,7 +2,7 @@ // Copyright 2022 @webb-tools/ // SPDX-License-Identifier: Apache-2.0 -import '@webb-tools/protocol-substrate-types'; +import '@webb-tools/tangle-substrate-types'; import { Currency } from '@webb-tools/abstract-api-provider'; import { BridgeApi } from '@webb-tools/abstract-api-provider'; diff --git a/libs/polkadot-api-provider/src/webb-provider/crowdloan.ts b/libs/polkadot-api-provider/src/webb-provider/crowdloan.ts index 4be49b686a..014eca1b3f 100644 --- a/libs/polkadot-api-provider/src/webb-provider/crowdloan.ts +++ b/libs/polkadot-api-provider/src/webb-provider/crowdloan.ts @@ -9,7 +9,7 @@ import { CrowdloanFundInfo, } from '@webb-tools/abstract-api-provider/crowdloan'; import { WebbError, WebbErrorCodes } from '@webb-tools/dapp-types/WebbError'; -import '@webb-tools/protocol-substrate-types'; +import '@webb-tools/tangle-substrate-types'; import { LoggerService } from '@webb-tools/app-util'; diff --git a/libs/polkadot-api-provider/src/webb-provider/ecdsa-claims.ts b/libs/polkadot-api-provider/src/webb-provider/ecdsa-claims.ts index 164ed7d554..929ac04f2c 100644 --- a/libs/polkadot-api-provider/src/webb-provider/ecdsa-claims.ts +++ b/libs/polkadot-api-provider/src/webb-provider/ecdsa-claims.ts @@ -1,4 +1,4 @@ -import '@webb-tools/protocol-substrate-types'; +import '@webb-tools/tangle-substrate-types'; import { ECDSAClaims } from '@webb-tools/abstract-api-provider/ecdsa-claims'; import { WebbError, WebbErrorCodes } from '@webb-tools/dapp-types/WebbError'; diff --git a/libs/polkadot-api-provider/src/webb-provider/wrap-unwrap.ts b/libs/polkadot-api-provider/src/webb-provider/wrap-unwrap.ts index 96ec56fb5f..cc4927ea6e 100644 --- a/libs/polkadot-api-provider/src/webb-provider/wrap-unwrap.ts +++ b/libs/polkadot-api-provider/src/webb-provider/wrap-unwrap.ts @@ -2,7 +2,7 @@ // SPDX-License-Identifier: Apache-2.0 import '@webb-tools/api-derive'; -import '@webb-tools/protocol-substrate-types'; +import '@webb-tools/tangle-substrate-types'; import { Amount, diff --git a/libs/react-hooks/src/types.ts b/libs/react-hooks/src/types.ts index 878e8ef7e8..094ee87923 100644 --- a/libs/react-hooks/src/types.ts +++ b/libs/react-hooks/src/types.ts @@ -6,11 +6,7 @@ // TODO: Resolve the below issue with new types package. // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-ignore -import { - AccountId, - CurrencyId, - // @ts-ignore -} from '@webb-tools/protocol-substrate-types/interfaces'; +import { AccountId, CurrencyId } from '@webb-tools/tangle-substrate-types'; export type CallParam = any; diff --git a/libs/webb-ui-components/src/components/Accordion/AccordionItem.tsx b/libs/webb-ui-components/src/components/Accordion/AccordionItem.tsx index adc7015e23..2e36314555 100644 --- a/libs/webb-ui-components/src/components/Accordion/AccordionItem.tsx +++ b/libs/webb-ui-components/src/components/Accordion/AccordionItem.tsx @@ -2,7 +2,7 @@ import * as AccordionPrimitive from '@radix-ui/react-accordion'; import { forwardRef } from 'react'; import { twMerge } from 'tailwind-merge'; -import { AccordionContentProps, AccordionItemProps } from './types'; +import { AccordionItemProps } from './types'; /** * The style wrapper around Radix Accordion, must use inside `` tag diff --git a/libs/webb-ui-components/src/components/AvatarGroup/AvatarGroup.tsx b/libs/webb-ui-components/src/components/AvatarGroup/AvatarGroup.tsx index 0e4e5557ab..bf694d2d55 100644 --- a/libs/webb-ui-components/src/components/AvatarGroup/AvatarGroup.tsx +++ b/libs/webb-ui-components/src/components/AvatarGroup/AvatarGroup.tsx @@ -48,6 +48,7 @@ export const AvatarGroup = forwardRef(
{children.slice(0, max).map((child, index) => { return React.cloneElement(child, { + key: index, ...child.props, size: 'md', className: 'mx-[-4px] last:mx-0', diff --git a/libs/webb-ui-components/src/components/Banner/Banner.tsx b/libs/webb-ui-components/src/components/Banner/Banner.tsx index 43376623bd..45fb57583d 100644 --- a/libs/webb-ui-components/src/components/Banner/Banner.tsx +++ b/libs/webb-ui-components/src/components/Banner/Banner.tsx @@ -27,7 +27,6 @@ export const Banner = React.forwardRef( buttonText, buttonProps, buttonClassName: buttonClassNameProp, - children, className: bannerClassNameProp, dappName, bannerText, diff --git a/libs/webb-ui-components/src/components/BridgeInputs/ShieldedAssetInput.tsx b/libs/webb-ui-components/src/components/BridgeInputs/ShieldedAssetInput.tsx index 904e9cc5c8..0f8b38190d 100644 --- a/libs/webb-ui-components/src/components/BridgeInputs/ShieldedAssetInput.tsx +++ b/libs/webb-ui-components/src/components/BridgeInputs/ShieldedAssetInput.tsx @@ -1,5 +1,5 @@ import { getRoundedAmountString } from '../../utils'; -import { ChevronRight, TokenIcon } from '@webb-tools/icons'; +import { ChevronRight } from '@webb-tools/icons'; import { Typography } from '../../typography'; import cx from 'classnames'; import { forwardRef, useMemo } from 'react'; diff --git a/libs/webb-ui-components/src/components/CopyWithTooltip/CopyWithTooltip.tsx b/libs/webb-ui-components/src/components/CopyWithTooltip/CopyWithTooltip.tsx index 83f9ca1a1b..9dc504fe35 100644 --- a/libs/webb-ui-components/src/components/CopyWithTooltip/CopyWithTooltip.tsx +++ b/libs/webb-ui-components/src/components/CopyWithTooltip/CopyWithTooltip.tsx @@ -1,5 +1,5 @@ import { FileCopyLine } from '@webb-tools/icons'; -import { useCallback, useState } from 'react'; +import { useState } from 'react'; import { twMerge } from 'tailwind-merge'; import { useCopyable } from '../../hooks'; diff --git a/libs/webb-ui-components/src/components/FeeDetails/FeeDetails.tsx b/libs/webb-ui-components/src/components/FeeDetails/FeeDetails.tsx index b20ad7baed..b3297434fa 100644 --- a/libs/webb-ui-components/src/components/FeeDetails/FeeDetails.tsx +++ b/libs/webb-ui-components/src/components/FeeDetails/FeeDetails.tsx @@ -4,7 +4,7 @@ import { TokenIcon, } from '@webb-tools/icons'; import cx from 'classnames'; -import { cloneElement, forwardRef, useEffect } from 'react'; +import { cloneElement, forwardRef } from 'react'; import { twMerge } from 'tailwind-merge'; import { Typography } from '../../typography/Typography'; import numberToString from '../../utils/numberToString'; diff --git a/libs/webb-ui-components/src/components/Input/types.ts b/libs/webb-ui-components/src/components/Input/types.ts index 881180cd7e..28d84d576b 100644 --- a/libs/webb-ui-components/src/components/Input/types.ts +++ b/libs/webb-ui-components/src/components/Input/types.ts @@ -1,5 +1,4 @@ -import { PropsOf, IWebbComponentBase } from '../../types'; -import { EventHandler } from 'react'; +import { IWebbComponentBase, PropsOf } from '../../types'; type OmittedKeys = 'disabled' | 'required' | 'readOnly' | 'size' | 'onChange'; diff --git a/libs/webb-ui-components/src/components/KeyCard/KeyCard.tsx b/libs/webb-ui-components/src/components/KeyCard/KeyCard.tsx index 4de55aeaf1..8dd07a8f82 100644 --- a/libs/webb-ui-components/src/components/KeyCard/KeyCard.tsx +++ b/libs/webb-ui-components/src/components/KeyCard/KeyCard.tsx @@ -1,8 +1,7 @@ -import { Typography } from '../../typography'; -import React, { forwardRef, useMemo } from 'react'; +import { forwardRef, useMemo } from 'react'; import { twMerge } from 'tailwind-merge'; +import { Typography } from '../../typography'; -import { Button } from '../buttons'; import { CopyWithTooltip } from '../CopyWithTooltip'; import { KeyCardProps } from './types'; diff --git a/libs/webb-ui-components/src/components/ListCard/RelayerListCard.tsx b/libs/webb-ui-components/src/components/ListCard/RelayerListCard.tsx index b112d6fb4b..3f003e2c85 100644 --- a/libs/webb-ui-components/src/components/ListCard/RelayerListCard.tsx +++ b/libs/webb-ui-components/src/components/ListCard/RelayerListCard.tsx @@ -1,9 +1,10 @@ import { ExternalLinkLine, Search } from '@webb-tools/icons'; import cx from 'classnames'; -import { forwardRef, useCallback, useEffect, useMemo, useState } from 'react'; +import { forwardRef, useMemo } from 'react'; import { Typography } from '../../typography'; import { shortenString } from '../../utils'; +import { getFlexBasic } from '@webb-tools/icons/utils'; import { Avatar } from '../Avatar'; import { Input } from '../Input'; import { RadioGroup, RadioItem } from '../Radio'; @@ -12,7 +13,6 @@ import { Button } from '../buttons'; import { ListCardWrapper } from './ListCardWrapper'; import { ListItem } from './ListItem'; import { RelayerListCardProps } from './types'; -import { getFlexBasic } from '@webb-tools/icons/utils'; /** * The relayer list card component diff --git a/libs/webb-ui-components/src/components/Notification/NotificationContext.tsx b/libs/webb-ui-components/src/components/Notification/NotificationContext.tsx index c9db5300c2..2af3540cf6 100644 --- a/libs/webb-ui-components/src/components/Notification/NotificationContext.tsx +++ b/libs/webb-ui-components/src/components/Notification/NotificationContext.tsx @@ -18,12 +18,13 @@ export type NotificationContextProps = { remove(key: SnackbarKey): void; }; -export const NotificationCTXDefaultValue = { - addToQueue(opts: Omit): SnackbarKey { +export const NotificationCTXDefaultValue: NotificationContextProps = { + addToQueue(): SnackbarKey { return 0; }, - // eslint-disable-next-line @typescript-eslint/no-empty-function - remove(key: SnackbarKey) {}, -}; + remove() { + // do nothing + }, +} as const satisfies NotificationContextProps; export const NotificationContext = React.createContext(NotificationCTXDefaultValue); diff --git a/libs/webb-ui-components/src/components/SideBar/SideBar.tsx b/libs/webb-ui-components/src/components/SideBar/SideBar.tsx index 315687a299..78c93316f8 100644 --- a/libs/webb-ui-components/src/components/SideBar/SideBar.tsx +++ b/libs/webb-ui-components/src/components/SideBar/SideBar.tsx @@ -1,14 +1,14 @@ 'use client'; -import { WebbLogoIcon, TangleIcon } from '@webb-tools/icons'; +import { TangleIcon, WebbLogoIcon } from '@webb-tools/icons'; import cx from 'classnames'; -import { FC, forwardRef, useState } from 'react'; +import { FC, forwardRef } from 'react'; import { twMerge } from 'tailwind-merge'; import useLocalStorageState from 'use-local-storage-state'; import { SideBarFooter, SideBarItems, SideBarLogo } from '.'; +import { SIDEBAR_OPEN_KEY } from '../../constants'; import { LogoProps } from '../Logo/types'; import { SidebarProps } from './types'; -import { SIDEBAR_OPEN_KEY } from '../../constants'; /** * Sidebar Navigation Menu Component @@ -50,13 +50,9 @@ export const SideBar = forwardRef( } ); - const [isHovering, setIsHovering] = useState(false); - return (
setIsHovering(true)} - onMouseLeave={() => setIsHovering(false)} {...props} ref={ref} > diff --git a/libs/webb-ui-components/src/components/Slider/Slider.tsx b/libs/webb-ui-components/src/components/Slider/Slider.tsx index 6f2a0f489a..dbc5a58a0d 100644 --- a/libs/webb-ui-components/src/components/Slider/Slider.tsx +++ b/libs/webb-ui-components/src/components/Slider/Slider.tsx @@ -1,6 +1,6 @@ import * as SliderPrimitive from '@radix-ui/react-slider'; import cx from 'classnames'; -import React, { useCallback, useEffect, useMemo, useState } from 'react'; +import React, { useCallback, useEffect, useState } from 'react'; import { twMerge } from 'tailwind-merge'; import { SliderProps, SliderThumbProps } from './types'; diff --git a/libs/webb-ui-components/src/components/Tooltip/Tooltip.tsx b/libs/webb-ui-components/src/components/Tooltip/Tooltip.tsx index be9fab0245..3b28d38d7e 100644 --- a/libs/webb-ui-components/src/components/Tooltip/Tooltip.tsx +++ b/libs/webb-ui-components/src/components/Tooltip/Tooltip.tsx @@ -1,6 +1,5 @@ import * as TooltipPrimitive from '@radix-ui/react-tooltip'; import cx from 'classnames'; -import { cloneElement, useMemo } from 'react'; import { twMerge } from 'tailwind-merge'; import { TooltipBodyProps, TooltipProps, TooltipTriggerProps } from './types'; diff --git a/libs/webb-ui-components/src/components/WebsiteFooter/WebsiteFooter.tsx b/libs/webb-ui-components/src/components/WebsiteFooter/WebsiteFooter.tsx index f88eac652a..df569aac0b 100644 --- a/libs/webb-ui-components/src/components/WebsiteFooter/WebsiteFooter.tsx +++ b/libs/webb-ui-components/src/components/WebsiteFooter/WebsiteFooter.tsx @@ -1,22 +1,13 @@ -import { - Common2Icon, - DiscordFill, - GithubFill, - LinkedInFill, - TelegramFill, - TwitterFill, - YouTubeFill, -} from '@webb-tools/icons'; import { IconBase } from '@webb-tools/icons/types'; +import capitalize from 'lodash/capitalize'; import Link from 'next/link'; import { ComponentProps, useState } from 'react'; -import capitalize from 'lodash/capitalize'; import { BRIDGE_URL, + DKG_STATS_URL, SOCIAL_ICONS_RECORD, SOCIAL_URLS_RECORD, - DKG_STATS_URL, TANGLE_MKT_URL, WEBB_AVAIABLE_SOCIALS, WEBB_CAREERS_URL, diff --git a/libs/webb-ui-components/src/containers/ConfirmationCard/DepositConfirm.tsx b/libs/webb-ui-components/src/containers/ConfirmationCard/DepositConfirm.tsx index ab956e76f1..1577b1fb09 100644 --- a/libs/webb-ui-components/src/containers/ConfirmationCard/DepositConfirm.tsx +++ b/libs/webb-ui-components/src/containers/ConfirmationCard/DepositConfirm.tsx @@ -57,18 +57,6 @@ export const DepositConfirm = forwardRef( return `${formatedAmount} ${symbolStr}`; }, [amount, fungibleTokenSymbol, wrappableTokenSymbol]); - const feeContent = useMemo(() => { - if (typeof fee === 'number' || typeof fee === 'string') { - const formatedFee = - typeof fee === 'number' - ? getRoundedAmountString(fee, 3, { roundingFunction: Math.round }) - : fee; - return `${formatedFee} ${feeToken ?? ''}`; - } - - return '--'; - }, [fee, feeToken]); - return (
( ref ) => { const { isMobile } = useCheckMobile(); - const { amount, fee } = useMemo(() => { + const { amount } = useMemo(() => { const amount = !amountInputProps.amount ? '--' : `${getRoundedAmountString(Number(amountInputProps.amount), 3, { @@ -71,7 +70,7 @@ export const DepositCard = forwardRef( -
+
( )}
-
+