// static/admin/js/prospects.js const prospectsLog = window.LogConfig.createLogger('prospecting-prospects'); function prospectsList() { return { ...data(), currentPage: 'prospects', prospects: [], loading: true, error: null, // Filters search: '', filterChannel: '', filterStatus: '', filterTier: '', // Pagination pagination: { page: 1, per_page: 20, total: 0, pages: 0 }, // Create modal showCreateModal: false, creating: false, newProspect: { channel: 'digital', domain_name: '', business_name: '', phone: '', email: '', city: '', source: 'street', notes: '', }, async init() { await I18n.loadModule('prospecting'); if (window._prospectsListInit) return; window._prospectsListInit = true; if (window.PlatformSettings) { this.pagination.per_page = await window.PlatformSettings.getRowsPerPage(); } prospectsLog.info('Prospects list initializing'); await this.loadProspects(); }, async loadProspects() { this.loading = true; this.error = null; try { const params = new URLSearchParams({ page: this.pagination.page, per_page: this.pagination.per_page, }); if (this.search) params.set('search', this.search); if (this.filterChannel) params.set('channel', this.filterChannel); if (this.filterStatus) params.set('status', this.filterStatus); if (this.filterTier) params.set('tier', this.filterTier); const response = await apiClient.get('/admin/prospecting/prospects?' + params); this.prospects = response.items || []; this.pagination.total = response.total || 0; this.pagination.pages = response.pages || 0; } catch (err) { this.error = err.message; prospectsLog.error('Failed to load prospects', err); } finally { this.loading = false; } }, async createProspect() { this.creating = true; try { const payload = { ...this.newProspect }; if (payload.channel === 'digital') { delete payload.business_name; delete payload.phone; delete payload.email; delete payload.city; } else { delete payload.domain_name; } await apiClient.post('/admin/prospecting/prospects', payload); Utils.showToast('Prospect created', 'success'); this.showCreateModal = false; this.resetNewProspect(); await this.loadProspects(); } catch (err) { Utils.showToast('Failed: ' + err.message, 'error'); } finally { this.creating = false; } }, resetNewProspect() { this.newProspect = { channel: 'digital', domain_name: '', business_name: '', phone: '', email: '', city: '', source: 'street', notes: '', }; }, goToPage(page) { this.pagination.page = page; this.loadProspects(); }, statusBadgeClass(status) { const classes = { pending: 'text-yellow-700 bg-yellow-100 dark:text-yellow-100 dark:bg-yellow-700', active: 'text-green-700 bg-green-100 dark:text-green-100 dark:bg-green-700', contacted: 'text-blue-700 bg-blue-100 dark:text-blue-100 dark:bg-blue-700', converted: 'text-purple-700 bg-purple-100 dark:text-purple-100 dark:bg-purple-700', inactive: 'text-gray-700 bg-gray-100 dark:text-gray-100 dark:bg-gray-700', error: 'text-red-700 bg-red-100 dark:text-red-100 dark:bg-red-700', }; return classes[status] || classes.pending; }, tierBadgeClass(tier) { const classes = { top_priority: 'text-red-700 bg-red-100 dark:text-red-100 dark:bg-red-700', quick_win: 'text-orange-700 bg-orange-100 dark:text-orange-100 dark:bg-orange-700', strategic: 'text-blue-700 bg-blue-100 dark:text-blue-100 dark:bg-blue-700', low_priority: 'text-gray-700 bg-gray-100 dark:text-gray-100 dark:bg-gray-700', }; return classes[tier] || classes.low_priority; }, scoreColor(score) { if (score == null) return 'text-gray-400'; if (score >= 70) return 'text-red-600'; if (score >= 50) return 'text-orange-600'; if (score >= 30) return 'text-blue-600'; return 'text-gray-600'; }, }; }