feat: Add CI/CD pipeline and code quality improvements
- Add GitHub Actions workflow for automated CI/CD - Configure Node.js 18.x and 20.x matrix testing - Add TypeScript type checking step - Add ESLint code quality checks with enhanced rules - Add Prettier formatting verification - Add production build validation - Upload build artifacts for deployment - Set up automated testing on push/PR - Replace console.log with environment-aware logger - Add pre-commit hooks for code quality - Exclude archive folder from linting 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -1,25 +1,28 @@
|
||||
|
||||
import { useToast as useOriginalToast, toast as originalToast } from '@/hooks/toast';
|
||||
import type { ToasterToast } from '@/hooks/toast/types';
|
||||
import {
|
||||
useToast as useOriginalToast,
|
||||
toast as originalToast,
|
||||
} from "@/hooks/toast";
|
||||
import { logger } from "@/utils/logger";
|
||||
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)
|
||||
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)
|
||||
message: string; // 메시지 내용 (title + description)
|
||||
timestamp: number; // 생성 시간
|
||||
variant?: string; // 토스트 종류 (default/destructive)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -32,7 +35,7 @@ class ToastHistoryManager {
|
||||
constructor() {
|
||||
// 주기적으로 오래된 히스토리 정리
|
||||
this.cleanupInterval = setInterval(
|
||||
() => this.cleanup(),
|
||||
() => this.cleanup(),
|
||||
TOAST_CONFIG.CLEANUP_INTERVAL
|
||||
);
|
||||
}
|
||||
@@ -44,7 +47,7 @@ class ToastHistoryManager {
|
||||
this.history.push({
|
||||
message,
|
||||
timestamp: Date.now(),
|
||||
variant
|
||||
variant,
|
||||
});
|
||||
|
||||
// 히스토리 크기 제한
|
||||
@@ -59,7 +62,7 @@ class ToastHistoryManager {
|
||||
cleanup(): void {
|
||||
const now = Date.now();
|
||||
this.history = this.history.filter(
|
||||
item => (now - item.timestamp) < TOAST_CONFIG.HISTORY_RETENTION
|
||||
(item) => now - item.timestamp < TOAST_CONFIG.HISTORY_RETENTION
|
||||
);
|
||||
}
|
||||
|
||||
@@ -68,11 +71,12 @@ class ToastHistoryManager {
|
||||
*/
|
||||
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
|
||||
|
||||
return this.history.some(
|
||||
(item) =>
|
||||
item.message === message &&
|
||||
item.variant === variant &&
|
||||
now - item.timestamp < TOAST_CONFIG.DEBOUNCE_TIME
|
||||
);
|
||||
}
|
||||
|
||||
@@ -82,7 +86,7 @@ class ToastHistoryManager {
|
||||
clear(): void {
|
||||
this.history = [];
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 정리 타이머 해제 (메모리 누수 방지)
|
||||
*/
|
||||
@@ -98,10 +102,9 @@ const toastHistory = new ToastHistoryManager();
|
||||
* 메시지 내용 추출 (title + description)
|
||||
*/
|
||||
const extractMessage = (params: Omit<ToasterToast, "id">): string => {
|
||||
return [
|
||||
params.title?.toString() || '',
|
||||
params.description?.toString() || ''
|
||||
].filter(Boolean).join(' - ');
|
||||
return [params.title?.toString() || "", params.description?.toString() || ""]
|
||||
.filter(Boolean)
|
||||
.join(" - ");
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -109,22 +112,22 @@ const extractMessage = (params: Omit<ToasterToast, "id">): string => {
|
||||
*/
|
||||
const debouncedToast = (params: Omit<ToasterToast, "id">) => {
|
||||
const message = extractMessage(params);
|
||||
|
||||
|
||||
// 빈 메시지 무시
|
||||
if (!message.trim()) {
|
||||
console.warn('빈 토스트 메시지가 무시되었습니다');
|
||||
logger.warn("빈 토스트 메시지가 무시되었습니다");
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
// 중복 검사
|
||||
if (toastHistory.isDuplicate(message, params.variant)) {
|
||||
console.log('중복 토스트 감지로 무시됨:', message);
|
||||
logger.info("중복 토스트 감지로 무시됨:", message);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
// 히스토리에 추가
|
||||
toastHistory.add(message, params.variant);
|
||||
|
||||
|
||||
// 실제 토스트 표시
|
||||
originalToast({
|
||||
...params,
|
||||
|
||||
Reference in New Issue
Block a user