/** * 관심종목(즐겨찾기) / 보유종목 관리 * - DB(gc_watchlist / gc_holdings)가 기준 저장소 * - 메모리 캐시만 사용 (localStorage 미사용) */ import { addWatchlistItem, removeWatchlistItem } from './backendApi'; /** 관심종목 변경 시 MarketSearchPanel·App 등이 동기화하도록 발행 */ export const FAVORITES_CHANGED_EVENT = 'gc-favorites-changed'; let favoritesCache: string[] | null = null; let holdingsCache: string[] | null = null; /** DB 로드 후 App·워크스페이스 훅에서 호출 */ export function initFavoritesFromDb(symbols: string[]): void { favoritesCache = [...symbols]; window.dispatchEvent(new CustomEvent(FAVORITES_CHANGED_EVENT, { detail: favoritesCache })); } export function initHoldingsFromDb(symbols: string[]): void { holdingsCache = [...symbols]; } export function getFavorites(): string[] { return favoritesCache ?? []; } export function saveFavorites(markets: string[], notify = true): void { favoritesCache = [...markets]; if (notify) { window.dispatchEvent(new CustomEvent(FAVORITES_CHANGED_EVENT, { detail: markets })); } } /** * 관심종목 토글 — DB 저장 + 실시간 전략 체크 대상 자동 연동(백엔드). * @returns 변경 후 관심종목 코드 목록 */ export async function toggleFavorite( market: string, meta?: { koreanName?: string; englishName?: string }, ): Promise { const list = getFavorites(); let next: string[]; if (list.includes(market)) { await removeWatchlistItem(market); next = list.filter(m => m !== market); } else { await addWatchlistItem({ symbol: market, koreanName: meta?.koreanName, englishName: meta?.englishName, }); next = [...list, market]; } saveFavorites(next); return next; } export function isFavorite(market: string): boolean { return getFavorites().includes(market); } export function getHoldings(): string[] { return holdingsCache ?? []; } export function saveHoldings(markets: string[]): void { holdingsCache = [...markets]; } /** 추가 → 변경 후 전체 목록 반환 (중복 무시) */ export function addHolding(market: string): string[] { const list = getHoldings(); if (list.includes(market)) return list; const next = [...list, market]; saveHoldings(next); return next; } /** 제거 → 변경 후 전체 목록 반환 */ export function removeHolding(market: string): string[] { const next = getHoldings().filter(m => m !== market); saveHoldings(next); return next; } export function isHolding(market: string): boolean { return getHoldings().includes(market); }