'use client'; import React, { useCallback } from 'react'; import { useToastContext } from '../context/ToastContext'; import { ToastType, ToastProps, ToastPosition, ToastLayout } from '../types'; export const useToast = () => { const { addToast, removeToast, updateToast, clearAllToasts, position, setPosition, layout, setLayout, } = useToastContext(); const toast = useCallback( (options: Omit & { className?: string }) => { return addToast(options); }, [addToast], ); const update = useCallback( (id: string, updates: Partial>) => { updateToast(id, updates); }, [updateToast], ); const dismiss = useCallback( (id: string) => { removeToast(id); }, [removeToast], ); const clearAll = useCallback(() => { clearAllToasts(); }, [clearAllToasts]); const changePosition = useCallback( (newPosition: ToastPosition) => { setPosition(newPosition); }, [setPosition], ); const changeLayout = useCallback( (newLayout: ToastLayout) => { setLayout(newLayout); }, [setLayout], ); // Promise-based toast (like Sonner) const promise = useCallback( ( promise: Promise | (() => Promise), options: { loading?: React.ReactNode; success?: React.ReactNode | ((data: T) => React.ReactNode); error?: React.ReactNode | ((error: any) => React.ReactNode); description?: React.ReactNode; duration?: number; onSuccess?: (data: T) => void; onError?: (error: any) => void; cancel?: { label: string; onClick?: () => void; }; }, ) => { const promiseFn = typeof promise === 'function' ? promise() : promise; const loadingId = addToast({ content: options.loading || 'Loading...', description: options.description, type: 'info', status: 'loading', duration: 0, // Don't auto-dismiss loading state cancel: options.cancel, }); promiseFn .then((data) => { const successContent = typeof options.success === 'function' ? options.success(data) : options.success || 'Success!'; updateToast(loadingId, { content: successContent, type: 'success', status: 'success', duration: options.duration || 3000, cancel: undefined, // Remove cancel on success }); options.onSuccess?.(data); }) .catch((error) => { const errorContent = typeof options.error === 'function' ? options.error(error) : options.error || 'Something went wrong'; updateToast(loadingId, { content: errorContent, type: 'error', status: 'error', duration: options.duration || 5000, cancel: undefined, // Remove cancel on error }); options.onError?.(error); }); return loadingId; }, [addToast, updateToast], ); // Loading toast const loading = useCallback( (content: React.ReactNode, options?: Partial>) => { return toast({ content, type: 'info', status: 'loading', duration: 0, ...options }); }, [toast], ); return { toast, update, dismiss, clearAll, changePosition, changeLayout, promise, // Promise-based toast loading, // Loading toast position, layout, default: ( content: React.ReactNode, options?: Partial>, ) => toast({ content, type: 'default', ...options }), info: ( content: React.ReactNode, options?: Partial>, ) => toast({ content, type: 'info', ...options }), success: ( content: React.ReactNode, options?: Partial>, ) => toast({ content, type: 'success', ...options }), warning: ( content: React.ReactNode, options?: Partial>, ) => toast({ content, type: 'warning', ...options }), error: ( content: React.ReactNode, options?: Partial>, ) => toast({ content, type: 'error', ...options }), custom: (content: React.ReactNode, options?: Partial>) => toast({ content, type: 'custom', ...options }), }; };