spb/company-atlas
Public
Python 66.3%
TypeScript 22.7%
JavaScript 8.6%
HTML 1.4%
CSS 0.7%
1'use client';2import { ArrowUpRight } from 'lucide-react';3import Link from 'next/link';4import { useEffect, useState } from 'react';5import { CountryChip, EventTypeBadge, ImportanceMeter } from '@/components/ui/badges';6import { LiveAgo } from '@/components/ui/live';7import { Sheet } from '@/components/ui/sheet';8import { clientApi } from '@/lib/client-api';9import { routes } from '@/lib/site';10import type { EventDetail, EventSource } from '@/lib/types';11import { useEventDrawer } from './event-drawer-context';12import { EventEvidence } from './event-evidence';1314/** Right-side (≥ lg) / bottom (< lg) drawer: the event, its evidence and links to the permanent pages. */15export function EventDrawer() {16 const { event, close } = useEventDrawer();17 const [detail, setDetail] = useState<{ id: string; sources: EventSource[]; loaded: boolean } | null>(null);1819 useEffect(() => {20 if (!event) return;21 const ctrl = new AbortController();22 setDetail({ id: event.id, sources: event.sources ?? [], loaded: false });23 clientApi24 .event(event.id, ctrl.signal)25 .then((d: EventDetail) => setDetail({ id: event.id, sources: d.sources ?? [], loaded: true }))26 .catch(() => setDetail((s) => (s ? { ...s, loaded: true } : s)));27 return () => ctrl.abort();28 }, [event]);2930 return (31 <Sheet32 open={event !== null}33 onClose={close}34 eyebrow={event ? <EventTypeBadge type={event.event_type} subtype={event.event_subtype} /> : undefined}35 title={event?.title}36 footer={37 event ? (38 <div className="flex flex-wrap items-center gap-2 text-sm">39 <Link href={routes.event(event.id)} onClick={close} className="btn btn-primary btn-sm">40 Open event page <ArrowUpRight className="size-3.5" aria-hidden />41 </Link>42 <Link href={routes.company(event.company.slug)} onClick={close} className="btn btn-sm">43 {event.company.display_name}44 </Link>45 {event.source_url && (46 <a href={event.source_url} target="_blank" rel="noopener noreferrer" className="btn btn-sm">47 Source ↗48 </a>49 )}50 </div>51 ) : undefined52 }53 >54 {event && (55 <div className="space-y-4" data-event-drawer>56 <div className="flex flex-wrap items-center gap-x-3 gap-y-1 text-sm">57 <Link href={routes.company(event.company.slug)} onClick={close} className="font-medium text-ink hover:text-accent">58 {event.company.display_name}59 </Link>60 <span className="mono text-xs text-ink-3">{event.company.canonical_domain}</span>61 <CountryChip code={event.company.country} />62 <span className="ml-auto inline-flex items-center gap-2 text-xs text-ink-3">63 <ImportanceMeter importance={event.importance} />64 <LiveAgo at={event.detected_at} />65 </span>66 </div>67 {event.summary && <p className="text-[14px] leading-relaxed text-ink-2">{event.summary}</p>}68 <EventEvidence event={event} sources={detail?.id === event.id ? detail.sources : event.sources} compact />69 {detail && detail.id === event.id && !detail.loaded && <p className="text-[11px] text-ink-3">Loading full source list…</p>}70 </div>71 )}72 </Sheet>73 );74}75