Skip to content

Commit

Permalink
fix: multi send receivers list modal added
Browse files Browse the repository at this point in the history
  • Loading branch information
siandreev committed Apr 30, 2024
1 parent 1794b7d commit 3a68228
Show file tree
Hide file tree
Showing 3 changed files with 222 additions and 59 deletions.
25 changes: 20 additions & 5 deletions packages/uikit/src/components/Notification.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -36,9 +36,10 @@ const NotificationContainer = styled(Container)<{ scrollbarWidth: number }>`
`}
`;

const NotificationWrapper: FC<PropsWithChildren<{ entered: boolean }>> = ({
const NotificationWrapper: FC<PropsWithChildren<{ entered: boolean; className?: string }>> = ({
children,
entered
entered,
className
}) => {
const sdk = useAppSdk();

Expand All @@ -47,7 +48,11 @@ const NotificationWrapper: FC<PropsWithChildren<{ entered: boolean }>> = ({
}, [sdk, entered]);

return (
<NotificationContainer className="notification-container" scrollbarWidth={scrollbarWidth}>
<NotificationContainer
className={'notification-container' + className ? ' ' + className : ''}
id=""
scrollbarWidth={scrollbarWidth}
>
{children}
</NotificationContainer>
);
Expand Down Expand Up @@ -406,7 +411,17 @@ export const Notification: FC<{
title?: ReactNode;
footer?: ReactNode;
children: (afterClose: (action?: () => void) => void) => React.ReactNode;
}> = ({ children, isOpen, hideButton, backShadow, handleClose, title, footer }) => {
wrapperClassName?: string;
}> = ({
children,
isOpen,
hideButton,
backShadow,
handleClose,
title,
footer,
wrapperClassName
}) => {
const [entered, setEntered] = useState(false);
const [open, setOpen] = useState(false);
const { displayType } = useTheme();
Expand Down Expand Up @@ -511,7 +526,7 @@ export const Notification: FC<{
>
<Splash ref={nodeRef} className="scrollable">
<NotificationOverlay handleClose={handleClose} entered={entered}>
<NotificationWrapper entered={entered}>
<NotificationWrapper entered={entered} className={wrapperClassName}>
<Wrapper>
<Padding onClick={handleCloseOnlyOnNotFullWidth} />
<GapAdjusted onClick={handleCloseOnlyOnNotFullWidth} />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@ import {
} from '../../../hooks/blockchain/useSendMultiTransfer';
import { useNavigate } from 'react-router-dom';
import { AppRoute } from '../../../libs/routes';
import { useDisclosure } from '../../../hooks/useDisclosure';
import { MultiSendReceiversNotification } from './MultiSendReceiversNotification';

const ConfirmWrapper = styled.div`
display: flex;
Expand Down Expand Up @@ -98,6 +100,17 @@ const WalletNameStyled = styled.div`
gap: 6px;
`;

const RecipientsContainer = styled.div`
display: flex;
flex-direction: column;
text-align: right;
`;

const ShowAllButton = styled(Body3)`
color: ${p => p.theme.textAccent};
cursor: pointer;
`;

