From 2f09f5b3d8243da6a554b1980286ea1779b4d4c4 Mon Sep 17 00:00:00 2001 From: evavirseda Date: Thu, 26 Dec 2024 17:24:26 +0100 Subject: [PATCH] refactor(wallet-dashboard): cleanup usage of `addNotification` and debris (#4553) * feat: cleanup notification * minor fix --- .../app/(protected)/layout.tsx | 2 - .../app/(protected)/vesting/page.tsx | 11 ++-- .../components/Dialogs/Assets/AssetDialog.tsx | 9 ++- .../Dialogs/SendToken/SendTokenDialog.tsx | 11 ++-- .../Dialogs/Staking/views/EnterAmountView.tsx | 11 ++-- .../views/EnterTimelockedAmountView.tsx | 17 ++--- .../views/UnstakeTimelockedObjectsView.tsx | 11 ++-- .../Dialogs/unstake/views/UnstakeView.tsx | 9 ++- .../Notifications/Notifications.tsx | 64 ------------------- apps/wallet-dashboard/components/index.ts | 1 - apps/wallet-dashboard/hooks/index.ts | 1 - .../hooks/useNotifications.ts | 9 --- .../stores/notificationStore.ts | 58 ----------------- 13 files changed, 34 insertions(+), 180 deletions(-) delete mode 100644 apps/wallet-dashboard/components/Notifications/Notifications.tsx delete mode 100644 apps/wallet-dashboard/hooks/useNotifications.ts delete mode 100644 apps/wallet-dashboard/stores/notificationStore.ts diff --git a/apps/wallet-dashboard/app/(protected)/layout.tsx b/apps/wallet-dashboard/app/(protected)/layout.tsx index 72fa80c67cc..61dadf84b57 100644 --- a/apps/wallet-dashboard/app/(protected)/layout.tsx +++ b/apps/wallet-dashboard/app/(protected)/layout.tsx @@ -2,7 +2,6 @@ // SPDX-License-Identifier: Apache-2.0 'use client'; -import { Notifications } from '@/components/index'; import React, { type PropsWithChildren } from 'react'; import { Sidebar, TopNav } from './components'; @@ -22,7 +21,6 @@ function DashboardLayout({ children }: PropsWithChildren): JSX.Element {
{children}
- ); } diff --git a/apps/wallet-dashboard/app/(protected)/vesting/page.tsx b/apps/wallet-dashboard/app/(protected)/vesting/page.tsx index e29d94a7fef..33572a16dff 100644 --- a/apps/wallet-dashboard/app/(protected)/vesting/page.tsx +++ b/apps/wallet-dashboard/app/(protected)/vesting/page.tsx @@ -13,9 +13,8 @@ import { } from '@/components'; import { UnstakeDialogView } from '@/components/Dialogs/unstake/enums'; import { useUnstakeDialog } from '@/components/Dialogs/unstake/hooks'; -import { useGetSupplyIncreaseVestingObjects, useNotifications } from '@/hooks'; +import { useGetSupplyIncreaseVestingObjects } from '@/hooks'; import { groupTimelockedStakedObjects, TimelockedStakedObjectsGrouped } from '@/lib/utils'; -import { NotificationType } from '@/stores/notificationStore'; import { useFeature } from '@growthbook/growthbook-react'; import { Panel, @@ -56,6 +55,7 @@ import { useRouter } from 'next/navigation'; import { useEffect, useState } from 'react'; import { StakedTimelockObject } from '@/components'; import { IotaSignAndExecuteTransactionOutput } from '@iota/wallet-standard'; +import toast from 'react-hot-toast'; export default function VestingDashboardPage(): JSX.Element { const [timelockedObjectsToUnstake, setTimelockedObjectsToUnstake] = @@ -66,7 +66,6 @@ export default function VestingDashboardPage(): JSX.Element { const router = useRouter(); const { data: system } = useIotaClientQuery('getLatestIotaSystemState'); const [isVestingScheduleDialogOpen, setIsVestingScheduleDialogOpen] = useState(false); - const { addNotification } = useNotifications(); const { data: activeValidators } = useGetActiveValidatorsInfo(); const { mutateAsync: signAndExecuteTransaction } = useSignAndExecuteTransaction(); const { theme } = useTheme(); @@ -163,7 +162,7 @@ export default function VestingDashboardPage(): JSX.Element { const handleCollect = () => { if (!unlockAllSupplyIncreaseVesting?.transactionBlock) { - addNotification('Failed to create a Transaction', NotificationType.Error); + toast.error('Failed to create a Transaction'); return; } signAndExecuteTransaction( @@ -177,10 +176,10 @@ export default function VestingDashboardPage(): JSX.Element { }, ) .then(() => { - addNotification('Collect transaction has been sent'); + toast.success('Collect transaction has been sent'); }) .catch(() => { - addNotification('Collect transaction was not sent', NotificationType.Error); + toast.error('Collect transaction was not sent'); }); }; diff --git a/apps/wallet-dashboard/components/Dialogs/Assets/AssetDialog.tsx b/apps/wallet-dashboard/components/Dialogs/Assets/AssetDialog.tsx index c71390a33aa..3283ef357de 100644 --- a/apps/wallet-dashboard/components/Dialogs/Assets/AssetDialog.tsx +++ b/apps/wallet-dashboard/components/Dialogs/Assets/AssetDialog.tsx @@ -9,10 +9,10 @@ import { createNftSendValidationSchema } from '@iota/core'; import { DetailsView, SendView } from './views'; import { IotaObjectData } from '@iota/iota-sdk/client'; import { AssetsDialogView } from './constants'; -import { useCreateSendAssetTransaction, useNotifications } from '@/hooks'; -import { NotificationType } from '@/stores/notificationStore'; +import { useCreateSendAssetTransaction } from '@/hooks'; import { TransactionDetailsView } from '../SendToken'; import { DialogLayout } from '../layout'; +import toast from 'react-hot-toast'; interface AssetsDialogProps { onClose: () => void; @@ -34,7 +34,6 @@ export function AssetDialog({ onClose, asset, refetchAssets }: AssetsDialogProps const [digest, setDigest] = useState(''); const activeAddress = account?.address ?? ''; const objectId = asset?.objectId ?? ''; - const { addNotification } = useNotifications(); const iotaClient = useIotaClient(); const validationSchema = createNftSendValidationSchema(activeAddress, objectId); @@ -57,10 +56,10 @@ export function AssetDialog({ onClose, asset, refetchAssets }: AssetsDialogProps setDigest(tx.digest); refetchAssets(); - addNotification('Transfer transaction successful', NotificationType.Success); + toast.success('Transfer transaction successful'); setView(AssetsDialogView.TransactionDetails); } catch { - addNotification('Transfer transaction failed', NotificationType.Error); + toast.error('Transfer transaction failed'); } } diff --git a/apps/wallet-dashboard/components/Dialogs/SendToken/SendTokenDialog.tsx b/apps/wallet-dashboard/components/Dialogs/SendToken/SendTokenDialog.tsx index a33f018a09c..2a9f3d1c330 100644 --- a/apps/wallet-dashboard/components/Dialogs/SendToken/SendTokenDialog.tsx +++ b/apps/wallet-dashboard/components/Dialogs/SendToken/SendTokenDialog.tsx @@ -4,14 +4,14 @@ import React, { useState } from 'react'; import { EnterValuesFormView, ReviewValuesFormView, TransactionDetailsView } from './views'; import { CoinBalance } from '@iota/iota-sdk/client'; -import { useSendCoinTransaction, useNotifications } from '@/hooks'; -import { NotificationType } from '@/stores/notificationStore'; +import { useSendCoinTransaction } from '@/hooks'; import { CoinFormat, useFormatCoin, useGetAllCoins } from '@iota/core'; import { Dialog, DialogContent, DialogPosition } from '@iota/apps-ui-kit'; import { FormDataValues } from './interfaces'; import { INITIAL_VALUES } from './constants'; import { IOTA_TYPE_ARG } from '@iota/iota-sdk/utils'; import { useTransferTransactionMutation } from '@/hooks'; +import toast from 'react-hot-toast'; interface SendCoinDialogProps { coin: CoinBalance; @@ -37,7 +37,6 @@ function SendTokenDialogBody({ const [fullAmount] = useFormatCoin(formData.amount, selectedCoin.coinType, CoinFormat.FULL); const { data: coinsData } = useGetAllCoins(selectedCoin.coinType, activeAddress); - const { addNotification } = useNotifications(); const isPayAllIota = selectedCoin.totalBalance === formData.amount && selectedCoin.coinType === IOTA_TYPE_ARG; @@ -58,18 +57,18 @@ function SendTokenDialogBody({ async function handleTransfer() { if (!transaction) { - addNotification('There was an error with the transaction', NotificationType.Error); + toast.error('There was an error with the transaction'); return; } transfer(transaction, { onSuccess: () => { setStep(FormStep.TransactionDetails); - addNotification('Transfer transaction has been sent', NotificationType.Success); + toast.success('Transfer transaction has been sent'); }, onError: () => { setOpen(false); - addNotification('Transfer transaction failed', NotificationType.Error); + toast.error('Transfer transaction failed'); }, }); } diff --git a/apps/wallet-dashboard/components/Dialogs/Staking/views/EnterAmountView.tsx b/apps/wallet-dashboard/components/Dialogs/Staking/views/EnterAmountView.tsx index b90de664794..58509774bc3 100644 --- a/apps/wallet-dashboard/components/Dialogs/Staking/views/EnterAmountView.tsx +++ b/apps/wallet-dashboard/components/Dialogs/Staking/views/EnterAmountView.tsx @@ -6,9 +6,9 @@ import { useFormatCoin, useBalance, CoinFormat, parseAmount, useCoinMetadata } f import { IOTA_TYPE_ARG } from '@iota/iota-sdk/utils'; import { useFormikContext } from 'formik'; import { useSignAndExecuteTransaction } from '@iota/dapp-kit'; -import { useNewStakeTransaction, useNotifications } from '@/hooks'; -import { NotificationType } from '@/stores/notificationStore'; +import { useNewStakeTransaction } from '@/hooks'; import EnterAmountDialogLayout from './EnterAmountDialogLayout'; +import toast from 'react-hot-toast'; export interface FormValues { amount: string; @@ -32,7 +32,6 @@ function EnterAmountView({ senderAddress, onSuccess, }: EnterAmountViewProps): JSX.Element { - const { addNotification } = useNotifications(); const { mutateAsync: signAndExecuteTransaction } = useSignAndExecuteTransaction(); const { values, resetForm } = useFormikContext(); @@ -65,7 +64,7 @@ function EnterAmountView({ function handleStake(): void { if (!newStakeData?.transaction) { - addNotification('Stake transaction was not created', NotificationType.Error); + toast.error('Stake transaction was not created'); return; } signAndExecuteTransaction( @@ -75,11 +74,11 @@ function EnterAmountView({ { onSuccess: (tx) => { onSuccess(tx.digest); - addNotification('Stake transaction has been sent'); + toast.success('Stake transaction has been sent'); resetForm(); }, onError: () => { - addNotification('Stake transaction was not sent', NotificationType.Error); + toast.error('Stake transaction was not sent'); }, }, ); diff --git a/apps/wallet-dashboard/components/Dialogs/Staking/views/EnterTimelockedAmountView.tsx b/apps/wallet-dashboard/components/Dialogs/Staking/views/EnterTimelockedAmountView.tsx index b21a6ad3bd1..b1e206dac35 100644 --- a/apps/wallet-dashboard/components/Dialogs/Staking/views/EnterTimelockedAmountView.tsx +++ b/apps/wallet-dashboard/components/Dialogs/Staking/views/EnterTimelockedAmountView.tsx @@ -12,14 +12,10 @@ import { import { IOTA_TYPE_ARG } from '@iota/iota-sdk/utils'; import { useFormikContext } from 'formik'; import { useSignAndExecuteTransaction } from '@iota/dapp-kit'; -import { - useGetCurrentEpochStartTimestamp, - useNewStakeTimelockedTransaction, - useNotifications, -} from '@/hooks'; -import { NotificationType } from '@/stores/notificationStore'; +import { useGetCurrentEpochStartTimestamp, useNewStakeTimelockedTransaction } from '@/hooks'; import { prepareObjectsForTimelockedStakingTransaction } from '@/lib/utils'; import EnterAmountDialogLayout from './EnterAmountDialogLayout'; +import toast from 'react-hot-toast'; export interface FormValues { amount: string; @@ -44,7 +40,6 @@ function EnterTimelockedAmountView({ handleClose, onSuccess, }: EnterTimelockedAmountViewProps): JSX.Element { - const { addNotification } = useNotifications(); const { mutateAsync: signAndExecuteTransaction } = useSignAndExecuteTransaction(); const { resetForm } = useFormikContext(); @@ -84,11 +79,11 @@ function EnterTimelockedAmountView({ function handleStake(): void { if (groupedTimelockObjects.length === 0) { - addNotification('Invalid stake amount. Please try again.', NotificationType.Error); + toast.error('Invalid stake amount. Please try again.'); return; } if (!newStakeData?.transaction) { - addNotification('Stake transaction was not created', NotificationType.Error); + toast.error('Stake transaction was not created'); return; } signAndExecuteTransaction( @@ -98,11 +93,11 @@ function EnterTimelockedAmountView({ { onSuccess: (tx) => { onSuccess?.(tx.digest); - addNotification('Stake transaction has been sent'); + toast.success('Stake transaction has been sent'); resetForm(); }, onError: () => { - addNotification('Stake transaction was not sent', NotificationType.Error); + toast.error('Stake transaction was not sent'); }, }, ); diff --git a/apps/wallet-dashboard/components/Dialogs/unstake/views/UnstakeTimelockedObjectsView.tsx b/apps/wallet-dashboard/components/Dialogs/unstake/views/UnstakeTimelockedObjectsView.tsx index 45e34ee5cf0..7ad5de11f24 100644 --- a/apps/wallet-dashboard/components/Dialogs/unstake/views/UnstakeTimelockedObjectsView.tsx +++ b/apps/wallet-dashboard/components/Dialogs/unstake/views/UnstakeTimelockedObjectsView.tsx @@ -4,7 +4,7 @@ import { StakeRewardsPanel, ValidatorStakingData } from '@/components'; import { DialogLayout, DialogLayoutBody, DialogLayoutFooter } from '../../layout'; import { Validator } from '../../Staking/views/Validator'; -import { useNewUnstakeTimelockedTransaction, useNotifications } from '@/hooks'; +import { useNewUnstakeTimelockedTransaction } from '@/hooks'; import { Collapsible, TimeUnit, @@ -24,7 +24,7 @@ import { } from '@iota/apps-ui-kit'; import { useCurrentAccount, useSignAndExecuteTransaction } from '@iota/dapp-kit'; import { IotaSignAndExecuteTransactionOutput } from '@iota/wallet-standard'; -import { NotificationType } from '@/stores/notificationStore'; +import toast from 'react-hot-toast'; interface UnstakeTimelockedObjectsViewProps { onClose: () => void; @@ -39,7 +39,6 @@ export function UnstakeTimelockedObjectsView({ onBack, onSuccess, }: UnstakeTimelockedObjectsViewProps) { - const { addNotification } = useNotifications(); const activeAddress = useCurrentAccount()?.address ?? ''; const { data: activeValidators } = useGetActiveValidatorsInfo(); @@ -71,7 +70,7 @@ export function UnstakeTimelockedObjectsView({ ); function handleCopySuccess() { - addNotification('Copied to clipboard'); + toast.success('Copied to clipboard'); } async function handleUnstake(): Promise { @@ -83,12 +82,12 @@ export function UnstakeTimelockedObjectsView({ }, { onSuccess: (tx) => { - addNotification('Unstake transaction has been sent'); + toast.success('Unstake transaction has been sent'); onSuccess(tx); }, }, ).catch(() => { - addNotification('Unstake transaction was not sent', NotificationType.Error); + toast.error('Unstake transaction was not sent'); }); } diff --git a/apps/wallet-dashboard/components/Dialogs/unstake/views/UnstakeView.tsx b/apps/wallet-dashboard/components/Dialogs/unstake/views/UnstakeView.tsx index 5d07eadcec3..81cad4d6ed6 100644 --- a/apps/wallet-dashboard/components/Dialogs/unstake/views/UnstakeView.tsx +++ b/apps/wallet-dashboard/components/Dialogs/unstake/views/UnstakeView.tsx @@ -24,9 +24,9 @@ import { Warning } from '@iota/ui-icons'; import { StakeRewardsPanel, ValidatorStakingData } from '@/components'; import { DialogLayout, DialogLayoutFooter, DialogLayoutBody } from '../../layout'; import { Validator } from '../../Staking/views/Validator'; -import { useNewUnstakeTransaction, useNotifications } from '@/hooks'; +import { useNewUnstakeTransaction } from '@/hooks'; import { IotaSignAndExecuteTransactionOutput } from '@iota/wallet-standard'; -import { NotificationType } from '@/stores/notificationStore'; +import toast from 'react-hot-toast'; interface UnstakeDialogProps { extendedStake: ExtendedDelegatedStake; @@ -44,7 +44,6 @@ export function UnstakeView({ showActiveStatus, }: UnstakeDialogProps): JSX.Element { const activeAddress = useCurrentAccount()?.address ?? ''; - const { addNotification } = useNotifications(); const { data: unstakeData, isPending: isUnstakeTxPending } = useNewUnstakeTransaction( activeAddress, extendedStake.stakedIotaId, @@ -81,12 +80,12 @@ export function UnstakeView({ }, { onSuccess: (tx) => { - addNotification('Unstake transaction has been sent'); + toast.success('Unstake transaction has been sent'); onSuccess(tx); }, }, ).catch(() => { - addNotification('Unstake transaction was not sent', NotificationType.Error); + toast.error('Unstake transaction was not sent'); }); } diff --git a/apps/wallet-dashboard/components/Notifications/Notifications.tsx b/apps/wallet-dashboard/components/Notifications/Notifications.tsx deleted file mode 100644 index 77493b164d9..00000000000 --- a/apps/wallet-dashboard/components/Notifications/Notifications.tsx +++ /dev/null @@ -1,64 +0,0 @@ -// Copyright (c) 2024 IOTA Stiftung -// SPDX-License-Identifier: Apache-2.0 - -'use client'; - -import { useEffect, useState } from 'react'; - -import { - NotificationData, - NotificationType, - useNotificationStore, -} from '@/stores/notificationStore'; - -const ALERT_FADE_OUT_DURATION = 700; - -const NOTIFICATION_TYPE_TO_COLOR = { - [NotificationType.Info]: 'bg-blue-500', - [NotificationType.Success]: 'bg-green-500', - [NotificationType.Error]: 'bg-red-500', - [NotificationType.Warning]: 'bg-yellow-500', -}; - -function Notification(props: { notification: NotificationData }): JSX.Element { - const clearNotification = useNotificationStore((state) => state.clearNotification); - const [transition, setTransition] = useState('opacity-100'); - - const { notification } = props; - - const bgColor = NOTIFICATION_TYPE_TO_COLOR[notification.type]; - - useEffect(() => { - const fadeOutputTimeout = setTimeout(() => { - setTransition('opacity-0'); - }, notification.duration - ALERT_FADE_OUT_DURATION); - - const removeTimeout = setTimeout(() => { - clearNotification(notification.index); - }, notification.duration); - - return () => { - clearTimeout(fadeOutputTimeout); - clearTimeout(removeTimeout); - }; - }, [notification, clearNotification]); - - return ( -
- {notification.message} -
- ); -} - -export default function Notifications(): JSX.Element { - const notifications = useNotificationStore((state) => state.notifications); - return ( -
- {notifications.map((notification) => ( - - ))} -
- ); -} diff --git a/apps/wallet-dashboard/components/index.ts b/apps/wallet-dashboard/components/index.ts index fcccf7b3a95..a20f84675b6 100644 --- a/apps/wallet-dashboard/components/index.ts +++ b/apps/wallet-dashboard/components/index.ts @@ -2,7 +2,6 @@ // SPDX-License-Identifier: Apache-2.0 export { default as RouteLink } from './RouteLink'; -export { default as Notifications } from './Notifications/Notifications'; export { default as Box } from './Box'; export { default as AmountBox } from './AmountBox'; export { default as Input } from './Input'; diff --git a/apps/wallet-dashboard/hooks/index.ts b/apps/wallet-dashboard/hooks/index.ts index 5ad872afeed..b88ba9388b2 100644 --- a/apps/wallet-dashboard/hooks/index.ts +++ b/apps/wallet-dashboard/hooks/index.ts @@ -3,7 +3,6 @@ export * from './useNewUnstakeTransaction'; export * from './useNewStakeTransaction'; -export * from './useNotifications'; export * from './useSendCoinTransaction'; export * from './useCreateSendAssetTransaction'; export * from './useGetCurrentEpochStartTimestamp'; diff --git a/apps/wallet-dashboard/hooks/useNotifications.ts b/apps/wallet-dashboard/hooks/useNotifications.ts deleted file mode 100644 index c5ec455b886..00000000000 --- a/apps/wallet-dashboard/hooks/useNotifications.ts +++ /dev/null @@ -1,9 +0,0 @@ -// Copyright (c) 2024 IOTA Stiftung -// SPDX-License-Identifier: Apache-2.0 - -import { useNotificationStore } from '@/stores/notificationStore'; - -export function useNotifications() { - const addNotification = useNotificationStore((state) => state.addNotification); - return { addNotification }; -} diff --git a/apps/wallet-dashboard/stores/notificationStore.ts b/apps/wallet-dashboard/stores/notificationStore.ts deleted file mode 100644 index 08f48e32d1e..00000000000 --- a/apps/wallet-dashboard/stores/notificationStore.ts +++ /dev/null @@ -1,58 +0,0 @@ -// Copyright (c) 2024 IOTA Stiftung -// SPDX-License-Identifier: Apache-2.0 - -import { indexGenerator } from '@/lib/utils'; -import { create } from 'zustand'; - -const indexGen = indexGenerator(200); - -export enum NotificationType { - Success = 'success', - Error = 'error', - Warning = 'warning', - Info = 'info', -} - -export type NotificationData = { - index: number; - message: string; - type: NotificationType; - duration: number; -}; - -interface NotificationsState { - notifications: NotificationData[]; - addNotification: (message: string, type?: NotificationType, duration?: number) => void; - clearNotification: (index: number) => void; -} - -export const useNotificationStore = create()((set) => ({ - notifications: [], - addNotification: ( - message: string, - type: NotificationType = NotificationType.Success, - duration: number = 3000, - ) => - set((state) => { - const index = indexGen.next().value; - - const newNotification: NotificationData = { - index, - message, - type, - duration, - }; - - return { - notifications: [...state.notifications, newNotification], - }; - }), - clearNotification: (index: number) => - set((state) => { - return { - notifications: [ - ...state.notifications.filter((notification) => notification.index !== index), - ], - }; - }), -}));