235 lines
8.8 KiB
Vue
235 lines
8.8 KiB
Vue
<script setup lang="ts">
|
|
import type { PolicyRegistration } from '~/types/brokerage-registration'
|
|
import { POLICY_DRAFT_STORAGE_KEY } from '~/types/brokerage-registration'
|
|
import {
|
|
createEmptyPolicyRegistration,
|
|
rebuildInstallmentSchedule,
|
|
setFinOneYearAfterInicio,
|
|
usePolicyDraftPersistence
|
|
} from '~/composables/usePolicyRegistrationModel'
|
|
|
|
definePageMeta({ ssr: false })
|
|
usePageTitle('Policy registration')
|
|
|
|
const toast = useToast()
|
|
const form = ref<PolicyRegistration>(createEmptyPolicyRegistration())
|
|
usePolicyDraftPersistence(form)
|
|
|
|
watch(
|
|
() => form.value.inicioVigencia,
|
|
() => setFinOneYearAfterInicio(form.value)
|
|
)
|
|
|
|
function refreshSchedule() {
|
|
form.value.cuotas = rebuildInstallmentSchedule(form.value)
|
|
}
|
|
|
|
watch(
|
|
() => [form.value.numCuotas, form.value.primaBruta, form.value.inicioVigencia] as const,
|
|
() => refreshSchedule(),
|
|
{ deep: true }
|
|
)
|
|
|
|
onMounted(() => {
|
|
refreshSchedule()
|
|
})
|
|
|
|
const draftSavedAt = ref<string | null>(null)
|
|
|
|
function saveDraft() {
|
|
try {
|
|
localStorage.setItem(POLICY_DRAFT_STORAGE_KEY, JSON.stringify(form.value))
|
|
draftSavedAt.value = new Date().toLocaleTimeString('en-US', { hour: 'numeric', minute: '2-digit' })
|
|
toast.add({ title: 'Borrador guardado', color: 'success' })
|
|
} catch {
|
|
toast.add({ title: 'No se pudo guardar', color: 'error' })
|
|
}
|
|
}
|
|
|
|
function clearDraft() {
|
|
form.value = createEmptyPolicyRegistration()
|
|
refreshSchedule()
|
|
try {
|
|
localStorage.removeItem(POLICY_DRAFT_STORAGE_KEY)
|
|
} catch {
|
|
/* ignore */
|
|
}
|
|
toast.add({ title: 'Borrador borrado', color: 'success' })
|
|
}
|
|
</script>
|
|
|
|
<template>
|
|
<div class="min-h-screen space-y-8 bg-gray-50 p-8">
|
|
<div class="flex flex-wrap items-start justify-between gap-4">
|
|
<div class="flex items-center gap-4">
|
|
<NuxtLink to="/policies">
|
|
<UButton icon="i-heroicons-arrow-left" color="neutral" variant="ghost">Back</UButton>
|
|
</NuxtLink>
|
|
<div>
|
|
<h1 class="text-2xl font-semibold tracking-tight text-[var(--text-primary)]">Nuevo registro · Póliza</h1>
|
|
<p class="text-[13px] text-[var(--text-muted)]">
|
|
Condiciones particulares, plan de pagos y referencias. Draft persists in this browser until an API is
|
|
wired.
|
|
</p>
|
|
</div>
|
|
</div>
|
|
<div class="flex flex-wrap items-center gap-2">
|
|
<UButton color="neutral" variant="soft" @click="saveDraft">Guardar borrador</UButton>
|
|
<span v-if="draftSavedAt" class="text-[11px] text-emerald-600 font-medium">
|
|
<UIcon name="i-heroicons-check-circle" style="width: 13px; height: 13px; vertical-align: -2px;" /> Saved at {{ draftSavedAt }}
|
|
</span>
|
|
<UButton color="neutral" variant="ghost" @click="clearDraft">Limpiar</UButton>
|
|
<NuxtLink to="/onboarding/policy-upload/new">
|
|
<UButton color="primary" variant="soft">Manual policy upload</UButton>
|
|
</NuxtLink>
|
|
</div>
|
|
</div>
|
|
|
|
<UCard class="max-w-5xl">
|
|
<template #header>
|
|
<span class="font-semibold text-[var(--text-primary)]">Identificación y ramo</span>
|
|
</template>
|
|
<div class="grid grid-cols-1 gap-4 sm:grid-cols-2 lg:grid-cols-3">
|
|
<UFormField label="Número póliza Mint">
|
|
<UInput v-model="form.mintPolicyNumber" disabled class="w-full" />
|
|
</UFormField>
|
|
<UFormField label="ID contratante">
|
|
<UInput v-model="form.contratanteId" class="w-full" />
|
|
</UFormField>
|
|
<UFormField label="Ramo">
|
|
<UInput v-model="form.ramo" class="w-full" />
|
|
</UFormField>
|
|
<UFormField label="Sub ramo">
|
|
<UInput v-model="form.subRamo" class="w-full" />
|
|
</UFormField>
|
|
<UFormField label="Aseguradora">
|
|
<UInput v-model="form.aseguradora" class="w-full" />
|
|
</UFormField>
|
|
<UFormField label="Producto">
|
|
<UInput v-model="form.producto" class="w-full" />
|
|
</UFormField>
|
|
<UFormField label="Agencia">
|
|
<UInput v-model="form.agencia" class="w-full" />
|
|
</UFormField>
|
|
<UFormField label="Nº póliza proveedor">
|
|
<UInput v-model="form.numeroPolizaProveedor" class="w-full" />
|
|
</UFormField>
|
|
<UFormField label="Acreedor">
|
|
<UInput v-model="form.acreedor" class="w-full" />
|
|
</UFormField>
|
|
</div>
|
|
</UCard>
|
|
|
|
<UCard class="max-w-5xl">
|
|
<template #header>
|
|
<span class="font-semibold text-[var(--text-primary)]">Vigencia y comisiones</span>
|
|
</template>
|
|
<div class="mb-6 grid grid-cols-1 gap-4 sm:grid-cols-3">
|
|
<UFormField label="Fecha emisión">
|
|
<UInput v-model="form.fechaEmision" type="datetime-local" class="w-full" />
|
|
</UFormField>
|
|
<UFormField label="Inicio vigencia">
|
|
<UInput v-model="form.inicioVigencia" type="datetime-local" class="w-full" />
|
|
</UFormField>
|
|
<UFormField label="Fin vigencia">
|
|
<UInput v-model="form.finVigencia" type="datetime-local" class="w-full" />
|
|
</UFormField>
|
|
</div>
|
|
<p class="mb-2 text-xs text-[var(--text-muted)]">Comisiones agente (%)</p>
|
|
<div class="grid grid-cols-1 gap-4 sm:grid-cols-3">
|
|
<div v-for="row in form.comisiones" :key="row.idx" class="flex items-end gap-2">
|
|
<UFormField :label="`Agente ${row.idx}`" class="flex-1">
|
|
<UInput v-model="row.agenteId" placeholder="ID" class="w-full" />
|
|
</UFormField>
|
|
<UFormField label="%" class="w-24">
|
|
<UInput v-model="row.porcentaje" class="w-full" />
|
|
</UFormField>
|
|
</div>
|
|
</div>
|
|
</UCard>
|
|
|
|
<UCard class="max-w-5xl">
|
|
<template #header>
|
|
<span class="font-semibold text-[var(--text-primary)]">Primas y forma de pago</span>
|
|
</template>
|
|
<div class="grid grid-cols-1 gap-4 sm:grid-cols-2 lg:grid-cols-3">
|
|
<UFormField label="Forma de pago">
|
|
<UInput v-model="form.formaPago" class="w-full" />
|
|
</UFormField>
|
|
<UFormField label="Valor asegurado">
|
|
<UInput v-model="form.valorAsegurado" class="w-full" />
|
|
</UFormField>
|
|
<UFormField label="Prima bruta">
|
|
<UInput v-model="form.primaBruta" class="w-full" />
|
|
</UFormField>
|
|
<UFormField label="Impuesto %">
|
|
<UInput v-model="form.impuestoPct" class="w-full" />
|
|
</UFormField>
|
|
<UFormField label="Prima neta">
|
|
<UInput v-model="form.primaNeta" class="w-full" />
|
|
</UFormField>
|
|
<UFormField label="Número de cuotas">
|
|
<UInput v-model.number="form.numCuotas" type="number" min="1" max="60" class="w-full" />
|
|
</UFormField>
|
|
</div>
|
|
</UCard>
|
|
|
|
<UCard class="max-w-5xl">
|
|
<template #header>
|
|
<div class="flex w-full items-center justify-between gap-4">
|
|
<span class="font-semibold text-[var(--text-primary)]">Plan de pagos</span>
|
|
<UButton size="xs" color="neutral" variant="soft" @click="refreshSchedule">Regenerar cuotas</UButton>
|
|
</div>
|
|
</template>
|
|
<div class="overflow-x-auto rounded-lg border border-[var(--card-border)] bg-[var(--surface)]">
|
|
<table class="min-w-full text-sm">
|
|
<thead>
|
|
<tr class="border-b border-[var(--card-border)] bg-[var(--surface)] text-left text-[var(--text-muted)]">
|
|
<th class="px-3 py-2 font-medium">#</th>
|
|
<th class="px-3 py-2 font-medium">Fecha vencimiento</th>
|
|
<th class="px-3 py-2 font-medium">Prima</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
<tr
|
|
v-for="row in form.cuotas"
|
|
:key="row.n"
|
|
class="border-b border-[var(--divider)] last:border-0"
|
|
>
|
|
<td class="px-3 py-2 text-[var(--text-muted)]">{{ row.n }}</td>
|
|
<td class="px-3 py-2">
|
|
<UInput v-model="row.fechaVencimiento" type="datetime-local" size="sm" />
|
|
</td>
|
|
<td class="px-3 py-2">
|
|
<UInput v-model="row.prima" size="sm" />
|
|
</td>
|
|
</tr>
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
</UCard>
|
|
|
|
<UCard class="max-w-5xl">
|
|
<template #header>
|
|
<span class="font-semibold text-[var(--text-primary)]">Referencias y notas</span>
|
|
</template>
|
|
<div class="space-y-4">
|
|
<UFormField label="Cotización Mint ID">
|
|
<UInput v-model="form.cotizacionMintId" class="w-full" />
|
|
</UFormField>
|
|
<div class="grid grid-cols-1 gap-4 sm:grid-cols-2">
|
|
<UFormField label="PDF cotización (nombre)">
|
|
<UInput v-model="form.pdfCotizacionNombre" class="w-full" />
|
|
</UFormField>
|
|
<UFormField label="PDF póliza (nombre)">
|
|
<UInput v-model="form.pdfPolizaNombre" class="w-full" />
|
|
</UFormField>
|
|
</div>
|
|
<UFormField label="Notas">
|
|
<UTextarea v-model="form.notas" :rows="4" class="w-full" />
|
|
</UFormField>
|
|
</div>
|
|
</UCard>
|
|
</div>
|
|
</template>
|