const FeeContainer = styled.div`
display: flex;
flex-direction: column;
Expand All @@ -116,6 +129,11 @@ const MultiSendConfirmContent: FC<{
onClose: () => void;
}> = ({ form, asset, listName, onClose }) => {
const { t } = useTranslation();
const {
isOpen: allRowsIsOpen,
onClose: allRowsOnClose,
onOpen: allRowsOnOpen
} = useDisclosure();
const image = useAssetImage(asset);
const { data: rate } = useRate(
typeof asset.address === 'string' ? asset.address : asset.address.toRawString()
Expand Down Expand Up @@ -168,64 +186,75 @@ const MultiSendConfirmContent: FC<{
const navigate = useNavigate();

return (
<ConfirmWrapper>
{image ? <Image full src={image} /> : <ImageMock full />}
<TransferLabel>Transfer</TransferLabel>
<Num2>{willBeSent}</Num2>
<FiatValue>{willBeSentInFiat}</FiatValue>
<ListBlockStyled noUserSelect>
<ListItemStyled hover={false}>
<Body2>Wallet</Body2>
{wallet && (
<WalletNameStyled>
<WalletEmoji
emojiSize="16px"
containerSize="16px"
emoji={wallet.emoji}
/>
<Label2>{wallet.name || t('wallet_title')}</Label2>
</WalletNameStyled>
)}
</ListItemStyled>
<ListItemStyled hover={false}>
<Body2>Recipients</Body2>
<Label2>{form.rows.length}</Label2>
</ListItemStyled>
<ListItemStyled hover={false}>
<Body2>List</Body2>
<Label2>{listName}</Label2>
</ListItemStyled>
<ListItemStyled hover={false}>
<Body2>Fee</Body2>
<FeeContainer>
{estimateError ? null : estimateLoading || !tonRate ? (
<>
<Skeleton margin="3px 0" width="100px" height="14px" />
<Skeleton margin="2px 0" width="80px" height="12px" />
</>
) : (
<>
<Label2>{tonFee}</Label2>
<Body3>{fiatFee}</Body3>
</>
<>
<ConfirmWrapper>
{image ? <Image full src={image} /> : <ImageMock full />}
<TransferLabel>Transfer</TransferLabel>
<Num2>{willBeSent}</Num2>
<FiatValue>{willBeSentInFiat}</FiatValue>
<ListBlockStyled noUserSelect>
<ListItemStyled hover={false}>
<Body2>Wallet</Body2>
{wallet && (
<WalletNameStyled>
<WalletEmoji
emojiSize="16px"
containerSize="16px"
emoji={wallet.emoji}
/>
<Label2>{wallet.name || t('wallet_title')}</Label2>
</WalletNameStyled>
)}
</FeeContainer>
</ListItemStyled>
</ListBlockStyled>
<ButtonBlock
</ListItemStyled>
<ListItemStyled hover={false}>
<Body2>Recipients</Body2>
<RecipientsContainer>
<Label2>{form.rows.length}&nbsp;wallets</Label2>
<ShowAllButton onClick={allRowsOnOpen}>Show all</ShowAllButton>
</RecipientsContainer>
</ListItemStyled>
<ListItemStyled hover={false}>
<Body2>List</Body2>
<Label2>{listName}</Label2>
</ListItemStyled>
<ListItemStyled hover={false}>
<Body2>Fee</Body2>
<FeeContainer>
{estimateError ? null : estimateLoading || !tonRate ? (
<>
<Skeleton margin="3px 0" width="100px" height="14px" />
<Skeleton margin="2px 0" width="80px" height="12px" />
</>
) : (
<>
<Label2>{tonFee}</Label2>
<Body3>{fiatFee}</Body3>
</>
)}
</FeeContainer>
</ListItemStyled>
</ListBlockStyled>
<ButtonBlock
form={formTokenized}
asset={asset}
feeEstimation={estimateData?.fee.weiAmount}
onSuccess={() => {
setTimeout(() => {
onClose();
navigate(AppRoute.activity);
}, 2000);
}}
isLoading={estimateLoading || !rate}
estimationError={!!estimateError}
/>
</ConfirmWrapper>
<MultiSendReceiversNotification
onClose={allRowsOnClose}
isOpen={allRowsIsOpen}
form={formTokenized}
asset={asset}
feeEstimation={estimateData?.fee.weiAmount}
onSuccess={() => {
setTimeout(() => {
onClose();
navigate(AppRoute.activity);
}, 2000);
}}
isLoading={estimateLoading || !rate}
estimationError={!!estimateError}
/>
</ConfirmWrapper>
</>
);
};

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
import { FC } from 'react';
import { Notification } from '../../Notification';
import styled, { createGlobalStyle } from 'styled-components';
import { Body2 } from '../../Text';
import { formatAddress } from '@tonkeeper/core/dist/utils/common';
import { MultiSendFormTokenized } from '../../../hooks/blockchain/useSendMultiTransfer';
import { formatFiatCurrency, formatter } from '../../../hooks/balance';
import { useAppContext } from '../../../hooks/appContext';
import { useRate } from '../../../state/rates';
import { TonAsset } from '@tonkeeper/core/dist/entries/crypto/asset/ton-asset';
import { shiftedDecimals } from '@tonkeeper/core/dist/utils/balance';

export const MultiSendReceiversNotification: FC<{
onClose: () => void;
isOpen: boolean;
form: MultiSendFormTokenized;
asset: TonAsset;
}> = ({ onClose, isOpen, form, asset }) => {
const WrapperStyles = createGlobalStyle`
.multi-send-receivers-notification {
max-width: 1000px;
}
`;

return (
<>
<WrapperStyles />
<Notification
title="Wallets"
isOpen={isOpen}
handleClose={onClose}
wrapperClassName="multi-send-receivers-notification"
>
{() => <ReceiversTable form={form} asset={asset} />}
</Notification>
</>
);
};

const ReceiversTableContainer = styled.div`
display: grid;
grid-template-columns: max-content minmax(88px, 1fr) max-content max-content;
column-gap: 8px;
align-items: center;
grid-auto-rows: 36px 1px;
padding: 0 12px;
background-color: ${p => p.theme.backgroundContent};
border-radius: ${p => p.theme.corner2xSmall};
`;

const RecipientCell = styled(Body2)`
color: ${p => p.theme.textSecondary};
font-family: ${p => p.theme.fontMono};
`;

const CommentCell = styled(Body2)`
overflow: hidden;
text-overflow: ellipsis;
`;

const FiatCell = styled(Body2)`
color: ${p => p.theme.textSecondary};
padding-right: 1rem;
`;

const AmountCell = styled(Body2)`
text-align: right;
`;

const Divider = styled.div`
background-color: ${p => p.theme.separatorCommon};
height: 1px;
grid-column: 1/-1;
margin: 0 -1rem;
`;

const ReceiversTable: FC<{ form: MultiSendFormTokenized; asset: TonAsset }> = ({ form, asset }) => {
const toStringReceiver = (item: MultiSendFormTokenized['rows'][number]['receiver']) => {
if (item && 'dns' in item) {
return item.dns.account.name;
}

return formatAddress(item!.address);
};

const { fiat } = useAppContext();
const { data: rate } = useRate(asset.address === 'TON' ? 'TON' : asset.address.toRawString());

const fiatToString = (weiAmount: MultiSendFormTokenized['rows'][number]['weiAmount']) => {
return formatFiatCurrency(
fiat,
shiftedDecimals(weiAmount, asset.decimals).multipliedBy(rate?.prices || 0)
);
};

const amountToString = (weiAmount: MultiSendFormTokenized['rows'][number]['weiAmount']) => {
return (
formatter.format(shiftedDecimals(weiAmount, asset.decimals), {
decimals: asset.decimals
}) +
' ' +
asset.symbol
);
};

return (
<ReceiversTableContainer>
{form.rows.map((item, index) => (
<>
<RecipientCell>{toStringReceiver(item.receiver)}</RecipientCell>
<CommentCell>{item.comment}</CommentCell>
<FiatCell>≈&nbsp;{fiatToString(item.weiAmount)}</FiatCell>
<AmountCell>{amountToString(item.weiAmount)}</AmountCell>
{index !== form.rows.length - 1 && <Divider />}
</>
))}
</ReceiversTableContainer>
);
};

0 comments on commit 3a68228

Please sign in to comment.