Hours by client: add search and CSV filtering; add alerts cron (BRT 08:00 guard) + alerts panel filters; admin companies shows last alert; PDF Inter font from public/fonts; fix Select empty value; type cleanups; tests for CSV/TZ; remove Knowledge Base nav

This commit is contained in:
Esdras Renan 2025-10-07 15:39:55 -03:00
parent 2cf399dcb1
commit 08cc8037d5
151 changed files with 1404 additions and 214 deletions

View file

@ -36,6 +36,7 @@ export function AdminCompaniesManager({ initialCompanies }: { initialCompanies:
const [isPending, startTransition] = useTransition()
const [form, setForm] = useState<Partial<Company>>({})
const [editingId, setEditingId] = useState<string | null>(null)
const [lastAlerts, setLastAlerts] = useState<Record<string, { createdAt: number; usagePct: number; threshold: number } | null>>({})
const resetForm = () => setForm({})
@ -43,6 +44,7 @@ export function AdminCompaniesManager({ initialCompanies }: { initialCompanies:
const r = await fetch("/api/admin/companies", { credentials: "include" })
const json = (await r.json()) as { companies: Company[] }
setCompanies(json.companies)
void loadLastAlerts(json.companies)
}
function handleEdit(c: Company) {
@ -50,6 +52,20 @@ export function AdminCompaniesManager({ initialCompanies }: { initialCompanies:
setForm({ ...c })
}
async function loadLastAlerts(list: Company[] = companies) {
if (!list || list.length === 0) return
const params = new URLSearchParams({ slugs: list.map((c) => c.slug).join(",") })
try {
const r = await fetch(`/api/admin/companies/last-alerts?${params.toString()}`, { credentials: "include" })
const json = (await r.json()) as { items: Record<string, { createdAt: number; usagePct: number; threshold: number } | null> }
setLastAlerts(json.items ?? {})
} catch {
// ignore
}
}
useMemo(() => { void loadLastAlerts(companies) }, [])
async function handleSubmit(e: React.FormEvent) {
e.preventDefault()
const payload = {
@ -191,6 +207,7 @@ export function AdminCompaniesManager({ initialCompanies }: { initialCompanies:
<TableHead>Domínio</TableHead>
<TableHead>Telefone</TableHead>
<TableHead>CNPJ</TableHead>
<TableHead>Último alerta</TableHead>
<TableHead>Ações</TableHead>
</TableRow>
</TableHeader>
@ -207,6 +224,11 @@ export function AdminCompaniesManager({ initialCompanies }: { initialCompanies:
<TableCell>{c.domain ?? "—"}</TableCell>
<TableCell>{c.phone ?? "—"}</TableCell>
<TableCell>{c.cnpj ?? "—"}</TableCell>
<TableCell>
{lastAlerts[c.slug]
? `${new Date(lastAlerts[c.slug]!.createdAt).toLocaleString("pt-BR")}`
: "—"}
</TableCell>
<TableCell>
<Button size="sm" variant="outline" onClick={() => handleEdit(c)}>
Editar