Purpose

Small, reusable presentational components shared across kundkort sections. All under frontend/kundkort/components/ui/ (or components/ for the page-level ones).

SectionHeading

components/ui/SectionHeading.tsx. <h2> with the wiki-uppercase muted-tracker style: 11 px, 0.08 em letter-spacing, --text-muted colour. Used as the title of every section card.

KvRow

components/ui/KvRow.tsx. Two-column key/value row with bottom border (suppressible via noBorder). Label is uppercase 11 px muted; value is right-aligned 13 px primary. Used heavily in Identity Card and ContactInfoCard.

GapBadge

components/ui/GapBadge.tsx. Tiny pill containing the literal string “GAP”. Used wherever a field is missing — see Financials Section, Koncern Section, Varumarken Section, Contacts Section.

ContactCard

components/ui/ContactCard.tsx. Card for a single KundkortContact. Coloured left border via roleColor prop. Renders name, role, phone (with phone_type “mobil”/“fast”), email (truncated with title attr), source pill. Falls back to “Ingen kontaktinfo” when neither phone nor email present. See Contacts Section for full breakdown.

SkeletonLoader

components/ui/SkeletonLoader.tsx. Full-page loading skeleton mimicking the kundkort layout: header, completeness bar, two-col grid, summary, financials, contacts. Uses an internal <SkeletonBlock> with animate-pulse. Rendered by Kundkort Page while useKundkort.loading === true.

LoadingCard

components/ui/LoadingCard.tsx. Smaller per-card loader — Tremor <Card> with title and a centered spinning blue ring. Used for the EcoAPI panels while useEcoApi.loading === true.

ErrorState

components/ui/ErrorState.tsx. Full-page error view. Picks title/message based on statusCode and error string:

TriggerTitle
401 / “Ej autentiserad""Ej autentiserad” + relogin button
404 / “Företaget hittades inte""Företaget hittades inte”
≥500”Serverfel"
"Nätverksfel""Kan inte nå servern”
else”Något gick fel” + raw error

Provides a “Tillbaka till sökning” link in every state except 401.

ErrorPanel

components/ErrorPanel.tsx + ErrorPanel.css. Persistent floating widget mounted by App (app.tsx:114). Polls GET /api/enrichment/errors?resolved=false&limit=1 once on mount; if any unresolved errors exist, fetches up to 50. Renders a fixed bottom-right toggle button “Fel (N)” that opens a side panel listing recent enrichment errors with a per-row “Försök igen” button (re-POSTs /api/kundkort/:orgNr/enrich).

Warning

The toggle button uses two emoji glyphs (warning sign and ✕). Other components avoid emojis. The polling does not refresh on a timer — only mount and panel-open.

components/Footer.tsx. Fixed bottom strip 36 px tall. Polls GET /api/config every 30 s for { dev_mode, enrichment_count, enrichment_limit }. Shows a usage-bar/progress indicator (green → yellow ≥80 % → red at 100 %) plus a red “DEVMODE” pill when the backend reports dev mode. Hidden in print via data-no-print.

CompanyHeader

components/CompanyHeader.tsx. Top of Kundkort Page body. Shows initials avatar (first letter of two name tokens), name, meta line (formatted org_nr · city · legal_form), three pills (Aktiv/Inaktiv status, “Score X/10” if lead_score, validation badge from getValidationStatus() thresholds: <3 grey “Ej validerad”, <5 amber “Delvis validerad”, else green “Validerad”), and a 3 px completeness bar driven by data.data_completeness_pct.

formatOrgNr

utils/formatOrgNr.ts. Strips non-digits; if exactly 10 digits, returns XXXXXX-XXXX. Otherwise returns input unchanged. Returns "—" for null/undefined/empty.

See also

Kundkort Page, Search Page, Auth Flow.

See also