From c86b017267a709b799cb53ebb9403652c1b7386a Mon Sep 17 00:00:00 2001 From: sehyunc <41171808+sehyunc@users.noreply.github.com> Date: Thu, 5 Sep 2024 15:15:03 -0700 Subject: [PATCH] toasts: set max duration for each toast --- app/components/task-toaster.tsx | 105 +++++++++++++++++--------------- hooks/use-withdraw.ts | 20 +++--- 2 files changed, 62 insertions(+), 63 deletions(-) diff --git a/app/components/task-toaster.tsx b/app/components/task-toaster.tsx index 56e4621b..4d650a6b 100644 --- a/app/components/task-toaster.tsx +++ b/app/components/task-toaster.tsx @@ -6,7 +6,6 @@ import { Task, useTaskHistoryWebSocket } from "@renegade-fi/react" import { toast } from "sonner" import { - WITHDRAW_TOAST_ID, formatTaskState, generateCompletionToastMessage, generateFailedToastMessage, @@ -20,23 +19,46 @@ import { isWithdrawTask, } from "@/lib/task" +const DURATION_MS = 10000 // 10 seconds + export function TaskToaster() { - const seen = React.useRef>(new Map()) + const toastTimers = React.useRef>(new Map()) + const seenStates = React.useRef>(new Map()) + + const scheduleToastDismissal = React.useCallback((id: string) => { + if (toastTimers.current.has(id)) { + clearTimeout(toastTimers.current.get(id)!) + } + const timer = setTimeout(() => { + toast.dismiss(id) + toastTimers.current.delete(id) + seenStates.current.delete(id) + }, DURATION_MS) + toastTimers.current.set(id, timer) + }, []) + + React.useEffect(() => { + const timers = toastTimers.current + return () => { + timers.forEach(clearTimeout) + } + }, []) + useTaskHistoryWebSocket({ onUpdate(task) { - if (seen.current.get(task.id)?.state === task.state) { - return - } - seen.current.set(task.id, task) + const currentState = `${task.id}-${task.state}` + if (seenStates.current.get(task.id) === currentState) return + seenStates.current.set(task.id, currentState) + if (isWithdrawTask(task)) { - processWithdrawTask(task) + processWithdrawTask(task, scheduleToastDismissal) } else if ( isDepositTask(task) || isPlaceOrderTask(task) || isCancelOrderTask(task) || isRefreshWalletTask(task) ) { - processTask(task) + processTask(task, scheduleToastDismissal) } }, }) @@ -44,77 +66,60 @@ export function TaskToaster() { return null } -function processTask(incomingTask: Task) { +function processTask( + incomingTask: Task, + scheduleToastDismissal: (id: string) => void, +) { const state = formatTaskState(incomingTask.state) + const id = incomingTask.id + if (incomingTask.state === "Completed") { const message = generateCompletionToastMessage(incomingTask) - toast.success(message, { - id: incomingTask.id, - description: state, - }) - return + toast.success(message, { id, description: state }) } else if (incomingTask.state === "Failed") { const message = generateFailedToastMessage(incomingTask) - toast.error(message, { - id: incomingTask.id, - }) + toast.error(message, { id }) } else if (incomingTask.state === "Proving") { const message = generateStartToastMessage(incomingTask) - toast.loading(message, { - id: incomingTask.id, - description: state, - }) + toast.loading(message, { id, description: state }) } else if ( incomingTask.state === "Updating Validity Proofs" && isDepositTask(incomingTask) ) { const message = generateCompletionToastMessage(incomingTask) - toast.success(message, { - id: incomingTask.id, - description: "Completed", - }) + toast.success(message, { id, description: "Completed" }) } else { const message = generateStartToastMessage(incomingTask) - toast.loading(message, { - id: incomingTask.id, - description: state, - }) + toast.loading(message, { id, description: state }) } + + scheduleToastDismissal(id) } -function processWithdrawTask(incomingTask: Task) { +function processWithdrawTask( + incomingTask: Task, + scheduleToastDismissal: (id: string) => void, +) { if (isWithdrawTask(incomingTask)) { const state = formatTaskState(incomingTask.state) - const id = WITHDRAW_TOAST_ID( - incomingTask.task_info.mint, - incomingTask.task_info.amount, - ) + const id = incomingTask.id + if (incomingTask.state === "Completed") { const message = generateCompletionToastMessage(incomingTask) - toast.success(message, { - id, - description: state, - }) - return + toast.success(message, { id, description: state }) } else if (incomingTask.state === "Failed") { const message = generateFailedToastMessage(incomingTask) - toast.error(message, { - id, - }) + toast.error(message, { id }) } else if (incomingTask.state === "Updating Validity Proofs") { const message = generateCompletionToastMessage(incomingTask) - toast.success(message, { - id, - description: "Completed", - }) + toast.success(message, { id, description: "Completed" }) } else if (incomingTask.state === "Proving") { return } else { const message = generateStartToastMessage(incomingTask) - toast.loading(message, { - id, - description: state, - }) + toast.loading(message, { id, description: state }) } + + scheduleToastDismissal(id) } } diff --git a/hooks/use-withdraw.ts b/hooks/use-withdraw.ts index 3a653a6e..a659b9cc 100644 --- a/hooks/use-withdraw.ts +++ b/hooks/use-withdraw.ts @@ -1,13 +1,15 @@ -import { Token, UpdateType, useConfig, usePayFees } from "@renegade-fi/react" +import { + Token, + useConfig, + usePayFees +} from "@renegade-fi/react" import { withdraw } from "@renegade-fi/react/actions" import { toast } from "sonner" import { isAddress } from "viem" import { useAccount } from "wagmi" import { - FAILED_WITHDRAWAL_MSG, - WITHDRAW_TOAST_ID, - constructStartToastMessage, + FAILED_WITHDRAWAL_MSG } from "@/lib/constants/task" import { safeParseUnits } from "@/lib/format" @@ -34,12 +36,6 @@ export function useWithdraw({ toast.error("Withdrawal amount is invalid") return } - const message = constructStartToastMessage(UpdateType.Withdraw) - const id = WITHDRAW_TOAST_ID(mint, parsedAmount) - - toast.loading(message, { - id, - }) await payFeesAsync() @@ -51,9 +47,7 @@ export function useWithdraw({ }) .then(onSuccess) .catch((e) => { - toast.error(FAILED_WITHDRAWAL_MSG(token, parsedAmount), { - id, - }) + toast.error(FAILED_WITHDRAWAL_MSG(token, parsedAmount)) console.error(`Error withdrawing: ${e.response?.data ?? e.message}`) }) }