import { ExternalLink } from 'lucide-react'; import Link from 'next/link'; import { Bars } from '@/components/charts/bars'; import { EventList } from '@/components/events/event-row'; import { Chip, ConfidenceBadge, SensorTierBadge, StatusBadge, CountryChip } from '@/components/ui/badges'; import { LiveAgo } from '@/components/ui/live'; import { Empty, Note, Stat, StatGrid } from '@/components/ui/section'; import { cn } from '@/lib/cn'; import { countryName } from '@/lib/countries'; import { fmtDate, fmtDateTime, fmtDayLabel, fmtDuration, fmtInt, fmtPct, fmtPrice, fmtScore, humanize, pathOf, plural } from '@/lib/format'; import { mergePeople, roleRank, type MergedPerson } from '@/lib/profile'; import { routes, SURFACE_LABELS, TIMELINE_FILTERS } from '@/lib/site'; import type { HistoryPayload, Job, JobsPage, Location, Person, Plan, Product, Sensor, Signal, TimelinePayload } from '@/lib/types'; import { SourceChip, WikidataProducts } from './profile-panels'; /* ------------------------------------------------------------------------------------------------------------ timeline */ export function TimelinePanel({ slug, data, filter }: { slug: string; data: TimelinePayload | null; filter: string }) { const groups = new Map(); for (const e of data?.items ?? []) { const d = e.day ?? e.detected_at.slice(0, 10); if (!groups.has(d)) groups.set(d, []); groups.get(d)!.push(e); } const days = [...groups.entries()].sort((a, b) => (a[0] < b[0] ? 1 : -1)); return (
{TIMELINE_FILTERS.map((f) => ( {f === 'all' ? 'All' : humanize(f)} ))}
{!data ? ( ) : days.length === 0 ? ( No {filter === 'all' ? '' : `${filter} `}events detected for this company yet — sensors are attached and observing. ) : (
{days.map(([day, items]) => (

{fmtDayLabel(day)} {items.length} {plural(items.length, 'event')}

))}
)}
); } /* ------------------------------------------------------------------------------------------------------------ signals */ export function SignalsPanel({ signals }: { signals: Signal[] }) { if (!signals.length) return Signals are pattern detections over the company’s own baselines and are labelled as such — never as facts.; return ( ); } /* ------------------------------------------------------------------------------------------------------------ jobs */ export function JobsPanel({ slug, data, status, ai }: { slug: string; data: JobsPage | null; status: string; ai: boolean }) { const summary = data?.meta?.summary ?? data?.summary; const base = routes.company(slug, 'jobs'); const link = (patch: { status?: string; ai?: boolean }) => { const st = patch.status ?? status; const a = patch.ai ?? ai; return `${base}${st !== 'open' ? `&status=${st}` : ''}${a ? '&ai=1' : ''}`; }; return (
{summary ? ( ) : ( Job summary unavailable. )} {summary && (summary.by_department.length > 0 || summary.by_country.length > 0) && (

By department

({ key: d.department, label: d.department, value: d.n }))} />

By country

({ key: d.country, label: countryName(d.country), value: d.n }))} />
)}
{[ ['open', 'Open'], ['removed', 'No longer listed'], ['all', 'All'], ].map(([v, l]) => ( {l} ))} AI-related only {data && {fmtInt(data.total)} listings}
{!data ? ( ) : data.items.length === 0 ? ( No monitored listings match this filter. ) : ( )} Counts reflect listings visible on the monitored careers surfaces only. A listing that is no longer visible is reported as “no longer listed” — it is not evidence of a hiring decision.
); } function JobsTable({ items }: { items: Job[] }) { return (
{items.map((j) => ( ))}
Title Department Location Type First seen Status
{j.url ? ( {j.title} ) : ( j.title )} {j.is_ai && ( AI )} {j.department ?? '—'} {j.location_text ?? '—'} {j.remote && · remote} {j.employment_type ? humanize(j.employment_type) : '—'} {j.seniority ? ` · ${j.seniority}` : ''} {fmtDate(j.first_seen_at)} {j.removed_at && {fmtDate(j.removed_at)}}
); } /* ------------------------------------------------------------------------------------------------------------ products */ export function ProductsPanel({ data, wikidataProducts = [], wikidataSource = null }: { data: { listed: Product[]; removed: Product[] } | null; wikidataProducts?: string[]; wikidataSource?: { url: string | null; retrieved_at: string } | null }) { if (!data) return ; if (!data.listed.length && !data.removed.length) { if (wikidataProducts.length) return (
Once a catalogue page is monitored, listed products appear here with first-seen / last-seen dates.
); return No product catalog surface has been reconciled for this company yet.; } const Row = ({ p }: { p: Product }) => (
  • {p.url ? ( {p.name} ) : ( {p.name} )} {p.category && {p.category}} first seen {fmtDate(p.first_seen_at)} {p.removed_at ? ` · no longer listed ${fmtDate(p.removed_at)}` : ` · last seen ${fmtDate(p.last_seen_at)}`}
    {p.description &&

    {p.description}

    }
  • ); return (

    Listed ({data.listed.length})

      {data.listed.map((p) => )}
    {data.removed.length > 0 && (

    No longer listed ({data.removed.length})

      {data.removed.map((p) => )}
    A product that disappears from the public catalog is recorded as “no longer listed”; the platform does not infer discontinuation without a first-party statement.
    )}
    ); } /* ------------------------------------------------------------------------------------------------------------ pricing */ export function PricingPanel({ data }: { data: { current: Plan[]; history: Plan[] } | null }) { if (!data) return ; if (!data.current.length && !data.history.length) return No public pricing page is monitored for this company yet.; return (

    Current plans

    {data.current.map((p) => (

    {p.plan_name}

    {p.contact_sales ? Contact sales : fmtPrice(p.price, p.currency, p.price_text)}

    {!p.contact_sales && (

    {p.billing_period ? `per ${p.billing_period}` : ''} {p.unit ? ` · per ${p.unit}` : ''}

    )} {p.features.length > 0 && (
      {p.features.slice(0, 6).map((f) => (
    • · {f}
    • ))}
    )}

    v{p.version_no} · since {fmtDate(p.valid_from)}

    ))}
    {data.history.length > 0 && (

    Version history

    {[...data.history].sort((a, b) => b.valid_from.localeCompare(a.valid_from)).map((p) => ( ))}
    Plan Version Price Billing Valid from Valid to Source
    {p.plan_name} v{p.version_no} {p.contact_sales ? 'Contact sales' : fmtPrice(p.price, p.currency, p.price_text)} {p.billing_period ?? '—'} {fmtDate(p.valid_from)} {p.valid_to ? fmtDate(p.valid_to) : '—'} {p.source_url ? ( {pathOf(p.source_url)} ) : ( '—' )}
    Every version of every plan is preserved; a price change creates a new version rather than overwriting the previous one.
    )}
    ); } /* ------------------------------------------------------------------------------------------------------------ locations */ export function LocationsPanel({ data, map }: { data: { items: Location[]; countries: string[] } | null; map?: React.ReactNode }) { if (!data) return ; if (!data.items.length) return No locations surface has been reconciled for this company yet.; const listed = data.items.filter((l) => l.status === 'listed'); const gone = data.items.filter((l) => l.status !== 'listed'); return (

    Listed ({listed.length} in {data.countries.length} {plural(data.countries.length, 'country', 'countries')})

      {listed.map((l) => (
    • {l.kind} {[l.city, l.region].filter(Boolean).join(', ') || l.name} since {fmtDate(l.first_seen_at)}
    • ))}
    {gone.length > 0 && ( <>

    No longer listed ({gone.length})

      {gone.map((l) => (
    • {l.kind} {[l.city, l.region].filter(Boolean).join(', ') || l.name} until {fmtDate(l.removed_at)}
    • ))}
    )} Only cities/regions/countries are recorded; exact street addresses are never inferred.
    {map}
    ); } /* ------------------------------------------------------------------------------------------------------------ leadership */ /** * Page-observed people and Wikidata-sourced executives merged by name (both chips kept when they agree), CEO / chair / * founders first. The "no longer listed" group stays separate with wording that depends on the source. */ export function PeoplePanel({ data }: { data: { listed: Person[]; no_longer_listed: Person[] } | null }) { if (!data) return ; if (!data.listed.length && !data.no_longer_listed.length) return No leadership page is monitored for this company yet, and Wikidata records no current executives for it.; const listed = mergePeople(data.listed); const gone = mergePeople(data.no_longer_listed); const nPage = listed.filter((p) => p.sources.includes('page')).length; const nWd = listed.filter((p) => p.sources.includes('wikidata')).length; const Row = ({ p }: { p: MergedPerson }) => { const onlyWd = p.sources.length === 1 && p.sources[0] === 'wikidata'; const when = p.status === 'listed' ? (onlyWd ? `recorded on Wikidata · retrieved ${fmtDate(p.last_seen_at)}` : `listed since ${fmtDate(p.first_seen_at)}`) : onlyWd ? `no longer recorded as current on Wikidata · ${fmtDate(p.removed_at ?? p.last_seen_at)}` : `no longer listed since ${fmtDate(p.removed_at ?? p.last_seen_at)}`; return (
  • {p.name} {p.title ?? 'title not stated'} {p.is_executive && roleRank(p.title) > 3 && executive} {p.sources.map((s) => ( ))} {when} {p.source_url && !onlyWd && ( <> {' · '} source ↗ )} {p.source_url && onlyWd && ( <> {' · '} statement ↗ )}
  • ); }; return (

    Currently listed ({listed.length}) {nPage > 0 && `${nPage} on the monitored leadership page`} {nPage > 0 && nWd > 0 && ' · '} {nWd > 0 && `${nWd} recorded on Wikidata`}

    {listed.length ?
      {listed.map((p) => )}
    : }
    {gone.length > 0 && (

    No longer listed ({gone.length})

      {gone.map((p) => )}
    )} Leadership data is limited to public professional context: the company’s own leadership page (observed by a sensor) and Wikidata position statements (with their retrieval time). A profile that disappears from the page is “no longer listed on the monitored leadership page”; a Wikidata position with an end date is “no longer recorded as current” — the platform never states why.
    ); } /* ------------------------------------------------------------------------------------------------------------ sensors */ export function SensorsTable({ items, className, withCompany = false }: { items: (Sensor & { company?: { slug: string; display_name: string } })[]; className?: string; withCompany?: boolean }) { if (!items.length) return No sensors attached yet.; return (
    {withCompany && } {items.map((s) => { const stale = s.last_success_at && Date.now() - new Date(s.last_success_at).getTime() > 2 * 86_400_000; return ( {withCompany && } ); })}
    CompanySurface URL Connector Status Tier Quality Last checked Obs. Changes Events
    {s.company ? {s.company.display_name} : '—'} {SURFACE_LABELS[s.surface] ?? s.surface} {pathOf(s.url)} {s.connector_id} {s.last_failure_class && {s.last_failure_class}} {fmtScore(s.quality_score)} {fmtInt(s.observation_count)} {fmtInt(s.change_count)} {fmtInt(s.event_count)}
    ); } /* ------------------------------------------------------------------------------------------------------------ history viewer */ export function HistoryPanel({ data }: { data: HistoryPayload | null }) { if (!data) return ; const sensors = data.sensors.filter((s) => s.versions.length > 0); if (!sensors.length) return No snapshot versions stored yet.; return (
    Every monitored page keeps its normalised versions. Open a version to read it as observed, or diff any two versions block by block. {sensors.map((s) => (
    {SURFACE_LABELS[s.surface] ?? s.surface} {pathOf(s.url)} {s.versions.length} {plural(s.versions.length, 'version')} · every {fmtDuration(s.current_interval_s)}
    {s.versions.map((v, i) => { const prev = s.versions[i + 1]; return ( ); })}
    v Fetched Title Blocks Text Hash Diff
    {v.version_no} {fmtDateTime(v.fetched_at)} {v.title ?? '—'} {fmtInt(v.block_count)} {fmtInt(v.text_length)} {v.content_hash.replace('sha256:', '').slice(0, 10)} {prev ? ( vs v{prev.version_no} ) : ( first version )}
    ))}
    ); } export function ConfidenceLegend() { return (

    Confidence labels: {['VERIFIED', 'HIGH_CONFIDENCE', 'LIKELY', 'INFERRED', 'LOW_CONFIDENCE'].map((l) => )}

    ); }