Skip to content

feat: sort the already authorized accounts to the bottom of the list to easier auth the unauthorized accounts #1662

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

Merged
merged 5 commits into from
Nov 17, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
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
41 changes: 35 additions & 6 deletions packages/extension-polkagate/src/components/AccountsTable.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,10 @@

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

import type { AccountJson } from '@polkadot/extension-base/background/types';

import { Grid, type SxProps, type Theme, Typography, useTheme } from '@mui/material';
import React, { useCallback, useContext, useMemo } from 'react';
import React, { useCallback, useContext, useMemo, useRef } from 'react';

import { openOrFocusTab } from '../fullscreen/accountDetails/components/CommonTasks';
import { useTranslation } from '../hooks';
Expand All @@ -22,23 +24,48 @@ interface Props {
accountTypeFilter?: AccountTypeFilterType;
selectedAccounts: string[];
setSelectedAccounts: React.Dispatch<React.SetStateAction<string[]>>;
manageConnectedAccounts?: boolean;
}

export default function AccountsTable ({ accountTypeFilter, areAllCheck, label, maxHeight = '112px', selectedAccounts, setSelectedAccounts, style }: Props): React.ReactElement<Props> {
const sortAccounts = (accountA: AccountJson, accountB: AccountJson, selectedList: string[]): number => {
const isASelected = selectedList.includes(accountA.address);
const isBSelected = selectedList.includes(accountB.address);

if (!isASelected && isBSelected) {
return -1;
} else if (isASelected && !isBSelected) {
return 1;
}

return 0;
};

function AccountsTable ({ accountTypeFilter, areAllCheck, label, manageConnectedAccounts, maxHeight = '112px', selectedAccounts, setSelectedAccounts, style }: Props): React.ReactElement<Props> {
const { t } = useTranslation();
const theme = useTheme();
const { accounts } = useContext(AccountContext);

// Sort only on the first render, store result in a ref
const sortedAccountsRef = useRef<AccountJson[] | null>(null);

const accountsToShow = useMemo(() => {
const filtered = accounts.filter(({ isExternal, isHardware, isHidden, isQR }) =>
const filtered = [...accounts].filter(({ isExternal, isHardware, isHidden, isQR }) =>
(accountTypeFilter?.includes('Watch-Only') && !isExternal) ||
(accountTypeFilter?.includes('Hardware') && !isHardware) ||
(accountTypeFilter?.includes('QR') && !isQR) ||
!isHidden
);

return filtered;
}, [accountTypeFilter, accounts]);
// Only sort accounts when:
// 1. We're in manage authorized accounts mode (manageConnectedAccounts is true)
// 2. The accounts haven't been sorted yet (sortedAccountsRef.current is null)
// 3. There are some selected accounts (selectedAccounts.length !== 0)
if (manageConnectedAccounts && !sortedAccountsRef.current && selectedAccounts.length !== 0) {
sortedAccountsRef.current = [...filtered].sort((a, b) => sortAccounts(a, b, selectedAccounts));
}

return filtered; // .sort((a, b) => sortAccounts(a, b, selectedAccounts))
}, [accountTypeFilter, accounts, manageConnectedAccounts, selectedAccounts]);

const onCheck = useCallback((address: string) => {
const isAlreadySelected = selectedAccounts.includes(address);
Expand Down Expand Up @@ -106,7 +133,7 @@ export default function AccountsTable ({ accountTypeFilter, areAllCheck, label,
/>
</Grid>
}
{accountsToShow.map(({ address }, index) => (
{(sortedAccountsRef.current ?? accountsToShow).map(({ address }, index) => (
<Grid container item key={index} sx={{ '> div:not(:last-child)': { borderRight: '1px solid', borderRightColor: 'secondary.light' }, height: '37px', textAlign: 'center' }} xs={12}>
<Grid alignItems='center' container item justifyContent='left' pl='15px' xs={8}>
<Identity address={address} identiconSize={25} showShortAddress showSocial={false} style={{ fontSize: '14px' }} subIdOnly />
Expand All @@ -130,3 +157,5 @@ export default function AccountsTable ({ accountTypeFilter, areAllCheck, label,
</Grid>
);
}

export default React.memo(AccountsTable);
20 changes: 7 additions & 13 deletions packages/extension-polkagate/src/partials/ConnectedDappIcon.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import { Avatar } from '@mui/material';
import React, { useCallback, useContext, useEffect, useState } from 'react';

import { ActionContext } from '../components';
import { useAnimateOnce } from '../hooks';
import { getAuthList } from '../messaging';
import { extractBaseUrl } from '../util/utils';

Expand All @@ -22,7 +23,8 @@ export default function ConnectedDappIcon (): React.ReactElement {
const [isConnected, setIsConnected] = useState<boolean | undefined>(undefined);
const [favIconUrl, setFavIconUrl] = useState<string | undefined>(undefined);
const [dappId, setDappId] = useState<string | undefined>(undefined);
const [flip, setFlip] = useState(false);

const flip = useAnimateOnce(Boolean(favIconUrl), { delay: 1000, duration: 1000 });

const isOnHomePage = window.location.hash === '#/';

Expand Down Expand Up @@ -55,15 +57,6 @@ export default function ConnectedDappIcon (): React.ReactElement {
}
}, []);

useEffect(() => {
if (!favIconUrl) {
return;
}

setFlip(true);
setTimeout(() => setFlip(false), 1000);
}, [favIconUrl]);

useEffect(() => {
if (isOnHomePage && isConnected === undefined && !checking && favIconUrl === undefined) {
checkTab().catch(console.error);
Expand All @@ -84,14 +77,15 @@ export default function ConnectedDappIcon (): React.ReactElement {
src={favIconUrl}
sx={{
borderRadius: '50%',
bottom: 5,
cursor: 'pointer',
height: '15px',
position: 'absolute',
right: 10,
right: '44%',
top: 6,
transform: flip ? 'rotateY(180deg)' : 'rotateY(0deg)',
transition: 'transform 1s',
width: '15px'
width: '15px',
zIndex: 10
}}
variant='circular'
/>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -53,10 +53,11 @@ export default function ManageAuthorizedAccounts ({ info, onBackClick }: Props):
</Grid>
<AccountsTable
areAllCheck={areAllCheck}
manageConnectedAccounts
maxHeight={window.innerHeight - 300}
selectedAccounts={selectedAccounts}
setSelectedAccounts={setSelectedAccounts}
style={{ margin: '35px auto 0', width: '92%' }}
style={{ margin: '25px auto 0', width: '92%' }}
/>
<TwoButtons
disabled={noChanges}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ interface Props {
backToAccountFS?: () => void | undefined;
}

export default function ManageAuthorizedDapps({ backToAccountFS, setDappInfo }: Props): React.ReactElement {
export default function ManageAuthorizedDapps ({ backToAccountFS, setDappInfo }: Props): React.ReactElement {
const isExtensionMode = useIsExtensionPopup();
const { t } = useTranslation();
const theme = useTheme();
Expand Down
19 changes: 10 additions & 9 deletions packages/extension-polkagate/src/popup/authManagement/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ interface FSModeType {
open: boolean;
}

const ExtensionMode = ({ dappInfo, onBackClick, setDappInfo }: ExtensionModeType) => {
const ExtensionMode = React.memo(function ExtensionMode ({ dappInfo, onBackClick, setDappInfo }: ExtensionModeType) {
const { t } = useTranslation();

return (
Expand All @@ -53,9 +53,9 @@ const ExtensionMode = ({ dappInfo, onBackClick, setDappInfo }: ExtensionModeType
}
</>
);
};
});

const FSMode = ({ backToAccountFS, dappInfo, onBackClick, open, setDappInfo }: FSModeType) => {
const FSMode = React.memo(function FSMode ({ backToAccountFS, dappInfo, onBackClick, open, setDappInfo }: FSModeType) {
const { t } = useTranslation();

return (
Expand All @@ -73,9 +73,9 @@ const FSMode = ({ backToAccountFS, dappInfo, onBackClick, open, setDappInfo }: F
</Grid>
</DraggableModal>
);
};
});

export default function AuthManagement ({ open, setDisplayPopup }: Props): React.ReactElement {
function AuthManagement ({ open, setDisplayPopup }: Props): React.ReactElement {
const onAction = useContext(ActionContext);
const isExtensionMode = useIsExtensionPopup();
const { id: dappId } = useParams<{ id: string | undefined }>();
Expand Down Expand Up @@ -104,11 +104,12 @@ export default function AuthManagement ({ open, setDisplayPopup }: Props): React

return (
<>
{
isExtensionMode
? <ExtensionMode dappInfo={dappInfo} onBackClick={onBackClick} setDappInfo={setDappInfo} />
: <FSMode backToAccountFS={backToAccountFS} dappInfo={dappInfo} onBackClick={onBackClick} open={!!open} setDappInfo={setDappInfo} />
{isExtensionMode
? <ExtensionMode dappInfo={dappInfo} onBackClick={onBackClick} setDappInfo={setDappInfo} />
: <FSMode backToAccountFS={backToAccountFS} dappInfo={dappInfo} onBackClick={onBackClick} open={!!open} setDappInfo={setDappInfo} />
}
</>
);
}

export default React.memo(AuthManagement);
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,7 @@ export default function Request ({ authRequest, hasBanner }: Props): React.React
</Grid>
<AccountsTable
areAllCheck={areAllCheck}
manageConnectedAccounts={alreadySelectedAccounts.length > 0}
maxHeight={hasBanner ? '150px' : '170px'}
selectedAccounts={selectedAccounts}
setSelectedAccounts={setSelectedAccounts}
Expand Down
Loading
Loading