Spaces:
Running
Running
| <html lang="en"> | |
| <head> | |
| <meta charset="UTF-8"> | |
| <meta name="viewport" content="width=device-width, initial-scale=1.0"> | |
| <title>Leads Management - HBU Asset Recovery</title> | |
| <link rel="icon" type="image/x-icon" href="/static/favicon.ico"> | |
| <script src="https://cdn.tailwindcss.com"></script> | |
| <script src="https://unpkg.com/feather-icons"></script> | |
| <link rel="stylesheet" href="style.css"> | |
| </head> | |
| <body class="bg-slate-900 text-slate-100"> | |
| <!-- Navigation --> | |
| <nav class="bg-slate-800 border-b border-orange-500/20 sticky top-0 z-50"> | |
| <div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8"> | |
| <div class="flex items-center justify-between h-16"> | |
| <div class="flex items-center"> | |
| <div class="flex-shrink-0 flex items-center"> | |
| <i data-feather="shield" class="text-orange-500 mr-2"></i> | |
| <span class="font-bold text-xl text-orange-500">HBU Asset Recovery</span> | |
| </div> | |
| </div> | |
| <div class="hidden md:block"> | |
| <div class="ml-10 flex items-baseline space-x-4"> | |
| <a href="index.html" class="text-slate-300 hover:bg-slate-700 hover:text-white px-3 py-2 rounded-md text-sm font-medium">Dashboard</a> | |
| <a href="leads.html" class="bg-orange-500 text-white px-3 py-2 rounded-md text-sm font-medium">Leads</a> | |
| <a href="automation.html" class="text-slate-300 hover:bg-slate-700 hover:text-white px-3 py-2 rounded-md text-sm font-medium">Automation</a> | |
| <a href="compliance.html" class="text-slate-300 hover:bg-slate-700 hover:text-white px-3 py-2 rounded-md text-sm font-medium">Compliance</a> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| </nav> | |
| <!-- Main Content --> | |
| <main class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-8"> | |
| <!-- Header Section --> | |
| <div class="flex items-center justify-between mb-8"> | |
| <div> | |
| <h1 class="text-3xl font-bold text-white">Lead Management</h1> | |
| <p class="text-slate-400 mt-1">Manage and track all asset recovery leads</p> | |
| </div> | |
| <button onclick="openAddLeadModal()" class="btn btn-primary"> | |
| <i data-feather="plus" class="h-4 w-4 mr-2"></i> | |
| Add New Lead | |
| </button> | |
| </div> | |
| <!-- Filters and Search --> | |
| <div class="bg-slate-800 rounded-lg p-6 mb-8"> | |
| <div class="grid grid-cols-1 md:grid-cols-4 gap-4"> | |
| <div> | |
| <input type="text" id="search-input" placeholder="Search leads..." | |
| class="form-input" onkeyup="filterLeads()"> | |
| </div> | |
| <div> | |
| <select id="status-filter" class="form-input" onchange="filterLeads()"> | |
| <option value="">All Statuses</option> | |
| <option value="NEW">New</option> | |
| <option value="ENRICHED">Enriched</option> | |
| <option value="CONTACTED">Contacted</option> | |
| <option value="NEGOTIATING">Negotiating</option> | |
| <option value="CLAIM_FILED">Claim Filed</option> | |
| <option value="RECOVERED">Recovered</option> | |
| </select> | |
| </div> | |
| <div> | |
| <select id="state-filter" class="form-input" onchange="filterLeads()"> | |
| <option value="">All States</option> | |
| <option value="OK">Oklahoma</option> | |
| <option value="FL">Florida</option> | |
| <option value="TX">Texas</option> | |
| <option value="CA">California</option> | |
| </select> | |
| </div> | |
| <div> | |
| <select id="value-filter" class="form-input" onchange="filterLeads()"> | |
| <option value="">All Values</option> | |
| <option value="0-10000">$0 - $10K</option> | |
| <option value="10000-50000">$10K - $50K</option> | |
| <option value="50000-100000">$50K - $100K</option> | |
| <option value="100000+">$100K+</option> | |
| </select> | |
| </div> | |
| </div> | |
| </div> | |
| <!-- Leads Table --> | |
| <div class="bg-slate-800 rounded-lg overflow-hidden"> | |
| <div class="overflow-x-auto"> | |
| <table class="table"> | |
| <thead> | |
| <tr> | |
| <th>Lead</th> | |
| <th>Contact</th> | |
| <th>Claim Amount</th> | |
| <th>ARV</th> | |
| <th>Equity %</th> | |
| <th>Status</th> | |
| <th>Score</th> | |
| <th>Actions</th> | |
| </tr> | |
| </thead> | |
| <tbody id="leads-table-body"> | |
| <!-- Leads will be loaded here --> | |
| </tbody> | |
| </table> | |
| </div> | |
| </div> | |
| <!-- Pagination --> | |
| <div class="flex items-center justify-between mt-6"> | |
| <div class="text-slate-400"> | |
| Showing <span id="showing-start">1</span> to <span id="showing-end">10</span> of <span id="total-leads">2,847</span> leads | |
| </div> | |
| <div class="flex space-x-2"> | |
| <button onclick="changePage(-1)" class="btn btn-secondary">Previous</button> | |
| <button onclick="changePage(1)" class="btn btn-secondary">Next</button> | |
| </div> | |
| </div> | |
| </main> | |
| <!-- Add Lead Modal --> | |
| <div id="add-lead-modal" class="modal hidden"> | |
| <div class="modal-content max-w-2xl"> | |
| <div class="flex items-center justify-between mb-6"> | |
| <h2 class="text-2xl font-bold text-white">Add New Lead</h2> | |
| <button onclick="closeAddLeadModal()" class="text-slate-400 hover:text-white"> | |
| <i data-feather="x" class="h-6 w-6"></i> | |
| </button> | |
| </div> | |
| <form id="add-lead-form" class="space-y-4"> | |
| <div class="grid grid-cols-2 gap-4"> | |
| <div class="form-group"> | |
| <label class="form-label">First Name *</label> | |
| <input type="text" name="firstName" class="form-input" required> | |
| </div> | |
| <div class="form-group"> | |
| <label class="form-label">Last Name *</label> | |
| <input type="text" name="lastName" class="form-input" required> | |
| </div> | |
| </div> | |
| <div class="grid grid-cols-2 gap-4"> | |
| <div class="form-group"> | |
| <label class="form-label">Phone</label> | |
| <input type="tel" name="phone" class="form-input"> | |
| </div> | |
| <div class="form-group"> | |
| <label class="form-label">Email</label> | |
| <input type="email" name="email" class="form-input"> | |
| </div> | |
| </div> | |
| <div class="form-group"> | |
| <label class="form-label">Address</label> | |
| <input type="text" name="address" class="form-input"> | |
| </div> | |
| <div class="grid grid-cols-3 gap-4"> | |
| <div class="form-group"> | |
| <label class="form-label">City</label> | |
| <input type="text" name="city" class="form-input"> | |
| </div> | |
| <div class="form-group"> | |
| <label class="form-label">State</label> | |
| <select name="state" class="form-input"> | |
| <option value="OK">Oklahoma</option> | |
| <option value="FL">Florida</option> | |
| <option value="TX">Texas</option> | |
| <option value="CA">California</option> | |
| </select> | |
| </div> | |
| <div class="form-group"> | |
| <label class="form-label">ZIP</label> | |
| <input type="text" name="zip" class="form-input"> | |
| </div> | |
| </div> | |
| <div class="grid grid-cols-2 gap-4"> | |
| <div class="form-group"> | |
| <label class="form-label">Claim Amount</label> | |
| <input type="number" name="claimAmount" class="form-input" step="0.01"> | |
| </div> | |
| <div class="form-group"> | |
| <label class="form-label">Source</label> | |
| <select name="source" class="form-input"> | |
| <option value="OSCN">OSCN</option> | |
| <option value="FLTreasure">FL Treasury</option> | |
| <option value="Manual">Manual</option> | |
| <option value="Referral">Referral</option> | |
| </select> | |
| </div> | |
| </div> | |
| <div class="flex justify-end space-x-4 mt-6"> | |
| <button type="button" onclick="closeAddLeadModal()" class="btn btn-secondary">Cancel</button> | |
| <button type="submit" class="btn btn-primary">Add Lead</button> | |
| </div> | |
| </form> | |
| </div> | |
| </div> | |
| <script src="script.js"></script> | |
| <script> | |
| // Lead management functionality | |
| class LeadManager { | |
| constructor() { | |
| this.leads = []; | |
| this.filteredLeads = []; | |
| this.currentPage = 1; | |
| this.leadsPerPage = 10; | |
| this.loadLeads(); | |
| } | |
| async loadLeads() { | |
| try { | |
| // Mock data - in real implementation, fetch from API | |
| this.leads = [ | |
| { | |
| id: '1', | |
| firstName: 'John', | |
| lastName: 'Doe', | |
| phone: '(555) 123-4567', | |
| email: 'john.doe@email.com', | |
| claimAmount: 45000, | |
| arv: 250000, | |
| equity: 78, | |
| status: 'NEGOTIATING', | |
| recoveryScore: 92, | |
| state: 'OK' | |
| }, | |
| { | |
| id: '2', | |
| firstName: 'Jane', | |
| lastName: 'Smith', | |
| phone: '(555) 987-6543', | |
| email: 'jane.smith@email.com', | |
| claimAmount: 120000, | |
| arv: 450000, | |
| equity: 85, | |
| status: 'CONTACTED', | |
| recoveryScore: 88, | |
| state: 'FL' | |
| }, | |
| { | |
| id: '3', | |
| firstName: 'Robert', | |
| lastName: 'Johnson', | |
| phone: '(555) 456-7890', | |
| email: 'robert.j@email.com', | |
| claimAmount: 35000, | |
| arv: 180000, | |
| equity: 65, | |
| status: 'ENRICHED', | |
| recoveryScore: 75, | |
| state: 'TX' | |
| } | |
| ]; | |
| this.filteredLeads = [...this.leads]; | |
| this.renderLeads(); | |
| } catch (error) { | |
| console.error('Failed to load leads:', error); | |
| showToast('Failed to load leads', 'error'); | |
| } | |
| } | |
| renderLeads() { | |
| const tbody = document.getElementById('leads-table-body'); | |
| if (!tbody) return; | |
| const start = (this.currentPage - 1) * this.leadsPerPage; | |
| const end = start + this.leadsPerPage; | |
| const pageLeads = this.filteredLeads.slice(start, end); | |
| tbody.innerHTML = pageLeads.map(lead => ` | |
| <tr class="hover:bg-slate-700/50"> | |
| <td> | |
| <div class="flex items-center"> | |
| <img class="h-8 w-8 rounded-full mr-3" src="http://static.photos/people/40x40/${lead.id}" alt="${lead.firstName}"> | |
| <div> | |
| <div class="text-white font-medium">${lead.firstName} ${lead.lastName}</div> | |
| <div class="text-slate-400 text-sm">${lead.state}</div> | |
| </div> | |
| </div> | |
| </td> | |
| <td> | |
| <div class="text-slate-300">${lead.phone}</div> | |
| <div class="text-slate-400 text-sm">${lead.email}</div> | |
| </td> | |
| <td class="text-white font-medium">$${lead.claimAmount.toLocaleString()}</td> | |
| <td class="text-slate-300">$${lead.arv.toLocaleString()}</td> | |
| <td> | |
| <div class="flex items-center"> | |
| <div class="w-16 bg-slate-700 rounded-full h-2 mr-2"> | |
| <div class="bg-orange-500 h-2 rounded-full" style="width: ${lead.equity}%"></div> | |
| </div> | |
| <span class="text-slate-300">${lead.equity}%</span> | |
| </div> | |
| </td> | |
| <td> | |
| <span class="badge badge-${this.getStatusColor(lead.status)}">${lead.status}</span> | |
| </td> | |
| <td> | |
| <div class="text-white font-medium">${lead.recoveryScore}</div> | |
| <div class="text-slate-400 text-sm">Score</div> | |
| </td> | |
| <td> | |
| <div class="flex space-x-2"> | |
| <button onclick="viewLead('${lead.id}')" class="text-blue-400 hover:text-blue-300"> | |
| <i data-feather="eye" class="h-4 w-4"></i> | |
| </button> | |
| <button onclick="skipTraceLead('${lead.id}')" class="text-green-400 hover:text-green-300"> | |
| <i data-feather="search" class="h-4 w-4"></i> | |
| </button> | |
| <button onclick="contactLead('${lead.id}')" class="text-orange-400 hover:text-orange-300"> | |
| <i data-feather="phone" class="h-4 w-4"></i> | |
| </button> | |
| <button onclick="editLead('${lead.id}')" class="text-slate-400 hover:text-slate-300"> | |
| <i data-feather="edit" class="h-4 w-4"></i> | |
| </button> | |
| </div> | |
| </td> | |
| </tr> | |
| `).join(''); | |
| feather.replace(); | |
| this.updatePagination(); | |
| } | |
| getStatusColor(status) { | |
| const colors = { | |
| 'NEW': 'info', | |
| 'ENRICHED': 'warning', | |
| 'CONTACTED': 'info', | |
| 'NEGOTIATING': 'warning', | |
| 'CLAIM_FILED': 'info', | |
| 'RECOVERED': 'success' | |
| }; | |
| return colors[status] || 'info'; | |
| } | |
| updatePagination() { | |
| const total = this.filteredLeads.length; | |
| const start = (this.currentPage - 1) * this.leadsPerPage + 1; | |
| const end = Math.min(this.currentPage * this.leadsPerPage, total); | |
| document.getElementById('showing-start').textContent = start; | |
| document.getElementById('showing-end').textContent = end; | |
| document.getElementById('total-leads').textContent = total; | |
| } | |
| filter(search, status, state, valueRange) { | |
| this.filteredLeads = this.leads.filter(lead => { | |
| const matchesSearch = !search || | |
| `${lead.firstName} ${lead.lastName}`.toLowerCase().includes(search.toLowerCase()) || | |
| lead.email?.toLowerCase().includes(search.toLowerCase()) || | |
| lead.phone?.includes(search); | |
| const matchesStatus = !status || lead.status === status; | |
| const matchesState = !state || lead.state === state; | |
| let matchesValue = true; | |
| if (valueRange) { | |
| const [min, max] = valueRange.split('-').map(v => v === '+' ? Infinity : parseInt(v)); | |
| matchesValue = lead.claimAmount >= min && lead.claimAmount <= max; | |
| } | |
| return matchesSearch && matchesStatus && matchesState && matchesValue; | |
| }); | |
| this.currentPage = 1; | |
| this.renderLeads(); | |
| } | |
| async addLead(leadData) { | |
| try { | |
| // In real implementation, send to API | |
| const newLead = { | |
| id: Date.now().toString(), | |
| ...leadData, | |
| status: 'NEW', | |
| recoveryScore: Math.floor(Math.random() * 30) + 70 | |
| }; | |
| this.leads.unshift(newLead); | |
| this.filteredLeads = [...this.leads]; | |
| this.renderLeads(); | |
| showToast('Lead added successfully', 'success'); | |
| closeAddLeadModal(); | |
| } catch (error) { | |
| console.error('Failed to add lead:', error); | |
| showToast('Failed to add lead', 'error'); | |
| } | |
| } | |
| } | |
| // Initialize lead manager | |
| const leadManager = new LeadManager(); | |
| // Global functions | |
| function filterLeads() { | |
| const search = document.getElementById('search-input').value; | |
| const status = document.getElementById('status-filter').value; | |
| const state = document.getElementById('state-filter').value; | |
| const valueRange = document.getElementById('value-filter').value; | |
| leadManager.filter(search, status, state, valueRange); | |
| } | |
| function changePage(direction) { | |
| const totalPages = Math.ceil(leadManager.filteredLeads.length / leadManager.leadsPerPage); | |
| leadManager.currentPage = Math.max(1, Math.min(totalPages, leadManager.currentPage + direction)); | |
| leadManager.renderLeads(); | |
| } | |
| function openAddLeadModal() { | |
| document.getElementById('add-lead-modal').classList.remove('hidden'); | |
| } | |
| function closeAddLeadModal() { | |
| document.getElementById('add-lead-modal').classList.add('hidden'); | |
| document.getElementById('add-lead-form').reset(); | |
| } | |
| function viewLead(id) { | |
| showToast(`Viewing lead ${id}`, 'info'); | |
| } | |
| function skipTraceLead(id) { | |
| showToast(`Skip tracing lead ${id}`, 'info'); | |
| } | |
| function contactLead(id) { | |
| showToast(`Contacting lead ${id}`, 'info'); | |
| } | |
| function editLead(id) { | |
| showToast(`Editing lead ${id}`, 'info'); | |
| } | |
| // Form submission | |
| document.getElementById('add-lead-form').addEventListener('submit', async (e) => { | |
| e.preventDefault(); | |
| const formData = new FormData(e.target); | |
| const leadData = Object.fromEntries(formData.entries()); | |
| await leadManager.addLead(leadData); | |
| }); | |
| </script> | |
| </body> | |
| </html> |