701 lines
27 KiB
Vue
701 lines
27 KiB
Vue
<script setup lang="ts">
|
|
import { z } from 'zod'
|
|
|
|
usePageTitle('New Quote')
|
|
|
|
const route = useRoute()
|
|
const router = useRouter()
|
|
|
|
const activeTab = computed(() => route.query.tab || 'car')
|
|
|
|
const tabs = [
|
|
{ id: 'car', label: 'Auto', icon: 'i-heroicons-truck', description: 'Motor, fleet & bind' },
|
|
{ id: 'life', label: 'Life', icon: 'i-heroicons-shield-check', description: 'Individual & corporate' },
|
|
{ id: 'fire_structure', label: 'Fire Structure', icon: 'i-heroicons-building-office-2', description: 'Building coverage' },
|
|
{ id: 'fire_contents', label: 'Fire Contents', icon: 'i-heroicons-building-office-2', description: 'Contents coverage' }
|
|
]
|
|
|
|
function setTab(tabId: string) {
|
|
router.push({ query: { tab: tabId } })
|
|
}
|
|
|
|
const autoForm = reactive({
|
|
customerSelection: {
|
|
selectedCustomer: null as any,
|
|
useSameForBuyer: true,
|
|
selectedBuyer: null as any
|
|
},
|
|
customerSearch: '',
|
|
vehicle: {
|
|
plate: '',
|
|
make: '',
|
|
model: '',
|
|
year: new Date().getFullYear(),
|
|
use_type: 'private',
|
|
car_type: 'sedan',
|
|
rc_limits: {
|
|
bodily_injury: 0,
|
|
property_damage: 0
|
|
},
|
|
market_value: 0,
|
|
requested_value: 0,
|
|
chassis_number: '',
|
|
engine_number: ''
|
|
},
|
|
providerSearch: '',
|
|
selectedProviders: [] as string[]
|
|
})
|
|
|
|
const lifeForm = reactive({
|
|
customerSelection: {
|
|
selectedCustomer: null as any,
|
|
useSameForBuyer: true,
|
|
selectedBuyer: null as any
|
|
},
|
|
customerSearch: '',
|
|
life: {
|
|
coverage_type: 'banking',
|
|
coverage_amount: 0,
|
|
coverage_years: 10,
|
|
smoker: false,
|
|
medications: [] as string[],
|
|
surgeries: [] as string[],
|
|
weight: 0,
|
|
height: 0
|
|
},
|
|
providerSearch: '',
|
|
selectedProviders: [] as string[]
|
|
})
|
|
|
|
const fireStructureForm = reactive({
|
|
customerSelection: {
|
|
selectedCustomer: null as any,
|
|
useSameForBuyer: true,
|
|
selectedBuyer: null as any
|
|
},
|
|
customerSearch: '',
|
|
property: {
|
|
location: '',
|
|
property_value: 0,
|
|
property_use: '',
|
|
security_measures: [] as string[],
|
|
market_value: 0
|
|
},
|
|
providerSearch: '',
|
|
selectedProviders: [] as string[]
|
|
})
|
|
|
|
const fireContentsForm = reactive({
|
|
customerSelection: {
|
|
selectedCustomer: null as any,
|
|
useSameForBuyer: true,
|
|
selectedBuyer: null as any
|
|
},
|
|
customerSearch: '',
|
|
contents: {
|
|
location: '',
|
|
contents_value: 0,
|
|
property_use: '',
|
|
security_measures: [] as string[],
|
|
high_value_items: [] as Array<{ description: string; value: number; type: string }>
|
|
},
|
|
providerSearch: '',
|
|
selectedProviders: [] as string[]
|
|
})
|
|
|
|
function getForm(tabId: string) {
|
|
switch (tabId) {
|
|
case 'car': return autoForm
|
|
case 'life': return lifeForm
|
|
case 'fire_structure': return fireStructureForm
|
|
case 'fire_contents': return fireContentsForm
|
|
default: return autoForm
|
|
}
|
|
}
|
|
|
|
const autoSchema = z.object({
|
|
vehicle: z.object({
|
|
plate: z.string().min(1, 'License plate is required'),
|
|
make: z.string().min(1, 'Make is required'),
|
|
model: z.string().min(1, 'Model is required'),
|
|
year: z.number().min(1900).max(new Date().getFullYear() + 1),
|
|
use_type: z.enum(['private', 'commercial', 'bus', 'taxi', 'school']),
|
|
car_type: z.enum(['sedan', 'suv', 'hatchback', 'coupe', 'convertible', 'pickup', 'van', 'minivan', 'truck']),
|
|
rc_limits: z.object({
|
|
bodily_injury: z.number().min(0),
|
|
property_damage: z.number().min(0)
|
|
}),
|
|
market_value: z.number().min(0),
|
|
requested_value: z.number().min(0),
|
|
chassis_number: z.string().optional(),
|
|
engine_number: z.string().optional()
|
|
})
|
|
})
|
|
|
|
const lifeSchema = z.object({
|
|
life: z.object({
|
|
coverage_type: z.enum(['banking', 'protection']),
|
|
coverage_amount: z.number().min(0),
|
|
coverage_years: z.number().min(1).max(100),
|
|
smoker: z.boolean(),
|
|
medications: z.array(z.string()).optional(),
|
|
surgeries: z.array(z.string()).optional(),
|
|
weight: z.number().min(0),
|
|
height: z.number().min(0)
|
|
})
|
|
})
|
|
|
|
const fireStructureSchema = z.object({
|
|
property: z.object({
|
|
location: z.string().min(1, 'Location is required'),
|
|
property_value: z.number().min(0),
|
|
property_use: z.string().min(1, 'Property use is required'),
|
|
security_measures: z.array(z.string()).optional(),
|
|
market_value: z.number().min(0)
|
|
})
|
|
})
|
|
|
|
const fireContentsSchema = z.object({
|
|
contents: z.object({
|
|
location: z.string().min(1, 'Location is required'),
|
|
contents_value: z.number().min(0),
|
|
property_use: z.string().min(1, 'Property use is required'),
|
|
security_measures: z.array(z.string()).optional(),
|
|
high_value_items: z.array(z.object({
|
|
description: z.string(),
|
|
value: z.number(),
|
|
type: z.string()
|
|
})).optional()
|
|
})
|
|
})
|
|
|
|
function getSchema(tabId: string) {
|
|
switch (tabId) {
|
|
case 'car': return autoSchema
|
|
case 'life': return lifeSchema
|
|
case 'fire_structure': return fireStructureSchema
|
|
case 'fire_contents': return fireContentsSchema
|
|
default: return autoSchema
|
|
}
|
|
}
|
|
|
|
const autoFormRef = ref()
|
|
const lifeFormRef = ref()
|
|
const fireStructureFormRef = ref()
|
|
const fireContentsFormRef = ref()
|
|
const isSubmitting = ref(false)
|
|
const submitError = ref('')
|
|
|
|
function getFormRef(tabId: string) {
|
|
switch (tabId) {
|
|
case 'car': return autoFormRef
|
|
case 'life': return lifeFormRef
|
|
case 'fire_structure': return fireStructureFormRef
|
|
case 'fire_contents': return fireContentsFormRef
|
|
default: return autoFormRef
|
|
}
|
|
}
|
|
|
|
async function submitQuote() {
|
|
submitError.value = ''
|
|
const formRef = getFormRef(activeTab.value)
|
|
|
|
if (formRef.value) {
|
|
try {
|
|
await formRef.value.validate()
|
|
} catch (error) {
|
|
submitError.value = 'Please fix the validation errors before submitting'
|
|
return
|
|
}
|
|
}
|
|
|
|
const form = getForm(activeTab.value)
|
|
|
|
if (!form.customerSelection.selectedCustomer) {
|
|
submitError.value = 'Please select a customer'
|
|
return
|
|
}
|
|
|
|
if (form.selectedProviders.length === 0) {
|
|
submitError.value = 'Please select at least one provider'
|
|
return
|
|
}
|
|
|
|
isSubmitting.value = true
|
|
|
|
try {
|
|
const payload = {
|
|
policy_type: activeTab.value,
|
|
insured: {
|
|
type: form.customerSelection.selectedCustomer.customer_type,
|
|
...(form.customerSelection.selectedCustomer.customer_type === 'individual' ? {
|
|
name: `${form.customerSelection.selectedCustomer.first_name} ${form.customerSelection.selectedCustomer.last_name}`,
|
|
date_of_birth: form.customerSelection.selectedCustomer.birth_date,
|
|
document_id: form.customerSelection.selectedCustomer.document_id,
|
|
gender: form.customerSelection.selectedCustomer.gender,
|
|
address: form.customerSelection.selectedCustomer.address,
|
|
phone: form.customerSelection.selectedCustomer.phone,
|
|
email: form.customerSelection.selectedCustomer.email
|
|
} : {
|
|
company_name: form.customerSelection.selectedCustomer.legal_name,
|
|
ruc: form.customerSelection.selectedCustomer.ruc,
|
|
legal_rep_name: form.customerSelection.selectedCustomer.legal_rep_name,
|
|
legal_rep_document: form.customerSelection.selectedCustomer.legal_rep_document_id
|
|
})
|
|
},
|
|
buyer: form.customerSelection.useSameForBuyer ? {
|
|
type: form.customerSelection.selectedCustomer.customer_type,
|
|
...(form.customerSelection.selectedCustomer.customer_type === 'individual' ? {
|
|
name: `${form.customerSelection.selectedCustomer.first_name} ${form.customerSelection.selectedCustomer.last_name}`,
|
|
date_of_birth: form.customerSelection.selectedCustomer.birth_date,
|
|
document_id: form.customerSelection.selectedCustomer.document_id,
|
|
gender: form.customerSelection.selectedCustomer.gender,
|
|
address: form.customerSelection.selectedCustomer.address,
|
|
phone: form.customerSelection.selectedCustomer.phone,
|
|
email: form.customerSelection.selectedCustomer.email
|
|
} : {
|
|
company_name: form.customerSelection.selectedCustomer.legal_name,
|
|
ruc: form.customerSelection.selectedCustomer.ruc,
|
|
legal_rep_name: form.customerSelection.selectedCustomer.legal_rep_name,
|
|
legal_rep_document: form.customerSelection.selectedCustomer.legal_rep_document_id
|
|
})
|
|
} : {
|
|
type: form.customerSelection.selectedBuyer.customer_type,
|
|
...(form.customerSelection.selectedBuyer.customer_type === 'individual' ? {
|
|
name: `${form.customerSelection.selectedBuyer.first_name} ${form.customerSelection.selectedBuyer.last_name}`,
|
|
date_of_birth: form.customerSelection.selectedBuyer.birth_date,
|
|
document_id: form.customerSelection.selectedCustomer.document_id,
|
|
gender: form.customerSelection.selectedCustomer.gender,
|
|
address: form.customerSelection.selectedCustomer.address,
|
|
phone: form.customerSelection.selectedCustomer.phone,
|
|
email: form.customerSelection.selectedCustomer.email
|
|
} : {
|
|
company_name: form.customerSelection.selectedBuyer.legal_name,
|
|
ruc: form.customerSelection.selectedBuyer.ruc,
|
|
legal_rep_name: form.customerSelection.selectedBuyer.legal_rep_name,
|
|
legal_rep_document: form.customerSelection.selectedBuyer.legal_rep_document_id
|
|
})
|
|
},
|
|
policy_details: getPolicyDetails(form),
|
|
selected_providers: form.selectedProviders.map(id => ({
|
|
provider_id: id,
|
|
email: ''
|
|
}))
|
|
}
|
|
|
|
const { data, error } = await usePolicy('/policies', {
|
|
method: 'POST',
|
|
body: payload
|
|
})
|
|
|
|
if (error.value) {
|
|
submitError.value = `Failed to create quote: ${error.value.message || 'Unknown error'}`
|
|
return
|
|
}
|
|
|
|
if (data.value) {
|
|
router.push(`/policies/${data.value.application_id}`)
|
|
}
|
|
} catch (error) {
|
|
submitError.value = `Failed to create quote: ${error instanceof Error ? error.message : 'Unknown error'}`
|
|
} finally {
|
|
isSubmitting.value = false
|
|
}
|
|
}
|
|
|
|
function getPolicyDetails(form: any) {
|
|
switch (activeTab.value) {
|
|
case 'car':
|
|
return {
|
|
plate: form.vehicle.plate,
|
|
make: form.vehicle.make,
|
|
model: form.vehicle.model,
|
|
year: form.vehicle.year,
|
|
use_type: form.vehicle.use_type,
|
|
car_type: form.vehicle.car_type,
|
|
chassis_number: form.vehicle.chassis_number,
|
|
engine_number: form.vehicle.engine_number,
|
|
rc_limits: form.vehicle.rc_limits,
|
|
market_value: form.vehicle.market_value,
|
|
requested_value: form.vehicle.requested_value
|
|
}
|
|
case 'life':
|
|
return {
|
|
coverage_type: form.life.coverage_type,
|
|
coverage_amount: form.life.coverage_amount,
|
|
coverage_years: form.life.coverage_years,
|
|
smoker: form.life.smoker,
|
|
medications: form.life.medications,
|
|
surgeries: form.life.surgeries,
|
|
weight: form.life.weight,
|
|
height: form.life.height
|
|
}
|
|
case 'fire_structure':
|
|
return {
|
|
location: form.property.location,
|
|
property_value: form.property.property_value,
|
|
property_use: form.property.property_use,
|
|
security_measures: form.property.security_measures,
|
|
market_value: form.property.market_value
|
|
}
|
|
case 'fire_contents':
|
|
return {
|
|
location: form.contents.location,
|
|
contents_value: form.contents.contents_value,
|
|
property_use: form.contents.property_use,
|
|
security_measures: form.contents.security_measures,
|
|
high_value_items: form.contents.high_value_items
|
|
}
|
|
default:
|
|
return {}
|
|
}
|
|
}
|
|
</script>
|
|
|
|
<template>
|
|
<div class="max-w-4xl mx-auto">
|
|
<div class="mb-8">
|
|
<div class="flex items-center gap-3 mb-2">
|
|
<div class="w-10 h-10 rounded-lg bg-[var(--brand)] flex items-center justify-center">
|
|
<UIcon :name="tabs.find(t => t.id === activeTab)?.icon" class="w-5 h-5 text-white" />
|
|
</div>
|
|
<div>
|
|
<h1 class="text-2xl font-semibold text-[var(--text-primary)]">New {{ tabs.find(t => t.id === activeTab)?.label || 'Insurance' }} Quote</h1>
|
|
<p class="text-[var(--text-muted)]">{{ tabs.find(t => t.id === activeTab)?.description || 'Create a new insurance quote' }}</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<UForm
|
|
v-if="activeTab === 'car'"
|
|
ref="autoFormRef"
|
|
:schema="autoSchema"
|
|
:state="autoForm"
|
|
@submit="submitQuote"
|
|
>
|
|
<UAccordion :items="[
|
|
{
|
|
label: 'Customer Selection',
|
|
icon: 'i-heroicons-user',
|
|
content: '',
|
|
value: 'customer',
|
|
defaultOpen: true
|
|
},
|
|
{
|
|
label: 'Vehicle Information',
|
|
icon: 'i-heroicons-truck',
|
|
content: '',
|
|
value: 'vehicle',
|
|
defaultOpen: true
|
|
},
|
|
{
|
|
label: 'Provider Selection',
|
|
icon: 'i-heroicons-building-office',
|
|
content: '',
|
|
value: 'provider',
|
|
defaultOpen: true
|
|
}
|
|
]">
|
|
<template #body="{ item }">
|
|
<div v-if="item.value === 'customer'" class="p-5">
|
|
<CustomerSelector
|
|
v-model="autoForm.customerSelection"
|
|
v-model:search="autoForm.customerSearch"
|
|
/>
|
|
</div>
|
|
<div v-if="item.value === 'vehicle'" class="p-5">
|
|
<div class="grid grid-cols-2 gap-4">
|
|
<UFormField name="vehicle.plate" label="License Plate" description="Vehicle license plate number" required>
|
|
<UInput v-model="autoForm.vehicle.plate" placeholder="ABC-123" size="lg" />
|
|
</UFormField>
|
|
<UFormField name="vehicle.make" label="Make" description="Vehicle manufacturer" required>
|
|
<UInput v-model="autoForm.vehicle.make" placeholder="Toyota" size="lg" />
|
|
</UFormField>
|
|
<UFormField name="vehicle.model" label="Model" description="Vehicle model name" required>
|
|
<UInput v-model="autoForm.vehicle.model" placeholder="Corolla" size="lg" />
|
|
</UFormField>
|
|
<UFormField name="vehicle.year" label="Year" description="Vehicle manufacturing year" required>
|
|
<UInput v-model="autoForm.vehicle.year" type="number" size="lg" />
|
|
</UFormField>
|
|
<UFormField name="vehicle.use_type" label="Use Type" description="Primary use of the vehicle" required>
|
|
<USelectMenu v-model="autoForm.vehicle.use_type" :items="[
|
|
{ label: 'Private', value: 'private' },
|
|
{ label: 'Commercial', value: 'commercial' },
|
|
{ label: 'Bus', value: 'bus' },
|
|
{ label: 'Taxi', value: 'taxi' },
|
|
{ label: 'School', value: 'school' }
|
|
]" size="lg" />
|
|
</UFormField>
|
|
<UFormField name="vehicle.car_type" label="Car Type" description="Vehicle body type" required>
|
|
<USelectMenu v-model="autoForm.vehicle.car_type" :items="[
|
|
{ label: 'Sedan', value: 'sedan' },
|
|
{ label: 'SUV', value: 'suv' },
|
|
{ label: 'Hatchback', value: 'hatchback' },
|
|
{ label: 'Coupe', value: 'coupe' },
|
|
{ label: 'Convertible', value: 'convertible' },
|
|
{ label: 'Pickup', value: 'pickup' },
|
|
{ label: 'Van', value: 'van' },
|
|
{ label: 'Minivan', value: 'minivan' },
|
|
{ label: 'Truck', value: 'truck' }
|
|
]" size="lg" />
|
|
</UFormField>
|
|
<UFormField name="vehicle.rc_limits.bodily_injury" label="Bodily Injury Limits" description="Third-party bodily injury coverage">
|
|
<UInput v-model="autoForm.vehicle.rc_limits.bodily_injury" type="number" placeholder="0" size="lg" />
|
|
</UFormField>
|
|
<UFormField name="vehicle.rc_limits.property_damage" label="Property Damage Limits" description="Third-party property damage coverage">
|
|
<UInput v-model="autoForm.vehicle.rc_limits.property_damage" type="number" placeholder="0" size="lg" />
|
|
</UFormField>
|
|
<UFormField name="vehicle.market_value" label="Market Value" description="Current market value of the vehicle">
|
|
<UInput v-model="autoForm.vehicle.market_value" type="number" placeholder="0" size="lg" />
|
|
</UFormField>
|
|
<UFormField name="vehicle.requested_value" label="Requested Value" description="Insured value for the vehicle">
|
|
<UInput v-model="autoForm.vehicle.requested_value" type="number" placeholder="0" size="lg" />
|
|
</UFormField>
|
|
<UFormField name="vehicle.chassis_number" label="Chassis Number" description="Vehicle chassis number (optional)">
|
|
<UInput v-model="autoForm.vehicle.chassis_number" placeholder="Optional" size="lg" />
|
|
</UFormField>
|
|
<UFormField name="vehicle.engine_number" label="Engine Number" description="Vehicle engine number (optional)">
|
|
<UInput v-model="autoForm.vehicle.engine_number" placeholder="Optional" size="lg" />
|
|
</UFormField>
|
|
</div>
|
|
</div>
|
|
<div v-if="item.value === 'provider'" class="p-5">
|
|
<ProviderSelector
|
|
v-model:search="autoForm.providerSearch"
|
|
v-model:selected="autoForm.selectedProviders"
|
|
/>
|
|
</div>
|
|
</template>
|
|
</UAccordion>
|
|
</UForm>
|
|
|
|
<UForm
|
|
v-if="activeTab === 'life'"
|
|
ref="lifeFormRef"
|
|
:schema="lifeSchema"
|
|
:state="lifeForm"
|
|
@submit="submitQuote"
|
|
>
|
|
<UAccordion :items="[
|
|
{
|
|
label: 'Customer Selection',
|
|
icon: 'i-heroicons-user',
|
|
content: '',
|
|
value: 'customer',
|
|
defaultOpen: true
|
|
},
|
|
{
|
|
label: 'Life Insurance Details',
|
|
icon: 'i-heroicons-shield-check',
|
|
content: '',
|
|
value: 'life',
|
|
defaultOpen: true
|
|
},
|
|
{
|
|
label: 'Provider Selection',
|
|
icon: 'i-heroicons-building-office',
|
|
content: '',
|
|
value: 'provider',
|
|
defaultOpen: true
|
|
}
|
|
]">
|
|
<template #body="{ item }">
|
|
<div v-if="item.value === 'customer'" class="p-5">
|
|
<CustomerSelector
|
|
v-model="lifeForm.customerSelection"
|
|
v-model:search="lifeForm.customerSearch"
|
|
/>
|
|
</div>
|
|
<div v-if="item.value === 'life'" class="p-5">
|
|
<div class="grid grid-cols-2 gap-4">
|
|
<UFormField name="life.coverage_type" label="Coverage Type" description="Type of life insurance coverage" required>
|
|
<USelectMenu v-model="lifeForm.life.coverage_type" :items="[
|
|
{ label: 'Banking', value: 'banking' },
|
|
{ label: 'Protection', value: 'protection' }
|
|
]" size="lg" />
|
|
</UFormField>
|
|
<UFormField name="life.coverage_amount" label="Coverage Amount" description="Amount of coverage in local currency">
|
|
<UInput v-model="lifeForm.life.coverage_amount" type="number" placeholder="0" size="lg" />
|
|
</UFormField>
|
|
<UFormField name="life.coverage_years" label="Coverage Years" description="Duration of the policy in years" required>
|
|
<UInput v-model="lifeForm.life.coverage_years" type="number" placeholder="10" size="lg" />
|
|
</UFormField>
|
|
<UFormField name="life.smoker" label="Smoker" description="Does the insured smoke tobacco?">
|
|
<UCheckbox v-model="lifeForm.life.smoker" label="Yes" />
|
|
</UFormField>
|
|
<UFormField name="life.medications" label="Medications" description="List any current medications (one per line)" class="col-span-2">
|
|
<ArrayInput
|
|
v-model="lifeForm.life.medications"
|
|
placeholder="Aspirin Lisinopril Metformin"
|
|
/>
|
|
</UFormField>
|
|
<UFormField name="life.surgeries" label="Surgeries" description="List any past surgeries (one per line)" class="col-span-2">
|
|
<ArrayInput
|
|
v-model="lifeForm.life.surgeries"
|
|
placeholder="Appendectomy, 2015 Cataract surgery, 2020"
|
|
/>
|
|
</UFormField>
|
|
<UFormField name="life.weight" label="Weight (kg)" description="Weight in kilograms">
|
|
<UInput v-model="lifeForm.life.weight" type="number" placeholder="70" size="lg" />
|
|
</UFormField>
|
|
<UFormField name="life.height" label="Height (cm)" description="Height in centimeters">
|
|
<UInput v-model="lifeForm.life.height" type="number" placeholder="175" size="lg" />
|
|
</UFormField>
|
|
</div>
|
|
</div>
|
|
<div v-if="item.value === 'provider'" class="p-5">
|
|
<ProviderSelector
|
|
v-model:search="lifeForm.providerSearch"
|
|
v-model:selected="lifeForm.selectedProviders"
|
|
/>
|
|
</div>
|
|
</template>
|
|
</UAccordion>
|
|
</UForm>
|
|
|
|
<UForm
|
|
v-if="activeTab === 'fire_structure'"
|
|
ref="fireStructureFormRef"
|
|
:schema="fireStructureSchema"
|
|
:state="fireStructureForm"
|
|
@submit="submitQuote"
|
|
>
|
|
<UAccordion :items="[
|
|
{
|
|
label: 'Customer Selection',
|
|
icon: 'i-heroicons-user',
|
|
content: '',
|
|
value: 'customer',
|
|
defaultOpen: true
|
|
},
|
|
{
|
|
label: 'Property Information',
|
|
icon: 'i-heroicons-building-office-2',
|
|
content: '',
|
|
value: 'property',
|
|
defaultOpen: true
|
|
},
|
|
{
|
|
label: 'Provider Selection',
|
|
icon: 'i-heroicons-building-office',
|
|
content: '',
|
|
value: 'provider',
|
|
defaultOpen: true
|
|
}
|
|
]">
|
|
<template #body="{ item }">
|
|
<div v-if="item.value === 'customer'" class="p-5">
|
|
<CustomerSelector
|
|
v-model="fireStructureForm.customerSelection"
|
|
v-model:search="fireStructureForm.customerSearch"
|
|
/>
|
|
</div>
|
|
<div v-if="item.value === 'property'" class="p-5">
|
|
<div class="grid grid-cols-2 gap-4">
|
|
<UFormField name="property.location" label="Location" description="Full property address" required>
|
|
<UInput v-model="fireStructureForm.property.location" placeholder="Full address" size="lg" />
|
|
</UFormField>
|
|
<UFormField name="property.property_value" label="Property Value" description="Current property value">
|
|
<UInput v-model="fireStructureForm.property.property_value" type="number" placeholder="0" size="lg" />
|
|
</UFormField>
|
|
<UFormField name="property.property_use" label="Property Use" description="How the property is used" required>
|
|
<UInput v-model="fireStructureForm.property.property_use" placeholder="e.g., residential, commercial" size="lg" />
|
|
</UFormField>
|
|
<UFormField name="property.market_value" label="Market Value" description="Current market value of the property">
|
|
<UInput v-model="fireStructureForm.property.market_value" type="number" placeholder="0" size="lg" />
|
|
</UFormField>
|
|
<UFormField name="property.security_measures" label="Security Measures" description="Security measures installed (one per line)" class="col-span-2">
|
|
<ArrayInput
|
|
v-model="fireStructureForm.property.security_measures"
|
|
placeholder="security_system sprinklers fire_extinguisher alarm_system"
|
|
/>
|
|
</UFormField>
|
|
</div>
|
|
</div>
|
|
<div v-if="item.value === 'provider'" class="p-5">
|
|
<ProviderSelector
|
|
v-model:search="fireStructureForm.providerSearch"
|
|
v-model:selected="fireStructureForm.selectedProviders"
|
|
/>
|
|
</div>
|
|
</template>
|
|
</UAccordion>
|
|
</UForm>
|
|
|
|
<UForm
|
|
v-if="activeTab === 'fire_contents'"
|
|
ref="fireContentsFormRef"
|
|
:schema="fireContentsSchema"
|
|
:state="fireContentsForm"
|
|
@submit="submitQuote"
|
|
>
|
|
<UAccordion :items="[
|
|
{
|
|
label: 'Customer Selection',
|
|
icon: 'i-heroicons-user',
|
|
content: '',
|
|
value: 'customer',
|
|
defaultOpen: true
|
|
},
|
|
{
|
|
label: 'Contents Information',
|
|
icon: 'i-heroicons-building-office-2',
|
|
content: '',
|
|
value: 'contents',
|
|
defaultOpen: true
|
|
},
|
|
{
|
|
label: 'Provider Selection',
|
|
icon: 'i-heroicons-building-office',
|
|
content: '',
|
|
value: 'provider',
|
|
defaultOpen: true
|
|
}
|
|
]">
|
|
<template #body="{ item }">
|
|
<div v-if="item.value === 'customer'" class="p-5">
|
|
<CustomerSelector
|
|
v-model="fireContentsForm.customerSelection"
|
|
v-model:search="fireContentsForm.customerSearch"
|
|
/>
|
|
</div>
|
|
<div v-if="item.value === 'contents'" class="p-5">
|
|
<div class="grid grid-cols-2 gap-4">
|
|
<UFormField name="contents.location" label="Location" description="Property address for contents coverage" required>
|
|
<UInput v-model="fireContentsForm.contents.location" placeholder="Full address" size="lg" />
|
|
</UFormField>
|
|
<UFormField name="contents.contents_value" label="Contents Value" description="Total value of all contents">
|
|
<UInput v-model="fireContentsForm.contents.contents_value" type="number" placeholder="0" size="lg" />
|
|
</UFormField>
|
|
<UFormField name="contents.property_use" label="Property Use" description="How the property is used" required>
|
|
<UInput v-model="fireContentsForm.contents.property_use" placeholder="e.g., residential, commercial" size="lg" />
|
|
</UFormField>
|
|
<UFormField name="contents.security_measures" label="Security Measures" description="Security measures installed (one per line)" class="col-span-2">
|
|
<ArrayInput
|
|
v-model="fireContentsForm.contents.security_measures"
|
|
placeholder="security_system sprinklers fire_extinguisher alarm_system"
|
|
/>
|
|
</UFormField>
|
|
</div>
|
|
</div>
|
|
<div v-if="item.value === 'provider'" class="p-5">
|
|
<ProviderSelector
|
|
v-model:search="fireContentsForm.providerSearch"
|
|
v-model:selected="fireContentsForm.selectedProviders"
|
|
/>
|
|
</div>
|
|
</template>
|
|
</UAccordion>
|
|
</UForm>
|
|
|
|
<div v-if="submitError" class="mb-4 p-4 bg-red-50 border border-red-200 rounded-lg">
|
|
<p class="text-red-600 text-sm">{{ submitError }}</p>
|
|
</div>
|
|
|
|
<div class="flex justify-end gap-3 mt-8 pt-6 border-t border-[var(--card-border)]">
|
|
<UButton color="neutral" variant="outline" size="lg" @click="router.back()" :disabled="isSubmitting">Cancel</UButton>
|
|
<UButton color="primary" size="lg" @click="submitQuote" :loading="isSubmitting" :disabled="isSubmitting">Create Quote</UButton>
|
|
</div>
|
|
</div>
|
|
</template>
|