Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

refactor: handle account icon's tooltip translations #1607

Merged
merged 5 commits into from
Oct 26, 2024
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
44 changes: 26 additions & 18 deletions packages/extension-polkagate/src/components/AccountIcons.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,43 +3,48 @@

/* eslint-disable react/jsx-max-props-per-line */

import type { Chain } from '@polkadot/extension-chains/types';
import type { IconTheme } from '@polkadot/react-identicon/types';
import type { Proxy } from '../util/types';

import { faShieldHalved, faSitemap } from '@fortawesome/free-solid-svg-icons';
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import { Grid, IconButton, useTheme } from '@mui/material';
import React, { useCallback, useContext } from 'react';
import React, { useCallback, useContext, useEffect,useState } from 'react';

import { useAnimateOnce, useTranslation } from '../hooks';
import { useAnimateOnce, useHasProxyTooltipText, useInfo, useIsRecoverableTooltipText, useProxies } from '../hooks';
import { windowOpen } from '../messaging';
import { PROXY_CHAINS } from '../util/constants';
import { getSubstrateAddress } from '../util/utils';
import { ActionContext } from './contexts';
import Identicon from './Identicon';
import { Infotip } from '.';

interface Props {
chain: Chain | null | undefined;
formatted: string | undefined;
address: string | undefined;
identiconTheme: IconTheme;
isSubId: boolean;
judgements?: RegExpMatchArray | null | undefined;
prefix?: number;
proxies: Proxy[] | undefined;
recoverable?: boolean;
}

