Skip to content

Commit

Permalink
Feat: Better dropdown for wallet creation (#2552)
Browse files Browse the repository at this point in the history
  • Loading branch information
tuul-wq authored Nov 1, 2024
1 parent 5a8c197 commit 6b516ab
Show file tree
Hide file tree
Showing 23 changed files with 137 additions and 357 deletions.
2 changes: 1 addition & 1 deletion src/renderer/features/app-shell/components/AppShell.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ export const AppShell = memo(() => {

return (
<div className="flex h-screen animate-in fade-in">
<aside className="z-20 flex w-[240px] shrink-0 flex-col gap-y-6 border-r border-r-container-border bg-left-navigation-menu-background p-4">
<aside className="flex w-[240px] shrink-0 flex-col gap-y-6 border-r border-r-container-border bg-left-navigation-menu-background p-4">
{headerNodes}
<Navigation />
</aside>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,55 +1,48 @@
import { type TFunction } from 'i18next';

import { WalletType } from '@/shared/core';
import { type WalletFamily, WalletType } from '@/shared/core';
import { useI18n } from '@/shared/i18n';
import { DropdownButton } from '@/shared/ui';
import { type ButtonDropdownOption } from '@/shared/ui/types';
import { useToggle } from '@/shared/lib/hooks';
import { Button, Icon } from '@/shared/ui';
import { Dropdown } from '@/shared/ui-kit';
import { WalletIcon } from '@/entities/wallet';
import { walletPairingModel } from '../model/wallet-pairing-model';

const getDropdownOptions = (t: TFunction): ButtonDropdownOption[] => {
const getDropdownOptions = (t: TFunction): { title: string; walletType: WalletFamily }[] => {
return [
{
id: 'vault',
title: t('wallets.addPolkadotVault'),
icon: <WalletIcon type={WalletType.POLKADOT_VAULT} />,
onClick: () => walletPairingModel.events.walletTypeSet(WalletType.POLKADOT_VAULT),
},
{
id: 'multi',
title: t('wallets.addMultisig'),
icon: <WalletIcon type={WalletType.MULTISIG} />,
onClick: () => walletPairingModel.events.walletTypeSet(WalletType.MULTISIG),
},
{
id: 'novaWallet',
title: t('wallets.addNovaWallet'),
icon: <WalletIcon type={WalletType.NOVA_WALLET} />,
onClick: () => walletPairingModel.events.walletTypeSet(WalletType.NOVA_WALLET),
},
{
id: 'walletConnect',
title: t('wallets.addWalletConnect'),
icon: <WalletIcon type={WalletType.WALLET_CONNECT} />,
onClick: () => walletPairingModel.events.walletTypeSet(WalletType.WALLET_CONNECT),
},
{
id: 'watch-only',
title: t('wallets.addWatchOnly'),
icon: <WalletIcon type={WalletType.WATCH_ONLY} />,
onClick: () => walletPairingModel.events.walletTypeSet(WalletType.WATCH_ONLY),
},
{ title: t('wallets.addPolkadotVault'), walletType: WalletType.POLKADOT_VAULT },
{ title: t('wallets.addMultisig'), walletType: WalletType.MULTISIG },
{ title: t('wallets.addNovaWallet'), walletType: WalletType.NOVA_WALLET },
{ title: t('wallets.addWalletConnect'), walletType: WalletType.WALLET_CONNECT },
{ title: t('wallets.addWatchOnly'), walletType: WalletType.WATCH_ONLY },
];
};

export const SelectWalletPairing = () => {
const { t } = useI18n();

const [isOpen, toggleIsOpen] = useToggle();

return (
<DropdownButton
options={getDropdownOptions(t)}
className="h-8.5 w-[140px] py-2"
title={t('wallets.addButtonTitle')}
/>
<Dropdown open={isOpen} onToggle={toggleIsOpen}>
<Dropdown.Trigger>
<Button
className="h-8.5 w-full justify-center py-2"
suffixElement={<Icon name={isOpen ? 'up' : 'down'} size={16} className="text-inherit" />}
>
{t('wallets.addButtonTitle')}
</Button>
</Dropdown.Trigger>
<Dropdown.Content>
{getDropdownOptions(t).map(({ title, walletType }) => (
<Dropdown.Item key={title} onSelect={() => walletPairingModel.events.walletTypeSet(walletType)}>
<div className="flex items-center gap-x-1.5">
<WalletIcon type={walletType} />
{title}
</div>
</Dropdown.Item>
))}
</Dropdown.Content>
</Dropdown>
);
};
20 changes: 12 additions & 8 deletions src/renderer/features/wallets/WalletSelect/ui/WalletButton.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import { Popover } from '@headlessui/react';

import { type Wallet } from '@/shared/core';
import { Icon } from '@/shared/ui';
import { Box, Popover } from '@/shared/ui-kit';
import { WalletCardLg } from '@/entities/wallet';

import { WalletFiatBalance } from './WalletFiatBalance';
Expand All @@ -11,11 +10,16 @@ type Props = {
};
export const WalletButton = ({ wallet }: Props) => {
return (
<Popover.Button className="w-full rounded-md border border-container-border bg-left-navigation-menu-background shadow-card-shadow">
<div className="flex items-center justify-between px-3 py-3">
<WalletCardLg wallet={wallet} description={<WalletFiatBalance walletId={wallet.id} className="truncate" />} />
<Icon name="down" size={16} className="ml-auto shrink-0" />
</div>
</Popover.Button>
<Popover.Trigger>
<button
type="button"
className="w-full rounded-md border border-container-border bg-left-navigation-menu-background shadow-card-shadow"
>
<Box direction="row" verticalAlign="center" horizontalAlign="space-between" padding={3}>
<WalletCardLg wallet={wallet} description={<WalletFiatBalance walletId={wallet.id} className="truncate" />} />
<Icon name="down" size={16} className="ml-auto shrink-0" />
</Box>
</button>
</Popover.Trigger>
);
};
8 changes: 4 additions & 4 deletions src/renderer/features/wallets/WalletSelect/ui/WalletPanel.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import { Popover } from '@headlessui/react';
import { useUnit } from 'effector-react';
import { type ReactNode, useEffect } from 'react';

import { type WalletFamily } from '@/shared/core';
import { useI18n } from '@/shared/i18n';
import { SearchInput, SmallTitleText } from '@/shared/ui';
import { Popover } from '@/shared/ui-kit';
import { type Callbacks, walletSelectModel } from '../model/wallet-select-model';

import { WalletGroup } from './WalletGroup';
Expand All @@ -22,11 +22,11 @@ export const WalletPanel = ({ action, onClose }: Props) => {
}, [onClose]);

return (
<Popover.Panel className="absolute z-10 mt-2 overflow-hidden rounded-md border border-token-container-border bg-token-container-background shadow-card-shadow">
<Popover.Content>
<section className="relative flex max-h-[700px] w-[300px] flex-col bg-card-background">
<header className="flex items-center justify-between border-b border-divider px-5 py-3">
<SmallTitleText>{t('wallets.title')}</SmallTitleText>
{action}
<div className="min-w-[140px]">{action}</div>
</header>

<div className="border-b border-divider p-2">
Expand All @@ -43,6 +43,6 @@ export const WalletPanel = ({ action, onClose }: Props) => {
})}
</div>
</section>
</Popover.Panel>
</Popover.Content>
);
};
31 changes: 5 additions & 26 deletions src/renderer/features/wallets/WalletSelect/ui/WalletSelect.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
import { Popover, Transition } from '@headlessui/react';
import { useUnit } from 'effector-react';
import { type ReactNode } from 'react';

import { Shimmering } from '@/shared/ui';
import { Popover, Skeleton } from '@/shared/ui-kit';
import { walletModel } from '@/entities/wallet';
import { walletSelectModel } from '../model/wallet-select-model';

Expand All @@ -16,33 +15,13 @@ export const WalletSelect = ({ action }: Props) => {
const activeWallet = useUnit(walletModel.$activeWallet);

if (!activeWallet) {
return <Shimmering width={208} height={56} />;
return <Skeleton width={208} height={56} />;
}

const hideWalletPanel = (close: () => void) => {
return () => {
close();
walletSelectModel.events.clearData();
};
};

return (
<Popover className="relative">
{({ close }) => (
<>
<WalletButton wallet={activeWallet} />
<Transition
enter="transition ease-out duration-200"
enterFrom="opacity-0 translate-y-1"
enterTo="opacity-100 translate-y-0"
leave="transition ease-in duration-150"
leaveFrom="opacity-100 translate-y-0"
leaveTo="opacity-0 translate-y-1"
>
<WalletPanel action={action} onClose={hideWalletPanel(close)} />
</Transition>
</>
)}
<Popover>
<WalletButton wallet={activeWallet} />
<WalletPanel action={action} onClose={walletSelectModel.events.clearData} />
</Popover>
);
};
64 changes: 33 additions & 31 deletions src/renderer/pages/Staking/ui/Actions.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@ import { type Address, type Stake } from '@/shared/core';
import { useI18n } from '@/shared/i18n';
import { useToggle } from '@/shared/lib/hooks';
import { toAccountId } from '@/shared/lib/utils';
import { BaseModal, Button, DropdownButton, Icon, SmallTitleText } from '@/shared/ui';
import { type ButtonDropdownOption } from '@/shared/ui/types';
import { BaseModal, Button, Icon, SmallTitleText } from '@/shared/ui';
import { Dropdown } from '@/shared/ui-kit';
import { ControllerOperations, OperationOptions, StashOperations } from '../lib/constants';
import { ControllerTypes, type Operations } from '../lib/types';

Expand All @@ -20,6 +20,7 @@ type Props = {
export const Actions = ({ canInteract, stakes, isStakingLoading, onNavigate }: Props) => {
const { t } = useI18n();
const [isDialogOpen, toggleIsDialogOpen] = useToggle();
const [isActionsOpen, toggleIsActionsOpen] = useToggle();

const [operation, setOperation] = useState<Operations>();
const [warningMessage, setWarningMessage] = useState('');
Expand Down Expand Up @@ -122,29 +123,6 @@ export const Actions = ({ canInteract, stakes, isStakingLoading, onNavigate }: P
}
};

const getAvailableButtonOptions = (): ButtonDropdownOption[] => {
if (noStakes || wrongOverlaps) {
return [];
}

return Object.entries(operationsSummary).reduce<ButtonDropdownOption[]>((acc, [key, value]) => {
if (stakes.length === value) {
const typedKey = key as Operations;
const option = OperationOptions[typedKey];

acc.push({
id: key,
icon: option.icon,
//eslint-disable-next-line i18next/no-literal-string
title: t(`staking.actions.${option.icon}Label`),
onClick: () => onClickAction(typedKey, option.path),
});
}

return acc;
}, []);
};

const getActionButtonText = (): string => {
if (noStakes) {
return t('staking.actions.selectAccPlaceholder');
Expand All @@ -160,12 +138,36 @@ export const Actions = ({ canInteract, stakes, isStakingLoading, onNavigate }: P
<>
<div className="flex items-center justify-between">
<SmallTitleText>{t('staking.overview.actionsTitle')}</SmallTitleText>
<DropdownButton
className="h-8.5 min-w-[228px]"
title={getActionButtonText()}
disabled={isStakingLoading || noStakes || wrongOverlaps}
options={getAvailableButtonOptions()}
/>
<div className="min-w-[228px]">
<Dropdown open={isActionsOpen} onToggle={toggleIsActionsOpen}>
<Dropdown.Trigger>
<Button
disabled={isStakingLoading || noStakes || wrongOverlaps}
className="h-8.5 w-full justify-center py-2"
suffixElement={<Icon name={isActionsOpen ? 'up' : 'down'} size={16} className="text-inherit" />}
>
{getActionButtonText()}
</Button>
</Dropdown.Trigger>
<Dropdown.Content>
{Object.entries(operationsSummary).map(([key, value]) => {
if (stakes.length !== value) return null;

const typedKey = key as Operations;
const option = OperationOptions[typedKey];

return (
<Dropdown.Item key={key} onSelect={() => onClickAction(typedKey, option.path)}>
<div className="flex w-full items-center gap-x-1.5">
<Icon name={option.icon} size={20} className="shrink-0 text-icon-accent" />
{t(option.title)}
</div>
</Dropdown.Item>
);
})}
</Dropdown.Content>
</Dropdown>
</div>
</div>

<BaseModal
Expand Down
7 changes: 4 additions & 3 deletions src/renderer/shared/ui-kit/Box/Box.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -73,10 +73,11 @@ export const Box = forwardRef<HTMLDivElement, BoxProps>(
ref,
) => {
const calculatedPadding = useMemo(
() =>
Array.isArray(padding)
() => {
return Array.isArray(padding)
? padding.map(getBoxSize<CSS.Property.Padding>).join(' ')
: getBoxSize<CSS.Property.Padding>(padding),
: getBoxSize<CSS.Property.Padding>(padding);
},
Array.isArray(padding) ? padding : [padding],
);

Expand Down
9 changes: 4 additions & 5 deletions src/renderer/shared/ui-kit/Dropdown/Dropdown.stories.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { type Meta, type StoryObj } from '@storybook/react';
import { useState } from 'react';

import { Button, Icon, Switch } from '@/shared/ui';
import { Button, Switch } from '@/shared/ui';
import { Box } from '../Box/Box';

import { Dropdown } from './Dropdown';
Expand All @@ -19,13 +19,12 @@ const meta: Meta<typeof Dropdown> = {
<Button>Trigger</Button>
</Dropdown.Trigger>
<Dropdown.Content>
<Dropdown.Item icon={<Icon name="rocket" size={16} />}>Item 1</Dropdown.Item>
<Dropdown.Item>Item 1</Dropdown.Item>
<Dropdown.Item>Item 2</Dropdown.Item>
<Dropdown.Item>Item 3</Dropdown.Item>
<Dropdown.Separator />
<Dropdown.Group label="Section 2">
<Dropdown.CheckboxItem checked>Item 4</Dropdown.CheckboxItem>
<Dropdown.CheckboxItem checked>Item 5</Dropdown.CheckboxItem>
<Dropdown.CheckboxItem checked={true}>Item 4</Dropdown.CheckboxItem>
<Dropdown.CheckboxItem checked={true}>Item 5</Dropdown.CheckboxItem>
<Dropdown.CheckboxItem checked={false}>Item 6</Dropdown.CheckboxItem>
</Dropdown.Group>
</Dropdown.Content>
Expand Down
Loading

0 comments on commit 6b516ab

Please sign in to comment.