170 lines
6.3 KiB
Vue
170 lines
6.3 KiB
Vue
<script setup lang="ts">
|
|
definePageMeta({ ssr: false })
|
|
usePageTitle('Quotes · Custom')
|
|
|
|
const toast = useToast()
|
|
|
|
const form = reactive({
|
|
clientName: '',
|
|
clientEmail: '',
|
|
clientPhone: '',
|
|
lineOfBusiness: '',
|
|
policyType: '',
|
|
carrier: '',
|
|
startDate: '',
|
|
endDate: '',
|
|
sumInsured: null as number | null,
|
|
premium: null as number | null,
|
|
commissionPct: null as number | null,
|
|
deductible: null as number | null,
|
|
notes: ''
|
|
})
|
|
|
|
const commissionAmount = computed(() => {
|
|
if (form.premium && form.commissionPct) return ((form.premium * form.commissionPct) / 100).toFixed(2)
|
|
return '0.00'
|
|
})
|
|
|
|
const linesOfBusiness = ['Auto', 'Health', 'Life', 'Property', 'Liability', 'Marine', 'Surety', 'Other']
|
|
|
|
const inputCls = 'w-full rounded-xl border border-[var(--sidebar-border)] bg-[var(--surface)] px-3 py-2 text-sm text-[var(--text-primary)] placeholder:text-[var(--text-muted)]'
|
|
const labelCls = 'block text-sm font-semibold text-[var(--text-muted)] mb-1.5'
|
|
|
|
async function save() {
|
|
if (!form.clientName.trim() || !form.lineOfBusiness) {
|
|
toast.add({ title: 'Missing fields', description: 'Client name and line of business are required.', color: 'warning' })
|
|
return
|
|
}
|
|
toast.add({ title: 'Quote saved', description: 'Your custom quote has been recorded.', color: 'success' })
|
|
await navigateTo('/quotes')
|
|
}
|
|
</script>
|
|
|
|
<template>
|
|
<div class="mx-auto max-w-4xl space-y-6 pb-12">
|
|
<NuxtLink to="/quotes" class="inline-flex">
|
|
<UButton color="neutral" variant="ghost" size="sm" icon="i-heroicons-arrow-left">Back to quotes</UButton>
|
|
</NuxtLink>
|
|
|
|
<div>
|
|
<h1 class="mt-1 text-2xl font-semibold tracking-tight text-[var(--text-primary)]">Custom quote entry</h1>
|
|
<p class="mt-1 text-[13px] text-[var(--text-muted)]">
|
|
Manually enter a quote for any line of business — quick single-page form.
|
|
</p>
|
|
</div>
|
|
|
|
<UCard :ui="{ body: { padding: 'p-5 sm:p-6' } }">
|
|
<template #header>
|
|
<div>
|
|
<p class="text-xs font-medium text-[var(--text-muted)]">Client</p>
|
|
<h2 class="mt-0.5 text-lg font-semibold text-[var(--text-primary)]">Client information</h2>
|
|
</div>
|
|
</template>
|
|
|
|
<div class="grid gap-4 sm:grid-cols-3">
|
|
<div>
|
|
<label :class="labelCls">Client name *</label>
|
|
<input v-model="form.clientName" :class="inputCls" placeholder="Full name" />
|
|
</div>
|
|
<div>
|
|
<label :class="labelCls">Email</label>
|
|
<input v-model="form.clientEmail" type="email" :class="inputCls" placeholder="client@example.com" />
|
|
</div>
|
|
<div>
|
|
<label :class="labelCls">Phone</label>
|
|
<input v-model="form.clientPhone" type="tel" :class="inputCls" placeholder="+1 (555) 000-0000" />
|
|
</div>
|
|
</div>
|
|
</UCard>
|
|
|
|
<UCard :ui="{ body: { padding: 'p-5 sm:p-6' } }">
|
|
<template #header>
|
|
<div>
|
|
<p class="text-xs font-medium text-[var(--text-muted)]">Policy</p>
|
|
<h2 class="mt-0.5 text-lg font-semibold text-[var(--text-primary)]">Policy details</h2>
|
|
</div>
|
|
</template>
|
|
|
|
<div class="space-y-4">
|
|
<div class="grid gap-4 sm:grid-cols-2">
|
|
<div>
|
|
<label :class="labelCls">Line of business *</label>
|
|
<select v-model="form.lineOfBusiness" :class="inputCls">
|
|
<option value="" disabled>Select line</option>
|
|
<option v-for="l in linesOfBusiness" :key="l" :value="l">{{ l }}</option>
|
|
</select>
|
|
</div>
|
|
<div>
|
|
<label :class="labelCls">Policy type / description</label>
|
|
<input v-model="form.policyType" :class="inputCls" placeholder="e.g. Comprehensive auto" />
|
|
</div>
|
|
</div>
|
|
|
|
<div class="grid gap-4 sm:grid-cols-3">
|
|
<div>
|
|
<label :class="labelCls">Carrier</label>
|
|
<input v-model="form.carrier" :class="inputCls" placeholder="Carrier name" />
|
|
</div>
|
|
<div>
|
|
<label :class="labelCls">Start date</label>
|
|
<input v-model="form.startDate" type="date" :class="inputCls" />
|
|
</div>
|
|
<div>
|
|
<label :class="labelCls">End date</label>
|
|
<input v-model="form.endDate" type="date" :class="inputCls" />
|
|
</div>
|
|
</div>
|
|
|
|
<div class="grid gap-4 sm:grid-cols-2">
|
|
<div>
|
|
<label :class="labelCls">Sum insured / limit</label>
|
|
<input v-model.number="form.sumInsured" type="number" :class="inputCls" placeholder="0.00" min="0" step="0.01" />
|
|
</div>
|
|
<div>
|
|
<label :class="labelCls">Deductible</label>
|
|
<input v-model.number="form.deductible" type="number" :class="inputCls" placeholder="0.00" min="0" step="0.01" />
|
|
</div>
|
|
</div>
|
|
|
|
<div class="grid gap-4 sm:grid-cols-3">
|
|
<div>
|
|
<label :class="labelCls">Premium</label>
|
|
<input v-model.number="form.premium" type="number" :class="inputCls" placeholder="0.00" min="0" step="0.01" />
|
|
</div>
|
|
<div>
|
|
<label :class="labelCls">Commission %</label>
|
|
<input v-model.number="form.commissionPct" type="number" :class="inputCls" placeholder="0" min="0" max="100" step="0.1" />
|
|
</div>
|
|
<div>
|
|
<label :class="labelCls">Commission amount</label>
|
|
<div :class="[inputCls, 'flex items-center bg-[var(--brand-soft)]/30 font-medium']">
|
|
{{ commissionAmount }}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</UCard>
|
|
|
|
<UCard :ui="{ body: { padding: 'p-5 sm:p-6' } }">
|
|
<template #header>
|
|
<div>
|
|
<p class="text-xs font-medium text-[var(--text-muted)]">Notes</p>
|
|
<h2 class="mt-0.5 text-lg font-semibold text-[var(--text-primary)]">Special conditions</h2>
|
|
</div>
|
|
</template>
|
|
|
|
<div>
|
|
<label :class="labelCls">Special conditions / notes</label>
|
|
<textarea v-model="form.notes" :class="inputCls" rows="4" placeholder="Any additional terms, conditions, or notes..." />
|
|
</div>
|
|
</UCard>
|
|
|
|
<div class="flex items-center justify-between">
|
|
<NuxtLink to="/quotes">
|
|
<UButton color="neutral" variant="ghost" size="sm">Cancel</UButton>
|
|
</NuxtLink>
|
|
<UButton color="primary" @click="save">Save quote</UButton>
|
|
</div>
|
|
</div>
|
|
</template>
|