'use client' import { useEffect, useState } from 'react' import { useTranslations } from 'next-intl' import { Badge } from '@/components/ui/badge' import { Button } from '@/components/ui/button' import { Dialog, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogTitle } from '@/components/ui/dialog' import { Input } from '@/components/ui/input' import { Skeleton } from '@/components/ui/skeleton' import type { ScbCandidate, ScbSearchResult } from '@/lib/parties/scb/client' import { formatOrgNumber } from '@/lib/utils' /** * "SCB hittar två företag som liknar Adobe Systems Software, vilket menar * du?" The picker for a party without an org number: the user chooses, * the org number lands on the party, and every later fetch is by number. * One match is still shown, never auto-picked. */ export function ScbPickerDialog({ open, onOpenChange, partyId, partyName, busy, onPick, }: { open: boolean onOpenChange: (open: boolean) => void partyId: string partyName: string busy: boolean onPick: (candidate: ScbCandidate) => Promise }) { const t = useTranslations('parties') const tCommon = useTranslations('common') const [query, setQuery] = useState('') const [loaded, setLoaded] = useState<{ key: string; result: ScbSearchResult | null; failed: boolean } | null>(null) const [selected, setSelected] = useState(null) const key = `${partyId}:${query.trim()}` const current = loaded && loaded.key === key ? loaded : null const loading = open && current === null useEffect(() => { if (!open) return let cancelled = false const ctrl = new AbortController() const timer = setTimeout(async () => { try { const params = query.trim() ? `?q=${encodeURIComponent(query.trim())}` : '' const res = await fetch(`/api/parties/${partyId}/enrich/candidates${params}`, { signal: ctrl.signal }) const json = (await res.json()) as { data?: ScbSearchResult } if (!cancelled) setLoaded({ key, result: res.ok ? (json.data ?? null) : null, failed: !res.ok }) } catch { if (!cancelled) setLoaded({ key, result: null, failed: true }) } }, query.trim() ? 300 : 0) return () => { cancelled = true clearTimeout(timer) ctrl.abort() } }, [open, partyId, query, key]) const result = current?.result ?? null const candidates = result?.candidates ?? [] const chosen = candidates.find((c) => c.orgNumber === selected) ?? null return ( {t('picker_title')} {result && !current?.failed ? result.truncated ? t('picker_too_many', { count: result.total, query: result.query }) : candidates.length === 0 ? t('picker_none', { query: result.query }) : t('picker_found', { count: candidates.length, query: result.query }) : t('picker_body', { name: partyName })}
{ setQuery(e.target.value) setSelected(null) }} placeholder={t('picker_search_placeholder')} aria-label={t('picker_search_placeholder')} /> {loading ? (
) : current?.failed ? (

{t('registry_unavailable_title')}

) : candidates.length > 0 ? (
    {candidates.map((c) => { const isSelected = selected === c.orgNumber return (
  • ) })}
) : null}
) }