Update life quotes to use new policy API structure
- Update life quote types to use insured/buyer instead of client - Update life fields: add coverage_type, coverage_amount, coverage_years, smoker, medications, surgeries, weight, height - Remove deprecated fields: dateOfBirth, age, gender, preexistingConditions, preexistingDetails, beneficiaryName, beneficiaryRelationship - Update life quote SetupStep component to use customer selection - Add Insured and Buyer sections with customer search and selection - Add health questionnaire with smoker, medications, surgeries, weight, height fields - Add coverage_type field (banking | protection) - Update life quote page to use new composables and API structure - Update validation to use insured/buyer validation - Update submission to use policy API with new structure
This commit is contained in:
@@ -1,6 +1,8 @@
|
||||
<script setup lang="ts">
|
||||
import { emptyLifeQuoteDraft } from '~/composables/useLifeQuoteDraft'
|
||||
import type { LifeQuoteIntakePayload, LifeQuoteMode, LifeQuoteSegment } from '~/types/life-quote-intake'
|
||||
import { useCustomerSelection } from '~/composables/useCustomerSelection'
|
||||
import { usePolicyApi } from '~/composables/usePolicyApi'
|
||||
|
||||
definePageMeta({ ssr: false })
|
||||
|
||||
@@ -24,6 +26,18 @@ const draft = reactive(emptyLifeQuoteDraft())
|
||||
const toast = useToast()
|
||||
const { quoteRequestEmailEnabled } = useQuoteRequestEmailEnabled()
|
||||
|
||||
// Use customer selection composable
|
||||
const {
|
||||
insured,
|
||||
buyer,
|
||||
isInsuredValid,
|
||||
isBuyerValid,
|
||||
validationErrors
|
||||
} = useCustomerSelection()
|
||||
|
||||
// Use policy API composable
|
||||
const { submitPolicyQuote } = usePolicyApi()
|
||||
|
||||
const modeCards: { id: LifeQuoteMode; title: string; hint: string; icon: string }[] = [
|
||||
{
|
||||
id: 'single',
|
||||
@@ -60,19 +74,6 @@ const segmentCards: { id: LifeQuoteSegment; title: string; hint: string; icon: s
|
||||
}
|
||||
]
|
||||
|
||||
function canProceedFromCustomer() {
|
||||
const c = draft.client
|
||||
if (!c.fullName.trim() || !c.email.trim()) {
|
||||
toast.add({
|
||||
title: 'Add legal name and email',
|
||||
description: 'We need them for notifications and the quote file.',
|
||||
color: 'warning'
|
||||
})
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
function canProceedFromSetup() {
|
||||
if (!draft.quoteMode) {
|
||||
toast.add({ title: 'Choose quote type', description: 'Single or comparative.', color: 'warning' })
|
||||
@@ -82,30 +83,26 @@ function canProceedFromSetup() {
|
||||
toast.add({ title: 'Choose policy type', description: 'Individual, corporate / key person, or group.', color: 'warning' })
|
||||
return false
|
||||
}
|
||||
if (!canProceedFromCustomer()) return false
|
||||
if (
|
||||
(draft.segment === 'corporate_keyman' || draft.segment === 'group') &&
|
||||
!draft.client.organizationName?.trim()
|
||||
) {
|
||||
if (!isInsuredValid.value) {
|
||||
toast.add({
|
||||
title: 'Add organization',
|
||||
description: 'Required for corporate and group policies.',
|
||||
title: 'Complete insured information',
|
||||
description: `Missing: ${validationErrors.value.insured.join(', ')}`,
|
||||
color: 'warning'
|
||||
})
|
||||
return false
|
||||
}
|
||||
if (!draft.life.dateOfBirth || !draft.life.gender) {
|
||||
if (!isBuyerValid.value) {
|
||||
toast.add({
|
||||
title: 'Complete age & health screening',
|
||||
description: 'Date of birth and gender are required for life underwriting.',
|
||||
title: 'Complete buyer information',
|
||||
description: `Missing: ${validationErrors.value.buyer.join(', ')}`,
|
||||
color: 'warning'
|
||||
})
|
||||
return false
|
||||
}
|
||||
if (!draft.life.coverageAmount || !draft.life.coverageTerm) {
|
||||
if (!draft.life.coverage_type || !draft.life.coverage_amount || !draft.life.coverage_years) {
|
||||
toast.add({
|
||||
title: 'Complete coverage intent',
|
||||
description: 'Select coverage amount and term.',
|
||||
title: 'Complete coverage details',
|
||||
description: 'Coverage type, amount, and years are required.',
|
||||
color: 'warning'
|
||||
})
|
||||
return false
|
||||
@@ -170,17 +167,23 @@ function goNext() {
|
||||
|
||||
function buildPayload(): LifeQuoteIntakePayload {
|
||||
return {
|
||||
quoteMode: draft.quoteMode!,
|
||||
segment: draft.segment!,
|
||||
client: { ...draft.client },
|
||||
life: { ...draft.life },
|
||||
solicit: {
|
||||
carrierIds: [...draft.solicit.carrierIds],
|
||||
planIds: [...draft.solicit.planIds]
|
||||
}
|
||||
policy_type: 'life',
|
||||
insured: insured.value,
|
||||
buyer: buyer.value,
|
||||
policy_details: { ...draft.life },
|
||||
selected_providers: draft.solicit.carrierIds.map(id => ({
|
||||
provider_id: id,
|
||||
email: getProviderEmail(id)
|
||||
}))
|
||||
}
|
||||
}
|
||||
|
||||
function getProviderEmail(providerId: string): string {
|
||||
// This would come from the providers API
|
||||
// For now, return a placeholder
|
||||
return `quotes@${providerId}.com`
|
||||
}
|
||||
|
||||
async function finalize() {
|
||||
if (!draft.quoteMode || !draft.segment) return
|
||||
if (intakeBusy.value) return
|
||||
@@ -204,6 +207,10 @@ async function finalize() {
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
// Submit to policy API
|
||||
const data = await submitPolicyQuote(payload)
|
||||
|
||||
toast.add({
|
||||
title: emailOn ? 'Quote requests recorded' : 'Quote run saved (no emails)',
|
||||
description: emailOn
|
||||
@@ -211,6 +218,9 @@ async function finalize() {
|
||||
: 'Outbound provider email is off in Settings — this request stays in-app for tables, APIs, or AI.',
|
||||
color: 'success'
|
||||
})
|
||||
|
||||
// Navigate to policy detail page
|
||||
await navigateTo(`/policies/${data.application_id}`)
|
||||
} finally {
|
||||
intakeBusy.value = false
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user