/* ── 관심종목 탭 순수 헬퍼 (라벨/색/시간) ── */ export const KIND_META = Object.freeze({ buy: Object.freeze({ label: '매수', color: '#22c55e', bg: 'rgba(34,197,94,0.12)' }), sell: Object.freeze({ label: '매도', color: '#ef4444', bg: 'rgba(239,68,68,0.12)' }), }); const FALLBACK_KIND = { color: '#94a3b8', bg: 'rgba(148,163,184,0.12)' }; export const kindMeta = (kind) => { if (Object.hasOwn(KIND_META, kind)) return KIND_META[kind]; return { ...FALLBACK_KIND, label: kind ?? '' }; }; export const CONDITION_LABEL = Object.freeze({ buy_ma20_pullback: 'MA20 눌림 반등', buy_breakout: '박스 상단 돌파', buy_rsi_bounce: 'RSI 과매도 반등', sell_stop_loss: '손절 라인', sell_ma_break: '이평선 이탈', sell_take_profit: '목표가 도달', sell_climax: '과열 소진', sell_trailing_stop: '트레일링 스톱', }); export const conditionLabel = (cond) => Object.hasOwn(CONDITION_LABEL, cond) ? CONDITION_LABEL[cond] : (cond ?? ''); export const normalizeTicker = (str) => String(str ?? '').trim(); export const relativeTime = (iso, now = Date.now()) => { if (!iso) return ''; const then = new Date(iso).getTime(); if (Number.isNaN(then)) return ''; const diffMs = now - then; if (diffMs < 0) return '방금'; const sec = Math.floor(diffMs / 1000); if (sec < 60) return '방금'; const min = Math.floor(sec / 60); if (min < 60) return `${min}분 전`; const hr = Math.floor(min / 60); if (hr < 24) return `${hr}시간 전`; const day = Math.floor(hr / 24); if (day === 1) return '어제'; if (day < 7) return `${day}일 전`; return new Date(iso).toLocaleDateString('ko-KR'); };