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

feat: Wipe wallet group #1331

Merged
merged 16 commits into from
Feb 28, 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
9 changes: 2 additions & 7 deletions src/core/keychain/KeychainManager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -451,15 +451,10 @@ class KeychainManager {

async getAccounts() {
const keychains = this.state.keychains || [];

const keychainArrays = await Promise.all(
const accounts = await Promise.all(
keychains.map((keychain) => keychain.getAccounts()),
);
const addresses = keychainArrays.reduce((res, arr) => {
return res.concat(arr);
}, []);

return addresses;
return accounts.flat();
}

async getWallets() {
Expand Down
17 changes: 17 additions & 0 deletions src/core/state/appSessions/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ export type ActiveSession = { address: Address; chainId: ChainId } | null;
export interface AppSessionsStore<T extends AppSession | V0AppSession> {
appSessions: Record<string, T>;
getActiveSession: ({ host }: { host: string }) => ActiveSession;
removeAddressSessions: ({ address }: { address: Address }) => void;
addSession: ({
host,
address,
Expand Down Expand Up @@ -83,6 +84,22 @@ export const appSessionsStore = createStore<AppSessionsStore<AppSession>>(
}
: null;
},
removeAddressSessions: ({ address }) => {
const appSessions = get().appSessions;
for (const [host, session] of Object.entries(appSessions)) {
if (!session.sessions[address]) continue;
delete appSessions[host].sessions[address];
if (session.activeSessionAddress !== address) continue;
const newActiveSessionAddress = Object.keys(session.sessions)[0];
if (newActiveSessionAddress) {
appSessions[host].activeSessionAddress =
newActiveSessionAddress as Address;
} else {
delete appSessions[host];
}
}
set({ appSessions: { ...appSessions } });
},
addSession: ({ host, address, chainId, url }) => {
const appSessions = get().appSessions;
const existingSession = appSessions[host];
Expand Down
15 changes: 15 additions & 0 deletions src/entries/popup/Routes.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,7 @@ import { RecoveryPhraseVerify } from './pages/settings/walletsAndKeys/recoveryPh
import { RecoveryPhraseWarning } from './pages/settings/walletsAndKeys/recoveryPhrase/warning';
import { WalletDetails } from './pages/settings/walletsAndKeys/walletDetails';
import { WalletsAndKeys } from './pages/settings/walletsAndKeys/walletsAndKeys';
import { WipeWalletGroupWarning } from './pages/settings/walletsAndKeys/wipeWalletGroupWarning';
import { WipeWalletWarning } from './pages/settings/walletsAndKeys/wipeWalletWarning';
import { Sign } from './pages/sign';
import { Swap } from './pages/swap';
Expand Down Expand Up @@ -647,6 +648,20 @@ const ROUTE_DATA = [
</AnimatedRoute>
),
},
{
path: ROUTES.SETTINGS__PRIVACY__WALLETS_AND_KEYS__WALLET_DETAILS__WIPE_WALLET_GROUP_WARNING,
element: (
<AnimatedRoute
direction="right"
navbar
navbarIcon="arrow"
background="surfaceSecondary"
protectedRoute
>
<WipeWalletGroupWarning />
</AnimatedRoute>
),
},
{
path: ROUTES.SETTINGS__PRIVACY__WALLETS_AND_KEYS__WALLET_DETAILS,
element: (
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -86,16 +86,16 @@ export default function WarningInfo({
</Box>
</Inline>

<Text size="16pt" weight="bold" color="label" align="center">
{i18n.t('common_titles.before_you_proceed')}
</Text>

<Inline alignHorizontal="center">
<Box alignItems="center" style={{ width: '106px' }}>
<Separator color="separatorTertiary" strokeWeight="1px" />
</Box>
</Inline>

<Text size="16pt" weight="bold" color="label" align="center">
{i18n.t('common_titles.before_you_proceed')}
</Text>

<Box paddingHorizontal="12px">
<IconAndCopyList iconAndCopyList={iconAndCopyList} />
</Box>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,161 @@
import { useState } from 'react';

import { i18n } from '~/core/languages';
import {
Box,
Button,
Column,
Columns,
Inline,
Row,
Rows,
Separator,
Stack,
Symbol,
Text,
} from '~/design-system';
import { Lens } from '~/design-system/components/Lens/Lens';

import { Checkbox } from '../Checkbox/Checkbox';
import {
IconAndCopyItem,
IconAndCopyList,
} from '../IconAndCopyList.tsx/IconAndCopyList';

const t = (s: string) =>
i18n.t(s, { scope: 'settings.privacy_and_security.wallets_and_keys' });

interface WarningInfoProps {
iconAndCopyList: IconAndCopyItem[];
onProceed: () => void;
testId?: string;
}

export default function WarningInfo({
iconAndCopyList,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

maybe this don't have to be a prop either, seems like a very specific component no need to abstract it, or change the name and abstract to use in the other similar screens?

onProceed,
testId,
BrodyHughes marked this conversation as resolved.
Show resolved Hide resolved
}: WarningInfoProps) {
const [acknowledgeCheck, setAcknowledgeCheck] = useState(false);

const buttonEnabled = !!acknowledgeCheck;
return (
<Box
height="full"
alignItems="center"
paddingHorizontal="20px"
style={{ height: 535 }}
>
<Rows alignVertical="justify">
<Row>
<Box alignItems="center">
<Stack space="24px">
<Inline alignHorizontal="center">
<Box
borderRadius="round"
boxShadow="18px accent"
style={{
height: 60,
width: 60,
overflow: 'hidden',
}}
>
<Box
display="flex"
alignItems="center"
justifyContent="center"
height="full"
top="0"
left="0"
right="0"
bottom="0"
position="relative"
style={{
background:
'radial-gradient(100% 144.46% at 0% 50%, #FF9233 0%, #FA423C 100%)',
zIndex: 1,
}}
>
<Symbol
symbol="exclamationmark.triangle.fill"
size={26}
color="label"
weight={'bold'}
/>
</Box>
</Box>
</Inline>

<Text size="16pt" weight="bold" color="label" align="center">
{i18n.t('common_titles.before_you_proceed')}
</Text>

<Inline alignHorizontal="center">
<Box alignItems="center" style={{ width: '106px' }}>
<Separator color="separatorTertiary" strokeWeight="1px" />
</Box>
</Inline>

<Box paddingHorizontal="12px">
<IconAndCopyList iconAndCopyList={iconAndCopyList} />
</Box>
</Stack>
</Box>
</Row>
<Row height="content">
<Columns alignVertical="center" alignHorizontal="center" space="7px">
<Column width="content">
<Checkbox
width="16px"
height="16px"
borderRadius="6px"
selected={acknowledgeCheck}
backgroundSelected="blue"
borderColorSelected="blue"
borderColor="labelTertiary"
onClick={() => setAcknowledgeCheck(!acknowledgeCheck)}
/>
</Column>
<Column width="content">
<Lens
testId="wallet-wipe-check"
onClick={() => setAcknowledgeCheck(!acknowledgeCheck)}
handleOpenMenu={() => setAcknowledgeCheck(!acknowledgeCheck)}
>
<Text
align="left"
size="12pt"
weight="bold"
color="labelSecondary"
>
{t('wipe_wallet_group.acknowlegement')}
</Text>
</Lens>
</Column>
</Columns>
</Row>

<Row height="content">
<Box width="full" paddingVertical="20px">
<Button
testId={testId}
color={buttonEnabled ? 'red' : 'fill'}
height="44px"
variant="flat"
width="full"
symbol={buttonEnabled ? 'trash' : 'arrow.up.circle.fill'}
blur="26px"
onClick={onProceed}
disabled={!buttonEnabled}
tabIndex={0}
>
{buttonEnabled
? t('wipe_wallet_group.delete')
: t('wipe_wallet_group.button_complete')}
</Button>
</Box>
</Row>
</Rows>
</Box>
);
}
33 changes: 33 additions & 0 deletions src/entries/popup/pages/settings/walletsAndKeys/walletDetails.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ import { ROUTES } from '~/entries/popup/urls';
import { CreateWalletPrompt } from '../../walletSwitcher/createWalletPrompt';
import { RemoveWalletPrompt } from '../../walletSwitcher/removeWalletPrompt';
import { RenameWalletPrompt } from '../../walletSwitcher/renameWalletPrompt';
import { ConfirmPasswordPrompt } from '../privacy/confirmPasswordPrompt';

const InfoButtonOptions = ({
account,
Expand Down Expand Up @@ -129,6 +130,7 @@ export function WalletDetails() {
const { visibleWallets } = useWallets();
const { deleteWalletName } = useWalletNamesStore();
const [createWalletAddress, setCreateWalletAddress] = useState<Address>();
const [showEnterPassword, setShowEnterPassword] = useState(false);

const { isWalletBackedUp, getWalletBackup, deleteWalletBackup } =
useWalletBackupsStore();
Expand Down Expand Up @@ -258,6 +260,16 @@ export function WalletDetails() {

return (
<Box>
<ConfirmPasswordPrompt
show={showEnterPassword}
onClose={() => setShowEnterPassword(false)}
extraState={{ ...state }}
onSuccess={() =>
navigate(
ROUTES.SETTINGS__PRIVACY__WALLETS_AND_KEYS__WALLET_DETAILS__WIPE_WALLET_GROUP_WARNING,
)
}
/>
<CreateWalletPrompt
onCancel={handleCancel}
show={!!createWalletAddress}
Expand Down Expand Up @@ -391,6 +403,27 @@ export function WalletDetails() {
}
onClick={handleCreateWalletOnGroup}
/>
<MenuItem
first
last
leftComponent={
<Symbol
size={18}
color="red"
weight="medium"
symbol="trash.fill"
/>
}
titleComponent={
<MenuItem.Title
text={i18n.t(
'settings.privacy_and_security.wallets_and_keys.wipe_wallet_group.delete',
)}
color="red"
/>
}
onClick={() => setShowEnterPassword(true)}
/>
</Menu>
)}
</MenuContainer>
Expand Down
Loading
Loading