'use client' import { useEffect, useState } from 'react' import { Dialog, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogTitle, } from '@/components/ui/dialog' import { Button } from '@/components/ui/button' import { Input } from '@/components/ui/input' import { Label } from '@/components/ui/label' import { toast } from 'sonner' import { Loader2 } from 'lucide-react' // Shape shared between the table row and the edit form. Optional fields // are stringified so the form has a single value type. export interface CompanyFormValue { id?: string name: string legalForm: string vatId: string registerCourt: string registerNumber: string website: string email: string phone: string city: string zip: string street: string tags: string } export const EMPTY_COMPANY: CompanyFormValue = { name: '', legalForm: '', vatId: '', registerCourt: '', registerNumber: '', website: '', email: '', phone: '', city: '', zip: '', street: '', tags: '', } interface Props { open: boolean onOpenChange: (o: boolean) => void // When `company` is null, the dialog is in "create" mode. company?: CompanyFormValue | null onSaved: () => void } // Single dialog for create + edit of a CRM Company. // - create mode → POST /api/aos/crm/companies // - edit mode → PATCH /api/aos/crm/companies/[id] // Both write an audit entry on the server side (GoBD). export function CompanyFormDialog({ open, onOpenChange, company, onSaved }: Props) { const [form, setForm] = useState(EMPTY_COMPANY) const [saving, setSaving] = useState(false) const isEdit = !!company?.id useEffect(() => { if (open) { setForm(company ?? EMPTY_COMPANY) } }, [open, company]) const update = (k: keyof CompanyFormValue, v: string) => setForm((f) => ({ ...f, [k]: v })) const submit = async () => { if (!form.name.trim()) { toast.error('Firmenname ist Pflicht'); return } setSaving(true) const t = toast.loading(isEdit ? 'Firma wird gespeichert…' : 'Firma wird angelegt…') try { // Normalise empty strings → null on the server side (Prisma schema is // nullable; the PATCH handler accepts strings or null). const payload: Record = { name: form.name.trim(), legalForm: form.legalForm.trim() || null, vatId: form.vatId.trim() || null, registerCourt: form.registerCourt.trim() || null, registerNumber: form.registerNumber.trim() || null, website: form.website.trim() || null, email: form.email.trim() || null, phone: form.phone.trim() || null, city: form.city.trim() || null, zip: form.zip.trim() || null, street: form.street.trim() || null, tags: form.tags.trim() || null, } const url = isEdit ? `/api/aos/crm/companies/${company!.id}` : '/api/aos/crm/companies' const method = isEdit ? 'PATCH' : 'POST' const r = await fetch(url, { method, headers: { 'content-type': 'application/json' }, body: JSON.stringify(payload), }) if (!r.ok) { const err = await r.json().catch(() => ({})) throw new Error(err.error || `${method} failed`) } toast.success(isEdit ? 'Firma aktualisiert' : 'Firma angelegt', { id: t }) onOpenChange(false) onSaved() } catch (err) { toast.error(err instanceof Error ? err.message : 'Speichern fehlgeschlagen', { id: t }) } finally { setSaving(false) } } return ( {isEdit ? 'Firma bearbeiten' : 'Neue Firma'} {isEdit ? 'Stammdaten aktualisieren. Änderungen werden im Audit-Log protokolliert (GoBD).' : 'Erfasse eine neue Firma im CRM. Audit-Log wird automatisch geschrieben.'}
update('name', v)} className="col-span-2" /> update('legalForm', v)} placeholder="GmbH, UG, e.K." /> update('vatId', v)} placeholder="DE123456789" mono /> update('registerCourt', v)} placeholder="Amtsgericht Hamburg" /> update('registerNumber', v)} mono /> update('website', v)} placeholder="mueller.de" /> update('email', v)} placeholder="info@firma.de" /> update('phone', v)} placeholder="+49 40 …" /> update('street', v)} /> update('zip', v)} /> update('city', v)} className="col-span-2" /> update('tags', v)} placeholder="kunde, agency, vip" className="col-span-2" />
) } function Field({ label, value, onChange, placeholder, mono, className, }: { label: string value: string onChange: (v: string) => void placeholder?: string mono?: boolean className?: string }) { return (
onChange(e.target.value)} placeholder={placeholder} className={`h-9 text-xs ${mono ? 'font-mono' : ''}`} />
) }