big refactor
This commit is contained in:
189
app/components/CustomerSelector.vue
Normal file
189
app/components/CustomerSelector.vue
Normal file
@@ -0,0 +1,189 @@
|
||||
<script setup lang="ts">
|
||||
const props = defineProps<{
|
||||
modelValue: {
|
||||
selectedCustomer: any
|
||||
useSameForBuyer: boolean
|
||||
selectedBuyer: any
|
||||
}
|
||||
search: string
|
||||
}>()
|
||||
|
||||
const emit = defineEmits<{
|
||||
'update:modelValue': [value: {
|
||||
selectedCustomer: any
|
||||
useSameForBuyer: boolean
|
||||
selectedBuyer: any
|
||||
}]
|
||||
'update:search': [value: string]
|
||||
}>()
|
||||
|
||||
const customerPage = ref(1)
|
||||
const localSearch = ref(props.search)
|
||||
const debouncedSearch = refDebounced(localSearch, 300)
|
||||
|
||||
watch(() => props.search, (newVal) => {
|
||||
localSearch.value = newVal
|
||||
})
|
||||
|
||||
const { data: customersData, pending: customersPending } = useCustomer('/customers', {
|
||||
query: computed(() => ({
|
||||
'page_size': 12,
|
||||
'page': customerPage.value,
|
||||
...(debouncedSearch.value && {
|
||||
'filters[0][field]': 'search',
|
||||
'filters[0][op]': '==',
|
||||
'filters[0][value]': debouncedSearch.value
|
||||
})
|
||||
}))
|
||||
})
|
||||
|
||||
function customerDisplayName(c: any) {
|
||||
if (!c) return ''
|
||||
return c.customer_type === 'corporate'
|
||||
? (c.commercial_name || c.legal_name)
|
||||
: `${c.first_name} ${c.last_name}`
|
||||
}
|
||||
|
||||
function customerSubtitle(c: any) {
|
||||
if (!c) return ''
|
||||
return c.customer_type === 'corporate' ? c.ruc : c.email
|
||||
}
|
||||
|
||||
function updateSelectedCustomer(customer: any) {
|
||||
emit('update:modelValue', {
|
||||
...props.modelValue,
|
||||
selectedCustomer: customer,
|
||||
selectedBuyer: props.modelValue.useSameForBuyer ? customer : props.modelValue.selectedBuyer
|
||||
})
|
||||
}
|
||||
|
||||
function updateSelectedBuyer(customer: any) {
|
||||
emit('update:modelValue', {
|
||||
...props.modelValue,
|
||||
selectedBuyer: customer
|
||||
})
|
||||
}
|
||||
|
||||
function updateUseSameForBuyer(value: boolean) {
|
||||
emit('update:modelValue', {
|
||||
...props.modelValue,
|
||||
useSameForBuyer: value,
|
||||
selectedBuyer: value ? props.modelValue.selectedCustomer : props.modelValue.selectedBuyer
|
||||
})
|
||||
}
|
||||
|
||||
function onSearchInput(value: string) {
|
||||
localSearch.value = value
|
||||
emit('update:search', value)
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="space-y-6">
|
||||
<!-- Insured Section -->
|
||||
<div>
|
||||
<label class="block text-sm font-medium text-[var(--text-primary)] mb-2">Insured</label>
|
||||
<p class="text-sm text-[var(--text-muted)] mb-4">Person or entity being insured</p>
|
||||
|
||||
<div v-if="!modelValue.selectedCustomer">
|
||||
<UInput
|
||||
:model-value="localSearch"
|
||||
@update:model-value="onSearchInput"
|
||||
placeholder="Search by name, email, RUC..."
|
||||
size="lg"
|
||||
icon="i-heroicons-magnifying-glass"
|
||||
/>
|
||||
|
||||
<div v-if="customersPending" class="mt-4 text-center text-[var(--text-muted)]">
|
||||
Loading customers...
|
||||
</div>
|
||||
|
||||
<div v-else-if="customersData?.data && customersData.data.length > 0" class="mt-4 space-y-2">
|
||||
<div
|
||||
v-for="c in customersData.data"
|
||||
:key="c.id"
|
||||
class="p-4 border border-[var(--card-border)] rounded-lg cursor-pointer hover:bg-[var(--card-border)] transition-colors"
|
||||
@click="updateSelectedCustomer(c)"
|
||||
>
|
||||
<div class="flex items-center gap-3">
|
||||
<UBadge :color="c.customer_type === 'corporate' ? 'purple' : 'blue'" variant="soft" size="sm">
|
||||
{{ c.customer_type === 'corporate' ? 'Corp' : 'Ind' }}
|
||||
</UBadge>
|
||||
<span class="font-medium text-[var(--text-primary)]">{{ customerDisplayName(c) }}</span>
|
||||
</div>
|
||||
<div class="text-sm text-[var(--text-muted)] mt-1">{{ customerSubtitle(c) }}</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div v-else class="mt-4 text-center text-[var(--text-muted)]">
|
||||
No customers found. Try a different search term.
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div v-else class="p-4 bg-[var(--brand-soft)] border border-[var(--brand)] rounded-lg">
|
||||
<div class="flex items-center justify-between">
|
||||
<div>
|
||||
<div class="flex items-center gap-3">
|
||||
<UBadge :color="modelValue.selectedCustomer.customer_type === 'corporate' ? 'purple' : 'blue'" variant="soft" size="sm">
|
||||
{{ modelValue.selectedCustomer.customer_type === 'corporate' ? 'Corp' : 'Ind' }}
|
||||
</UBadge>
|
||||
<span class="font-medium text-[var(--text-primary)]">{{ customerDisplayName(modelValue.selectedCustomer) }}</span>
|
||||
</div>
|
||||
<div class="text-sm text-[var(--brand)] mt-1">{{ customerSubtitle(modelValue.selectedCustomer) }}</div>
|
||||
</div>
|
||||
<UButton size="sm" color="neutral" variant="outline" @click="updateSelectedCustomer(null)">Change</UButton>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Buyer Section -->
|
||||
<div>
|
||||
<div class="flex items-center gap-3 mb-2">
|
||||
<label class="block text-sm font-medium text-[var(--text-primary)]">Buyer</label>
|
||||
<div class="flex items-center gap-2">
|
||||
<UToggle :model-value="modelValue.useSameForBuyer" @update:model-value="updateUseSameForBuyer" />
|
||||
<span class="text-sm text-[var(--text-muted)]">Same as insured</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<p v-if="modelValue.useSameForBuyer" class="text-sm text-[var(--text-muted)]">
|
||||
Using same person as insured
|
||||
</p>
|
||||
|
||||
<div v-else>
|
||||
<UInput
|
||||
:model-value="localSearch"
|
||||
@update:model-value="onSearchInput"
|
||||
placeholder="Search by name, email, RUC..."
|
||||
size="lg"
|
||||
icon="i-heroicons-magnifying-glass"
|
||||
/>
|
||||
|
||||
<div v-if="customersPending" class="mt-4 text-center text-[var(--text-muted)]">
|
||||
Loading customers...
|
||||
</div>
|
||||
|
||||
<div v-else-if="customersData?.data && customersData.data.length > 0" class="mt-4 space-y-2">
|
||||
<div
|
||||
v-for="c in customersData.data"
|
||||
:key="c.id"
|
||||
class="p-4 border border-[var(--card-border)] rounded-lg cursor-pointer hover:bg-[var(--card-border)] transition-colors"
|
||||
@click="updateSelectedBuyer(c)"
|
||||
>
|
||||
<div class="flex items-center gap-3">
|
||||
<UBadge :color="c.customer_type === 'corporate' ? 'purple' : 'blue'" variant="soft" size="sm">
|
||||
{{ c.customer_type === 'corporate' ? 'Corp' : 'Ind' }}
|
||||
</UBadge>
|
||||
<span class="font-medium text-[var(--text-primary)]">{{ customerDisplayName(c) }}</span>
|
||||
</div>
|
||||
<div class="text-sm text-[var(--text-muted)] mt-1">{{ customerSubtitle(c) }}</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div v-else class="mt-4 text-center text-[var(--text-muted)]">
|
||||
No customers found. Try a different search term.
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
Reference in New Issue
Block a user