The useToast hook was refactored into smaller, more manageable files to improve code organization and maintainability.
155 lines
3.7 KiB
TypeScript
155 lines
3.7 KiB
TypeScript
|
|
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<typeof setInterval>;
|
|
|
|
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<ToasterToast, "id">): string => {
|
|
return [
|
|
params.title?.toString() || '',
|
|
params.description?.toString() || ''
|
|
].filter(Boolean).join(' - ');
|
|
};
|
|
|
|
/**
|
|
* 중복 방지 토스트 표시 함수
|
|
*/
|
|
const debouncedToast = (params: Omit<ToasterToast, "id">) => {
|
|
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();
|
|
};
|