1770 lines
64 KiB
Vue
1770 lines
64 KiB
Vue
<script setup lang="ts">
|
|
definePageMeta({ ssr: false })
|
|
usePageTitle('Policy Detail')
|
|
|
|
const route = useRoute()
|
|
const policyId = route.params.id as string
|
|
|
|
// ── Types ────────────────────────────────────────────────────────────────────
|
|
interface PolicyDetail {
|
|
id: string
|
|
policyNumber: string
|
|
status: 'active' | 'pending' | 'lapsed' | 'cancelled' | 'expired'
|
|
lob: 'Auto' | 'Health' | 'Life' | 'General Risk'
|
|
insurer: string
|
|
insurerLogo: string
|
|
effectiveDate: string
|
|
expirationDate: string
|
|
issueDate: string
|
|
lastRenewalDate: string | null
|
|
annualPremium: number
|
|
paymentFrequency: 'Monthly' | 'Quarterly' | 'Semi-annual' | 'Annual'
|
|
nextPaymentDate: string
|
|
paymentStatus: 'current' | 'overdue' | 'grace_period'
|
|
coverageAmount: number
|
|
deductible: number
|
|
coverageDetails: { label: string; value: string }[]
|
|
titular: { name: string; cedula: string; phone: string; email: string }
|
|
agent: string
|
|
vehicle?: { make: string; model: string; year: number; vin: string; plate: string; color: string; isFleet: boolean; fleetName?: string; groupDiscount?: string }
|
|
dependents?: { name: string; relationship: string; dob: string; cedula: string }[]
|
|
beneficiaries?: { name: string; relationship: string; percentage: number; type: 'primary' | 'contingent' }[]
|
|
mortgageHolder?: { company: string; loanNumber: string; type: string }
|
|
property?: { address: string; type: string; constructionYear: number; area: string; value: number }
|
|
endorsements: { id: string; date: string; type: string; description: string; premium: number }[]
|
|
claims: { id: string; date: string; type: string; status: string; amount: number; description: string }[]
|
|
renewals: { period: string; premium: number; status: string }[]
|
|
documents: { id: string; name: string; type: string; date: string; size: string }[]
|
|
activity: { date: string; agent: string; action: string; detail: string }[]
|
|
economicGroup: string | null
|
|
relatedPolicies: { id: string; policyNumber: string; lob: string; titular: string; status: string }[]
|
|
billing: {
|
|
outstandingBalance: number
|
|
lastPaymentDate: string
|
|
lastPaymentAmount: number
|
|
paymentMethod: string
|
|
paymentHistory: { date: string; amount: number; method: string; status: string }[]
|
|
}
|
|
commission: {
|
|
rate: number
|
|
amount: number
|
|
status: string
|
|
producer: string
|
|
earned: number
|
|
paid: number
|
|
owed: number
|
|
nextPaymentDate: string
|
|
}
|
|
}
|
|
|
|
// ── Mock data ────────────────────────────────────────────────────────────────
|
|
const policy = ref<PolicyDetail>({
|
|
id: 'POL-4401',
|
|
policyNumber: 'AUTO-2024-004401',
|
|
status: 'active',
|
|
lob: 'Auto',
|
|
insurer: 'ASSA Compañía de Seguros',
|
|
insurerLogo: 'i-heroicons-shield-check',
|
|
effectiveDate: '2024-03-15',
|
|
expirationDate: '2025-03-15',
|
|
issueDate: '2024-03-10',
|
|
lastRenewalDate: '2024-03-15',
|
|
annualPremium: 1_245_000,
|
|
paymentFrequency: 'Quarterly',
|
|
nextPaymentDate: '2025-06-15',
|
|
paymentStatus: 'current',
|
|
coverageAmount: 45_000_000,
|
|
deductible: 500_000,
|
|
coverageDetails: [
|
|
{ label: 'Responsabilidad Civil', value: '₡25,000,000' },
|
|
{ label: 'Daños Propios', value: '₡45,000,000' },
|
|
{ label: 'Robo Total', value: '₡45,000,000' },
|
|
{ label: 'Asistencia en Carretera', value: 'Incluida' },
|
|
{ label: 'Vidrios y Espejos', value: '₡1,500,000' },
|
|
{ label: 'Gastos Médicos', value: '₡5,000,000' },
|
|
{ label: 'Extensión Territorial', value: 'Centroamérica' },
|
|
],
|
|
titular: {
|
|
name: 'Transportes del Norte S.A.',
|
|
cedula: '3-101-456789',
|
|
phone: '+506 2222-8800',
|
|
email: 'seguros@transportesnorte.cr',
|
|
},
|
|
agent: 'María Fernanda Solís',
|
|
vehicle: {
|
|
make: 'Toyota',
|
|
model: 'Hilux SRV 4x4',
|
|
year: 2024,
|
|
vin: 'JT3HN87R5Y0234567',
|
|
plate: '123-ABC',
|
|
color: 'Blanco Perlado',
|
|
isFleet: true,
|
|
fleetName: 'Flota Transportes Norte',
|
|
groupDiscount: '12%',
|
|
},
|
|
endorsements: [
|
|
{ id: 'END-001', date: '2024-06-20', type: 'Adición', description: 'Agregar cobertura de vidrios polarizados', premium: 35_000 },
|
|
{ id: 'END-002', date: '2024-09-05', type: 'Modificación', description: 'Cambio de deducible de ₡750,000 a ₡500,000', premium: 48_000 },
|
|
],
|
|
claims: [
|
|
{ id: 'CLM-2201', date: '2024-05-12', type: 'Colisión', status: 'Resuelto', amount: 2_350_000, description: 'Colisión lateral en Ruta 1, San José. Daño en puerta derecha y guardafango.' },
|
|
{ id: 'CLM-2202', date: '2024-08-23', type: 'Vidrios', status: 'Resuelto', amount: 185_000, description: 'Reemplazo de parabrisas por impacto de piedra en carretera Interamericana.' },
|
|
{ id: 'CLM-2203', date: '2025-01-10', type: 'Robo parcial', status: 'En revisión', amount: 890_000, description: 'Robo de accesorios del vehículo estacionado en parqueo de Alajuela.' },
|
|
],
|
|
renewals: [
|
|
{ period: '2021-2022', premium: 980_000, status: 'Completado' },
|
|
{ period: '2022-2023', premium: 1_050_000, status: 'Completado' },
|
|
{ period: '2023-2024', premium: 1_150_000, status: 'Completado' },
|
|
{ period: '2024-2025', premium: 1_245_000, status: 'Vigente' },
|
|
],
|
|
documents: [
|
|
{ id: 'DOC-01', name: 'Póliza Original AUTO-2024-004401', type: 'Póliza', date: '2024-03-10', size: '2.4 MB' },
|
|
{ id: 'DOC-02', name: 'Endoso END-001 — Vidrios Polarizados', type: 'Endoso', date: '2024-06-20', size: '580 KB' },
|
|
{ id: 'DOC-03', name: 'Endoso END-002 — Cambio Deducible', type: 'Endoso', date: '2024-09-05', size: '612 KB' },
|
|
{ id: 'DOC-04', name: 'Certificado de Seguro Vigente', type: 'Certificado', date: '2025-01-15', size: '340 KB' },
|
|
{ id: 'DOC-05', name: 'Recibo de Prima Q1-2025', type: 'Recibo', date: '2025-03-15', size: '128 KB' },
|
|
],
|
|
activity: [
|
|
{ date: '2025-03-15', agent: 'María Fernanda Solís', action: 'Renovación procesada', detail: 'Renovación período 2024-2025 confirmada con ASSA. Prima ajustada +8.3%.' },
|
|
{ date: '2025-01-15', agent: 'Sistema', action: 'Certificado emitido', detail: 'Certificado de seguro vigente generado automáticamente.' },
|
|
{ date: '2025-01-10', agent: 'Carlos Méndez', action: 'Reclamo abierto', detail: 'CLM-2203 registrado: robo parcial de accesorios en Alajuela.' },
|
|
{ date: '2024-09-05', agent: 'María Fernanda Solís', action: 'Endoso aplicado', detail: 'END-002: Reducción de deducible aprobada por ASSA.' },
|
|
{ date: '2024-06-20', agent: 'María Fernanda Solís', action: 'Endoso aplicado', detail: 'END-001: Cobertura de vidrios polarizados agregada.' },
|
|
{ date: '2024-03-10', agent: 'María Fernanda Solís', action: 'Póliza emitida', detail: 'Póliza AUTO-2024-004401 emitida por ASSA para Toyota Hilux 2024.' },
|
|
],
|
|
billing: {
|
|
outstandingBalance: 0,
|
|
lastPaymentDate: '2025-03-15',
|
|
lastPaymentAmount: 311_250,
|
|
paymentMethod: 'Transferencia bancaria',
|
|
paymentHistory: [
|
|
{ date: '2025-03-15', amount: 311_250, method: 'Transferencia', status: 'Pagado' },
|
|
{ date: '2024-12-15', amount: 311_250, method: 'Transferencia', status: 'Pagado' },
|
|
{ date: '2024-09-15', amount: 311_250, method: 'Transferencia', status: 'Pagado' },
|
|
{ date: '2024-06-15', amount: 311_250, method: 'Cheque', status: 'Pagado' },
|
|
],
|
|
},
|
|
commission: {
|
|
rate: 15,
|
|
amount: 186_750,
|
|
status: 'Earned',
|
|
producer: 'María Fernanda Solís',
|
|
earned: 186_750,
|
|
paid: 140_063,
|
|
owed: 46_687,
|
|
nextPaymentDate: '2025-04-30',
|
|
},
|
|
economicGroup: 'Grupo Transportes del Norte',
|
|
relatedPolicies: [
|
|
{ id: 'POL-4402', policyNumber: 'AUTO-2024-004402', lob: 'Auto', titular: 'Transportes del Norte S.A.', status: 'active' },
|
|
{ id: 'POL-3310', policyNumber: 'PROP-2023-003310', lob: 'General Risk', titular: 'Transportes del Norte S.A.', status: 'active' },
|
|
],
|
|
})
|
|
|
|
// ── Tabs ──────────────────────────────────────────────────────────────────────
|
|
type TabId = 'overview' | 'claims' | 'renewals' | 'documents' | 'view-policy' | 'activity'
|
|
const activeTab = ref<TabId>('overview')
|
|
const tabs: { id: TabId; label: string; icon: string }[] = [
|
|
{ id: 'overview', label: 'Overview', icon: 'i-heroicons-squares-2x2' },
|
|
{ id: 'claims', label: 'Claims', icon: 'i-heroicons-document-text' },
|
|
{ id: 'renewals', label: 'Renewals', icon: 'i-heroicons-arrow-path' },
|
|
{ id: 'documents', label: 'Documents', icon: 'i-heroicons-folder-open' },
|
|
{ id: 'view-policy', label: 'View Policy', icon: 'i-heroicons-document-magnifying-glass' },
|
|
{ id: 'activity', label: 'Activity', icon: 'i-heroicons-clock' },
|
|
]
|
|
|
|
// ── Helpers ───────────────────────────────────────────────────────────────────
|
|
const fmtMoney = (n: number) => '₡' + n.toLocaleString('es-CR')
|
|
const fmtDate = (d: string) => new Date(d).toLocaleDateString('es-CR', { day: '2-digit', month: 'short', year: 'numeric' })
|
|
|
|
const statusClass = (s: string) => {
|
|
const map: Record<string, string> = {
|
|
active: 'pol-status-active', pending: 'pol-status-pending', lapsed: 'pol-status-lapsed',
|
|
cancelled: 'pol-status-cancelled', expired: 'pol-status-expired',
|
|
'Resuelto': 'pol-status-active', 'En revisión': 'pol-status-pending', 'Denegado': 'pol-status-lapsed',
|
|
'Completado': 'pol-status-active', 'Vigente': 'pol-status-pending',
|
|
}
|
|
return map[s] ?? 'pol-status-cancelled'
|
|
}
|
|
|
|
const statusLabel = (s: string) => {
|
|
const map: Record<string, string> = { active: 'Active', pending: 'Pending', lapsed: 'Lapsed', cancelled: 'Cancelled', expired: 'Expired' }
|
|
return map[s] ?? s
|
|
}
|
|
|
|
const paymentStatusClass = (s: string) => {
|
|
const map: Record<string, string> = { current: 'pol-pay-current', overdue: 'pol-pay-overdue', grace_period: 'pol-pay-grace' }
|
|
return map[s] ?? ''
|
|
}
|
|
const paymentStatusLabel = (s: string) => {
|
|
const map: Record<string, string> = { current: 'Current', overdue: 'Overdue', grace_period: 'Grace Period' }
|
|
return map[s] ?? s
|
|
}
|
|
|
|
const docTypeClass = (t: string) => {
|
|
const map: Record<string, string> = {
|
|
'Póliza': 'pol-doc-poliza', 'Endoso': 'pol-doc-endoso',
|
|
'Certificado': 'pol-doc-certificado', 'Recibo': 'pol-doc-recibo',
|
|
}
|
|
return map[t] ?? 'pol-doc-other'
|
|
}
|
|
|
|
const renewalChange = (idx: number) => {
|
|
if (idx === 0) return null
|
|
const prev = policy.value.renewals[idx - 1].premium
|
|
const curr = policy.value.renewals[idx].premium
|
|
return ((curr - prev) / prev * 100).toFixed(1)
|
|
}
|
|
|
|
const lobIcon = (lob: string) => {
|
|
const map: Record<string, string> = { Auto: 'i-heroicons-truck', Health: 'i-heroicons-heart', Life: 'i-heroicons-shield-check', 'General Risk': 'i-heroicons-building-office-2' }
|
|
return map[lob] ?? 'i-heroicons-document'
|
|
}
|
|
|
|
const daysUntilExpiration = computed(() => {
|
|
const now = new Date()
|
|
const exp = new Date(policy.value.expirationDate)
|
|
return Math.max(0, Math.ceil((exp.getTime() - now.getTime()) / (1000 * 60 * 60 * 24)))
|
|
})
|
|
|
|
const expandedClaim = ref<string | null>(null)
|
|
const toggleClaim = (id: string) => { expandedClaim.value = expandedClaim.value === id ? null : id }
|
|
|
|
// ── Viewable Documents (View Policy tab) ────────────────────────────────────
|
|
const viewableDocs = [
|
|
{ id: 'VD-001', name: 'Póliza Original AUTO-2024-004401', type: 'policy', url: '#', pages: 12 },
|
|
{ id: 'VD-002', name: 'Endoso END-001 — Vidrios Polarizados', type: 'endorsement', url: '#', pages: 2 },
|
|
{ id: 'VD-003', name: 'Endoso END-002 — Reducción Deducible', type: 'endorsement', url: '#', pages: 1 },
|
|
{ id: 'VD-004', name: 'Certificado de Seguro Vigente', type: 'certificate', url: '#', pages: 1 },
|
|
{ id: 'VD-005', name: 'Póliza Relacionada AUTO-2024-004402', type: 'related', url: '#', pages: 8 },
|
|
{ id: 'VD-006', name: 'Póliza Relacionada PROP-2023-003310', type: 'related', url: '#', pages: 15 },
|
|
]
|
|
|
|
const selectedDoc = ref(viewableDocs[0])
|
|
|
|
const viewableDocGroups = computed(() => [
|
|
{ label: 'Policy', items: viewableDocs.filter(d => d.type === 'policy') },
|
|
{ label: 'Endorsements', items: viewableDocs.filter(d => d.type === 'endorsement') },
|
|
{ label: 'Certificates', items: viewableDocs.filter(d => d.type === 'certificate') },
|
|
{ label: 'Related Policies', items: viewableDocs.filter(d => d.type === 'related') },
|
|
])
|
|
|
|
const docTypeBadgeClass = (t: string) => {
|
|
const map: Record<string, string> = {
|
|
policy: 'pol-vd-badge-policy', endorsement: 'pol-vd-badge-endorsement',
|
|
certificate: 'pol-vd-badge-certificate', related: 'pol-vd-badge-related',
|
|
}
|
|
return map[t] ?? ''
|
|
}
|
|
|
|
const docTypeBadgeLabel = (t: string) => {
|
|
const map: Record<string, string> = {
|
|
policy: 'Policy', endorsement: 'Endorsement',
|
|
certificate: 'Certificate', related: 'Related',
|
|
}
|
|
return map[t] ?? t
|
|
}
|
|
</script>
|
|
|
|
<template>
|
|
<div class="pol-root mx-auto max-w-6xl pb-12">
|
|
<!-- Back link -->
|
|
<NuxtLink to="/policies" class="pol-back-link">
|
|
<UIcon name="i-heroicons-arrow-left" class="w-3.5 h-3.5" />
|
|
Back to Policies
|
|
</NuxtLink>
|
|
|
|
<!-- Header -->
|
|
<div class="pol-detail-header">
|
|
<div class="pol-detail-header-left">
|
|
<div class="pol-detail-title-row">
|
|
<h1 class="pol-detail-title">{{ policy.policyNumber }}</h1>
|
|
<span class="pol-status-badge pol-status-pill" :class="statusClass(policy.status)">{{ statusLabel(policy.status) }}</span>
|
|
<span class="pol-lob-chip" :class="`pol-lob-${policy.lob.toLowerCase().replace(' ', '-')}`">
|
|
<UIcon :name="lobIcon(policy.lob)" class="w-3 h-3" />
|
|
{{ policy.lob }}
|
|
</span>
|
|
</div>
|
|
<div class="pol-detail-subtitle">
|
|
<UIcon :name="policy.insurerLogo" class="w-4 h-4" style="color: #01696f;" />
|
|
<span>{{ policy.insurer }}</span>
|
|
<span class="pol-detail-sep">·</span>
|
|
<span>{{ policy.titular.name }}</span>
|
|
</div>
|
|
</div>
|
|
<div class="pol-detail-header-right">
|
|
<button class="pol-btn-secondary">
|
|
<UIcon name="i-heroicons-arrow-path" class="w-3.5 h-3.5" />
|
|
Renew
|
|
</button>
|
|
<button class="pol-btn-secondary">
|
|
<UIcon name="i-heroicons-arrow-down-tray" class="w-3.5 h-3.5" />
|
|
Download
|
|
</button>
|
|
<button class="pol-btn-secondary">
|
|
<UIcon name="i-heroicons-printer" class="w-3.5 h-3.5" />
|
|
Print
|
|
</button>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Tab navigation -->
|
|
<div class="pol-main-tabs">
|
|
<button
|
|
v-for="t in tabs"
|
|
:key="t.id"
|
|
type="button"
|
|
class="pol-main-tab"
|
|
:class="activeTab === t.id ? 'pol-main-tab-on' : 'pol-main-tab-off'"
|
|
@click="activeTab = t.id"
|
|
>
|
|
<UIcon :name="t.icon" class="w-3.5 h-3.5" />
|
|
{{ t.label }}
|
|
<span v-if="t.id === 'claims'" class="pol-tab-count" :class="activeTab === 'claims' ? 'pol-tab-count-on' : ''">{{ policy.claims.length }}</span>
|
|
<span v-if="t.id === 'documents'" class="pol-tab-count" :class="activeTab === 'documents' ? 'pol-tab-count-on' : ''">{{ policy.documents.length }}</span>
|
|
</button>
|
|
</div>
|
|
|
|
<!-- Quick Info Strip -->
|
|
<div class="pol-quick-strip">
|
|
<div class="pol-quick-item">
|
|
<UIcon name="i-heroicons-calendar" class="w-4 h-4 pol-quick-icon" />
|
|
<div class="pol-quick-data">
|
|
<span class="pol-quick-value" :class="daysUntilExpiration <= 30 ? 'pol-quick-warn' : ''">{{ daysUntilExpiration }}</span>
|
|
<span class="pol-quick-label">Days to Expiry</span>
|
|
</div>
|
|
</div>
|
|
<div class="pol-quick-sep" />
|
|
<div class="pol-quick-item">
|
|
<UIcon name="i-heroicons-banknotes" class="w-4 h-4 pol-quick-icon" />
|
|
<div class="pol-quick-data">
|
|
<span class="pol-quick-value">{{ fmtMoney(policy.billing.outstandingBalance) }}</span>
|
|
<span class="pol-quick-label">Outstanding</span>
|
|
</div>
|
|
</div>
|
|
<div class="pol-quick-sep" />
|
|
<div class="pol-quick-item">
|
|
<UIcon name="i-heroicons-document-text" class="w-4 h-4 pol-quick-icon" />
|
|
<div class="pol-quick-data">
|
|
<span class="pol-quick-value">{{ policy.claims.length }}</span>
|
|
<span class="pol-quick-label">Total Claims</span>
|
|
</div>
|
|
</div>
|
|
<div class="pol-quick-sep" />
|
|
<div class="pol-quick-item">
|
|
<UIcon name="i-heroicons-currency-dollar" class="w-4 h-4 pol-quick-icon" />
|
|
<div class="pol-quick-data">
|
|
<span class="pol-quick-value">{{ fmtMoney(policy.commission.amount) }}</span>
|
|
<span class="pol-quick-label">Commission</span>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- ═══════════════════ OVERVIEW TAB ═══════════════════ -->
|
|
<template v-if="activeTab === 'overview'">
|
|
<div class="pol-grid-2">
|
|
<!-- Policy Information -->
|
|
<div class="pol-card pol-card-padded pol-grid-span-2">
|
|
<div class="pol-card-title">Policy Information</div>
|
|
<div class="pol-info-grid">
|
|
<div class="pol-info-item">
|
|
<span class="pol-label">Policy Number</span>
|
|
<span class="pol-value pol-mono">{{ policy.policyNumber }}</span>
|
|
</div>
|
|
<div class="pol-info-item">
|
|
<span class="pol-label">Status</span>
|
|
<span class="pol-status-badge pol-status-pill" :class="statusClass(policy.status)">{{ statusLabel(policy.status) }}</span>
|
|
</div>
|
|
<div class="pol-info-item">
|
|
<span class="pol-label">Line of Business</span>
|
|
<span class="pol-value">{{ policy.lob }}</span>
|
|
</div>
|
|
<div class="pol-info-item">
|
|
<span class="pol-label">Insurer</span>
|
|
<span class="pol-value">{{ policy.insurer }}</span>
|
|
</div>
|
|
<div class="pol-info-item">
|
|
<span class="pol-label">Effective Date</span>
|
|
<span class="pol-value">{{ fmtDate(policy.effectiveDate) }}</span>
|
|
</div>
|
|
<div class="pol-info-item">
|
|
<span class="pol-label">Expiration Date</span>
|
|
<span class="pol-value">{{ fmtDate(policy.expirationDate) }}</span>
|
|
</div>
|
|
<div class="pol-info-item">
|
|
<span class="pol-label">Issue Date</span>
|
|
<span class="pol-value">{{ fmtDate(policy.issueDate) }}</span>
|
|
</div>
|
|
<div class="pol-info-item">
|
|
<span class="pol-label">Last Renewal</span>
|
|
<span class="pol-value">{{ policy.lastRenewalDate ? fmtDate(policy.lastRenewalDate) : '—' }}</span>
|
|
</div>
|
|
<div class="pol-info-item">
|
|
<span class="pol-label">Annual Premium</span>
|
|
<span class="pol-value pol-value-bold">{{ fmtMoney(policy.annualPremium) }}</span>
|
|
</div>
|
|
<div class="pol-info-item">
|
|
<span class="pol-label">Payment Frequency</span>
|
|
<span class="pol-value">{{ policy.paymentFrequency }}</span>
|
|
</div>
|
|
<div class="pol-info-item">
|
|
<span class="pol-label">Next Payment</span>
|
|
<span class="pol-value">{{ fmtDate(policy.nextPaymentDate) }}</span>
|
|
</div>
|
|
<div class="pol-info-item">
|
|
<span class="pol-label">Payment Status</span>
|
|
<span class="pol-pay-badge" :class="paymentStatusClass(policy.paymentStatus)">{{ paymentStatusLabel(policy.paymentStatus) }}</span>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Coverage Details -->
|
|
<div class="pol-card pol-card-padded">
|
|
<div class="pol-card-title">Coverage Details</div>
|
|
<div class="pol-coverage-header">
|
|
<div class="pol-info-item">
|
|
<span class="pol-label">Coverage Amount</span>
|
|
<span class="pol-value pol-value-bold">{{ fmtMoney(policy.coverageAmount) }}</span>
|
|
</div>
|
|
<div class="pol-info-item">
|
|
<span class="pol-label">Deductible</span>
|
|
<span class="pol-value pol-value-bold">{{ fmtMoney(policy.deductible) }}</span>
|
|
</div>
|
|
</div>
|
|
<div class="pol-divider" />
|
|
<div class="pol-coverage-list">
|
|
<div v-for="c in policy.coverageDetails" :key="c.label" class="pol-coverage-row">
|
|
<span class="pol-coverage-label">{{ c.label }}</span>
|
|
<span class="pol-coverage-value">{{ c.value }}</span>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Policyholder -->
|
|
<div class="pol-card pol-card-padded">
|
|
<div class="pol-card-title">Policyholder</div>
|
|
<div class="pol-holder-info">
|
|
<div class="pol-holder-avatar">
|
|
<UIcon name="i-heroicons-building-office" class="w-5 h-5" />
|
|
</div>
|
|
<div>
|
|
<div class="pol-holder-name">{{ policy.titular.name }}</div>
|
|
<div class="pol-holder-cedula">{{ policy.titular.cedula }}</div>
|
|
</div>
|
|
</div>
|
|
<div class="pol-divider" />
|
|
<div class="pol-info-item" style="margin-bottom: 10px;">
|
|
<span class="pol-label">Phone</span>
|
|
<span class="pol-value">{{ policy.titular.phone }}</span>
|
|
</div>
|
|
<div class="pol-info-item" style="margin-bottom: 10px;">
|
|
<span class="pol-label">Email</span>
|
|
<span class="pol-value">{{ policy.titular.email }}</span>
|
|
</div>
|
|
<div class="pol-info-item">
|
|
<span class="pol-label">Agent</span>
|
|
<span class="pol-value">{{ policy.agent }}</span>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- LOB-Specific: Auto -->
|
|
<template v-if="policy.lob === 'Auto' && policy.vehicle">
|
|
<div class="pol-card pol-card-padded pol-grid-span-2">
|
|
<div class="pol-card-title">
|
|
<UIcon name="i-heroicons-truck" class="w-4 h-4" style="color: #2563eb;" />
|
|
Vehicle Details
|
|
</div>
|
|
<div class="pol-info-grid">
|
|
<div class="pol-info-item">
|
|
<span class="pol-label">Make / Model</span>
|
|
<span class="pol-value pol-value-bold">{{ policy.vehicle.year }} {{ policy.vehicle.make }} {{ policy.vehicle.model }}</span>
|
|
</div>
|
|
<div class="pol-info-item">
|
|
<span class="pol-label">Color</span>
|
|
<span class="pol-value">{{ policy.vehicle.color }}</span>
|
|
</div>
|
|
<div class="pol-info-item">
|
|
<span class="pol-label">VIN</span>
|
|
<span class="pol-value pol-mono">{{ policy.vehicle.vin }}</span>
|
|
</div>
|
|
<div class="pol-info-item">
|
|
<span class="pol-label">Plate</span>
|
|
<span class="pol-value pol-mono">{{ policy.vehicle.plate }}</span>
|
|
</div>
|
|
</div>
|
|
<template v-if="policy.vehicle.isFleet">
|
|
<div class="pol-divider" />
|
|
<div class="pol-fleet-banner">
|
|
<UIcon name="i-heroicons-truck" class="w-4 h-4" />
|
|
<div>
|
|
<span class="pol-fleet-name">{{ policy.vehicle.fleetName }}</span>
|
|
<span class="pol-fleet-discount">Group discount: {{ policy.vehicle.groupDiscount }}</span>
|
|
</div>
|
|
</div>
|
|
</template>
|
|
</div>
|
|
</template>
|
|
|
|
<!-- LOB-Specific: Health -->
|
|
<template v-if="policy.lob === 'Health' && policy.dependents">
|
|
<div class="pol-card pol-card-flush pol-grid-span-2">
|
|
<div class="pol-card-head">
|
|
<span>Dependents</span>
|
|
<span class="pol-card-head-count">{{ policy.dependents.length }}</span>
|
|
</div>
|
|
<div class="pol-table-wrap">
|
|
<table class="pol-table">
|
|
<thead><tr>
|
|
<th class="pol-th">Name</th><th class="pol-th">Relationship</th><th class="pol-th">Date of Birth</th><th class="pol-th">Cédula</th>
|
|
</tr></thead>
|
|
<tbody>
|
|
<tr v-for="d in policy.dependents" :key="d.cedula" class="pol-row">
|
|
<td class="pol-td pol-value-bold">{{ d.name }}</td>
|
|
<td class="pol-td">{{ d.relationship }}</td>
|
|
<td class="pol-td">{{ fmtDate(d.dob) }}</td>
|
|
<td class="pol-td pol-mono">{{ d.cedula }}</td>
|
|
</tr>
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
</div>
|
|
</template>
|
|
|
|
<!-- LOB-Specific: Life -->
|
|
<template v-if="policy.lob === 'Life' && policy.beneficiaries">
|
|
<div class="pol-card pol-card-flush pol-grid-span-2">
|
|
<div class="pol-card-head">
|
|
<span>Beneficiaries</span>
|
|
<span class="pol-card-head-count">{{ policy.beneficiaries.length }}</span>
|
|
</div>
|
|
<div class="pol-table-wrap">
|
|
<table class="pol-table">
|
|
<thead><tr>
|
|
<th class="pol-th">Name</th><th class="pol-th">Relationship</th><th class="pol-th">Type</th><th class="pol-th pol-th-right">%</th>
|
|
</tr></thead>
|
|
<tbody>
|
|
<tr v-for="b in policy.beneficiaries" :key="b.name" class="pol-row">
|
|
<td class="pol-td pol-value-bold">{{ b.name }}</td>
|
|
<td class="pol-td">{{ b.relationship }}</td>
|
|
<td class="pol-td"><span class="pol-status-badge" :class="b.type === 'primary' ? 'pol-status-active' : 'pol-status-cancelled'">{{ b.type }}</span></td>
|
|
<td class="pol-td pol-td-right pol-value-bold">{{ b.percentage }}%</td>
|
|
</tr>
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
</div>
|
|
<div v-if="policy.mortgageHolder" class="pol-card pol-card-padded pol-grid-span-2">
|
|
<div class="pol-card-title">Mortgage Holder</div>
|
|
<div class="pol-info-grid">
|
|
<div class="pol-info-item"><span class="pol-label">Company</span><span class="pol-value">{{ policy.mortgageHolder.company }}</span></div>
|
|
<div class="pol-info-item"><span class="pol-label">Loan Number</span><span class="pol-value pol-mono">{{ policy.mortgageHolder.loanNumber }}</span></div>
|
|
<div class="pol-info-item"><span class="pol-label">Type</span><span class="pol-value">{{ policy.mortgageHolder.type }}</span></div>
|
|
</div>
|
|
</div>
|
|
</template>
|
|
|
|
<!-- LOB-Specific: General Risk / Property -->
|
|
<template v-if="policy.lob === 'General Risk' && policy.property">
|
|
<div class="pol-card pol-card-padded pol-grid-span-2">
|
|
<div class="pol-card-title">
|
|
<UIcon name="i-heroicons-building-office-2" class="w-4 h-4" style="color: #d97706;" />
|
|
Property Details
|
|
</div>
|
|
<div class="pol-info-grid">
|
|
<div class="pol-info-item"><span class="pol-label">Address</span><span class="pol-value">{{ policy.property.address }}</span></div>
|
|
<div class="pol-info-item"><span class="pol-label">Type</span><span class="pol-value">{{ policy.property.type }}</span></div>
|
|
<div class="pol-info-item"><span class="pol-label">Construction Year</span><span class="pol-value">{{ policy.property.constructionYear }}</span></div>
|
|
<div class="pol-info-item"><span class="pol-label">Area</span><span class="pol-value">{{ policy.property.area }}</span></div>
|
|
<div class="pol-info-item"><span class="pol-label">Insured Value</span><span class="pol-value pol-value-bold">{{ fmtMoney(policy.property.value) }}</span></div>
|
|
</div>
|
|
</div>
|
|
</template>
|
|
|
|
<!-- Endorsements -->
|
|
<div v-if="policy.endorsements.length > 0" class="pol-card pol-card-flush pol-grid-span-2">
|
|
<div class="pol-card-head">
|
|
<span>Endorsements</span>
|
|
<span class="pol-card-head-count">{{ policy.endorsements.length }}</span>
|
|
</div>
|
|
<div class="pol-table-wrap">
|
|
<table class="pol-table">
|
|
<thead><tr>
|
|
<th class="pol-th">ID</th><th class="pol-th">Date</th><th class="pol-th">Type</th><th class="pol-th">Description</th><th class="pol-th pol-th-right">Premium Impact</th>
|
|
</tr></thead>
|
|
<tbody>
|
|
<tr v-for="e in policy.endorsements" :key="e.id" class="pol-row">
|
|
<td class="pol-td pol-mono">{{ e.id }}</td>
|
|
<td class="pol-td">{{ fmtDate(e.date) }}</td>
|
|
<td class="pol-td"><span class="pol-endorse-type">{{ e.type }}</span></td>
|
|
<td class="pol-td">{{ e.description }}</td>
|
|
<td class="pol-td pol-td-right pol-value-bold" style="color: #d97706;">+{{ fmtMoney(e.premium) }}</td>
|
|
</tr>
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Billing & Payments -->
|
|
<div class="pol-card pol-card-padded">
|
|
<div class="pol-card-title">
|
|
<UIcon name="i-heroicons-banknotes" class="w-4 h-4" style="color: #01696f;" />
|
|
Billing & Payments
|
|
</div>
|
|
<div class="pol-info-grid">
|
|
<div class="pol-info-item">
|
|
<span class="pol-label">Outstanding Balance</span>
|
|
<span class="pol-value pol-value-bold" :style="policy.billing.outstandingBalance === 0 ? 'color: #059669;' : 'color: #e11d48;'">
|
|
{{ fmtMoney(policy.billing.outstandingBalance) }}
|
|
<span v-if="policy.billing.outstandingBalance === 0" class="pol-billing-current-tag">Current</span>
|
|
</span>
|
|
</div>
|
|
<div class="pol-info-item">
|
|
<span class="pol-label">Last Payment</span>
|
|
<span class="pol-value">{{ fmtDate(policy.billing.lastPaymentDate) }} — {{ fmtMoney(policy.billing.lastPaymentAmount) }}</span>
|
|
</div>
|
|
<div class="pol-info-item">
|
|
<span class="pol-label">Payment Method</span>
|
|
<span class="pol-value">{{ policy.billing.paymentMethod }}</span>
|
|
</div>
|
|
</div>
|
|
<div class="pol-divider" />
|
|
<div class="pol-label" style="margin-bottom: 8px;">Recent Payments</div>
|
|
<div class="pol-table-wrap">
|
|
<table class="pol-table pol-table-compact">
|
|
<thead><tr>
|
|
<th class="pol-th">Date</th><th class="pol-th pol-th-right">Amount</th><th class="pol-th">Method</th><th class="pol-th">Status</th>
|
|
</tr></thead>
|
|
<tbody>
|
|
<tr v-for="p in policy.billing.paymentHistory" :key="p.date" class="pol-row">
|
|
<td class="pol-td">{{ fmtDate(p.date) }}</td>
|
|
<td class="pol-td pol-td-right pol-value-bold">{{ fmtMoney(p.amount) }}</td>
|
|
<td class="pol-td">{{ p.method }}</td>
|
|
<td class="pol-td"><span class="pol-status-badge pol-status-pill pol-status-active">{{ p.status }}</span></td>
|
|
</tr>
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Commission -->
|
|
<div class="pol-card pol-card-padded">
|
|
<div class="pol-card-title">
|
|
<UIcon name="i-heroicons-currency-dollar" class="w-4 h-4" style="color: #01696f;" />
|
|
Commission
|
|
</div>
|
|
<div class="pol-commission-highlight">
|
|
<span class="pol-commission-amount">{{ fmtMoney(policy.commission.amount) }}</span>
|
|
<span class="pol-commission-rate">{{ policy.commission.rate }}% of {{ fmtMoney(policy.annualPremium) }}</span>
|
|
</div>
|
|
<div class="pol-divider" />
|
|
<div class="pol-info-grid">
|
|
<div class="pol-info-item">
|
|
<span class="pol-label">Commission Rate</span>
|
|
<span class="pol-value pol-value-bold">{{ policy.commission.rate }}%</span>
|
|
</div>
|
|
<div class="pol-info-item">
|
|
<span class="pol-label">Annual Amount</span>
|
|
<span class="pol-value pol-value-bold">{{ fmtMoney(policy.commission.amount) }}</span>
|
|
</div>
|
|
<div class="pol-info-item">
|
|
<span class="pol-label">Status</span>
|
|
<span class="pol-status-badge pol-status-pill pol-status-active">{{ policy.commission.status }}</span>
|
|
</div>
|
|
<div class="pol-info-item">
|
|
<span class="pol-label">Producer / Agent of Record</span>
|
|
<span class="pol-value">{{ policy.commission.producer }}</span>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Agent Payout Breakdown -->
|
|
<div class="pol-divider" />
|
|
<div class="pol-card-title" style="margin-top: 4px;">
|
|
<UIcon name="i-heroicons-banknotes" class="w-4 h-4" style="color: #01696f;" />
|
|
Agent Payout
|
|
</div>
|
|
<div class="pol-agent-payout">
|
|
<div class="pol-payout-bar">
|
|
<div class="pol-payout-paid" :style="{ width: (policy.commission.paid / policy.commission.earned * 100) + '%' }" />
|
|
</div>
|
|
<div class="pol-payout-legend">
|
|
<span class="pol-payout-legend-item"><span class="pol-payout-dot pol-payout-dot-paid" /> Paid {{ fmtMoney(policy.commission.paid) }}</span>
|
|
<span class="pol-payout-legend-item"><span class="pol-payout-dot pol-payout-dot-owed" /> Owed {{ fmtMoney(policy.commission.owed) }}</span>
|
|
</div>
|
|
</div>
|
|
<div class="pol-info-grid" style="margin-top: 12px;">
|
|
<div class="pol-info-item">
|
|
<span class="pol-label">Total Earned</span>
|
|
<span class="pol-value pol-value-bold">{{ fmtMoney(policy.commission.earned) }}</span>
|
|
</div>
|
|
<div class="pol-info-item">
|
|
<span class="pol-label">Paid to Agent</span>
|
|
<span class="pol-value" style="color: #059669;">{{ fmtMoney(policy.commission.paid) }}</span>
|
|
</div>
|
|
<div class="pol-info-item">
|
|
<span class="pol-label">Amount Owed</span>
|
|
<span class="pol-value pol-value-bold" style="color: #d97706;">{{ fmtMoney(policy.commission.owed) }}</span>
|
|
</div>
|
|
<div class="pol-info-item">
|
|
<span class="pol-label">Next Payment Date</span>
|
|
<span class="pol-value">{{ fmtDate(policy.commission.nextPaymentDate) }}</span>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Related Policies -->
|
|
<div v-if="policy.economicGroup" class="pol-card pol-card-flush pol-grid-span-2">
|
|
<div class="pol-card-head">
|
|
<div style="display: flex; align-items: center; gap: 8px;">
|
|
<UIcon name="i-heroicons-building-library" class="w-4 h-4" style="color: #01696f;" />
|
|
<span>{{ policy.economicGroup }}</span>
|
|
</div>
|
|
<span class="pol-card-head-count">{{ policy.relatedPolicies.length }} related</span>
|
|
</div>
|
|
<div class="pol-table-wrap">
|
|
<table class="pol-table">
|
|
<thead><tr>
|
|
<th class="pol-th">Policy #</th><th class="pol-th">LOB</th><th class="pol-th">Titular</th><th class="pol-th">Status</th>
|
|
</tr></thead>
|
|
<tbody>
|
|
<tr v-for="rp in policy.relatedPolicies" :key="rp.id" class="pol-row" style="cursor: pointer;">
|
|
<td class="pol-td"><NuxtLink :to="`/policies/${rp.id}`" class="pol-customer-link">{{ rp.policyNumber }}</NuxtLink></td>
|
|
<td class="pol-td">{{ rp.lob }}</td>
|
|
<td class="pol-td">{{ rp.titular }}</td>
|
|
<td class="pol-td"><span class="pol-status-badge pol-status-pill" :class="statusClass(rp.status)">{{ statusLabel(rp.status) }}</span></td>
|
|
</tr>
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</template>
|
|
|
|
<!-- ═══════════════════ CLAIMS TAB ═══════════════════ -->
|
|
<template v-if="activeTab === 'claims'">
|
|
<div class="pol-card pol-card-flush">
|
|
<div class="pol-card-head">
|
|
<span>Claims History</span>
|
|
<span class="pol-card-head-count">{{ policy.claims.length }}</span>
|
|
</div>
|
|
<div class="pol-table-wrap">
|
|
<table class="pol-table">
|
|
<thead><tr>
|
|
<th class="pol-th">Claim ID</th><th class="pol-th">Date Filed</th><th class="pol-th">Type</th><th class="pol-th">Status</th><th class="pol-th pol-th-right">Amount</th><th class="pol-th pol-th-actions" />
|
|
</tr></thead>
|
|
<tbody>
|
|
<template v-for="c in policy.claims" :key="c.id">
|
|
<tr class="pol-row pol-row-clickable" @click="toggleClaim(c.id)">
|
|
<td class="pol-td"><NuxtLink :to="`/claims/${c.id}`" class="pol-policy-link pol-mono" @click.stop>{{ c.id }}</NuxtLink></td>
|
|
<td class="pol-td">{{ fmtDate(c.date) }}</td>
|
|
<td class="pol-td">{{ c.type }}</td>
|
|
<td class="pol-td"><span class="pol-status-badge pol-status-pill" :class="statusClass(c.status)">{{ c.status }}</span></td>
|
|
<td class="pol-td pol-td-right pol-value-bold">{{ fmtMoney(c.amount) }}</td>
|
|
<td class="pol-td pol-td-actions">
|
|
<UIcon :name="expandedClaim === c.id ? 'i-heroicons-chevron-up' : 'i-heroicons-chevron-down'" class="w-4 h-4" style="color: #8a8a86;" />
|
|
</td>
|
|
</tr>
|
|
<tr v-if="expandedClaim === c.id" class="pol-claim-expand-row">
|
|
<td colspan="6" class="pol-claim-expand-cell">
|
|
<p class="pol-claim-desc">{{ c.description }}</p>
|
|
</td>
|
|
</tr>
|
|
</template>
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
</div>
|
|
</template>
|
|
|
|
<!-- ═══════════════════ RENEWALS TAB ═══════════════════ -->
|
|
<template v-if="activeTab === 'renewals'">
|
|
<div class="pol-card pol-card-flush">
|
|
<div class="pol-card-head">
|
|
<span>Renewal History</span>
|
|
<span class="pol-card-head-count">{{ policy.renewals.length }} periods</span>
|
|
</div>
|
|
<div class="pol-table-wrap">
|
|
<table class="pol-table">
|
|
<thead><tr>
|
|
<th class="pol-th">Period</th><th class="pol-th pol-th-right">Premium</th><th class="pol-th pol-th-right">Change</th><th class="pol-th">Status</th>
|
|
</tr></thead>
|
|
<tbody>
|
|
<tr v-for="(r, idx) in policy.renewals" :key="r.period" class="pol-row">
|
|
<td class="pol-td pol-value-bold">{{ r.period }}</td>
|
|
<td class="pol-td pol-td-right pol-value-bold">{{ fmtMoney(r.premium) }}</td>
|
|
<td class="pol-td pol-td-right">
|
|
<span v-if="renewalChange(idx) !== null" class="pol-renewal-change" :class="Number(renewalChange(idx)) > 0 ? 'pol-change-up' : 'pol-change-down'">
|
|
{{ Number(renewalChange(idx)) > 0 ? '+' : '' }}{{ renewalChange(idx) }}%
|
|
</span>
|
|
<span v-else class="pol-value" style="color: #8a8a86;">—</span>
|
|
</td>
|
|
<td class="pol-td"><span class="pol-status-badge pol-status-pill" :class="statusClass(r.status)">{{ r.status }}</span></td>
|
|
</tr>
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
</div>
|
|
</template>
|
|
|
|
<!-- ═══════════════════ DOCUMENTS TAB ═══════════════════ -->
|
|
<template v-if="activeTab === 'documents'">
|
|
<div class="pol-docs-grid">
|
|
<div v-for="doc in policy.documents" :key="doc.id" class="pol-card pol-card-padded pol-doc-card">
|
|
<div class="pol-doc-row">
|
|
<div class="pol-doc-icon-wrap">
|
|
<UIcon name="i-heroicons-document-text" class="w-5 h-5" />
|
|
</div>
|
|
<div class="pol-doc-info">
|
|
<div class="pol-doc-name">{{ doc.name }}</div>
|
|
<div class="pol-doc-meta">
|
|
<span class="pol-doc-type-badge" :class="docTypeClass(doc.type)">{{ doc.type }}</span>
|
|
<span>{{ fmtDate(doc.date) }}</span>
|
|
<span class="pol-detail-sep">·</span>
|
|
<span>{{ doc.size }}</span>
|
|
</div>
|
|
</div>
|
|
<button class="pol-btn-secondary pol-btn-sm">
|
|
<UIcon name="i-heroicons-arrow-down-tray" class="w-3.5 h-3.5" />
|
|
Download
|
|
</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</template>
|
|
|
|
<!-- ═══════════════════ VIEW POLICY TAB ═══════════════════ -->
|
|
<template v-if="activeTab === 'view-policy'">
|
|
<div class="pol-vd-layout">
|
|
<!-- Sidebar -->
|
|
<div class="pol-vd-sidebar">
|
|
<template v-for="group in viewableDocGroups" :key="group.label">
|
|
<template v-if="group.items.length">
|
|
<div class="pol-vd-group-label">{{ group.label }}</div>
|
|
<button
|
|
v-for="doc in group.items"
|
|
:key="doc.id"
|
|
class="pol-vd-card"
|
|
:class="selectedDoc.id === doc.id ? 'pol-vd-card-active' : ''"
|
|
@click="selectedDoc = doc"
|
|
>
|
|
<div class="pol-vd-card-name">{{ doc.name }}</div>
|
|
<div class="pol-vd-card-meta">
|
|
<span class="pol-vd-type-badge" :class="docTypeBadgeClass(doc.type)">{{ docTypeBadgeLabel(doc.type) }}</span>
|
|
<span class="pol-vd-pages">{{ doc.pages }} {{ doc.pages === 1 ? 'page' : 'pages' }}</span>
|
|
</div>
|
|
</button>
|
|
</template>
|
|
</template>
|
|
</div>
|
|
|
|
<!-- Viewer Panel -->
|
|
<div class="pol-vd-viewer">
|
|
<!-- Toolbar -->
|
|
<div class="pol-vd-toolbar">
|
|
<div class="pol-vd-toolbar-left">
|
|
<UIcon name="i-heroicons-document-text" class="w-4 h-4" style="color: #01696f;" />
|
|
<span class="pol-vd-toolbar-name">{{ selectedDoc.name }}</span>
|
|
</div>
|
|
<div class="pol-vd-toolbar-center">
|
|
<span class="pol-vd-page-indicator">Page 1 of {{ selectedDoc.pages }}</span>
|
|
</div>
|
|
<div class="pol-vd-toolbar-right">
|
|
<button class="pol-vd-zoom-btn" title="Zoom out">
|
|
<UIcon name="i-heroicons-minus" class="w-3.5 h-3.5" />
|
|
</button>
|
|
<span class="pol-vd-zoom-level">100%</span>
|
|
<button class="pol-vd-zoom-btn" title="Zoom in">
|
|
<UIcon name="i-heroicons-plus" class="w-3.5 h-3.5" />
|
|
</button>
|
|
<div class="pol-vd-toolbar-sep" />
|
|
<button class="pol-btn-secondary pol-btn-sm">
|
|
<UIcon name="i-heroicons-arrow-down-tray" class="w-3.5 h-3.5" />
|
|
Download
|
|
</button>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- PDF Placeholder -->
|
|
<div class="pol-vd-pdf-area">
|
|
<div class="pol-vd-pdf-paper">
|
|
<UIcon name="i-heroicons-document-text" class="pol-vd-pdf-icon" />
|
|
<div class="pol-vd-pdf-label">PDF preview</div>
|
|
<div class="pol-vd-pdf-docname">{{ selectedDoc.name }}</div>
|
|
<div class="pol-vd-pdf-pages">{{ selectedDoc.pages }} {{ selectedDoc.pages === 1 ? 'page' : 'pages' }}</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</template>
|
|
|
|
<!-- ═══════════════════ ACTIVITY TAB ═══════════════════ -->
|
|
<template v-if="activeTab === 'activity'">
|
|
<div class="pol-card pol-card-padded">
|
|
<div class="pol-card-title" style="margin-bottom: 16px;">Activity Timeline</div>
|
|
<div class="pol-timeline">
|
|
<div v-for="(a, idx) in policy.activity" :key="idx" class="pol-timeline-item">
|
|
<div class="pol-timeline-line-wrap">
|
|
<div class="pol-timeline-dot" />
|
|
<div v-if="idx < policy.activity.length - 1" class="pol-timeline-line" />
|
|
</div>
|
|
<div class="pol-timeline-content">
|
|
<div class="pol-timeline-header">
|
|
<span class="pol-timeline-action">{{ a.action }}</span>
|
|
<span class="pol-timeline-date">{{ fmtDate(a.date) }}</span>
|
|
</div>
|
|
<div class="pol-timeline-detail">{{ a.detail }}</div>
|
|
<div class="pol-timeline-agent">
|
|
<span class="pol-agent-circle">{{ a.agent.split(' ').map(w => w[0]).join('').slice(0, 2) }}</span>
|
|
{{ a.agent }}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</template>
|
|
</div>
|
|
</template>
|
|
|
|
<style scoped>
|
|
/* =====================================================================
|
|
POLICY DETAIL PAGE — scoped, pol- prefix
|
|
===================================================================== */
|
|
|
|
.pol-root {
|
|
--pol-brand: #01696f;
|
|
--pol-brand-soft: rgba(1, 105, 111, 0.06);
|
|
--pol-border: rgba(0, 0, 0, 0.06);
|
|
--pol-border-strong: rgba(0, 0, 0, 0.08);
|
|
--pol-muted: #8a8a86;
|
|
--pol-surface: #ffffff;
|
|
}
|
|
|
|
/* ---- Back link ---- */
|
|
.pol-back-link {
|
|
display: inline-flex;
|
|
align-items: center;
|
|
gap: 5px;
|
|
font-size: 12px;
|
|
font-weight: 500;
|
|
color: var(--pol-muted);
|
|
text-decoration: none;
|
|
margin-bottom: 12px;
|
|
transition: color 150ms ease;
|
|
}
|
|
.pol-back-link:hover { color: var(--pol-brand); }
|
|
|
|
/* ---- Detail header ---- */
|
|
.pol-detail-header {
|
|
display: flex;
|
|
align-items: flex-start;
|
|
justify-content: space-between;
|
|
gap: 16px;
|
|
margin-bottom: 20px;
|
|
flex-wrap: wrap;
|
|
}
|
|
.pol-detail-header-left { display: flex; flex-direction: column; gap: 6px; }
|
|
.pol-detail-header-right { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
|
|
.pol-detail-title-row { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; }
|
|
.pol-detail-title {
|
|
font-size: 22px;
|
|
font-weight: 700;
|
|
letter-spacing: -0.01em;
|
|
color: var(--text-primary, #1a1a1a);
|
|
line-height: 1;
|
|
}
|
|
.pol-detail-subtitle {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 6px;
|
|
font-size: 13px;
|
|
color: var(--text-muted, #5c5650);
|
|
}
|
|
.pol-detail-sep { color: var(--pol-muted); opacity: 0.5; }
|
|
|
|
/* ---- LOB chip ---- */
|
|
.pol-lob-chip {
|
|
display: inline-flex;
|
|
align-items: center;
|
|
gap: 4px;
|
|
font-size: 11px;
|
|
font-weight: 600;
|
|
padding: 2px 8px 2px 5px;
|
|
border-radius: 10px;
|
|
white-space: nowrap;
|
|
}
|
|
.pol-lob-auto { background: rgba(59, 130, 246, 0.08); color: #2563eb; }
|
|
.pol-lob-health { background: rgba(236, 72, 153, 0.08); color: #db2777; }
|
|
.pol-lob-life { background: rgba(16, 185, 129, 0.08); color: #059669; }
|
|
.pol-lob-general-risk { background: rgba(245, 158, 11, 0.08); color: #d97706; }
|
|
|
|
/* ---- Main tabs ---- */
|
|
.pol-main-tabs {
|
|
display: inline-flex;
|
|
gap: 2px;
|
|
padding: 3px;
|
|
border-radius: 8px;
|
|
background: rgba(0, 0, 0, 0.04);
|
|
margin-bottom: 20px;
|
|
}
|
|
.pol-main-tab {
|
|
display: inline-flex;
|
|
align-items: center;
|
|
gap: 5px;
|
|
padding: 6px 12px;
|
|
border-radius: 6px;
|
|
font-size: 12px;
|
|
font-weight: 500;
|
|
border: none;
|
|
cursor: pointer;
|
|
transition: all 150ms ease;
|
|
white-space: nowrap;
|
|
}
|
|
.pol-main-tab-on {
|
|
background: #fff;
|
|
color: var(--text-primary, #1a1a1a);
|
|
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.08);
|
|
}
|
|
.pol-main-tab-off {
|
|
background: transparent;
|
|
color: var(--pol-muted);
|
|
}
|
|
.pol-main-tab-off:hover { color: var(--text-primary, #1a1a1a); }
|
|
|
|
/* ---- Tab count badge ---- */
|
|
.pol-tab-count {
|
|
font-size: 9px;
|
|
font-weight: 600;
|
|
padding: 0px 5px;
|
|
border-radius: 9999px;
|
|
background: rgba(0, 0, 0, 0.06);
|
|
color: var(--pol-muted);
|
|
}
|
|
.pol-tab-count-on { background: rgba(1, 105, 111, 0.1); color: var(--pol-brand); }
|
|
|
|
/* ---- Cards ---- */
|
|
.pol-card {
|
|
background: var(--pol-surface);
|
|
border-radius: 12px;
|
|
border: 1px solid var(--pol-border);
|
|
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.03);
|
|
}
|
|
.pol-card-padded { padding: 20px; }
|
|
.pol-card-flush { overflow: hidden; }
|
|
.pol-card-title {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 6px;
|
|
font-size: 14px;
|
|
font-weight: 600;
|
|
color: var(--text-primary, #1a1a1a);
|
|
margin-bottom: 14px;
|
|
}
|
|
.pol-card-head {
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: space-between;
|
|
padding: 10px 16px;
|
|
border-bottom: 1px solid var(--pol-border);
|
|
font-size: 13px;
|
|
font-weight: 600;
|
|
color: var(--text-primary, #1a1a1a);
|
|
}
|
|
.pol-card-head-count {
|
|
font-size: 11px;
|
|
font-weight: 600;
|
|
color: var(--pol-muted);
|
|
background: rgba(0, 0, 0, 0.04);
|
|
padding: 2px 8px;
|
|
border-radius: 10px;
|
|
}
|
|
|
|
/* ---- 2-col grid ---- */
|
|
.pol-grid-2 {
|
|
display: grid;
|
|
grid-template-columns: 1fr 1fr;
|
|
gap: 12px;
|
|
}
|
|
.pol-grid-span-2 { grid-column: span 2; }
|
|
|
|
/* ---- Info grid (label/value pairs) ---- */
|
|
.pol-info-grid {
|
|
display: grid;
|
|
grid-template-columns: 1fr 1fr;
|
|
gap: 14px 24px;
|
|
}
|
|
.pol-info-item {
|
|
display: flex;
|
|
flex-direction: column;
|
|
gap: 3px;
|
|
}
|
|
.pol-label {
|
|
font-size: 11px;
|
|
font-weight: 600;
|
|
text-transform: uppercase;
|
|
letter-spacing: 0.04em;
|
|
color: var(--pol-muted);
|
|
}
|
|
.pol-value {
|
|
font-size: 13px;
|
|
color: var(--text-primary, #1a1a1a);
|
|
}
|
|
.pol-value-bold { font-weight: 600; }
|
|
.pol-mono {
|
|
font-family: ui-monospace, 'SF Mono', 'Cascadia Mono', monospace;
|
|
font-size: 12px;
|
|
}
|
|
|
|
/* ---- Buttons ---- */
|
|
.pol-btn-primary {
|
|
display: inline-flex;
|
|
align-items: center;
|
|
gap: 6px;
|
|
padding: 7px 14px;
|
|
font-size: 12px;
|
|
font-weight: 600;
|
|
color: #ffffff;
|
|
background: var(--pol-brand);
|
|
border: none;
|
|
border-radius: 8px;
|
|
cursor: pointer;
|
|
transition: background 150ms ease;
|
|
}
|
|
.pol-btn-primary:hover { background: #015258; }
|
|
.pol-btn-secondary {
|
|
display: inline-flex;
|
|
align-items: center;
|
|
gap: 6px;
|
|
padding: 7px 14px;
|
|
font-size: 12px;
|
|
font-weight: 600;
|
|
color: var(--text-primary, #1a1a1a);
|
|
background: #ffffff;
|
|
border: 1px solid var(--pol-border-strong);
|
|
border-radius: 8px;
|
|
cursor: pointer;
|
|
transition: all 150ms ease;
|
|
}
|
|
.pol-btn-secondary:hover {
|
|
border-color: rgba(1, 105, 111, 0.2);
|
|
color: var(--pol-brand);
|
|
}
|
|
.pol-btn-sm { padding: 5px 10px; font-size: 11px; }
|
|
|
|
/* ---- Status badges ---- */
|
|
.pol-status-badge {
|
|
display: inline-block;
|
|
font-size: 10px;
|
|
font-weight: 600;
|
|
padding: 2px 8px;
|
|
border-radius: 10px;
|
|
white-space: nowrap;
|
|
}
|
|
.pol-status-pill { border-radius: 9999px; }
|
|
.pol-status-active { background: rgba(16, 185, 129, 0.1); color: #059669; }
|
|
.pol-status-pending { background: rgba(245, 158, 11, 0.1); color: #d97706; }
|
|
.pol-status-lapsed { background: rgba(244, 63, 94, 0.1); color: #e11d48; }
|
|
.pol-status-cancelled { background: rgba(0, 0, 0, 0.05); color: var(--pol-muted); }
|
|
.pol-status-expired { background: rgba(249, 115, 22, 0.1); color: #ea580c; }
|
|
|
|
/* ---- Payment status ---- */
|
|
.pol-pay-badge {
|
|
display: inline-block;
|
|
font-size: 10px;
|
|
font-weight: 600;
|
|
padding: 2px 8px;
|
|
border-radius: 9999px;
|
|
white-space: nowrap;
|
|
}
|
|
.pol-pay-current { background: rgba(16, 185, 129, 0.1); color: #059669; }
|
|
.pol-pay-overdue { background: rgba(244, 63, 94, 0.1); color: #e11d48; }
|
|
.pol-pay-grace { background: rgba(245, 158, 11, 0.1); color: #d97706; }
|
|
|
|
/* ---- Divider ---- */
|
|
.pol-divider {
|
|
height: 1px;
|
|
background: var(--pol-border);
|
|
margin: 12px 0;
|
|
}
|
|
|
|
/* ---- Coverage ---- */
|
|
.pol-coverage-header {
|
|
display: grid;
|
|
grid-template-columns: 1fr 1fr;
|
|
gap: 14px;
|
|
}
|
|
.pol-coverage-list { display: flex; flex-direction: column; gap: 0; }
|
|
.pol-coverage-row {
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: space-between;
|
|
padding: 7px 0;
|
|
border-bottom: 1px solid rgba(0, 0, 0, 0.03);
|
|
}
|
|
.pol-coverage-row:last-child { border-bottom: none; }
|
|
.pol-coverage-label { font-size: 13px; color: var(--text-muted, #5c5650); }
|
|
.pol-coverage-value { font-size: 13px; font-weight: 600; color: var(--text-primary, #1a1a1a); }
|
|
|
|
/* ---- Policyholder ---- */
|
|
.pol-holder-info {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 12px;
|
|
margin-bottom: 4px;
|
|
}
|
|
.pol-holder-avatar {
|
|
width: 40px;
|
|
height: 40px;
|
|
border-radius: 10px;
|
|
background: var(--pol-brand-soft);
|
|
color: var(--pol-brand);
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
flex-shrink: 0;
|
|
}
|
|
.pol-holder-name { font-size: 14px; font-weight: 600; color: var(--text-primary, #1a1a1a); }
|
|
.pol-holder-cedula { font-size: 12px; color: var(--pol-muted); font-family: ui-monospace, 'SF Mono', 'Cascadia Mono', monospace; }
|
|
|
|
/* ---- Fleet banner ---- */
|
|
.pol-fleet-banner {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 10px;
|
|
padding: 10px 14px;
|
|
border-radius: 8px;
|
|
background: rgba(59, 130, 246, 0.04);
|
|
border: 1px solid rgba(59, 130, 246, 0.1);
|
|
color: #2563eb;
|
|
}
|
|
.pol-fleet-name { font-size: 13px; font-weight: 600; display: block; }
|
|
.pol-fleet-discount { font-size: 11px; font-weight: 500; opacity: 0.8; display: block; margin-top: 1px; }
|
|
|
|
/* ---- Table ---- */
|
|
.pol-table-wrap { overflow-x: auto; }
|
|
.pol-table {
|
|
width: 100%;
|
|
border-collapse: collapse;
|
|
font-size: 13px;
|
|
}
|
|
.pol-th {
|
|
padding: 8px 12px;
|
|
text-align: left;
|
|
font-size: 11px;
|
|
font-weight: 600;
|
|
text-transform: uppercase;
|
|
letter-spacing: 0.04em;
|
|
color: var(--pol-muted);
|
|
border-bottom: 1px solid var(--pol-border);
|
|
white-space: nowrap;
|
|
}
|
|
.pol-th-right { text-align: right; }
|
|
.pol-th-actions { text-align: center; width: 48px; }
|
|
.pol-td {
|
|
padding: 8px 12px;
|
|
vertical-align: middle;
|
|
border-bottom: 1px solid rgba(0, 0, 0, 0.03);
|
|
font-size: 13px;
|
|
}
|
|
.pol-td-right { text-align: right; }
|
|
.pol-td-actions { text-align: center; white-space: nowrap; }
|
|
.pol-row { transition: background 120ms ease; }
|
|
.pol-row:hover { background: rgba(0, 0, 0, 0.015); }
|
|
.pol-row:last-child .pol-td { border-bottom: none; }
|
|
.pol-row-clickable { cursor: pointer; }
|
|
|
|
/* ---- Customer link ---- */
|
|
.pol-customer-link {
|
|
font-size: 13px;
|
|
font-weight: 500;
|
|
color: var(--pol-brand);
|
|
text-decoration: none;
|
|
transition: color 150ms ease;
|
|
}
|
|
.pol-customer-link:hover { color: #015258; text-decoration: underline; }
|
|
|
|
/* ---- Endorsement type ---- */
|
|
.pol-endorse-type {
|
|
display: inline-block;
|
|
font-size: 11px;
|
|
font-weight: 600;
|
|
padding: 2px 7px;
|
|
border-radius: 6px;
|
|
background: rgba(139, 92, 246, 0.08);
|
|
color: #7c3aed;
|
|
}
|
|
|
|
/* ---- Claims expand ---- */
|
|
.pol-claim-expand-row { background: rgba(0, 0, 0, 0.015); }
|
|
.pol-claim-expand-cell { padding: 12px 16px !important; border-bottom: 1px solid var(--pol-border); }
|
|
.pol-claim-desc { font-size: 13px; color: var(--text-muted, #5c5650); line-height: 1.5; margin: 0; }
|
|
|
|
/* ---- Renewal change ---- */
|
|
.pol-renewal-change { font-size: 12px; font-weight: 600; }
|
|
.pol-change-up { color: #e11d48; }
|
|
.pol-change-down { color: #059669; }
|
|
|
|
/* ---- Documents grid ---- */
|
|
.pol-docs-grid { display: flex; flex-direction: column; gap: 8px; }
|
|
.pol-doc-card { padding: 14px 18px !important; }
|
|
.pol-doc-row {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 14px;
|
|
}
|
|
.pol-doc-icon-wrap {
|
|
width: 38px;
|
|
height: 38px;
|
|
border-radius: 10px;
|
|
background: var(--pol-brand-soft);
|
|
color: var(--pol-brand);
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
flex-shrink: 0;
|
|
}
|
|
.pol-doc-info { flex: 1; min-width: 0; }
|
|
.pol-doc-name {
|
|
font-size: 13px;
|
|
font-weight: 600;
|
|
color: var(--text-primary, #1a1a1a);
|
|
white-space: nowrap;
|
|
overflow: hidden;
|
|
text-overflow: ellipsis;
|
|
}
|
|
.pol-doc-meta {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 6px;
|
|
font-size: 11px;
|
|
color: var(--pol-muted);
|
|
margin-top: 3px;
|
|
}
|
|
.pol-doc-type-badge {
|
|
display: inline-block;
|
|
font-size: 9px;
|
|
font-weight: 700;
|
|
text-transform: uppercase;
|
|
letter-spacing: 0.04em;
|
|
padding: 1px 6px;
|
|
border-radius: 4px;
|
|
}
|
|
.pol-doc-poliza { background: rgba(1, 105, 111, 0.08); color: var(--pol-brand); }
|
|
.pol-doc-endoso { background: rgba(139, 92, 246, 0.08); color: #7c3aed; }
|
|
.pol-doc-certificado { background: rgba(59, 130, 246, 0.08); color: #2563eb; }
|
|
.pol-doc-recibo { background: rgba(245, 158, 11, 0.08); color: #d97706; }
|
|
.pol-doc-other { background: rgba(0, 0, 0, 0.05); color: var(--pol-muted); }
|
|
|
|
/* ---- Activity timeline ---- */
|
|
.pol-timeline { display: flex; flex-direction: column; }
|
|
.pol-timeline-item { display: flex; gap: 14px; }
|
|
.pol-timeline-line-wrap {
|
|
display: flex;
|
|
flex-direction: column;
|
|
align-items: center;
|
|
flex-shrink: 0;
|
|
width: 16px;
|
|
}
|
|
.pol-timeline-dot {
|
|
width: 10px;
|
|
height: 10px;
|
|
border-radius: 50%;
|
|
background: var(--pol-brand);
|
|
flex-shrink: 0;
|
|
margin-top: 4px;
|
|
}
|
|
.pol-timeline-line {
|
|
width: 2px;
|
|
flex: 1;
|
|
background: var(--pol-border);
|
|
min-height: 20px;
|
|
}
|
|
.pol-timeline-content {
|
|
flex: 1;
|
|
padding-bottom: 20px;
|
|
}
|
|
.pol-timeline-header {
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: space-between;
|
|
gap: 8px;
|
|
margin-bottom: 4px;
|
|
}
|
|
.pol-timeline-action {
|
|
font-size: 13px;
|
|
font-weight: 600;
|
|
color: var(--text-primary, #1a1a1a);
|
|
}
|
|
.pol-timeline-date {
|
|
font-size: 11px;
|
|
color: var(--pol-muted);
|
|
white-space: nowrap;
|
|
}
|
|
.pol-timeline-detail {
|
|
font-size: 13px;
|
|
color: var(--text-muted, #5c5650);
|
|
line-height: 1.5;
|
|
margin-bottom: 6px;
|
|
}
|
|
.pol-timeline-agent {
|
|
display: inline-flex;
|
|
align-items: center;
|
|
gap: 6px;
|
|
font-size: 11px;
|
|
color: var(--pol-muted);
|
|
font-weight: 500;
|
|
}
|
|
.pol-agent-circle {
|
|
width: 20px;
|
|
height: 20px;
|
|
border-radius: 50%;
|
|
background: var(--pol-brand-soft);
|
|
color: var(--pol-brand);
|
|
display: inline-flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
font-size: 8px;
|
|
font-weight: 700;
|
|
letter-spacing: 0.02em;
|
|
}
|
|
|
|
/* ---- Quick Info Strip ---- */
|
|
.pol-quick-strip {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 0;
|
|
padding: 12px 20px;
|
|
background: var(--pol-surface);
|
|
border-radius: 12px;
|
|
border: 1px solid var(--pol-border);
|
|
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.03);
|
|
margin-bottom: 20px;
|
|
}
|
|
.pol-quick-item {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 10px;
|
|
flex: 1;
|
|
min-width: 0;
|
|
}
|
|
.pol-quick-icon { color: var(--pol-brand); flex-shrink: 0; }
|
|
.pol-quick-data { display: flex; flex-direction: column; gap: 1px; }
|
|
.pol-quick-value {
|
|
font-size: 16px;
|
|
font-weight: 700;
|
|
color: var(--text-primary, #1a1a1a);
|
|
line-height: 1.2;
|
|
}
|
|
.pol-quick-warn { color: #e11d48; }
|
|
.pol-quick-label {
|
|
font-size: 10px;
|
|
font-weight: 600;
|
|
text-transform: uppercase;
|
|
letter-spacing: 0.04em;
|
|
color: var(--pol-muted);
|
|
}
|
|
.pol-quick-sep {
|
|
width: 1px;
|
|
height: 32px;
|
|
background: var(--pol-border);
|
|
margin: 0 16px;
|
|
flex-shrink: 0;
|
|
}
|
|
|
|
/* ---- Billing current tag ---- */
|
|
.pol-billing-current-tag {
|
|
display: inline-block;
|
|
font-size: 9px;
|
|
font-weight: 700;
|
|
text-transform: uppercase;
|
|
letter-spacing: 0.04em;
|
|
padding: 1px 6px;
|
|
border-radius: 4px;
|
|
background: rgba(16, 185, 129, 0.1);
|
|
color: #059669;
|
|
margin-left: 6px;
|
|
vertical-align: middle;
|
|
}
|
|
|
|
/* ---- Compact table ---- */
|
|
.pol-table-compact .pol-th { padding: 6px 10px; font-size: 10px; }
|
|
.pol-table-compact .pol-td { padding: 6px 10px; font-size: 12px; }
|
|
|
|
/* ---- Commission highlight ---- */
|
|
.pol-commission-highlight {
|
|
display: flex;
|
|
flex-direction: column;
|
|
align-items: center;
|
|
gap: 2px;
|
|
padding: 16px;
|
|
border-radius: 8px;
|
|
background: rgba(1, 105, 111, 0.04);
|
|
border: 1px solid rgba(1, 105, 111, 0.08);
|
|
margin-bottom: 4px;
|
|
}
|
|
.pol-commission-amount {
|
|
font-size: 22px;
|
|
font-weight: 700;
|
|
color: var(--pol-brand);
|
|
line-height: 1;
|
|
}
|
|
.pol-commission-rate {
|
|
font-size: 11px;
|
|
font-weight: 500;
|
|
color: var(--pol-muted);
|
|
}
|
|
|
|
/* ---- Agent Payout ---- */
|
|
.pol-agent-payout { padding: 0 0 4px; }
|
|
.pol-payout-bar {
|
|
height: 8px;
|
|
border-radius: 4px;
|
|
background: rgba(217, 119, 6, 0.15);
|
|
overflow: hidden;
|
|
margin-bottom: 8px;
|
|
}
|
|
.pol-payout-paid {
|
|
height: 100%;
|
|
border-radius: 4px;
|
|
background: #059669;
|
|
transition: width 0.3s ease;
|
|
}
|
|
.pol-payout-legend {
|
|
display: flex;
|
|
gap: 16px;
|
|
font-size: 12px;
|
|
color: var(--pol-text);
|
|
}
|
|
.pol-payout-legend-item {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 5px;
|
|
}
|
|
.pol-payout-dot {
|
|
display: inline-block;
|
|
width: 8px;
|
|
height: 8px;
|
|
border-radius: 50%;
|
|
}
|
|
.pol-payout-dot-paid { background: #059669; }
|
|
.pol-payout-dot-owed { background: #d97706; }
|
|
|
|
/* ---- View Policy (PDF Viewer) Tab ---- */
|
|
.pol-vd-layout {
|
|
display: flex;
|
|
gap: 0;
|
|
border: 1px solid rgba(0, 0, 0, 0.06);
|
|
border-radius: 12px;
|
|
overflow: hidden;
|
|
background: #fff;
|
|
min-height: 600px;
|
|
}
|
|
.pol-vd-sidebar {
|
|
width: 280px;
|
|
flex-shrink: 0;
|
|
padding: 16px;
|
|
overflow-y: auto;
|
|
background: #fafaf9;
|
|
border-right: 1px solid rgba(0, 0, 0, 0.06);
|
|
}
|
|
.pol-vd-group-label {
|
|
font-size: 11px;
|
|
font-weight: 600;
|
|
text-transform: uppercase;
|
|
letter-spacing: 0.04em;
|
|
color: #8a8a86;
|
|
margin: 16px 0 6px;
|
|
}
|
|
.pol-vd-group-label:first-child {
|
|
margin-top: 0;
|
|
}
|
|
.pol-vd-card {
|
|
display: block;
|
|
width: 100%;
|
|
text-align: left;
|
|
padding: 10px 12px;
|
|
border-radius: 8px;
|
|
border: 1px solid rgba(0, 0, 0, 0.06);
|
|
background: #fff;
|
|
margin-bottom: 6px;
|
|
cursor: pointer;
|
|
transition: all 0.15s ease;
|
|
}
|
|
.pol-vd-card:hover {
|
|
border-color: rgba(1, 105, 111, 0.25);
|
|
background: rgba(1, 105, 111, 0.02);
|
|
}
|
|
.pol-vd-card-active {
|
|
border-color: #01696f;
|
|
background: rgba(1, 105, 111, 0.06);
|
|
box-shadow: 0 0 0 1px rgba(1, 105, 111, 0.15);
|
|
}
|
|
.pol-vd-card-name {
|
|
font-size: 12.5px;
|
|
font-weight: 500;
|
|
color: #1a1a18;
|
|
line-height: 1.3;
|
|
margin-bottom: 6px;
|
|
}
|
|
.pol-vd-card-meta {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 8px;
|
|
}
|
|
.pol-vd-type-badge {
|
|
font-size: 10px;
|
|
font-weight: 600;
|
|
text-transform: uppercase;
|
|
letter-spacing: 0.03em;
|
|
padding: 1px 6px;
|
|
border-radius: 4px;
|
|
}
|
|
.pol-vd-badge-policy { background: rgba(1, 105, 111, 0.1); color: #01696f; }
|
|
.pol-vd-badge-endorsement { background: rgba(168, 85, 247, 0.1); color: #7c3aed; }
|
|
.pol-vd-badge-certificate { background: rgba(16, 185, 129, 0.1); color: #059669; }
|
|
.pol-vd-badge-related { background: rgba(59, 130, 246, 0.1); color: #2563eb; }
|
|
.pol-vd-pages {
|
|
font-size: 11px;
|
|
color: #8a8a86;
|
|
}
|
|
|
|
/* Viewer panel */
|
|
.pol-vd-viewer {
|
|
flex: 1;
|
|
display: flex;
|
|
flex-direction: column;
|
|
min-width: 0;
|
|
}
|
|
.pol-vd-toolbar {
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: space-between;
|
|
padding: 10px 16px;
|
|
border-bottom: 1px solid rgba(0, 0, 0, 0.06);
|
|
background: #fafaf9;
|
|
gap: 12px;
|
|
}
|
|
.pol-vd-toolbar-left {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 8px;
|
|
min-width: 0;
|
|
flex: 1;
|
|
}
|
|
.pol-vd-toolbar-name {
|
|
font-size: 12.5px;
|
|
font-weight: 500;
|
|
color: #1a1a18;
|
|
white-space: nowrap;
|
|
overflow: hidden;
|
|
text-overflow: ellipsis;
|
|
}
|
|
.pol-vd-toolbar-center {
|
|
flex-shrink: 0;
|
|
}
|
|
.pol-vd-page-indicator {
|
|
font-size: 12px;
|
|
color: #8a8a86;
|
|
font-weight: 500;
|
|
}
|
|
.pol-vd-toolbar-right {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 6px;
|
|
flex-shrink: 0;
|
|
}
|
|
.pol-vd-zoom-btn {
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
width: 28px;
|
|
height: 28px;
|
|
border-radius: 6px;
|
|
border: 1px solid rgba(0, 0, 0, 0.06);
|
|
background: #fff;
|
|
color: #6b6b67;
|
|
cursor: pointer;
|
|
transition: all 0.15s ease;
|
|
}
|
|
.pol-vd-zoom-btn:hover {
|
|
border-color: rgba(0, 0, 0, 0.12);
|
|
color: #1a1a18;
|
|
}
|
|
.pol-vd-zoom-level {
|
|
font-size: 11.5px;
|
|
font-weight: 500;
|
|
color: #6b6b67;
|
|
min-width: 36px;
|
|
text-align: center;
|
|
}
|
|
.pol-vd-toolbar-sep {
|
|
width: 1px;
|
|
height: 20px;
|
|
background: rgba(0, 0, 0, 0.08);
|
|
margin: 0 4px;
|
|
}
|
|
|
|
/* PDF area */
|
|
.pol-vd-pdf-area {
|
|
flex: 1;
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
padding: 32px;
|
|
background: #f0f0ee;
|
|
}
|
|
.pol-vd-pdf-paper {
|
|
width: 100%;
|
|
max-width: 520px;
|
|
min-height: 400px;
|
|
background: #fff;
|
|
border-radius: 4px;
|
|
box-shadow:
|
|
0 1px 3px rgba(0, 0, 0, 0.08),
|
|
0 4px 12px rgba(0, 0, 0, 0.04),
|
|
0 0 0 1px rgba(0, 0, 0, 0.04);
|
|
display: flex;
|
|
flex-direction: column;
|
|
align-items: center;
|
|
justify-content: center;
|
|
gap: 12px;
|
|
padding: 40px 24px;
|
|
}
|
|
.pol-vd-pdf-icon {
|
|
width: 48px;
|
|
height: 48px;
|
|
color: #c4c4c0;
|
|
}
|
|
.pol-vd-pdf-label {
|
|
font-size: 14px;
|
|
font-weight: 600;
|
|
color: #8a8a86;
|
|
letter-spacing: 0.02em;
|
|
}
|
|
.pol-vd-pdf-docname {
|
|
font-size: 12.5px;
|
|
color: #6b6b67;
|
|
text-align: center;
|
|
max-width: 360px;
|
|
line-height: 1.4;
|
|
}
|
|
.pol-vd-pdf-pages {
|
|
font-size: 11px;
|
|
color: #a3a3a0;
|
|
margin-top: 4px;
|
|
}
|
|
|
|
/* ---- Responsive ---- */
|
|
@media (max-width: 768px) {
|
|
.pol-grid-2 { grid-template-columns: 1fr; }
|
|
.pol-grid-span-2 { grid-column: span 1; }
|
|
.pol-info-grid { grid-template-columns: 1fr; }
|
|
.pol-detail-header { flex-direction: column; }
|
|
.pol-detail-header-right { width: 100%; }
|
|
.pol-main-tabs { overflow-x: auto; width: 100%; }
|
|
.pol-quick-strip { flex-wrap: wrap; gap: 12px; }
|
|
.pol-quick-sep { display: none; }
|
|
.pol-quick-item { flex: 0 0 calc(50% - 6px); }
|
|
.pol-vd-layout { flex-direction: column; }
|
|
.pol-vd-sidebar { width: 100%; border-right: none; border-bottom: 1px solid rgba(0, 0, 0, 0.06); max-height: 240px; }
|
|
}
|
|
</style>
|