import { useToast as useOriginalToast, toast as originalToast } from '@/hooks/toast'; import type { ToasterToast } from '@/hooks/toast/types'; /** * 토스트 중복 방지를 위한 설정값 */ const TOAST_CONFIG = { DEFAULT_DURATION: 3000, // 기본 토스트 표시 시간 (ms) DEBOUNCE_TIME: 1500, // 동일 메시지 무시 시간 (ms) HISTORY_LIMIT: 10, // 히스토리에 저장할 최대 토스트 수 CLEANUP_INTERVAL: 30000, // 히스토리 정리 주기 (ms) HISTORY_RETENTION: 10000 // 히스토리 보관 기간 (ms) }; /** * 토스트 메시지 히스토리 인터페이스 */ interface ToastHistoryItem { message: string; // 메시지 내용 (title + description) timestamp: number; // 생성 시간 variant?: string; // 토스트 종류 (default/destructive) } /** * 토스트 히스토리 관리 클래스 */ class ToastHistoryManager { private history: ToastHistoryItem[] = []; private cleanupInterval: ReturnType; constructor() { // 주기적으로 오래된 히스토리 정리 this.cleanupInterval = setInterval( () => this.cleanup(), TOAST_CONFIG.CLEANUP_INTERVAL ); } /** * 새 토스트를 히스토리에 추가 */ add(message: string, variant?: string): void { this.history.push({ message, timestamp: Date.now(), variant }); // 히스토리 크기 제한 if (this.history.length > TOAST_CONFIG.HISTORY_LIMIT) { this.history.shift(); } } /** * 오래된 히스토리 정리 */ cleanup(): void { const now = Date.now(); this.history = this.history.filter( item => (now - item.timestamp) < TOAST_CONFIG.HISTORY_RETENTION ); } /** * 최근에 동일한 토스트가 표시되었는지 확인 */ isDuplicate(message: string, variant?: string): boolean { const now = Date.now(); return this.history.some(item => item.message === message && item.variant === variant && (now - item.timestamp) < TOAST_CONFIG.DEBOUNCE_TIME ); } /** * 히스토리 초기화 (테스트용) */ clear(): void { this.history = []; } /** * 정리 타이머 해제 (메모리 누수 방지) */ dispose(): void { clearInterval(this.cleanupInterval); } } // 싱글톤 인스턴스 생성 const toastHistory = new ToastHistoryManager(); /** * 메시지 내용 추출 (title + description) */ const extractMessage = (params: Omit): string => { return [ params.title?.toString() || '', params.description?.toString() || '' ].filter(Boolean).join(' - '); }; /** * 중복 방지 토스트 표시 함수 */ const debouncedToast = (params: Omit) => { const message = extractMessage(params); // 빈 메시지 무시 if (!message.trim()) { console.warn('빈 토스트 메시지가 무시되었습니다'); return; } // 중복 검사 if (toastHistory.isDuplicate(message, params.variant)) { console.log('중복 토스트 감지로 무시됨:', message); return; } // 히스토리에 추가 toastHistory.add(message, params.variant); // 실제 토스트 표시 originalToast({ ...params, duration: params.duration || TOAST_CONFIG.DEFAULT_DURATION, }); }; /** * 토스트 훅 래퍼 */ export const useToast = () => { const toast = useOriginalToast(); return { ...toast, toast: debouncedToast, }; }; /** * 토스트 함수 래퍼 (훅을 사용하지 않는 컨텍스트용) */ export const toast = debouncedToast; // 메모리 누수 방지를 위한 정리 함수 (필요시 호출) export const disposeToastHistory = () => { toastHistory.dispose(); };