{% extends "base_sidebar.html" %} {% block title %}LIA – Renewals Dashboard{% endblock %} {% block alpine_data %}x-data="{ campaignId: 'live', searchQuery: '', myCustomersOnly: false, currentUserId: 'lia-bot', selectedCustomer: null, statusFilter: 'all', monthsFilter: null, paymentFilter: null, channelFilter: null, advisorFilter: 'all', campaignFilter: 'all', currentView: 'overview', loading: true, error: null, async init() { const params = new URLSearchParams(window.location.search); this.currentView = params.get('view') || 'overview'; const status = params.get('status'); if (this.currentView === 'live-campaign') { this.statusFilter = 'all'; } else if (this.currentView === 'all-customers') { this.statusFilter = 'all'; } else if (this.currentView === 'missed-opportunities' || status === 'declined') { this.statusFilter = 'declined'; } else if (this.currentView === 'no-response' || status === 'no-response') { this.statusFilter = 'no-response'; } else if (this.currentView === 'declined') { this.statusFilter = 'declined'; } await this.loadCustomers(); }, async loadCustomers() { this.loading = true; this.error = null; try { const response = await fetch('/api/lia/campaign-customers'); if (!response.ok) throw new Error('Failed to load customers'); const data = await response.json(); this.customers = data.customers || []; } catch (err) { this.error = err.message; this.customers = []; } finally { this.loading = false; } }, customers: [], get uniqueAdvisors() { const advisors = this.customers.map(c => c.assignedAdvisor).filter(a => a && a !== 'lia-bot' && a !== ''); return [...new Set(advisors)]; }, get uniqueCampaigns() { const campaigns = this.customers.map(c => c.campaign).filter(c => c && c !== ''); return [...new Set(campaigns)]; }, get hasActiveFilters() { return this.statusFilter !== 'all' || this.monthsFilter !== null || this.paymentFilter !== null || this.channelFilter !== null || this.advisorFilter !== 'all' || this.campaignFilter !== 'all' || this.searchQuery.trim() !== '' || this.myCustomersOnly; }, clearAllFilters() { this.statusFilter = 'all'; this.monthsFilter = null; this.paymentFilter = null; this.channelFilter = null; this.advisorFilter = 'all'; this.campaignFilter = 'all'; this.searchQuery = ''; this.myCustomersOnly = false; }, formatAdvisorName(email) { if (!email) return 'Unknown'; return email.split('@')[0].replace(/[._]/g, ' ').replace(/\b\w/g, l => l.toUpperCase()); }, get filteredCustomers() { return this.customers.filter(c => { // Status filter let statusMatch = true; if (this.statusFilter !== 'all') { if (this.statusFilter === 'engaged') statusMatch = ['ENGAGED', 'OFFER_SENT'].includes(c.status); else if (this.statusFilter === 'appointment') statusMatch = c.status === 'APPOINTMENT_BOOKED'; else if (this.statusFilter === 'sold') statusMatch = c.status === 'SOLD'; else if (this.statusFilter === 'declined') statusMatch = c.status === 'DECLINED'; else if (this.statusFilter === 'declined-offer') statusMatch = c.status === 'DECLINED_OFFER'; else if (this.statusFilter === 'no-response') statusMatch = ['NOT_CONTACTED', 'CONTACT_ATTEMPTED'].includes(c.status); } // Search filter (handle missing fields gracefully) let searchMatch = true; if (this.searchQuery.trim() !== '') { const query = this.searchQuery.toLowerCase(); searchMatch = (c.name || '').toLowerCase().includes(query) || (c.reg || '').toLowerCase().includes(query) || (c.phone || '').toLowerCase().includes(query) || (c.campaign || '').toLowerCase().includes(query) || (c.agreementNumber || '').toLowerCase().includes(query) || (c.model || '').toLowerCase().includes(query); } // Months remaining filter (matches milestone values from buttons: 3, 6, 9, 12) let monthsMatch = true; if (this.monthsFilter !== null) { monthsMatch = c.monthsRemaining <= this.monthsFilter; } // Payment band filter - filter by current payment ranges let paymentMatch = true; if (this.paymentFilter !== null) { const payment = c.currentPayment; if (payment === null || payment === undefined) { paymentMatch = false; } else { if (this.paymentFilter === 'under300') paymentMatch = payment < 300; else if (this.paymentFilter === '300to500') paymentMatch = payment >= 300 && payment <= 500; else if (this.paymentFilter === 'over500') paymentMatch = payment > 500; } } // Channel filter let channelMatch = true; if (this.channelFilter !== null) { channelMatch = (c.lastContactChannel || 'WhatsApp') === this.channelFilter; } // Advisor dropdown filter let advisorDropdownMatch = true; if (this.advisorFilter !== 'all') { if (this.advisorFilter === 'lia-bot') { advisorDropdownMatch = !c.assignedAdvisor || c.assignedAdvisor === 'lia-bot' || c.assignedAdvisor === ''; } else { advisorDropdownMatch = c.assignedAdvisor === this.advisorFilter; } } // Campaign dropdown filter let campaignMatch = true; if (this.campaignFilter !== 'all') { campaignMatch = c.campaign === this.campaignFilter; } // My Customers Only filter let advisorMatch = true; if (this.myCustomersOnly) { advisorMatch = c.assignedAdvisor === this.currentUserId; } return statusMatch && searchMatch && monthsMatch && paymentMatch && channelMatch && advisorDropdownMatch && campaignMatch && advisorMatch; }); }, getStatusColor(status) { const colors = { 'SOLD': 'bg-emerald-100 text-emerald-700 border-emerald-200', 'APPOINTMENT_BOOKED': 'bg-blue-100 text-blue-700 border-blue-200', 'ENGAGED': 'bg-indigo-100 text-indigo-700 border-indigo-200', 'OFFER_SENT': 'bg-purple-100 text-purple-700 border-purple-200', 'DECLINED': 'bg-red-100 text-red-700 border-red-200', 'DECLINED_OFFER': 'bg-orange-100 text-orange-700 border-orange-200', 'NOT_CONTACTED': 'bg-gray-100 text-gray-600 border-gray-200', 'CONTACT_ATTEMPTED': 'bg-yellow-100 text-yellow-700 border-yellow-200' }; return colors[status] || 'bg-gray-100 text-gray-600 border-gray-200'; }, getStatusLabel(status) { const labels = { 'SOLD': 'Sold', 'APPOINTMENT_BOOKED': 'Appointment Booked', 'ENGAGED': 'Engaged', 'OFFER_SENT': 'Offer Sent', 'DECLINED': 'Declined', 'DECLINED_OFFER': 'Declined Offer', 'NOT_CONTACTED': 'Not Contacted', 'CONTACT_ATTEMPTED': 'Contact Attempted' }; return labels[status] || status; }, getRowBgColor(status) { const colors = { 'SOLD': 'bg-emerald-50/30', 'APPOINTMENT_BOOKED': 'bg-blue-50/30', 'ENGAGED': 'bg-indigo-50/20', 'DECLINED': 'bg-red-50/20', 'DECLINED_OFFER': 'bg-orange-50/20' }; return colors[status] || 'bg-white'; } }"{% endblock %} {% block topbar %}
•
Current
£
-
Proposed
£
Stage
m
-
Last Touch
Next
No customers match your filters