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

Hook up account selector on main page #561

Merged
merged 2 commits into from
Nov 5, 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
Original file line number Diff line number Diff line change
Expand Up @@ -161,9 +161,7 @@
&_search-form {
display: flex;

.account-search__form {
width: 100%;

.form-search {
.form-input__field {
height: rem(32px);
padding: rem(10px);
Expand Down Expand Up @@ -211,7 +209,9 @@
display: flex;
padding: rem(12px) 0;
align-items: center;
border: unset;
border-bottom: 1px solid $color-grey-3;
background: none;

&:last-child {
border-bottom: none;
Expand Down Expand Up @@ -264,6 +264,11 @@
height: rem(24px);
border-radius: rem(5px);
background-color: $color-main-bg;

img {
max-width: rem(24px);
max-height: rem(24px);
}
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ export default function Header({
<MenuButton setMenuOpen={setMenuOpen} menuOpen={menuOpen} hideMenu={hideMenu} />
</div>
<MenuTiles menuOpen={menuOpen} setMenuOpen={setMenuOpen} />
<AccountSelector showAccountSelector={accountOpen} />
<AccountSelector showAccountSelector={accountOpen} onUpdateSelectedAccount={() => setAccountOpen(false)} />
</div>
);
}
Original file line number Diff line number Diff line change
@@ -1,97 +1,119 @@
import React from 'react';
import React, { ChangeEvent, useMemo, useState } from 'react';
import CarretRight from '@assets/svgX/caret-right.svg';
import Form from '@popup/popupX/shared/Form/Form';
import EthLogo from '@assets/svgX/eth-logo.svg';
import DnwLogo from '@assets/svgX/dnw-logo.svg';
import EureLogo from '@assets/svgX/eure-logo.svg';
import BtcLogo from '@assets/svgX/btc-logo.svg';
import ArrowsUpDown from '@assets/svgX/arrows-down-up.svg';
import FormSearch from '@popup/popupX/shared/Form/Search';
import { Search } from '@popup/popupX/shared/Form/Search';
import Button from '@popup/popupX/shared/Button';
import { useAtom, useAtomValue } from 'jotai';
import { credentialsAtomWithLoading, selectedAccountAtom } from '@popup/store/account';
import { displayNameAndSplitAddress } from '@popup/shared/utils/account-helpers';
import { useAccountInfo } from '@popup/shared/AccountInfoListenerContext';
import { displayAsCcd } from 'wallet-common-helpers';
import { WalletCredential } from '@shared/storage/types';
import { useTranslation } from 'react-i18next';
import clsx from 'clsx';
import { tokensAtom } from '@popup/store/token';
import Img from '@popup/shared/Img';

type Props = { showAccountSelector: boolean };
function CcdBalance({ credential }: { credential: WalletCredential }) {
const accountInfo = useAccountInfo(credential);
const balance =
accountInfo === undefined ? '' : displayAsCcd(accountInfo.accountAmount.microCcdAmount, false, true);
// eslint-disable-next-line react/jsx-no-useless-fragment
return <>{balance}</>;
}

type Props = { showAccountSelector: boolean; onUpdateSelectedAccount: () => void };

function compareAsc(left: WalletCredential, right: WalletCredential): number {
if (left.credName === '' && right.credName !== '') {
return 1;
}
if (right.credName === '' && left.credName !== '') {
return -1;
}
return left.credName.localeCompare(right.credName) || left.address.localeCompare(right.address);
}

function compareDesc(left: WalletCredential, right: WalletCredential): number {
return compareAsc(right, left);
}

export default function AccountSelector({ showAccountSelector, onUpdateSelectedAccount }: Props) {
const { t } = useTranslation('x', { keyPrefix: 'header.accountSelector' });
const credentialsLoading = useAtomValue(credentialsAtomWithLoading);
const [selectedAccount, setSelectedAccount] = useAtom(selectedAccountAtom);
const [search, setSearch] = useState('');
const [ascSort, setAscSort] = useState(true);
const credentials = credentialsLoading.value ?? [];
const tokens = useAtomValue(tokensAtom);
const filtered = useMemo(
() =>
credentials.filter(
(credential) =>
credential.credName.toLowerCase().includes(search.toLowerCase()) ||
credential.address.toLowerCase().includes(search.toLowerCase())
),
[search, credentials]
);
const sorted = useMemo(() => filtered.sort(ascSort ? compareAsc : compareDesc), [filtered, ascSort]);
const onAccountClick = (address: string) => () => {
setSelectedAccount(address);
onUpdateSelectedAccount();
};

export default function AccountSelector({ showAccountSelector }: Props) {
if (!showAccountSelector) return null;
return (
<div className="main-header__account-selector fade-menu-bg">
<div className="main-header__account-selector_group">
<div className="main-header__account-selector_search-form">
<Form
onSubmit={() => {}}
// formMethods={}
className="account-search__form"
>
{(f) => {
return (
<FormSearch
control={f.control}
name="network"
placeholder="Search by name"
autoFocus
defaultValue="https://whatevertheaddressIs.com"
/>
);
}}
</Form>
<Button.IconText icon={<ArrowsUpDown />} label="Sort A-Z" />
<Search
autoFocus
placeholder={t('searchBy')}
value={search}
onChange={(e: ChangeEvent<HTMLInputElement>) => setSearch(e.target.value)}
/>
<Button.IconText
icon={<ArrowsUpDown />}
label={ascSort ? t('sortAsc') : t('sortDesc')}
onClick={() => setAscSort((a) => !a)}
/>
</div>
<div className="main-header__account-selector_list">
<div className="main-header__account-selector_list-item active">
<div className="account">
<CarretRight />
<span className="text__additional_small">Accout 1 / 6gk...k7o</span>
</div>
<div className="balance">
<span className="text__additional_small">1.2M CCD</span>
</div>
<div className="tokens">
<div className="token-icon">
<EthLogo />
</div>
<div className="token-icon">
<DnwLogo />
</div>
<div className="token-icon">
<EureLogo />
</div>
<div className="token-icon">
<BtcLogo />
</div>
</div>
</div>
<div className="main-header__account-selector_list-item">
<div className="account">
<CarretRight />
<span className="text__additional_small">Accout 2 / 6gk...k7o</span>
</div>
<div className="balance">
<span className="text__additional_small">0.4M CCD</span>
</div>
<div className="tokens">
<div className="token-icon">
<EthLogo />
</div>
<div className="token-icon">
<DnwLogo />
</div>
</div>
</div>
<div className="main-header__account-selector_list-item">
{sorted.map((credential) => (
<Button.Base
className={clsx('main-header__account-selector_list-item', {
active: credential.address === selectedAccount,
})}
onClick={onAccountClick(credential.address)}
>
<div className="account">
<CarretRight />
<span className="text__additional_small">Accout 3 / 6gk...k7o</span>
{credential.address === selectedAccount && <CarretRight />}
<span className="text__additional_small">{displayNameAndSplitAddress(credential)}</span>
</div>
<div className="balance">
<span className="text__additional_small">200k CCD</span>
<span className="text__additional_small">
<CcdBalance credential={credential} />
</span>
</div>
<div className="tokens">
<div className="token-icon">
<EthLogo />
</div>
{tokens.loading ||
Object.values(tokens.value[credential.address]).flatMap((contractTokens) =>
contractTokens.flatMap((token) =>
token.metadata.thumbnail?.url === undefined
? []
: [
<div className="token-icon">
<Img
src={token.metadata.thumbnail.url}
alt={token.metadata.symbol ?? '?'}
withDefaults
/>
</div>,
]
)
)}
</div>
</div>
</div>
</Button.Base>
))}
</div>
</div>
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,11 @@ const t = {
restore: 'Restore',
oldUI: 'Old UI',
},
accountSelector: {
sortAsc: 'Sort A-Z',
sortDesc: 'Sort Z-A',
searchBy: 'Search by name or address',
},
};

export default t;