import { useCalendar, useGeoNews } from '../hooks/useApi' import clsx from 'clsx' import { Calendar, Clock, Globe, AlertTriangle } from 'lucide-react' import type { EconomicEvent, AssetClass } from '../types' import { format, parseISO, isAfter, isBefore, addDays } from 'date-fns' import { fr } from 'date-fns/locale' const ASSET_EMOJIS: Record = { energy: '⛽', metals: '🥇', agriculture: '🌾', equities: '📈', indices: '📊', forex: '💱', rates: '🏦', } const COUNTRY_FLAGS: Record = { US: '🇺🇸', EU: '🇪🇺', CN: '🇨🇳', JP: '🇯🇵', GB: '🇬🇧', DE: '🇩🇪', FR: '🇫🇷', Global: '🌍', } const IMPORTANCE_CONFIG: Record = { high: { color: 'text-red-400 border-red-700/40', label: 'Majeur', dots: 3 }, medium: { color: 'text-yellow-400 border-yellow-700/40', label: 'Modéré', dots: 2 }, low: { color: 'text-slate-400 border-slate-700/40', label: 'Mineur', dots: 1 }, } function EventCard({ ev }: { ev: EconomicEvent }) { const cfg = IMPORTANCE_CONFIG[ev.importance] const isPast = ev.actual !== undefined && ev.actual !== null const today = new Date() const evDate = parseISO(ev.date) const isToday = format(evDate, 'yyyy-MM-dd') === format(today, 'yyyy-MM-dd') const isSoon = !isToday && isAfter(evDate, today) && isBefore(evDate, addDays(today, 3)) return (
{COUNTRY_FLAGS[ev.country] ?? '🌍'} {'●'.repeat(cfg.dots)} {isToday && AUJOURD'HUI} {isSoon && !isToday && BIENTÔT}
{ev.title}
{format(evDate, "EEEE d MMM yyyy", { locale: fr })} · {ev.country}
{cfg.label}
{ev.previous &&
Préc: {ev.previous}
} {ev.forecast &&
Prév: {ev.forecast}
} {ev.actual &&
Réel: {ev.actual}
}
{ev.asset_impact && ev.asset_impact.length > 0 && (
{ev.asset_impact.map(cls => ( {ASSET_EMOJIS[cls] ?? ''} {cls} ))}
)}
) } export default function CalendarPage() { const { data: calendar, isLoading } = useCalendar() const { data: news } = useGeoNews() const today = new Date() const upcoming = calendar?.filter(ev => isAfter(parseISO(ev.date), today)) ?? [] const past = calendar?.filter(ev => isBefore(parseISO(ev.date), today)) ?? [] const highImpactNews = news?.filter(n => n.impact_score > 0.4).slice(0, 5) ?? [] return (

Calendrier Économique & Géopolitique

Événements macro, catalyseurs géopolitiques, dates clés

{/* Legend */}
●●● Majeur (forte volatilité attendue)
●● Modéré
Mineur
{/* Economic calendar */}
Événements à venir ({upcoming.length})
{isLoading ? ( [1,2,3].map(i =>
) ) : upcoming.length > 0 ? ( upcoming.map((ev, i) => ) ) : (
Démarrer le backend pour charger le calendrier
)} {past.length > 0 && ( <>
Événements passés ({past.length})
{past.map((ev, i) => )} )}
{/* Right: geo alerts + timeline */}
Alertes géopolitiques
{highImpactNews.length > 0 ? (
{highImpactNews.map((n, i) => (
{n.title}
{Math.round(n.impact_score * 100)}
{n.source}
))}
) : (
Charger les actualités géopolitiques
)}
{/* Trade opportunity windows */}
Fenêtres d'opportunité
{[ { window: 'Pré-FOMC (-3j)', strategy: 'Straddle sur SPY', rationale: 'IV monte avant décision' }, { window: 'Pré-NFP (-2j)', strategy: 'Straddle sur indices', rationale: 'Directional uncertainty' }, { window: 'Post-OPEC', strategy: 'Bull Call Spread USO', rationale: 'Cut → oil spike probable' }, { window: 'Pré-USDA Crop', strategy: 'Long Call WEAT', rationale: 'Supply news catalyst' }, { window: 'Élections US approche', strategy: 'Long VIX Call', rationale: 'Vol expansion garantie' }, ].map((op, i) => (
{op.window}
{op.strategy}
{op.rationale}
))}
{/* Geo-event impact guide */}
Guide d'impact
{[ { event: 'Conflit Moyen-Orient', impact: 'Oil +10-20%', cls: 'energy' }, { event: 'Sanctions Russie', impact: 'Gaz +15-40%', cls: 'energy' }, { event: 'Tarifs US-Chine', impact: 'Soja -8%', cls: 'agriculture' }, { event: 'Crise sanitaire', impact: 'Or +7-12%', cls: 'metals' }, { event: 'Hausses Fed', impact: 'USD +2-4%', cls: 'forex' }, { event: 'Guerre Ukraine', impact: 'Blé +15-50%', cls: 'agriculture' }, ].map((g, i) => (
{g.event} {g.impact}
))}
) }