Policy header, all five child collections, and the insurance reference catalogs become create/edit/delete-able on the RBAC foundation. API: - Policy gains archivedAt (soft-delete); list/browser default to archivedAt=null with ?includeArchived opt-in. - PoliciesService: header create/update/archive/restore (customer FK validated for a clean 404); add/update/remove for installments, vehicles, drivers, beneficiaries, claims — each scoped to its policy so one policy's id can't touch another's rows; lookups CRUD for providers, policy types, adjusters. - PoliciesController write routes: header create/update need STAFF+ (policy:create/update), archive/restore need MANAGER+ (policy:delete), every child route needs policy:update. New LookupsController at /lookups (read open; mutate needs lookup:manage / MANAGER+). Mutations audited. - DTOs (policy header, children, lookups); dates coerced; shared coerce.ts. Web: - Generic ChildCollection editor (config-driven add/edit/remove table), reused by both the policy detail child editors and the catalogs screen. - PolicyForm (header) with type/provider selects and a debounced CustomerPicker; /polizas/nuevo (accepts ?customerId prefill) and /polizas/[id]/editar. Policy detail: gated action bar (Editar/Archivar) + "Administrar detalles" child editors for all five collections. - /catalogos admin screen (aseguradoras/tipos/ajustadores), nav-gated on lookup:manage. "Nueva póliza" buttons on the list and on the customer detail (prefilled). api.ts + types for all of the above. Verified against dev: policy create (dates coerced, archivedAt null), installment/vehicle add, VIEWER child-add 403, cross-policy child guard 404, lookups CRUD with VIEWER 403 / MANAGER 201, archive drops from the default list and includeArchived surfaces it. Both apps compile clean. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
42 lines
1.1 KiB
TypeScript
42 lines
1.1 KiB
TypeScript
"use client";
|
|
|
|
import { Suspense } from "react";
|
|
import Link from "next/link";
|
|
import { useSearchParams } from "next/navigation";
|
|
import { AppShell } from "@/components/AppShell";
|
|
import { PolicyForm } from "@/components/PolicyForm";
|
|
import { useCan } from "@/lib/abilities";
|
|
|
|
export default function NuevaPolizaPage() {
|
|
return (
|
|
<AppShell>
|
|
<Suspense fallback={null}>
|
|
<NuevaPoliza />
|
|
</Suspense>
|
|
</AppShell>
|
|
);
|
|
}
|
|
|
|
function NuevaPoliza() {
|
|
const allowed = useCan("policy:create");
|
|
const params = useSearchParams();
|
|
const customerId = params.get("customerId") ?? undefined;
|
|
const customerName = params.get("customerName") ?? undefined;
|
|
|
|
return (
|
|
<>
|
|
<div className="page-head">
|
|
<Link href="/polizas" className="back-link">← Pólizas</Link>
|
|
<h1 className="page-title">Nueva póliza</h1>
|
|
</div>
|
|
{allowed ? (
|
|
<PolicyForm fixedCustomerId={customerId} fixedCustomerName={customerName} />
|
|
) : (
|
|
<div className="state-box state-error">
|
|
No tiene permisos para crear pólizas.
|
|
</div>
|
|
)}
|
|
</>
|
|
);
|
|
}
|