export default function AccountIcons ({ chain, formatted, identiconTheme, isSubId, judgements, prefix, proxies, recoverable = false }: Props): React.ReactElement<Props> {
function AccountIcons ({ address, identiconTheme, isSubId, judgements, prefix }: Props): React.ReactElement<Props> {
Nick-1979 marked this conversation as resolved.
Show resolved Hide resolved
const theme = useTheme();
const { t } = useTranslation();
const onAction = useContext(ActionContext);

const address = getSubstrateAddress(formatted);
const { api, chain, formatted } = useInfo(address);
const proxies = useProxies(api, formatted);

const shakeProxy = useAnimateOnce(!!proxies?.length);
const shakeShield = useAnimateOnce(recoverable);

const [isRecoverable, setRecoverable] = useState<boolean | undefined>();

const shakeShield = useAnimateOnce(isRecoverable);
const recoverableToolTipTxt = useIsRecoverableTooltipText(address, isRecoverable);
const hasProxy = proxies ? !!proxies.length : undefined;
const proxyTooltipTxt = useHasProxyTooltipText(address, hasProxy);

useEffect((): void => {
api?.query?.['recovery']?.['recoverable'](formatted)
.then((r: any) => setRecoverable(!!r.isSome)).catch(console.error);
}, [api, formatted]);
Nick-1979 marked this conversation as resolved.
Show resolved Hide resolved

const openManageProxy = useCallback(() => {
address && chain && PROXY_CHAINS.includes(chain.genesisHash ?? '') && onAction(`/manageProxies/${address}`);
Expand All @@ -50,7 +55,7 @@ export default function AccountIcons ({ chain, formatted, identiconTheme, isSubI
}, [address]);

return (
<Grid container direction='column' sx={{ width: '17%', ml: '8px' }}>
<Grid container direction='column' sx={{ ml: '8px', width: '17%' }}>
<Grid item m='auto' width='fit-content'>
<Identicon
iconTheme={identiconTheme}
Expand All @@ -63,12 +68,13 @@ export default function AccountIcons ({ chain, formatted, identiconTheme, isSubI
</Grid>
<Grid container direction='row' item justifyContent='center'>
<Grid item>
<Infotip placement='bottom-start' text={t('Is recoverable')}>
<Infotip placement='bottom-start' text={recoverableToolTipTxt}>
<IconButton
onClick={openSocialRecovery}
sx={{ height: '15px', width: '15px' }}>
sx={{ height: '15px', width: '15px' }}
>
<FontAwesomeIcon
color={recoverable ? theme.palette.success.main : theme.palette.action.disabledBackground}
color={isRecoverable ? theme.palette.success.main : theme.palette.action.disabledBackground}
fontSize='13px'
icon={faShieldHalved}
shake={shakeShield}
Expand All @@ -77,7 +83,7 @@ export default function AccountIcons ({ chain, formatted, identiconTheme, isSubI
</Infotip>
</Grid>
<Grid item>
<Infotip placement='bottom-end' text={t('Has proxy')}>
<Infotip placement='bottom-end' text={proxyTooltipTxt}>
<IconButton onClick={openManageProxy} sx={{ height: '15px', width: '15px' }}>
<FontAwesomeIcon
color={proxies?.length ? theme.palette.success.main : theme.palette.action.disabledBackground}
Expand All @@ -92,3 +98,5 @@ export default function AccountIcons ({ chain, formatted, identiconTheme, isSubI
</Grid>
);
}

export default React.memo(AccountIcons);
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,10 @@ import type { Proxy } from '../../../util/types';
import { faChain, faCheckCircle, faCircleInfo, faShieldHalved, faSitemap } from '@fortawesome/free-solid-svg-icons';
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import { Grid, IconButton, useTheme } from '@mui/material';
import React, { useCallback, useContext, useEffect, useMemo, useState } from 'react';
import React, { useCallback, useContext, useEffect, useState } from 'react';

import { ActionContext, Infotip } from '../../../components';
import { useAnimateOnce, useInfo, useTranslation } from '../../../hooks';
import { useAnimateOnce, useHasIdentityTooltipText, useHasProxyTooltipText, useInfo, useIsRecoverableTooltipText } from '../../../hooks';
import { windowOpen } from '../../../messaging';
import { IDENTITY_CHAINS, PROXY_CHAINS, SOCIAL_RECOVERY_CHAINS } from '../../../util/constants';

Expand All @@ -24,8 +24,7 @@ interface AddressDetailsProps {
accountInfo: DeriveAccountInfo | undefined | null
}

function AccountIconsFs ({ accountInfo, address }: AddressDetailsProps): React.ReactElement {
const { t } = useTranslation();
function AccountIconsFs({ accountInfo, address }: AddressDetailsProps): React.ReactElement {
const theme = useTheme();

const onAction = useContext(ActionContext);
Expand All @@ -39,57 +38,16 @@ function AccountIconsFs ({ accountInfo, address }: AddressDetailsProps): React.R
const shakeIdentity = useAnimateOnce(hasID);
const shakeShield = useAnimateOnce(isRecoverable);

const identityToolTipTxt = useMemo(() => {
if (!chain) {
return 'Account is in Any Chain mode';
}

switch (hasID) {
case true:
return 'Has Identity';
case false:
return 'No Identity';
default:
return 'Checking';
}
}, [chain, hasID]);

const recoverableToolTipTxt = useMemo(() => {
if (!chain) {
return 'Account is in Any Chain mode';
}

switch (isRecoverable) {
case true:
return 'Recoverable';
case false:
return 'Not Recoverable';
default:
return 'Checking';
}
}, [chain, isRecoverable]);

const proxyTooltipTxt = useMemo(() => {
if (!chain) {
return 'Account is in Any Chain mode';
}

switch (hasProxy) {
case true:
return 'Has Proxy';
case false:
return 'No Proxy';
default:
return 'Checking';
}
}, [chain, hasProxy]);
const identityToolTipTxt = useHasIdentityTooltipText(address, hasID);
const recoverableToolTipTxt = useIsRecoverableTooltipText(address, isRecoverable);
const proxyTooltipTxt = useHasProxyTooltipText(address, hasProxy);
Nick-1979 marked this conversation as resolved.
Show resolved Hide resolved

useEffect((): void => {
setHasID(undefined);
setIsRecoverable(undefined);
setHasProxy(undefined);

if (!api || !address || !account?.genesisHash || api.genesisHash.toHex() !== account.genesisHash) {
if (!api || !formatted || !account?.genesisHash || api.genesisHash.toHex() !== account.genesisHash) {
Nick-1979 marked this conversation as resolved.
Show resolved Hide resolved
return;
}

Expand Down Expand Up @@ -119,7 +77,7 @@ function AccountIconsFs ({ accountInfo, address }: AddressDetailsProps): React.R
} else {
setHasProxy(false);
}
}, [api, address, formatted, account?.genesisHash, accountInfo]);
}, [api, formatted, account?.genesisHash, accountInfo]);

const openIdentity = useCallback(() => {
address && chain && windowOpen(`/manageIdentity/${address}`).catch(console.error);
Expand All @@ -136,7 +94,7 @@ function AccountIconsFs ({ accountInfo, address }: AddressDetailsProps): React.R
return (
<Grid alignItems='center' container direction='column' display='grid' height='72px' item justifyContent='center' justifyItems='center' width='fit-content'>
<Grid item onClick={openIdentity} sx={{ cursor: 'pointer', height: '24px', m: 'auto', p: '2px', width: 'fit-content' }}>
<Infotip placement='right' text={t(identityToolTipTxt)}>
<Infotip placement='right' text={identityToolTipTxt}>
{hasID
? accountInfo?.identity?.displayParent
? <FontAwesomeIcon
Expand All @@ -157,7 +115,7 @@ function AccountIconsFs ({ accountInfo, address }: AddressDetailsProps): React.R
</Infotip>
</Grid>
<Grid height='24px' item my='1px' width='24px'>
<Infotip placement='right' text={t(recoverableToolTipTxt)}>
<Infotip placement='right' text={recoverableToolTipTxt}>
<IconButton
onClick={openSocialRecovery}
sx={{ height: '24px', width: '24px' }}
Expand All @@ -171,7 +129,7 @@ function AccountIconsFs ({ accountInfo, address }: AddressDetailsProps): React.R
</Infotip>
</Grid>
<Grid height='24px' item width='fit-content'>
<Infotip placement='right' text={t(proxyTooltipTxt)}>
<Infotip placement='right' text={proxyTooltipTxt}>
<IconButton onClick={openManageProxy} sx={{ height: '16px', width: '16px' }}>
<FontAwesomeIcon
icon={faSitemap}
Expand Down
3 changes: 3 additions & 0 deletions packages/extension-polkagate/src/hooks/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -49,12 +49,15 @@ export { useGenericLedger } from './useGenericLedger';
export { default as useGenesisHash } from './useGenesisHash';
export { default as useGenesisHashOptions } from './useGenesisHashOptions';
export { default as useHasDelegated } from './useHasDelegated';
export { default as useHasIdentityTooltipText } from './useHasIdentityTooltipText';
export { default as useHasProxyTooltipText } from './useHasProxyTooltipText';
export { default as useIdentity } from './useIdentity';
export { default as useInfo } from './useInfo';
export { default as useIsExposed } from './useIsExposed';
export { default as useIsExtensionPopup } from './useIsExtensionPopup';
export { default as useIsLoginEnabled } from './useIsLoginEnabled';
export { default as useIsMounted } from './useIsMounted';
export { default as useIsRecoverableTooltipText } from './useIsRecoverableTooltipText';
export { default as useIsTestnetEnabled } from './useIsTestnetEnabled';
export { default as useIsValidator } from './useIsValidator';
export { useLedger } from './useLedger';
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
// Copyright 2019-2024 @polkadot/extension-polkagate authors & contributors
// SPDX-License-Identifier: Apache-2.0

import { useMemo } from 'react';

import { useChain, useTranslation } from '.';

export default function useHasIdentityTooltipText (address: string | undefined, hasID: boolean | undefined): string {
const { t } = useTranslation();

const chain = useChain(address);
const anyChinModeText = t('Account is in Any Chain mode');
Nick-1979 marked this conversation as resolved.
Show resolved Hide resolved

return useMemo(() => {
if (!chain) {
return anyChinModeText;
}

switch (hasID) {
case true:
return t('Has identity');
case false:
return t('No identity');
default:
return t('Checking');
}
}, [anyChinModeText, chain, hasID, t]);
}
28 changes: 28 additions & 0 deletions packages/extension-polkagate/src/hooks/useHasProxyTooltipText.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
// Copyright 2019-2024 @polkadot/extension-polkagate authors & contributors
// SPDX-License-Identifier: Apache-2.0

import { useMemo } from 'react';

import { useChain, useTranslation } from '.';

export default function useHasProxyTooltipText (address: string | undefined, hasProxy: boolean | undefined): string {
const { t } = useTranslation();

const chain = useChain(address);
const anyChinModeText = t('Account is in Any Chain mode');
Nick-1979 marked this conversation as resolved.
Show resolved Hide resolved

return useMemo(() => {
if (!chain) {
return anyChinModeText;
}

switch (hasProxy) {
case true:
return t('Has proxy');
case false:
return t('No proxy');
default:
return t('Checking');
}
}, [anyChinModeText, chain, hasProxy, t]);
Nick-1979 marked this conversation as resolved.
Show resolved Hide resolved
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
// Copyright 2019-2024 @polkadot/extension-polkagate authors & contributors
// SPDX-License-Identifier: Apache-2.0

import { useMemo } from 'react';

import { useChain, useTranslation } from '.';

export default function useIsRecoverableTooltipText (address: string | undefined, isRecoverable: boolean | undefined): string {
const { t } = useTranslation();

const chain = useChain(address);
const anyChinModeText = t('Account is in Any Chain mode');
Nick-1979 marked this conversation as resolved.
Show resolved Hide resolved

return useMemo(() => {
if (!chain) {
return anyChinModeText;
}

switch (isRecoverable) {
case true:
return t('Recoverable');
case false:
return t('Not recoverable');
default:
return t('Checking');
}
}, [anyChinModeText, chain, isRecoverable, t]);
}
17 changes: 3 additions & 14 deletions packages/extension-polkagate/src/popup/home/AccountPreview.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import React, { useCallback, useContext, useEffect, useState } from 'react';
import { ActionContext } from '../../components';
import AccountFeatures from '../../components/AccountFeatures';
import AccountIcons from '../../components/AccountIcons';
import { useInfo, useMyAccountIdentity, useProxies } from '../../hooks';
import { useInfo, useMyAccountIdentity } from '../../hooks';
import useIsExtensionPopup from '../../hooks/useIsExtensionPopup';
import { showAccount } from '../../messaging';
import { AccountMenu } from '../../partials';
Expand All @@ -22,7 +22,6 @@ import AccountDetail from './AccountDetail';
export interface Props {
actions?: React.ReactNode;
address: string;
// children?: React.ReactNode;
isExternal?: boolean | null;
isHardware?: boolean | null;
isHidden?: boolean;
Expand All @@ -38,21 +37,14 @@ export interface Props {

export default function AccountPreview ({ address, hideNumbers, isHidden, name, quickActionOpen, setQuickActionOpen, toggleActions, type }: Props): React.ReactElement<Props> {
const onExtension = useIsExtensionPopup();
const { api, chain, formatted } = useInfo(address);
const { chain, formatted } = useInfo(address);
const onAction = useContext(ActionContext);
const proxies = useProxies(api, formatted);
const identity = useMyAccountIdentity(address);

const [showAccountMenu, setShowAccountMenu] = useState(false);
const [recoverable, setRecoverable] = useState<boolean | undefined>();

const _judgement = identity && JSON.stringify(identity.judgements).match(/reasonable|knownGood/gi);

useEffect((): void => {
api?.query?.['recovery']?.['recoverable'](formatted)
.then((r: any) => setRecoverable(!!r.isSome)).catch(console.error);
}, [api, formatted]);

useEffect((): void => {
setShowAccountMenu(false);
}, [toggleActions]);
Expand Down Expand Up @@ -83,14 +75,11 @@ export default function AccountPreview ({ address, hideNumbers, isHidden, name,
return (
<Grid alignItems='center' container overflow='hidden' p='15px 0 13px' position='relative'>
<AccountIcons
chain={chain}
formatted={formatted || address}
address={address}
identiconTheme={identiconTheme}
isSubId={!!identity?.displayParent}
judgements={_judgement}
prefix={chain?.ss58Format ?? 42}
proxies={proxies}
recoverable={recoverable}
/>
<AccountDetail
address={address}
Expand Down
Loading