Number of seconds to wait before retry is enabled.
User-facing message to display.
Callback invoked when countdown completes.
export function showRateLimitNotification(
retryAfterSeconds: number,
message: string,
onComplete: () => void,
): void {
console.warn(
`[ErrorHandling] Rate limit detected. Waiting ${retryAfterSeconds}s before retry.`,
);
import("sonner")
.then(({ toast }) => {
let secondsRemaining = retryAfterSeconds;
// Create a custom description element with countdown
const createCountdownDescription = (remaining: number) => {
return React.createElement(
"div",
{ style: { display: "flex", flexDirection: "column", gap: "8px" } },
React.createElement("p", { style: { margin: 0 } }, message),
React.createElement(
"p",
{ style: { margin: 0, fontSize: "0.9em", opacity: 0.8 } },
`Retry available in ${remaining}s...`,
),
);
};
// Show initial toast
const toastId = toast.loading("Rate limit active", {
description: createCountdownDescription(secondsRemaining),
duration: retryAfterSeconds * 1000 + 2000, // Duration + buffer
});
// Update countdown every second
const intervalId = setInterval(() => {
secondsRemaining -= 1;
if (secondsRemaining <= 0) {
clearInterval(intervalId);
// Show completion toast with retry button
toast.success("Rate limit lifted - Retry now available", {
id: toastId,
description:
"You can now retry your request. Click the button or try again manually.",
action: {
label: "Retry Now",
onClick: onComplete,
},
duration: 8000,
});
} else {
// Update toast with new countdown
toast.loading("Rate limit active", {
id: toastId,
description: createCountdownDescription(secondsRemaining),
duration: retryAfterSeconds * 1000 + 2000,
});
}
}, 1000);
})
.catch((toastError) => {
console.error(
"[ErrorHandling] Failed to show rate limit notification:",
toastError,
);
});
}
Displays a rate limit notification with countdown timer. Shows a custom toast with disabled retry button that enables after the wait period elapses.