import { Transaction } from '@/components/TransactionCard'; import { CATEGORY_TITLE_SUGGESTIONS } from '@/constants/categoryIcons'; // 지출 제목 사용 빈도를 저장하는 로컬 스토리지 키 const TITLE_PREFERENCES_KEY = 'userTitlePreferences'; // 최대 저장 제목 개수 (카테고리별) const MAX_TITLES_PER_CATEGORY = 15; // 최소 사용 횟수 (이 횟수 미만이면 삭제 대상) const MIN_USAGE_COUNT = 2; // 사용자 제목 선호도 타입 정의 export interface TitlePreference { count: number; // 사용 횟수 lastUsed: string; // 마지막 사용 일시 (ISO 문자열) } // 카테고리별 제목 선호도 export interface CategoryTitlePreferences { [title: string]: TitlePreference; } // 전체 제목 선호도 데이터 구조 export interface UserTitlePreferences { 음식: CategoryTitlePreferences; 쇼핑: CategoryTitlePreferences; 교통: CategoryTitlePreferences; 기타: CategoryTitlePreferences; [key: string]: CategoryTitlePreferences; } /** * 로컬 스토리지에서 사용자 제목 선호도 데이터 로드 */ export const loadUserTitlePreferences = (): UserTitlePreferences => { try { const storedPreferences = localStorage.getItem(TITLE_PREFERENCES_KEY); if (storedPreferences) { return JSON.parse(storedPreferences); } } catch (error) { console.error('제목 선호도 데이터 로드 중 오류:', error); } // 기본값 반환 - 기본 카테고리 구조 생성 return { 음식: {}, 쇼핑: {}, 교통: {}, 기타: {} }; }; /** * 사용자 제목 선호도 데이터 저장 */ export const saveUserTitlePreferences = (preferences: UserTitlePreferences): void => { try { localStorage.setItem(TITLE_PREFERENCES_KEY, JSON.stringify(preferences)); } catch (error) { console.error('제목 선호도 데이터 저장 중 오류:', error); } }; /** * 트랜잭션에서 제목 사용 업데이트 * 새로운 트랜잭션이 추가되거나 수정될 때 호출 */ export const updateTitleUsage = (transaction: Transaction): void => { // 타입이 expense가 아니거나 제목이 없으면 무시 if (transaction.type !== 'expense' || !transaction.title) return; const { category, title } = transaction; const preferences = loadUserTitlePreferences(); // 해당 카테고리가 없으면 초기화 if (!preferences[category]) { preferences[category] = {}; } // 해당 제목이 없으면 새로 추가 (새 제목 삽입) if (!preferences[category][title]) { console.log(`새 제목 추가: "${title}" (${category} 카테고리)`); preferences[category][title] = { count: 0, lastUsed: new Date().toISOString() }; } // 카운트 증가 및 마지막 사용 시간 업데이트 preferences[category][title].count += 1; preferences[category][title].lastUsed = new Date().toISOString(); // 카테고리별 최대 제목 수 관리 (사용 빈도가 낮은 제목 제거) const titles = Object.entries(preferences[category]); if (titles.length > MAX_TITLES_PER_CATEGORY) { // 사용 횟수 및 최근 사용일 기준으로 정렬 const sortedTitles = titles.sort((a, b) => { // 먼저 사용 횟수로 비교 (내림차순) const countDiff = b[1].count - a[1].count; if (countDiff !== 0) return countDiff; // 사용 횟수가 같으면 최근 사용일로 비교 (내림차순) return new Date(b[1].lastUsed).getTime() - new Date(a[1].lastUsed).getTime(); }); // 정렬 후 하위 항목 제거 (기준: MIN_USAGE_COUNT 미만 & 가장 적게 사용됨) const titlesToRemove = sortedTitles .slice(MAX_TITLES_PER_CATEGORY) .filter(([_, pref]) => pref.count < MIN_USAGE_COUNT) .map(([title]) => title); if (titlesToRemove.length > 0) { console.log(`사용 빈도가 낮은 제목 제거: ${titlesToRemove.length}개`); // 제거할 제목들을 선호도에서 삭제 titlesToRemove.forEach(title => { delete preferences[category][title]; }); } } // 저장 saveUserTitlePreferences(preferences); }; /** * 카테고리별 추천 제목 목록 가져오기 * 사용자 선호도 + 기본 추천 제목 결합 */ export const getPersonalizedTitleSuggestions = (category: string): string[] => { // 기본 제목 목록 const defaultSuggestions = CATEGORY_TITLE_SUGGESTIONS[category] || []; try { const preferences = loadUserTitlePreferences(); const categoryPreferences = preferences[category] || {}; // 사용 횟수 기준으로 정렬된 사용자 정의 제목 목록 const personalizedTitles = Object.entries(categoryPreferences) .sort((a, b) => { // 우선 사용 횟수로 정렬 (내림차순) const countDiff = b[1].count - a[1].count; if (countDiff !== 0) return countDiff; // 사용 횟수가 같으면 최근 사용일자로 정렬 (내림차순) const dateA = new Date(a[1].lastUsed).getTime(); const dateB = new Date(b[1].lastUsed).getTime(); return dateB - dateA; }) .map(([title]) => title); // 사용자 선호 제목에는 없지만 기본 제목에 있는 항목 추가 const remainingDefaultTitles = defaultSuggestions.filter( title => !personalizedTitles.includes(title) ); // 최종 개인화된 제목 목록 (선호도 순 + 기본 제목) return [...personalizedTitles, ...remainingDefaultTitles]; } catch (error) { console.error('개인화된 제목 목록 생성 중 오류:', error); return defaultSuggestions; } }; /** * 트랜잭션 추가 시 제목 사용 빈도 업데이트 및 관리 함수 * AddTransactionButton에서 호출하기 위한 래퍼 함수 */ export const manageTitleSuggestions = (transaction: Transaction): void => { // 제목 사용 업데이트 (추가 및 카운트 증가) updateTitleUsage(transaction); // 개발 모드에서 저장된 제목 선호도 로깅 if (process.env.NODE_ENV === 'development') { const preferences = loadUserTitlePreferences(); const category = transaction.category; if (preferences[category]) { const count = Object.keys(preferences[category]).length; console.log(`${category} 카테고리 저장된 제목 수: ${count}개`); } } };