feat(CC-070): add Companies Intelligence page (live search via intelligence API)

This commit is contained in:
admin-valentin 2026-08-02 12:27:00 +00:00
parent f4c94ae813
commit c7deff3259

View file

@ -0,0 +1,140 @@
'use client';
import { useState } from 'react';
import { useQuery } from '@tanstack/react-query';
import { apiFetch } from '../../../../lib/api';
import { useSession } from '../../../../components/session-provider';
interface CompanyResult {
cui?: string; companyId?: string; name?: string; companyName?: string;
industry?: string; county?: string; city?: string; country?: string;
employees?: number; revenue?: number; registrationDate?: string;
isActive?: boolean; caenCode?: string; caenLabel?: string;
}
export default function CompaniesIntelligencePage() {
const { activeTenant } = useSession();
const tenantId = activeTenant?.tenantId ?? '';
const [q, setQ] = useState('');
const [submitted, setSubmitted] = useState('');
const { data, isLoading, error } = useQuery({
queryKey: ['intel-companies', tenantId, submitted],
queryFn: () => apiFetch<{ results?: CompanyResult[]; total?: number } | CompanyResult[]>(
`/v1/intelligence/companies/search?q=${encodeURIComponent(submitted)}&limit=20`,
{ tenantId }
),
enabled: Boolean(tenantId) && submitted.length >= 2,
staleTime: 300_000,
});
const results: CompanyResult[] = Array.isArray(data) ? data : (data as any)?.results ?? [];
return (
<div className="max-w-3xl space-y-6 p-6">
<div>
<h1 className="font-display text-2xl font-semibold text-ink">Baza de date Companii</h1>
<p className="text-sm text-ink-faint mt-1">
Caută companii din registrul de business nume, CUI, domeniu de activitate.
</p>
</div>
{/* Search box */}
<form onSubmit={(e) => { e.preventDefault(); if (q.trim().length >= 2) setSubmitted(q.trim()); }}
className="flex gap-2">
<input
placeholder="Caută companie (minim 2 caractere)…"
value={q} onChange={(e) => setQ(e.target.value)}
className="flex-1 rounded-lg border bg-card px-4 py-2.5 text-sm text-ink focus:outline-none focus:ring-2 focus:ring-ring"
/>
<button type="submit" disabled={q.trim().length < 2}
className="btn btn-primary px-5 py-2.5 text-sm rounded-lg disabled:opacity-50">
Caută
</button>
</form>
{/* Results */}
{isLoading && (
<div className="text-center text-sm text-ink-faint py-8">Se caută</div>
)}
{error && (
<div className="card p-4 bg-signal-danger/5 border-signal-danger/20">
<p className="text-sm text-signal-danger">Eroare la căutare. Verifică conexiunea la baza de date.</p>
</div>
)}
{!isLoading && submitted && results.length === 0 && !error && (
<div className="card p-8 text-center space-y-2">
<p className="text-2xl">🔍</p>
<p className="text-sm text-ink-faint">Niciun rezultat pentru &quot;{submitted}&quot;</p>
</div>
)}
{results.length > 0 && (
<div className="space-y-3">
<p className="text-xs text-ink-faint">{results.length} rezultate pentru &quot;{submitted}&quot;</p>
<div className="card divide-y divide-border/50">
{results.map((company, i) => {
const name = company.name ?? company.companyName ?? '—';
const id = company.cui ?? company.companyId ?? String(i);
return (
<div key={id} className="p-4 space-y-1">
<div className="flex items-start justify-between gap-3">
<div className="flex-1 min-w-0">
<p className="text-sm font-semibold text-ink">{name}</p>
{(company.cui || company.companyId) && (
<p className="text-[10px] text-ink-faint font-mono mt-0.5">
CUI: {company.cui ?? company.companyId}
</p>
)}
</div>
{company.isActive !== undefined && (
<span className={`shrink-0 rounded-full px-2 py-0.5 text-[10px] font-medium ${
company.isActive ? 'bg-signal-ok/10 text-signal-ok' : 'bg-muted text-ink-faint'
}`}>
{company.isActive ? 'Activ' : 'Inactiv'}
</span>
)}
</div>
<div className="flex flex-wrap gap-3">
{company.industry && (
<span className="text-[10px] text-ink-faint">🏭 {company.industry}</span>
)}
{(company.caenCode || company.caenLabel) && (
<span className="text-[10px] text-ink-faint">📋 {company.caenCode}{company.caenLabel ? `${company.caenLabel}` : ''}</span>
)}
{(company.city || company.county) && (
<span className="text-[10px] text-ink-faint">📍 {[company.city, company.county].filter(Boolean).join(', ')}</span>
)}
{company.employees && (
<span className="text-[10px] text-ink-faint">👥 {company.employees.toLocaleString('ro-RO')} angajați</span>
)}
{company.registrationDate && (
<span className="text-[10px] text-ink-faint">📅 {company.registrationDate.slice(0, 10)}</span>
)}
</div>
</div>
);
})}
</div>
</div>
)}
{!submitted && (
<div className="card p-6 space-y-3">
<p className="text-xs font-semibold text-ink-faint uppercase tracking-wider">Cum funcționează</p>
<div className="space-y-2">
{[
'🔍 Caută după denumire completă sau parțială',
'🔢 Caută după CUI (cod unic de identificare)',
'📊 Rezultatele includ date ONRC: CAEN, angajați, locație',
'⚡ Rezultatele sunt live din baza de date de intelligence',
].map((s) => <p key={s} className="text-xs text-ink-faint">{s}</p>)}
</div>
</div>
)}
</div>
);
}