Skip to content

Commit

Permalink
Fix: Staking card stack (#2872)
Browse files Browse the repository at this point in the history
  • Loading branch information
tuul-wq authored Dec 19, 2024
1 parent 31f8a26 commit 1e4c5d9
Show file tree
Hide file tree
Showing 4 changed files with 126 additions and 131 deletions.
68 changes: 33 additions & 35 deletions src/renderer/pages/Staking/ui/NominatorItem.tsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
import { useUnit } from 'effector-react';
import { type ReactNode } from 'react';

import { type Account, type Address, type Asset, type Chain } from '@/shared/core';
import { type Address, type Asset, type Chain } from '@/shared/core';
import { useI18n } from '@/shared/i18n';
import { cnTw, nonNullable } from '@/shared/lib/utils';
import { FootnoteText, Icon, Plate, Shimmering } from '@/shared/ui';
import { FootnoteText, Icon, Plate } from '@/shared/ui';
import { AccountExplorers } from '@/shared/ui-entities';
import { Checkbox } from '@/shared/ui-kit';
import { Checkbox, Skeleton } from '@/shared/ui-kit';
import { AssetBalance } from '@/entities/asset';
import { AssetFiatBalance } from '@/entities/price';
import { walletModel, walletUtils } from '@/entities/wallet';
Expand All @@ -17,7 +17,7 @@ type Props = {
asset?: Asset;
chain: Chain;
isStakingLoading: boolean;
stake: NominatorInfo<Account>;
stake: NominatorInfo;
content: ReactNode;
onToggleNominator: (nominator: Address, boolean: boolean) => void;
onCheckValidators: (stash?: Address) => void;
Expand All @@ -39,46 +39,44 @@ export const NominatorsItem = ({
const activeWallet = useUnit(walletModel.$activeWallet);

return (
<Plate className="grid grid-cols-[1fr,104px,104px,20px] items-center gap-x-6">
<Plate className="grid grid-cols-[1fr,104px,104px,20px] items-center gap-x-6 py-2.5">
{activeWallet && !walletUtils.isWatchOnly(activeWallet) && nominatorsLength > 1 ? (
<div className="w-full">
<div className="flex w-full gap-x-2">
<Checkbox
disabled={isStakingLoading}
checked={stake.isSelected}
onChange={(checked) => onToggleNominator(stake.address, checked)}
>
<div className="grid w-full max-w-[207px] grid-cols-[minmax(10px,1fr),auto]">{content}</div>
</Checkbox>
/>
<div className="grid w-full max-w-[207px] grid-cols-[minmax(10px,1fr),auto]">{content}</div>
</div>
) : (
<div className="grid max-w-[222px] grid-cols-[minmax(10px,1fr),auto] items-center gap-x-2">{content}</div>
)}
<div className="flex flex-col items-end gap-y-0.5 justify-self-end">
{!stake.totalStake || !asset ? (
<>
<Shimmering width={82} height={15} />
<Shimmering width={56} height={10} />
</>
) : (
<>
<AssetBalance value={stake.totalStake} asset={asset} />
<AssetFiatBalance amount={stake.totalStake} asset={asset} />
</>
)}
</div>
<div className="flex flex-col items-end gap-y-0.5 justify-self-end">
{!stake.totalReward || !asset ? (
<>
<Shimmering width={82} height={15} />
<Shimmering width={56} height={10} />
</>
) : (
<>
<AssetBalance value={stake.totalReward} asset={asset} />
<AssetFiatBalance amount={stake.totalReward} asset={asset} />
</>
)}
</div>

{!stake.totalStake || !asset ? (
<div className="flex flex-col items-end gap-y-1.5 pb-1">
<Skeleton width={20} height={4} />
<Skeleton width={14} height={3} />
</div>
) : (
<div className="flex flex-col items-end justify-self-end">
<AssetBalance value={stake.totalStake} asset={asset} />
<AssetFiatBalance amount={stake.totalStake} asset={asset} />
</div>
)}

{!stake.totalReward || !asset ? (
<div className="flex flex-col items-end gap-y-1.5 pb-1">
<Skeleton width={20} height={4} />
<Skeleton width={14} height={3} />
</div>
) : (
<div className="flex flex-col items-end justify-self-end">
<AssetBalance value={stake.totalReward} asset={asset} />
<AssetFiatBalance amount={stake.totalReward} asset={asset} />
</div>
)}

<AccountExplorers accountId={stake.account.accountId} chain={chain}>
{nonNullable(stake.stash) && (
<button
Expand Down
162 changes: 78 additions & 84 deletions src/renderer/pages/Staking/ui/ShardedList.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@ import { Trans } from 'react-i18next';
import { type Address, type Asset, type Chain, type Explorer } from '@/shared/core';
import { type ShardAccount } from '@/shared/core/types/account';
import { useI18n } from '@/shared/i18n';
import { Accordion, FootnoteText, Plate, Shimmering, Tooltip } from '@/shared/ui';
import { Checkbox } from '@/shared/ui-kit';
import { FootnoteText } from '@/shared/ui';
import { CardStack, Checkbox, Skeleton, Tooltip } from '@/shared/ui-kit';
import { AssetBalance } from '@/entities/asset';
import { AssetFiatBalance } from '@/entities/price';
import { useStakingData } from '@/entities/staking';
Expand Down Expand Up @@ -66,90 +66,84 @@ export const ShardedList = ({
);

return (
<Plate className="border-b-4 border-double p-0 shadow-stack">
<Accordion className="w-auto">
<div className="flex rounded-md border-b border-divider px-3 py-2 transition-colors hover:bg-action-background-hover">
<Accordion.Button buttonClass="ml-auto w-auto" iconOpened="shelfDown" iconClosed="shelfRight" />
<div className="w-full p-2">
<Checkbox
checked={shardsStats.selected === shardsStake.length}
semiChecked={shardsStats.selected > 0 && shardsStats.selected < shardsStake.length}
onChange={selectAllShards}
>
<div className="grid grid-cols-[174px,104px,104px] items-center gap-x-6">
<div className="flex items-center gap-x-2">
<FootnoteText className="h-5 rounded-full bg-input-background-disabled px-2 py-px text-text-secondary">
{shardsStake.length}
</FootnoteText>
<FootnoteText className="truncate text-text-secondary first-letter:uppercase">
{shardsStake[0].account.name}
</FootnoteText>
<Tooltip
offsetPx={-60}
content={
<Trans
t={t}
i18nKey="staking.tooltips.redeemAndUnstake"
values={{ countUnstake: shardsStats.unstaking, countWithdraw: shardsStats.withdraw }}
/>
}
>
<div className="flex items-center gap-x-1">
{Boolean(shardsStats.unstaking) && <span className="h-1.5 w-1.5 rounded-full bg-icon-accent" />}
{Boolean(shardsStats.withdraw) && <span className="h-1.5 w-1.5 rounded-full bg-icon-positive" />}
</div>
</Tooltip>
</div>
<div className="flex flex-col items-end gap-y-0.5 justify-self-end">
{!shardsStake[0]?.totalStake || !asset ? (
<>
<Shimmering width={82} height={15} />
<Shimmering width={56} height={10} />
</>
) : (
<>
<AssetBalance value={shardsStats.totalStake.toString()} asset={asset} />
<AssetFiatBalance amount={shardsStats.totalStake.toString()} asset={asset} />
</>
)}
</div>
<div className="flex flex-col items-end gap-y-0.5 justify-self-end">
{!shardsStake[0]?.totalReward || !asset ? (
<>
<Shimmering width={82} height={15} />
<Shimmering width={56} height={10} />
</>
) : (
<>
<AssetBalance value={shardsStats.totalReward.toString()} asset={asset} />
<AssetFiatBalance amount={shardsStats.totalReward.toString()} asset={asset} />
</>
)}
</div>
<CardStack>
<CardStack.Trigger>
<div className="flex gap-x-2 py-1.5">
<Checkbox
checked={shardsStats.selected === shardsStake.length}
semiChecked={shardsStats.selected > 0 && shardsStats.selected < shardsStake.length}
onChange={selectAllShards}
onClick={(event) => event.stopPropagation()}
/>
<div className="grid grid-cols-[174px,104px,104px] items-center gap-x-6">
<div className="flex items-center gap-x-2">
<FootnoteText className="h-5 rounded-full bg-input-background-disabled px-2 py-px text-text-secondary">
{shardsStake.length}
</FootnoteText>
<FootnoteText className="truncate text-text-secondary first-letter:uppercase">
{shardsStake[0].account.name}
</FootnoteText>
<Tooltip>
<Tooltip.Trigger>
<div className="flex items-center gap-x-1">
{Boolean(shardsStats.unstaking) && <span className="h-1.5 w-1.5 rounded-full bg-icon-accent" />}
{Boolean(shardsStats.withdraw) && <span className="h-1.5 w-1.5 rounded-full bg-icon-positive" />}
</div>
</Tooltip.Trigger>
<Tooltip.Content>
<Trans
t={t}
i18nKey="staking.tooltips.redeemAndUnstake"
values={{ countUnstake: shardsStats.unstaking, countWithdraw: shardsStats.withdraw }}
/>
</Tooltip.Content>
</Tooltip>
</div>

{!shardsStake[0]?.totalStake || !asset ? (
<div className="flex flex-col items-end gap-y-1.5 pb-1">
<Skeleton width={20} height={4} />
<Skeleton width={14} height={3} />
</div>
) : (
<div className="flex flex-col items-end justify-self-end">
<AssetBalance value={shardsStats.totalStake.toString()} asset={asset} />
<AssetFiatBalance amount={shardsStats.totalStake.toString()} asset={asset} />
</div>
)}

{!shardsStake[0]?.totalReward || !asset ? (
<div className="flex flex-col items-end gap-y-1.5 pb-1">
<Skeleton width={20} height={4} />
<Skeleton width={14} height={3} />
</div>
) : (
<div className="flex flex-col items-end justify-self-end">
<AssetBalance value={shardsStats.totalReward.toString()} asset={asset} />
<AssetFiatBalance amount={shardsStats.totalReward.toString()} asset={asset} />
</div>
</Checkbox>
)}
</div>
</div>

<Accordion.Content>
<ul className="pl-6">
{shardsStake.map((shard) => (
<li key={shard.account.id}>
<NominatorsItem
isStakingLoading={isStakingLoading}
content={getContent(shard)}
stake={shard}
nominatorsLength={shardsStake.length}
asset={asset}
chain={chain}
onToggleNominator={onToggleNominator}
onCheckValidators={onCheckValidators}
/>
</li>
))}
</ul>
</Accordion.Content>
</Accordion>
</Plate>
</CardStack.Trigger>
<CardStack.Content>
<ul className="pl-6">
{shardsStake.map((shard) => (
<li key={shard.account.id}>
<NominatorsItem
isStakingLoading={isStakingLoading}
content={getContent(shard)}
stake={shard}
nominatorsLength={shardsStake.length}
asset={asset}
chain={chain}
onToggleNominator={onToggleNominator}
onCheckValidators={onCheckValidators}
/>
</li>
))}
</ul>
</CardStack.Content>
</CardStack>
);
};
9 changes: 6 additions & 3 deletions src/renderer/shared/ui-kit/Checkbox/Checkbox.tsx
Original file line number Diff line number Diff line change
@@ -1,17 +1,18 @@
import * as CheckboxItem from '@radix-ui/react-checkbox';
import { type PropsWithChildren } from 'react';
import { type MouseEvent, type PropsWithChildren } from 'react';

import { cnTw } from '@/shared/lib/utils';
import './Checkbox.css';
import { Icon } from '@/shared/ui/Icon/Icon';
import { LabelText } from '@/shared/ui/Typography';
import './Checkbox.css';

type Props = {
checked?: boolean;
semiChecked?: boolean;
disabled?: boolean;
checkboxPosition?: 'center' | 'top';
onChange?: (checked: boolean, semiChecked?: boolean) => void;
onClick?: (event: MouseEvent<HTMLButtonElement>) => void;
};

export const Checkbox = ({
Expand All @@ -21,6 +22,7 @@ export const Checkbox = ({
checkboxPosition = 'center',
children,
onChange,
onClick,
}: PropsWithChildren<Props>) => {
const checkedState = checked ? true : semiChecked ? 'indeterminate' : false;
const iconColor = disabled ? 'text-filter-border' : 'text-white';
Expand Down Expand Up @@ -48,13 +50,14 @@ export const Checkbox = ({
)}
disabled={disabled}
onCheckedChange={handleChange}
onClick={onClick}
>
<CheckboxItem.Indicator>
{checked && <Icon name="checked" size={16} className={iconColor} />}
{!checked && semiChecked && <Icon name="semiChecked" size={16} className={iconColor} />}
</CheckboxItem.Indicator>
</CheckboxItem.Root>
{Boolean(children) && children}
{children}
</LabelText>
);
};
18 changes: 9 additions & 9 deletions src/renderer/shared/ui/Markdown/Markdown.tsx
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import noop from 'lodash/noop';
import { type ChangeEvent, useState } from 'react';
import ReactMarkdown, { type Components, type Options } from 'react-markdown';
import rehypeRaw from 'rehype-raw';
Expand Down Expand Up @@ -72,17 +73,16 @@ const components: Components = {
<Checkbox
{...props}
onChange={(newCheckedState: boolean) => {
if (typeof props.onChange === 'function') {
// Simulate a ChangeEvent for props.onChange to fit types
const event = {
target: {
checked: newCheckedState,
},
} as ChangeEvent<HTMLInputElement>;
if (typeof props.onChange !== 'function') return;

props.onChange(event);
}
const event = {
target: {
checked: newCheckedState,
},
} as ChangeEvent<HTMLInputElement>;
props.onChange(event);
}}
onClick={noop}
/>
) : (
<input {...props} />
Expand Down

0 comments on commit 1e4c5d9

Please sign in to comment.