feat(prospecting): add complete prospecting module for lead discovery and scoring
Some checks failed
Some checks failed
Migrates scanning pipeline from marketing-.lu-domains app into Orion module. Supports digital (domain scan) and offline (manual capture) lead channels with enrichment, scoring, campaign management, and interaction tracking. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
137
app/modules/prospecting/static/admin/js/campaigns.js
Normal file
137
app/modules/prospecting/static/admin/js/campaigns.js
Normal file
@@ -0,0 +1,137 @@
|
||||
// static/admin/js/campaigns.js
|
||||
|
||||
const campLog = window.LogConfig.createLogger('prospecting-campaigns');
|
||||
|
||||
function campaignManager() {
|
||||
return {
|
||||
...data(),
|
||||
|
||||
currentPage: 'campaigns',
|
||||
|
||||
templates: [],
|
||||
loading: true,
|
||||
error: null,
|
||||
filterLeadType: '',
|
||||
|
||||
showCreateModal: false,
|
||||
showEditModal: false,
|
||||
editingTemplateId: null,
|
||||
|
||||
templateForm: {
|
||||
name: '',
|
||||
lead_type: 'no_website',
|
||||
channel: 'email',
|
||||
language: 'fr',
|
||||
subject_template: '',
|
||||
body_template: '',
|
||||
is_active: true,
|
||||
},
|
||||
|
||||
leadTypes: [
|
||||
{ value: 'no_website', label: 'No Website' },
|
||||
{ value: 'bad_website', label: 'Bad Website' },
|
||||
{ value: 'gmail_only', label: 'Gmail Only' },
|
||||
{ value: 'security_issues', label: 'Security Issues' },
|
||||
{ value: 'performance_issues', label: 'Performance Issues' },
|
||||
{ value: 'outdated_cms', label: 'Outdated CMS' },
|
||||
{ value: 'general', label: 'General' },
|
||||
],
|
||||
|
||||
placeholders: [
|
||||
'{business_name}', '{domain}', '{score}', '{issues}',
|
||||
'{primary_email}', '{primary_phone}', '{city}',
|
||||
],
|
||||
|
||||
async init() {
|
||||
await I18n.loadModule('prospecting');
|
||||
|
||||
if (window._campaignsInit) return;
|
||||
window._campaignsInit = true;
|
||||
|
||||
campLog.info('Campaign manager initializing');
|
||||
await this.loadTemplates();
|
||||
},
|
||||
|
||||
async loadTemplates() {
|
||||
this.loading = true;
|
||||
this.error = null;
|
||||
try {
|
||||
const response = await apiClient.get('/admin/prospecting/campaigns/templates');
|
||||
this.templates = response.items || response || [];
|
||||
} catch (err) {
|
||||
this.error = err.message;
|
||||
campLog.error('Failed to load templates', err);
|
||||
} finally {
|
||||
this.loading = false;
|
||||
}
|
||||
},
|
||||
|
||||
filteredTemplates() {
|
||||
if (!this.filterLeadType) return this.templates;
|
||||
return this.templates.filter(t => t.lead_type === this.filterLeadType);
|
||||
},
|
||||
|
||||
editTemplate(tpl) {
|
||||
this.editingTemplateId = tpl.id;
|
||||
this.templateForm = {
|
||||
name: tpl.name,
|
||||
lead_type: tpl.lead_type,
|
||||
channel: tpl.channel,
|
||||
language: tpl.language,
|
||||
subject_template: tpl.subject_template || '',
|
||||
body_template: tpl.body_template,
|
||||
is_active: tpl.is_active,
|
||||
};
|
||||
this.showEditModal = true;
|
||||
},
|
||||
|
||||
async saveTemplate() {
|
||||
try {
|
||||
if (this.showEditModal && this.editingTemplateId) {
|
||||
await apiClient.put(
|
||||
'/admin/prospecting/campaigns/templates/' + this.editingTemplateId,
|
||||
this.templateForm,
|
||||
);
|
||||
Utils.showToast('Template updated', 'success');
|
||||
} else {
|
||||
await apiClient.post('/admin/prospecting/campaigns/templates', this.templateForm);
|
||||
Utils.showToast('Template created', 'success');
|
||||
}
|
||||
this.showCreateModal = false;
|
||||
this.showEditModal = false;
|
||||
this.resetForm();
|
||||
await this.loadTemplates();
|
||||
} catch (err) {
|
||||
Utils.showToast('Failed: ' + err.message, 'error');
|
||||
}
|
||||
},
|
||||
|
||||
async deleteTemplate(id) {
|
||||
if (!confirm('Delete this template?')) return;
|
||||
try {
|
||||
await apiClient.delete('/admin/prospecting/campaigns/templates/' + id);
|
||||
Utils.showToast('Template deleted', 'success');
|
||||
await this.loadTemplates();
|
||||
} catch (err) {
|
||||
Utils.showToast('Failed: ' + err.message, 'error');
|
||||
}
|
||||
},
|
||||
|
||||
insertPlaceholder(ph) {
|
||||
this.templateForm.body_template += ph;
|
||||
},
|
||||
|
||||
resetForm() {
|
||||
this.editingTemplateId = null;
|
||||
this.templateForm = {
|
||||
name: '',
|
||||
lead_type: 'no_website',
|
||||
channel: 'email',
|
||||
language: 'fr',
|
||||
subject_template: '',
|
||||
body_template: '',
|
||||
is_active: true,
|
||||
};
|
||||
},
|
||||
};
|
||||
}
|
||||
Reference in New Issue
Block a user