From 1391db5eed4c286d93de258b103dce4d142ea619 Mon Sep 17 00:00:00 2001 From: asiaznik Date: Fri, 3 Feb 2023 20:15:34 +0100 Subject: [PATCH] chore: new designs --- .../hooks/use-ethereum-transaction-toasts.tsx | 82 ++++---- .../use-ethereum-withdraw-approval-toasts.tsx | 29 ++- .../use-vega-transaction-toasts.spec.tsx | 4 +- .../lib/hooks/use-vega-transaction-toasts.tsx | 148 +++++++------- libs/tailwindcss-config/src/theme.js | 8 +- .../components/progress-bar/progress-bar.tsx | 2 + .../src/components/toast/toast.module.css | 8 +- .../src/components/toast/toast.stories.tsx | 71 ++++++- .../ui-toolkit/src/components/toast/toast.tsx | 180 ++++++++++++++---- .../toast/toasts-container.stories.tsx | 25 ++- .../src/components/toast/toasts-container.tsx | 29 +-- .../src/components/toast/use-toasts.ts | 1 - ...se-ethereum-withdraw-approvals-manager.tsx | 2 +- .../use-ethereum-withdraw-approvals-store.tsx | 8 + libs/withdraws/src/lib/withdrawals-table.tsx | 8 +- 15 files changed, 409 insertions(+), 196 deletions(-) diff --git a/apps/trading/lib/hooks/use-ethereum-transaction-toasts.tsx b/apps/trading/lib/hooks/use-ethereum-transaction-toasts.tsx index 4db68c326..b3f17565f 100644 --- a/apps/trading/lib/hooks/use-ethereum-transaction-toasts.tsx +++ b/apps/trading/lib/hooks/use-ethereum-transaction-toasts.tsx @@ -3,6 +3,7 @@ import { useAssetsDataProvider } from '@vegaprotocol/assets'; import { ETHERSCAN_TX, useEtherscanLink } from '@vegaprotocol/environment'; import { formatNumber, t, toBigNum } from '@vegaprotocol/react-helpers'; import type { Toast, ToastContent } from '@vegaprotocol/ui-toolkit'; +import { Panel } from '@vegaprotocol/ui-toolkit'; import { CLOSE_AFTER } from '@vegaprotocol/ui-toolkit'; import { useToasts } from '@vegaprotocol/ui-toolkit'; import { ExternalLink, Intent, ProgressBar } from '@vegaprotocol/ui-toolkit'; @@ -46,34 +47,35 @@ const EthTransactionDetails = ({ tx }: { tx: EthStoredTxState }) => { if (isWithdraw) label = t('Withdraw'); if (isDeposit) label = t('Deposit'); assetInfo = ( -
- - {label}{' '} - {formatNumber(toBigNum(tx.args[1], asset.decimals), asset.decimals)}{' '} - {asset.symbol} - -
+ + {label}{' '} + {formatNumber(toBigNum(tx.args[1], asset.decimals), asset.decimals)}{' '} + {asset.symbol} + ); } } - return ( - <> - {assetInfo} - {tx.status === EthTxStatus.Pending && ( -
- - {t('Awaiting confirmations')}{' '} - {`(${tx.confirmations}/${tx.requiredConfirmations})`} - - -
- )} - - ); + if (assetInfo || tx.requiresConfirmation) { + return ( + + {assetInfo} + {tx.status === EthTxStatus.Pending && ( + <> +

+ {t('Awaiting confirmations')}{' '} + {`(${tx.confirmations}/${tx.requiredConfirmations})`} +

+ + + )} +
+ ); + } + + return null; }; type EthTxToastContentProps = { @@ -82,26 +84,26 @@ type EthTxToastContentProps = { const EthTxRequestedToastContent = ({ tx }: EthTxToastContentProps) => { return ( -
-

{t('Action required')}

+ <> +

{t('Action required')}

{t( 'Please go to your wallet application and approve or reject the transaction.' )}

-
+ ); }; const EthTxPendingToastContent = ({ tx }: EthTxToastContentProps) => { return ( -
-

{t('Awaiting confirmation')}

+ <> +

{t('Awaiting confirmation')}

{t('Please wait for your transaction to be confirmed.')}

-
+ ); }; @@ -114,11 +116,11 @@ const EthTxErrorToastContent = ({ tx }: EthTxToastContentProps) => { errorMessage = tx.error.message; } return ( -
-

{t('Error occurred')}

-

{errorMessage}

+ <> +

{t('Error occurred')}

+

{errorMessage}

-
+ ); }; @@ -138,20 +140,20 @@ const EtherscanLink = ({ tx }: EthTxToastContentProps) => { const EthTxConfirmedToastContent = ({ tx }: EthTxToastContentProps) => { return ( -
-

{t('Transaction confirmed')}

+ <> +

{t('Transaction confirmed')}

{t('Your transaction has been confirmed.')}

-
+ ); }; const EthTxCompletedToastContent = ({ tx }: EthTxToastContentProps) => { const isDeposit = isDepositTransaction(tx); return ( -
-

+ <> +

{t('Processing')} {isDeposit && t('deposit')}

@@ -160,7 +162,7 @@ const EthTxCompletedToastContent = ({ tx }: EthTxToastContentProps) => {

-
+ ); }; diff --git a/apps/trading/lib/hooks/use-ethereum-withdraw-approval-toasts.tsx b/apps/trading/lib/hooks/use-ethereum-withdraw-approval-toasts.tsx index 5799d3eb1..61939de38 100644 --- a/apps/trading/lib/hooks/use-ethereum-withdraw-approval-toasts.tsx +++ b/apps/trading/lib/hooks/use-ethereum-withdraw-approval-toasts.tsx @@ -1,5 +1,6 @@ import { formatNumber, t, toBigNum } from '@vegaprotocol/react-helpers'; import type { Toast } from '@vegaprotocol/ui-toolkit'; +import { Panel } from '@vegaprotocol/ui-toolkit'; import { CLOSE_AFTER } from '@vegaprotocol/ui-toolkit'; import { useToasts } from '@vegaprotocol/ui-toolkit'; import { Intent } from '@vegaprotocol/ui-toolkit'; @@ -32,23 +33,26 @@ const EthWithdrawalApprovalToastContent = ({ if (tx.status === ApprovalStatus.Delayed) { title = t('Delayed'); } + if (tx.status === ApprovalStatus.Ready) { + title = t('Approved'); + } const num = formatNumber( toBigNum(tx.withdrawal.amount, tx.withdrawal.asset.decimals), tx.withdrawal.asset.decimals ); const details = ( -
- + + {t('Withdraw')} {num} {tx.withdrawal.asset.symbol} - -
+ + ); return ( -
+ <> {title.length > 0 &&

{title}

} {details} -
+ ); }; @@ -60,21 +64,28 @@ export const useEthereumWithdrawApprovalsToasts = () => { state.setToast, state.remove, ]); - const dismissTx = useEthWithdrawApprovalsStore((state) => state.dismiss); + const [dismissTx, deleteTx] = useEthWithdrawApprovalsStore((state) => [ + state.dismiss, + state.delete, + ]); const fromWithdrawalApproval = useCallback( (tx: EthWithdrawalApprovalState): Toast => ({ id: `withdrawal-${tx.id}`, intent: intentMap[tx.status], onClose: () => { - dismissTx(tx.id); + if ([ApprovalStatus.Error, ApprovalStatus.Ready].includes(tx.status)) { + deleteTx(tx.id); + } else { + dismissTx(tx.id); + } remove(`withdrawal-${tx.id}`); }, loader: tx.status === ApprovalStatus.Pending, content: , closeAfter: isFinal(tx) ? CLOSE_AFTER : undefined, }), - [dismissTx, remove] + [deleteTx, dismissTx, remove] ); useEthWithdrawApprovalsStore.subscribe( diff --git a/apps/trading/lib/hooks/use-vega-transaction-toasts.spec.tsx b/apps/trading/lib/hooks/use-vega-transaction-toasts.spec.tsx index 7ed3d8676..3fb7d229f 100644 --- a/apps/trading/lib/hooks/use-vega-transaction-toasts.spec.tsx +++ b/apps/trading/lib/hooks/use-vega-transaction-toasts.spec.tsx @@ -260,7 +260,7 @@ describe('VegaTransactionDetails', () => { const { queryByTestId } = render( ); - expect(queryByTestId('vega-tx-details')).toBeNull(); + expect(queryByTestId('toast-panel')).toBeNull(); }); it.each([ { tx: withdraw, details: 'Withdraw 12.34 $A' }, @@ -275,6 +275,6 @@ describe('VegaTransactionDetails', () => { { tx: batch, details: 'Batch market instruction' }, ])('display details for transaction', ({ tx, details }) => { const { queryByTestId } = render(); - expect(queryByTestId('vega-tx-details')?.textContent).toEqual(details); + expect(queryByTestId('toast-panel')?.textContent).toEqual(details); }); }); diff --git a/apps/trading/lib/hooks/use-vega-transaction-toasts.tsx b/apps/trading/lib/hooks/use-vega-transaction-toasts.tsx index e097dcce9..2ceb014ab 100644 --- a/apps/trading/lib/hooks/use-vega-transaction-toasts.tsx +++ b/apps/trading/lib/hooks/use-vega-transaction-toasts.tsx @@ -1,4 +1,3 @@ -import type { ReactNode } from 'react'; import { useCallback } from 'react'; import first from 'lodash/first'; import compact from 'lodash/compact'; @@ -25,6 +24,7 @@ import { VegaTxStatus, } from '@vegaprotocol/wallet'; import type { Toast, ToastContent } from '@vegaprotocol/ui-toolkit'; +import { Panel } from '@vegaprotocol/ui-toolkit'; import { CLOSE_AFTER } from '@vegaprotocol/ui-toolkit'; import { useToasts } from '@vegaprotocol/ui-toolkit'; import { Button, ExternalLink, Intent } from '@vegaprotocol/ui-toolkit'; @@ -42,6 +42,7 @@ import { DApp, EXPLORER_TX, useLinks } from '@vegaprotocol/environment'; import { getRejectionReason, useOrderByIdQuery } from '@vegaprotocol/orders'; import { useMarketList } from '@vegaprotocol/market-list'; import type { Side } from '@vegaprotocol/types'; +import { OrderRejectionReasonMapping, OrderStatus } from '@vegaprotocol/types'; import { OrderStatusMapping } from '@vegaprotocol/types'; const intentMap: { [s in VegaTxStatus]: Intent } = { @@ -100,20 +101,6 @@ const isTransactionTypeSupported = (tx: VegaStoredTxState) => { ); }; -const Details = ({ - children, - title = '', -}: { - children: ReactNode; - title?: string; -}) => ( -
-
- {children} -
-
-); - type SizeAtPriceProps = { side: Side; size: string; @@ -154,8 +141,8 @@ const SubmitOrderDetails = ({ const side = order ? order.side : data.side; return ( -
-

+ +

{order ? t( `Submit order - ${OrderStatusMapping[order.status].toLowerCase()}` @@ -177,10 +164,7 @@ const SubmitOrderDetails = ({ price={price} />

- {order && order.rejectionReason && ( -

{getRejectionReason(order)}

- )} -

+ ); }; @@ -196,7 +180,7 @@ const EditOrderDetails = ({ }); const { data: markets } = useMarketList(); - const originalOrder = orderById?.orderByID; + const originalOrder = order || orderById?.orderByID; if (!originalOrder) return null; const market = markets?.find((m) => m.id === originalOrder.market.id); if (!market) return null; @@ -230,8 +214,8 @@ const EditOrderDetails = ({ ); return ( -
-

+ +

{order ? t(`Edit order - ${OrderStatusMapping[order.status].toLowerCase()}`) : t('Edit order')} @@ -241,10 +225,7 @@ const EditOrderDetails = ({ {original}

{edited}

- {order && order.rejectionReason && ( -

{getRejectionReason(order)}

- )} -

+ ); }; @@ -279,8 +260,8 @@ const CancelOrderDetails = ({ /> ); return ( -
-

+ +

{order ? t( `Cancel order - ${OrderStatusMapping[order.status].toLowerCase()}` @@ -291,10 +272,7 @@ const CancelOrderDetails = ({

{original}

- {order && order.rejectionReason && ( -

{getRejectionReason(order)}

- )} -

+ ); }; @@ -313,9 +291,11 @@ export const VegaTransactionDetails = ({ tx }: { tx: VegaStoredTxState }) => { asset.decimals ); return ( -
- {t('Withdraw')} {num} {asset.symbol} -
+ + + {t('Withdraw')} {num} {asset.symbol} + + ); } } @@ -332,7 +312,7 @@ export const VegaTransactionDetails = ({ tx }: { tx: VegaStoredTxState }) => { tx.body.orderCancellation.marketId === undefined && tx.body.orderCancellation.orderId === undefined ) { - return
{t('Cancel all orders')}
; + return {t('Cancel all orders')}; } // CANCEL @@ -355,11 +335,15 @@ export const VegaTransactionDetails = ({ tx }: { tx: VegaStoredTxState }) => { m.id === (tx.body as OrderCancellationBody).orderCancellation.marketId )?.tradableInstrument.instrument.code; return ( -
- {marketName - ? `${t('Cancel all orders for')} ${marketName}` - : t('Cancel all orders')} -
+ + {marketName ? ( + <> + {t('Cancel all orders for')} {marketName} + + ) : ( + t('Cancel all orders') + )} + ); } } @@ -381,15 +365,16 @@ export const VegaTransactionDetails = ({ tx }: { tx: VegaStoredTxState }) => { const market = marketId && markets?.find((m) => m.id === marketId); if (market) { return ( -
- {t('Close position for')} {market.tradableInstrument.instrument.code} -
+ + {t('Close position for')}{' '} + {market.tradableInstrument.instrument.code} + ); } } if (isBatchMarketInstructionsTransaction(tx.body)) { - return
{t('Batch market instruction')}
; + return {t('Batch market instruction')}; } if (isTransferTransaction(tx.body)) { @@ -418,22 +403,22 @@ export const VegaTransactionDetails = ({ tx }: { tx: VegaStoredTxState }) => { type VegaTxToastContentProps = { tx: VegaStoredTxState }; const VegaTxRequestedToastContent = ({ tx }: VegaTxToastContentProps) => ( -
-

{t('Action required')}

+ <> +

{t('Action required')}

{t( 'Please go to your Vega wallet application and approve or reject the transaction.' )}

-
+ ); const VegaTxPendingToastContentProps = ({ tx }: VegaTxToastContentProps) => { const explorerLink = useLinks(DApp.Explorer); return ( -
-

{t('Awaiting confirmation')}

+ <> +

{t('Awaiting confirmation')}

{t('Please wait for your transaction to be confirmed')}

{tx.txHash && (

@@ -446,7 +431,7 @@ const VegaTxPendingToastContentProps = ({ tx }: VegaTxToastContentProps) => {

)} -
+ ); }; @@ -460,7 +445,7 @@ const VegaTxCompleteToastsContent = ({ tx }: VegaTxToastContentProps) => { if (isWithdrawTransaction(tx.body)) { const completeWithdrawalButton = tx.withdrawal && ( -
+

-

+

); return ( -
-

{t('Funds unlocked')}

+ <> +

{t('Funds unlocked')}

{t('Your funds have been unlocked for withdrawal')}

{tx.txHash && (

@@ -491,7 +476,32 @@ const VegaTxCompleteToastsContent = ({ tx }: VegaTxToastContentProps) => { )} {completeWithdrawalButton} -

+ + ); + } + + if (tx.order && tx.order.rejectionReason) { + return ( + <> +

{t('Rejected')}

+

+ {t( + 'Your order has been rejected because: %s', + OrderRejectionReasonMapping[tx.order.rejectionReason] + )} +

+ {tx.txHash && ( +

+ + {t('View in block explorer')} + +

+ )} + + ); } @@ -526,8 +536,8 @@ const VegaTxCompleteToastsContent = ({ tx }: VegaTxToastContentProps) => { } return ( -
-

{t('Confirmed')}

+ <> +

{t('Confirmed')}

{t('Your transaction has been confirmed ')}

{tx.txHash && (

@@ -540,7 +550,7 @@ const VegaTxCompleteToastsContent = ({ tx }: VegaTxToastContentProps) => {

)} -
+ ); }; @@ -571,16 +581,16 @@ const VegaTxErrorToastContent = ({ tx }: VegaTxToastContentProps) => { } return ( -
-

{label}

-

{errorMessage}

+ <> +

{label}

+

{errorMessage}

{walletError && ( )} -
+ ); }; @@ -626,9 +636,15 @@ export const useVegaTransactionToasts = () => { if (tx.status === VegaTxStatus.Error) { content = ; } + + const intent = + tx.order && [OrderStatus.STATUS_REJECTED].includes(tx.order.status) + ? Intent.Danger + : intentMap[tx.status]; + return { id: `vega-${tx.id}`, - intent: intentMap[tx.status], + intent, onClose: onClose(tx), loader: tx.status === VegaTxStatus.Pending, content, diff --git a/libs/tailwindcss-config/src/theme.js b/libs/tailwindcss-config/src/theme.js index 4d0aeffec..7141c76f4 100644 --- a/libs/tailwindcss-config/src/theme.js +++ b/libs/tailwindcss-config/src/theme.js @@ -174,16 +174,16 @@ module.exports = { '60%': { transform: 'rotate( 0.0deg)' }, '100%': { transform: 'rotate( 0.0deg)' }, }, - 'vertical-progress': { - from: { height: '0' }, - to: { height: '100%' }, + 'progress': { + from: { width: '0' }, + to: { width: '100%' }, }, }, animation: { rotate: 'rotate 2s linear alternate infinite', 'rotate-back': 'rotate 2s linear reverse infinite', wave: 'wave 2s linear infinite', - 'vertical-progress': 'vertical-progress 5s linear 1', + 'progress': 'progress 5s cubic-bezier(.39,.58,.57,1) 1', }, data: { selected: 'state~="checked"', diff --git a/libs/ui-toolkit/src/components/progress-bar/progress-bar.tsx b/libs/ui-toolkit/src/components/progress-bar/progress-bar.tsx index 1d40955f3..0421d6a61 100644 --- a/libs/ui-toolkit/src/components/progress-bar/progress-bar.tsx +++ b/libs/ui-toolkit/src/components/progress-bar/progress-bar.tsx @@ -11,6 +11,7 @@ interface ProgressBarProps { export const ProgressBar = ({ className, intent, value }: ProgressBarProps) => { return (
{ )} >
; const Template: ComponentStory = (args) => { - const toastContent = ( - <> -

Lorem ipsum dolor sit amet consectetur adipisicing elit.

-

Eaque exercitationem saepe cupiditate sunt impedit.

-

I really like 🥪🥪🥪!

- - ); - return ; + return ; }; export const Default = Template.bind({}); @@ -24,6 +19,16 @@ Default.args = { id: 'def', intent: Intent.None, state: 'showing', + content: ( + <> +

Optional heading

+

This is a message that can return over multiple lines.

+

+ Optional link +

+ + ), + onClose: () => undefined, }; export const Primary = Template.bind({}); @@ -31,6 +36,17 @@ Primary.args = { id: 'pri', intent: Intent.Primary, state: 'showing', + content: ( + <> +

Optional heading

+

This is a message that can return over multiple lines.

+

+ Optional link +

+ Lorem ipsum dolor sit amet consectetur adipisicing elit + + ), + onClose: () => undefined, }; export const Danger = Template.bind({}); @@ -38,6 +54,17 @@ Danger.args = { id: 'dan', intent: Intent.Danger, state: 'showing', + content: ( + <> +

Optional heading

+

This is a message that can return over multiple lines.

+

+ Optional link +

+ Lorem ipsum dolor sit amet consectetur adipisicing elit + + ), + onClose: () => undefined, }; export const Warning = Template.bind({}); @@ -45,6 +72,21 @@ Warning.args = { id: 'war', intent: Intent.Warning, state: 'showing', + content: ( + <> +

Optional heading

+

This is a message that can return over multiple lines.

+

+ Optional link +

+ + Deposit 10.00 tUSDX +

Awaiting confirmations (1/3)

+ +
+ + ), + onClose: () => undefined, }; export const Success = Template.bind({}); @@ -52,4 +94,15 @@ Success.args = { id: 'suc', intent: Intent.Success, state: 'showing', + content: ( + <> +

Optional heading

+

This is a message that can return over multiple lines.

+

+ Optional link +

+ Lorem ipsum dolor sit amet consectetur adipisicing elit + + ), + onClose: () => undefined, }; diff --git a/libs/ui-toolkit/src/components/toast/toast.tsx b/libs/ui-toolkit/src/components/toast/toast.tsx index ce9012571..99d952f69 100644 --- a/libs/ui-toolkit/src/components/toast/toast.tsx +++ b/libs/ui-toolkit/src/components/toast/toast.tsx @@ -3,7 +3,8 @@ import styles from './toast.module.css'; import type { IconName } from '@blueprintjs/icons'; import { IconNames } from '@blueprintjs/icons'; import classNames from 'classnames'; -import { useEffect } from 'react'; +import type { ForwardedRef, HTMLAttributes, ReactNode } from 'react'; +import { forwardRef, useEffect } from 'react'; import { useCallback } from 'react'; import { useLayoutEffect } from 'react'; import { useRef } from 'react'; @@ -33,23 +34,38 @@ const toastIconMapping: { [i in Intent]: IconName } = { [Intent.None]: IconNames.HELP, [Intent.Primary]: IconNames.INFO_SIGN, [Intent.Success]: IconNames.TICK_CIRCLE, - [Intent.Warning]: IconNames.ERROR, + [Intent.Warning]: IconNames.WARNING_SIGN, [Intent.Danger]: IconNames.ERROR, }; -const getToastAccent = (intent: Intent) => ({ - // strip - 'bg-gray-200 text-black text-opacity-70': intent === Intent.None, - 'bg-vega-blue text-white text-opacity-70': intent === Intent.Primary, - 'bg-success text-white text-opacity-70': intent === Intent.Success, - 'bg-warning text-white text-opacity-70': intent === Intent.Warning, - 'bg-vega-pink text-white text-opacity-70': intent === Intent.Danger, -}); - -export const CLOSE_DELAY = 750; +export const CLOSE_DELAY = 500; export const TICKER = 100; export const CLOSE_AFTER = 5000; +export const Panel = forwardRef< + HTMLDivElement, + { + ref: ForwardedRef; + } & HTMLAttributes +>(({ children, ref, className, ...props }) => { + return ( +
h4]:font-bold', + className + )} + {...props} + > + {children} +
+ ); +}); + export const Toast = ({ id, intent, @@ -85,7 +101,7 @@ export const Toast = ({ } }); return () => cancelAnimationFrame(req); - }, [id]); + }, [id, intent, content]); // DO NOT REMOVE DEPS: intent, content useEffect(() => { const i = setInterval(() => { @@ -130,8 +146,54 @@ export const Toast = ({ } }} className={classNames( - 'relative w-[300px] top-0 rounded-md border overflow-hidden mb-2', - 'text-black bg-white dark:border-zinc-700', + 'w-[320px] rounded-md overflow-hidden', + 'shadow-[8px_8px_16px_0_rgba(0,0,0,0.4)]', + 'text-black dark:text-white', + 'font-alpha liga-0-calt-0 text-[14px] leading-[19px]', + // background + { + 'bg-vega-light-100 dark:bg-vega-dark-100 ': intent === Intent.None, + 'bg-vega-blue-300 dark:bg-vega-blue-700': intent === Intent.Primary, + 'bg-vega-green-300 dark:bg-vega-green-700': intent === Intent.Success, + 'bg-vega-orange-300 dark:bg-vega-orange-700': + intent === Intent.Warning, + 'bg-vega-pink-300 dark:bg-vega-pink-700': intent === Intent.Danger, + }, + // panel's colours + { + '[&_[data-panel]]:bg-vega-light-150 [&_[data-panel]]:dark:bg-vega-dark-150 ': + intent === Intent.None, + '[&_[data-panel]]:bg-vega-blue-350 [&_[data-panel]]:dark:bg-vega-blue-650': + intent === Intent.Primary, + '[&_[data-panel]]:bg-vega-green-350 [&_[data-panel]]:dark:bg-vega-green-650': + intent === Intent.Success, + '[&_[data-panel]]:bg-vega-orange-350 [&_[data-panel]]:dark:bg-vega-orange-650': + intent === Intent.Warning, + '[&_[data-panel]]:bg-vega-pink-350 [&_[data-panel]]:dark:bg-vega-pink-650': + intent === Intent.Danger, + }, + // panels's progress bar colours + '[&_[data-progress-bar]]:mt-[10px] [&_[data-progress-bar]]:mb-[4px]', + { + '[&_[data-progress-bar]]:bg-vega-light-200 [&_[data-progress-bar]]:dark:bg-vega-dark-200 ': + intent === Intent.None, + '[&_[data-progress-bar]]:bg-vega-blue-400 [&_[data-progress-bar]]:dark:bg-vega-blue-600': + intent === Intent.Primary, + '[&_[data-progress-bar-value]]:bg-vega-blue-500 [&_[data-progress-bar-value]]:dark:bg-vega-blue-500': + intent === Intent.Primary, + '[&_[data-progress-bar]]:bg-vega-green-400 [&_[data-progress-bar]]:dark:bg-vega-green-600': + intent === Intent.Success, + '[&_[data-progress-bar-value]]:bg-vega-green-600 [&_[data-progress-bar-value]]:dark:bg-vega-green-500': + intent === Intent.Success, + '[&_[data-progress-bar]]:bg-vega-orange-400 [&_[data-progress-bar]]:dark:bg-vega-orange-600': + intent === Intent.Warning, + '[&_[data-progress-bar-value]]:bg-vega-orange-500 [&_[data-progress-bar-value]]:dark:bg-vega-orange-500': + intent === Intent.Warning, + '[&_[data-progress-bar]]:bg-vega-pink-400 [&_[data-progress-bar]]:dark:bg-vega-pink-600': + intent === Intent.Danger, + '[&_[data-progress-bar-value]]:bg-vega-pink-500 [&_[data-progress-bar-value]]:dark:bg-vega-pink-500': + intent === Intent.Danger, + }, { [styles['initial']]: state === 'initial', [styles['showing']]: state === 'showing', @@ -144,49 +206,83 @@ export const Toast = ({ type="button" data-testid="toast-close" onClick={closeToast} - className="absolute p-2 top-0 right-0" + className="absolute p-[8px] top-[3px] right-[3px] z-20" > - +
+ {loader ? ( +
+ +
+ ) : ( + + )} +
+
p]:mb-[2.5px]', + // toast heading + '[&>h3]:text-[14px] [&>h3]:leading-[13px] [&>h3]:uppercase [&>h3]:mb-[8px]' + )} + data-testid="toast-content" + > + {content} {withProgress && (
)} -
- {loader ? ( -
- -
- ) : ( - - )} -
-
-
- {content}
diff --git a/libs/ui-toolkit/src/components/toast/toasts-container.stories.tsx b/libs/ui-toolkit/src/components/toast/toasts-container.stories.tsx index b3da05404..1a8ecab28 100644 --- a/libs/ui-toolkit/src/components/toast/toasts-container.stories.tsx +++ b/libs/ui-toolkit/src/components/toast/toasts-container.stories.tsx @@ -84,7 +84,7 @@ const usePrice = create((set) => ({ const Template: ComponentStory = (args) => { const setPrice = usePrice((state) => state.setPrice); - const { add, close, closeAll, update, remove, toasts } = useToasts( + const { add, close, closeAll, update, remove, toasts, setToast } = useToasts( (state) => ({ add: state.add, close: state.close, @@ -92,6 +92,7 @@ const Template: ComponentStory = (args) => { update: state.update, remove: state.remove, toasts: state.toasts, + setToast: state.setToast, }) ); @@ -196,6 +197,26 @@ const Template: ComponentStory = (args) => { > 🧽 + ); @@ -203,5 +224,5 @@ const Template: ComponentStory = (args) => { export const Default = Template.bind({}); Default.args = { - order: 'asc', + order: 'desc', }; diff --git a/libs/ui-toolkit/src/components/toast/toasts-container.tsx b/libs/ui-toolkit/src/components/toast/toasts-container.tsx index 13be8ee4b..96100baa9 100644 --- a/libs/ui-toolkit/src/components/toast/toasts-container.tsx +++ b/libs/ui-toolkit/src/components/toast/toasts-container.tsx @@ -7,6 +7,8 @@ import { Toast } from './toast'; import type { Toasts } from './use-toasts'; import { useToasts } from './use-toasts'; +import { Portal } from '@radix-ui/react-portal'; + type ToastsContainerProps = { toasts: Toasts; order: 'asc' | 'desc'; @@ -39,19 +41,21 @@ export const ToastsContainer = ({ }, [count, order, toasts]); return ( -
} className={classNames( 'group', - 'absolute top-0 right-0 pt-2 pr-2 max-w-full z-20 max-h-full overflow-x-hidden overflow-y-auto', + 'absolute bottom-0 right-0 z-20 ', + 'p-[8px_16px_16px_16px]', + 'max-w-full max-h-full overflow-x-hidden overflow-y-auto', { hidden: Object.keys(toasts).length === 0, } )} >
    {toasts && @@ -63,23 +67,26 @@ export const ToastsContainer = ({ ); })}
-
+ ); }; diff --git a/libs/ui-toolkit/src/components/toast/use-toasts.ts b/libs/ui-toolkit/src/components/toast/use-toasts.ts index c27922909..185933170 100644 --- a/libs/ui-toolkit/src/components/toast/use-toasts.ts +++ b/libs/ui-toolkit/src/components/toast/use-toasts.ts @@ -71,7 +71,6 @@ export const useToasts = create( const found = state.toasts[toast.id]; if (found) { if (!isEqual(found, toast)) { - console.log('updating', toast.id); Object.assign(found, toast); } } else { diff --git a/libs/web3/src/lib/use-ethereum-withdraw-approvals-manager.tsx b/libs/web3/src/lib/use-ethereum-withdraw-approvals-manager.tsx index 5669a0c09..0d670a9a6 100644 --- a/libs/web3/src/lib/use-ethereum-withdraw-approvals-manager.tsx +++ b/libs/web3/src/lib/use-ethereum-withdraw-approvals-manager.tsx @@ -103,7 +103,7 @@ export const useEthWithdrawApprovalsManager = () => { update(transaction.id, { status: ApprovalStatus.Ready, approval, - dialogOpen: false, + dialogOpen: true, }); const signer = provider.getSigner(); createEthTransaction( diff --git a/libs/web3/src/lib/use-ethereum-withdraw-approvals-store.tsx b/libs/web3/src/lib/use-ethereum-withdraw-approvals-store.tsx index ef5c2c67c..7437f4b3a 100644 --- a/libs/web3/src/lib/use-ethereum-withdraw-approvals-store.tsx +++ b/libs/web3/src/lib/use-ethereum-withdraw-approvals-store.tsx @@ -46,6 +46,7 @@ export interface EthWithdrawApprovalStore { > ) => void; dismiss: (index: number) => void; + delete: (index: number) => void; } export const useEthWithdrawApprovalsStore = create( @@ -108,5 +109,12 @@ export const useEthWithdrawApprovalsStore = create( }) ); }, + delete: (index: number) => { + set( + produce((state: EthWithdrawApprovalStore) => { + delete state.transactions[index]; + }) + ); + }, })) ); diff --git a/libs/withdraws/src/lib/withdrawals-table.tsx b/libs/withdraws/src/lib/withdrawals-table.tsx index 393b60577..653bcfd5e 100644 --- a/libs/withdraws/src/lib/withdrawals-table.tsx +++ b/libs/withdraws/src/lib/withdrawals-table.tsx @@ -229,13 +229,15 @@ export const VerificationStatus = ({ state }: { state: VerifyState }) => { ); return ( <> -

- {t("The amount you're withdrawing has triggered a time delay")} -

+

{t("The amount you're withdrawing has triggered a time delay")}

{t(`Cannot be completed until ${formattedTime}`)}

); } + if (state.status === ApprovalStatus.Ready) { + return

{t('The withdrawal has been approved.')}

; + } + return null; };