update reservation

This commit is contained in:
root
2026-05-25 15:56:14 -04:00
parent 914ae839a7
commit 8ed572b3bd
17 changed files with 809 additions and 63 deletions
@@ -5,12 +5,38 @@ import { useParams, useRouter } from 'next/navigation'
import Link from 'next/link'
import { ADMIN_API_BASE } from '@/lib/api'
interface CompanyAddressProfile {
streetAddress?: string | null
city?: string | null
country?: string | null
zipCode?: string | null
legalName?: string | null
legalForm?: string | null
companyEmail?: string | null
managerName?: string | null
iceNumber?: string | null
operatingLicenseNumber?: string | null
operatingLicenseIssuedAt?: string | null
operatingLicenseIssuedBy?: string | null
fax?: string | null
yearsActive?: string | null
representativeName?: string | null
representativeTitle?: string | null
responsibleName?: string | null
responsibleRole?: string | null
responsibleIdentityNumber?: string | null
responsibleQualification?: string | null
responsiblePhone?: string | null
responsibleEmail?: string | null
}
interface CompanyDetail {
id: string
name: string
slug: string
email: string
phone: string | null
address: CompanyAddressProfile | string | null
status: string
subscriptionPaymentRef: string | null
createdAt: string
@@ -100,6 +126,25 @@ interface FormState {
status: string
subscriptionPaymentRef: string
}
companyProfile: {
legalForm: string
managerName: string
zipCode: string
fax: string
yearsActive: string
iceNumber: string
operatingLicenseNumber: string
operatingLicenseIssuedAt: string
operatingLicenseIssuedBy: string
representativeName: string
representativeTitle: string
responsibleName: string
responsibleRole: string
responsibleIdentityNumber: string
responsibleQualification: string
responsiblePhone: string
responsibleEmail: string
}
subscription: {
plan: string
billingPeriod: string
@@ -175,7 +220,13 @@ function toNullable(value: string) {
return trimmed ? trimmed : null
}
function normalizeAddressProfile(value: CompanyDetail['address']): CompanyAddressProfile {
if (!value || typeof value !== 'object' || Array.isArray(value)) return {}
return value
}
function createFormState(company: CompanyDetail): FormState {
const address = normalizeAddressProfile(company.address)
return {
company: {
name: company.name ?? '',
@@ -185,6 +236,25 @@ function createFormState(company: CompanyDetail): FormState {
status: company.status ?? 'TRIALING',
subscriptionPaymentRef: company.subscriptionPaymentRef ?? '',
},
companyProfile: {
legalForm: address.legalForm ?? '',
managerName: address.managerName ?? '',
zipCode: address.zipCode ?? '',
fax: address.fax ?? '',
yearsActive: address.yearsActive ?? '',
iceNumber: address.iceNumber ?? '',
operatingLicenseNumber: address.operatingLicenseNumber ?? '',
operatingLicenseIssuedAt: address.operatingLicenseIssuedAt ?? '',
operatingLicenseIssuedBy: address.operatingLicenseIssuedBy ?? '',
representativeName: address.representativeName ?? '',
representativeTitle: address.representativeTitle ?? '',
responsibleName: address.responsibleName ?? '',
responsibleRole: address.responsibleRole ?? '',
responsibleIdentityNumber: address.responsibleIdentityNumber ?? '',
responsibleQualification: address.responsibleQualification ?? '',
responsiblePhone: address.responsiblePhone ?? '',
responsibleEmail: address.responsibleEmail ?? '',
},
subscription: {
plan: company.subscription?.plan ?? 'STARTER',
billingPeriod: company.subscription?.billingPeriod ?? 'MONTHLY',
@@ -303,6 +373,30 @@ export default function AdminCompanyDetailPage() {
email: form.company.email,
phone: toNullable(form.company.phone),
subscriptionPaymentRef: toNullable(form.company.subscriptionPaymentRef),
address: {
streetAddress: toNullable(form.brand.publicAddress),
city: toNullable(form.brand.publicCity),
country: toNullable(form.brand.publicCountry),
zipCode: toNullable(form.companyProfile.zipCode),
legalName: toNullable(form.contractSettings.legalName),
legalForm: toNullable(form.companyProfile.legalForm),
companyEmail: toNullable(form.company.email),
managerName: toNullable(form.companyProfile.managerName),
iceNumber: toNullable(form.companyProfile.iceNumber),
operatingLicenseNumber: toNullable(form.companyProfile.operatingLicenseNumber),
operatingLicenseIssuedAt: toNullable(form.companyProfile.operatingLicenseIssuedAt),
operatingLicenseIssuedBy: toNullable(form.companyProfile.operatingLicenseIssuedBy),
fax: toNullable(form.companyProfile.fax),
yearsActive: toNullable(form.companyProfile.yearsActive),
representativeName: toNullable(form.companyProfile.representativeName),
representativeTitle: toNullable(form.companyProfile.representativeTitle),
responsibleName: toNullable(form.companyProfile.responsibleName),
responsibleRole: toNullable(form.companyProfile.responsibleRole),
responsibleIdentityNumber: toNullable(form.companyProfile.responsibleIdentityNumber),
responsibleQualification: toNullable(form.companyProfile.responsibleQualification),
responsiblePhone: toNullable(form.companyProfile.responsiblePhone),
responsibleEmail: toNullable(form.companyProfile.responsibleEmail),
},
},
subscription: {
plan: form.subscription.plan,
@@ -637,6 +731,94 @@ export default function AdminCompanyDetailPage() {
</div>
</section>
<section className="panel p-6">
<h2 className="text-base font-semibold">Company legal profile</h2>
<div className="mt-4 grid gap-6">
<div className="grid gap-4 md:grid-cols-2">
<label>
<span className={LABEL_CLASS}>Legal form</span>
<input className={INPUT_CLASS} value={form.companyProfile.legalForm} onChange={(e) => updateSection('companyProfile', { legalForm: e.target.value })} />
</label>
<label>
<span className={LABEL_CLASS}>Manager / owner name</span>
<input className={INPUT_CLASS} value={form.companyProfile.managerName} onChange={(e) => updateSection('companyProfile', { managerName: e.target.value })} />
</label>
<label>
<span className={LABEL_CLASS}>ZIP / postal code</span>
<input className={INPUT_CLASS} value={form.companyProfile.zipCode} onChange={(e) => updateSection('companyProfile', { zipCode: e.target.value })} />
</label>
<label>
<span className={LABEL_CLASS}>Fax</span>
<input className={INPUT_CLASS} value={form.companyProfile.fax} onChange={(e) => updateSection('companyProfile', { fax: e.target.value })} />
</label>
<label>
<span className={LABEL_CLASS}>Years active</span>
<input className={INPUT_CLASS} value={form.companyProfile.yearsActive} onChange={(e) => updateSection('companyProfile', { yearsActive: e.target.value })} />
</label>
<label>
<span className={LABEL_CLASS}>ICE number</span>
<input className={INPUT_CLASS} value={form.companyProfile.iceNumber} onChange={(e) => updateSection('companyProfile', { iceNumber: e.target.value })} />
</label>
<label>
<span className={LABEL_CLASS}>Operating license number</span>
<input className={INPUT_CLASS} value={form.companyProfile.operatingLicenseNumber} onChange={(e) => updateSection('companyProfile', { operatingLicenseNumber: e.target.value })} />
</label>
<label>
<span className={LABEL_CLASS}>Operating license issue date</span>
<input className={INPUT_CLASS} value={form.companyProfile.operatingLicenseIssuedAt} onChange={(e) => updateSection('companyProfile', { operatingLicenseIssuedAt: e.target.value })} />
</label>
<label className="md:col-span-2">
<span className={LABEL_CLASS}>Issuing authority</span>
<input className={INPUT_CLASS} value={form.companyProfile.operatingLicenseIssuedBy} onChange={(e) => updateSection('companyProfile', { operatingLicenseIssuedBy: e.target.value })} />
</label>
</div>
<div className="border-t border-zinc-800 pt-6">
<h3 className="text-sm font-semibold text-zinc-200">Legal representative</h3>
<div className="mt-4 grid gap-4 md:grid-cols-2">
<label>
<span className={LABEL_CLASS}>Representative name</span>
<input className={INPUT_CLASS} value={form.companyProfile.representativeName} onChange={(e) => updateSection('companyProfile', { representativeName: e.target.value })} />
</label>
<label>
<span className={LABEL_CLASS}>Representative title</span>
<input className={INPUT_CLASS} value={form.companyProfile.representativeTitle} onChange={(e) => updateSection('companyProfile', { representativeTitle: e.target.value })} />
</label>
</div>
</div>
<div className="border-t border-zinc-800 pt-6">
<h3 className="text-sm font-semibold text-zinc-200">Responsible person</h3>
<div className="mt-4 grid gap-4 md:grid-cols-2">
<label>
<span className={LABEL_CLASS}>Responsible name</span>
<input className={INPUT_CLASS} value={form.companyProfile.responsibleName} onChange={(e) => updateSection('companyProfile', { responsibleName: e.target.value })} />
</label>
<label>
<span className={LABEL_CLASS}>Responsible role</span>
<input className={INPUT_CLASS} value={form.companyProfile.responsibleRole} onChange={(e) => updateSection('companyProfile', { responsibleRole: e.target.value })} />
</label>
<label>
<span className={LABEL_CLASS}>Identity document number</span>
<input className={INPUT_CLASS} value={form.companyProfile.responsibleIdentityNumber} onChange={(e) => updateSection('companyProfile', { responsibleIdentityNumber: e.target.value })} />
</label>
<label>
<span className={LABEL_CLASS}>Qualification / diploma / experience</span>
<input className={INPUT_CLASS} value={form.companyProfile.responsibleQualification} onChange={(e) => updateSection('companyProfile', { responsibleQualification: e.target.value })} />
</label>
<label>
<span className={LABEL_CLASS}>Responsible phone</span>
<input className={INPUT_CLASS} value={form.companyProfile.responsiblePhone} onChange={(e) => updateSection('companyProfile', { responsiblePhone: e.target.value })} />
</label>
<label>
<span className={LABEL_CLASS}>Responsible email</span>
<input className={INPUT_CLASS} type="email" value={form.companyProfile.responsibleEmail} onChange={(e) => updateSection('companyProfile', { responsibleEmail: e.target.value })} />
</label>
</div>
</div>
</div>
</section>
<section className="panel p-6">
<h2 className="text-base font-semibold">Operations and finance</h2>
<div className="mt-4 grid gap-6">
@@ -11,6 +11,7 @@ interface Company {
slug: string
status: string
email: string
contractSettings: { legalName: string | null } | null
subscription: { plan: string; status: string } | null
_count: { employees: number; vehicles: number }
}
@@ -32,6 +33,7 @@ export default function AdminCompaniesPage() {
loading: 'Loading…',
empty: 'No companies found',
company: 'Company',
legalName: 'Legal name',
slug: 'Slug',
status: 'Status',
plan: 'Plan',
@@ -47,6 +49,7 @@ export default function AdminCompaniesPage() {
loading: 'Chargement…',
empty: 'Aucune entreprise trouvée',
company: 'Entreprise',
legalName: 'Raison sociale',
slug: 'Slug',
status: 'Statut',
plan: 'Plan',
@@ -62,6 +65,7 @@ export default function AdminCompaniesPage() {
loading: 'جارٍ التحميل…',
empty: 'لم يتم العثور على شركات',
company: 'الشركة',
legalName: 'الاسم القانوني',
slug: 'Slug',
status: 'الحالة',
plan: 'الخطة',
@@ -162,6 +166,9 @@ export default function AdminCompaniesPage() {
<tr key={c.id} className="hover:bg-zinc-800/30 transition-colors">
<td className="px-6 py-4">
<p className="font-medium text-zinc-100">{c.name}</p>
{c.contractSettings?.legalName && c.contractSettings.legalName !== c.name ? (
<p className="text-xs text-zinc-400">{copy.legalName}: {c.contractSettings.legalName}</p>
) : null}
<p className="text-xs text-zinc-500">{c.email}</p>
</td>
<td className="px-6 py-4 text-zinc-400 font-mono text-xs">{c.slug}</td>