Add nuxt-skills and update auto quotes to use new policy API structure

- Add nuxt-skills (vue, nuxt, nuxt-ui) to .claude/skills/
- Create useCustomerSelection() composable for managing insured/buyer selection
- Create usePolicyApi() composable for policy API operations
- Update auto quote components to use insured/buyer instead of client
- Update vehicle fields: remove valorVehiculo, add market_value, requested_value, rc_limits
- Make chassis_number and engine_number optional
- Update auto quote types and composables to match new API structure
- Update auto quote page to submit to policy API with new structure
This commit is contained in:
2026-04-27 14:56:53 -05:00
parent 67482f6629
commit a2eb1f3789
154 changed files with 10346 additions and 51 deletions

View File

@@ -4,13 +4,8 @@ export function emptyAutoQuoteDraft(): AutoQuoteDraft {
return {
quoteMode: null,
segment: null,
client: {
fullName: '',
email: '',
phone: '',
documentId: '',
organizationName: ''
},
insured: null,
buyer: null,
vehicle: {
subRamo: '',
clase: '',
@@ -20,7 +15,11 @@ export function emptyAutoQuoteDraft(): AutoQuoteDraft {
placa: '',
year: '',
capacidadPasajeros: '',
valorVehiculo: ''
rc_limits: '',
market_value: 0,
requested_value: 0,
chassis_number: '',
engine_number: ''
},
solicit: {
carrierIds: [],

View File

@@ -0,0 +1,137 @@
/**
* Composable for managing customer selection in quote flows
* Handles insured and buyer selection with validation
*/
export function useCustomerSelection() {
const selectedCustomer = ref<any>(null) // Auto-generated type from useCustomer
const useSameForBuyer = ref(true)
const selectedBuyer = ref<any>(null)
/**
* Convert customer-service customer to policy-service insured/buyer
* Maps customer fields to policy-service structure
*/
const toPolicyPerson = (customer: any) => {
if (customer.customer_type === 'corporate') {
return {
type: 'corporate',
company_name: customer.legal_name,
ruc: customer.ruc,
legal_rep_name: customer.legal_rep_name,
legal_rep_document: customer.legal_rep_document_id,
email: customer.email,
phone: customer.phone,
address: customer.address
}
}
return {
type: 'individual',
name: `${customer.first_name} ${customer.last_name}`.trim(),
date_of_birth: customer.birth_date,
document_id: customer.document_id,
email: customer.email,
phone: customer.phone,
address: customer.address
}
}
/**
* Get insured person from selected customer
*/
const insured = computed(() => {
if (!selectedCustomer.value) return null
return toPolicyPerson(selectedCustomer.value)
})
/**
* Get buyer person (either same as insured or different)
*/
const buyer = computed(() => {
if (useSameForBuyer.value) {
return insured.value
}
if (!selectedBuyer.value) return null
return toPolicyPerson(selectedBuyer.value)
})
/**
* Validate customer has required fields for policy submission
*/
const validateCustomer = (customer: any) => {
const missing: string[] = []
if (customer.customer_type === 'corporate') {
if (!customer.legal_name) missing.push('legal_name')
if (!customer.ruc) missing.push('ruc')
if (!customer.legal_rep_name) missing.push('legal_rep_name')
if (!customer.legal_rep_document_id) missing.push('legal_rep_document_id')
} else {
if (!customer.first_name) missing.push('first_name')
if (!customer.last_name) missing.push('last_name')
if (!customer.birth_date) missing.push('birth_date')
if (!customer.document_id) missing.push('document_id')
}
return { valid: missing.length === 0, missing }
}
/**
* Check if insured is valid
*/
const isInsuredValid = computed(() => {
if (!selectedCustomer.value) return false
return validateCustomer(selectedCustomer.value).valid
})
/**
* Check if buyer is valid
*/
const isBuyerValid = computed(() => {
if (useSameForBuyer.value) {
return isInsuredValid.value
}
if (!selectedBuyer.value) return false
return validateCustomer(selectedBuyer.value).valid
})
/**
* Get validation errors
*/
const validationErrors = computed(() => {
const errors: { insured: string[]; buyer: string[] } = { insured: [], buyer: [] }
if (selectedCustomer.value) {
const validation = validateCustomer(selectedCustomer.value)
errors.insured = validation.missing
}
if (!useSameForBuyer.value && selectedBuyer.value) {
const validation = validateCustomer(selectedBuyer.value)
errors.buyer = validation.missing
}
return errors
})
/**
* Reset selection
*/
function reset() {
selectedCustomer.value = null
selectedBuyer.value = null
useSameForBuyer.value = true
}
return {
selectedCustomer,
selectedBuyer,
useSameForBuyer,
insured,
buyer,
isInsuredValid,
isBuyerValid,
validationErrors,
reset
}
}

View File

@@ -0,0 +1,67 @@
/**
* Composable for policy API operations
* Handles quote submission and acceptance
*/
export function usePolicyApi() {
const { $policy } = useNuxtApp()
const toast = useToast()
const router = useRouter()
/**
* Submit a policy quote request
*/
async function submitPolicyQuote(payload: {
policy_type: 'car' | 'life' | 'fire_structure' | 'fire_contents'
insured: any
buyer: any
policy_details: any
selected_providers: Array<{ provider_id: string; email: string }>
}) {
try {
const data = await $policy('/policies', {
method: 'POST',
body: payload
}) as any
toast.add({ title: 'Quote submitted successfully', color: 'green' })
return data
} catch (e: any) {
toast.add({
title: 'Failed to submit quote',
description: e?.data?.error ?? e.message,
color: 'red'
})
throw e
}
}
/**
* Accept a quote plan and trigger solicitation
*/
async function acceptQuote(applicationId: string, acceptedPlanId: string, acceptedBy: string) {
try {
const data = await $policy(`/policies/${applicationId}/accept`, {
method: 'POST',
body: {
accepted_plan_id: acceptedPlanId,
accepted_by: acceptedBy
}
}) as any
toast.add({ title: 'Plan accepted successfully', color: 'green' })
return data
} catch (e: any) {
toast.add({
title: 'Failed to accept plan',
description: e?.data?.error ?? e.message,
color: 'red'
})
throw e
}
}
return {
submitPolicyQuote,
acceptQuote
}
}