/** * Verdict label helpers — convert long verdict strings to short display values * and derive CSS colour classes from emoji prefixes. */ /** * Converts a long verdict label into a short display string. * e.g. "🟢 BUY (High Conviction)" → "Strong" */ export function verdictShort(label: string | null | undefined): string { if (!label) return '—'; if (label.includes('No Data')) return 'No Data'; if (label.includes('High Conviction')) return 'Strong Buy'; if (label.includes('Speculative')) return 'Speculative'; if (label.includes('Momentum')) return 'Momentum'; if (label.includes('BUY')) return 'Buy'; if (label.includes('Efficient')) return 'Efficient'; if (label.includes('Attractive')) return 'Attractive'; if (label.includes('Neutral')) return 'Hold'; if (label.includes('REJECT')) return 'Reject'; if (label.includes('Avoid')) return 'Avoid'; return label.replace(/[\u{1F7E2}\u{1F7E1}\u{1F534}]/u, '').trim(); } /** * Returns a CSS colour class based on the verdict label content. * * Signal mapping: * 🟢 / High Conviction / Efficient / Attractive → green * 🟡 / Speculative / Momentum → yellow * Neutral / Hold / no signal → blue (calm, not alarming) * 🔴 / Avoid / Reject / REJECT → red */ export function vClass( label: string | null | undefined, ): 'green' | 'yellow' | 'red' | 'blue' | 'gray' { if (!label) return 'gray'; // Insufficient data is unknown, not a neutral opinion — render gray if (label.includes('No Data')) return 'gray'; if ( label.startsWith('🟢') || label.includes('High Conviction') || label.includes('Efficient') || label.includes('Attractive') ) return 'green'; if (label.startsWith('🟡') || label.includes('Speculative') || label.includes('Momentum')) return 'yellow'; if ( label.startsWith('🔴') || label.includes('Avoid') || label.includes('Reject') || label.includes('REJECT') ) return 'red'; if (label.includes('Neutral') || label.includes('Hold') || label.includes('BUY')) return 'blue'; return 'gray'; } /** * Returns a CSS colour class for a portfolio advice string based on its emoji prefix. * 🟢 → 'green', 🟡 → 'yellow', 🟠 → 'orange', 🔴 → 'red', else 'gray'. */ export function advClass( advice: string | null | undefined, ): 'green' | 'yellow' | 'orange' | 'red' | 'gray' { if (advice?.includes('🟢')) return 'green'; if (advice?.includes('🟡')) return 'yellow'; if (advice?.includes('🟠')) return 'orange'; if (advice?.includes('🔴')) return 'red'; return 'gray'; } /** * Returns 'green' for non-negative G/L percentage, 'red' otherwise. * Accepts string (e.g. "12.5") or number. */ export function glClass(pct: string | number | null | undefined): 'green' | 'red' { return parseFloat(String(pct ?? 0)) >= 0 ? 'green' : 'red'; }