diff --git a/influence/app/controllers/campaigns.js b/influence/app/controllers/campaigns.js index c88791b..8848819 100644 --- a/influence/app/controllers/campaigns.js +++ b/influence/app/controllers/campaigns.js @@ -9,17 +9,31 @@ class CampaignsController { try { const campaigns = await nocoDB.getAllCampaigns(); - // Get email counts for each campaign + // Get email counts for each campaign and normalize data structure const campaignsWithCounts = await Promise.all(campaigns.map(async (campaign) => { const id = campaign.Id ?? campaign.id; let emailCount = 0; if (id != null) { emailCount = await nocoDB.getCampaignEmailCount(id); } - // Normalize id property for frontend + + // Normalize campaign data structure for frontend return { id, - ...campaign, + slug: campaign['Campaign Slug'] || campaign.slug, + title: campaign['Campaign Title'] || campaign.title, + description: campaign['Description'] || campaign.description, + email_subject: campaign['Email Subject'] || campaign.email_subject, + email_body: campaign['Email Body'] || campaign.email_body, + call_to_action: campaign['Call to Action'] || campaign.call_to_action, + status: campaign['Status'] || campaign.status, + allow_smtp_email: campaign['Allow SMTP Email'] || campaign.allow_smtp_email, + allow_mailto_link: campaign['Allow Mailto Link'] || campaign.allow_mailto_link, + collect_user_info: campaign['Collect User Info'] || campaign.collect_user_info, + show_email_count: campaign['Show Email Count'] || campaign.show_email_count, + target_government_levels: campaign['Target Government Levels'] || campaign.target_government_levels, + created_at: campaign.CreatedAt || campaign.created_at, + updated_at: campaign.UpdatedAt || campaign.updated_at, emailCount }; })); @@ -55,11 +69,25 @@ class CampaignsController { const normalizedId = campaign.Id ?? campaign.id ?? id; const emailCount = await nocoDB.getCampaignEmailCount(normalizedId); + // Normalize campaign data structure for frontend res.json({ success: true, campaign: { id: normalizedId, - ...campaign, + slug: campaign['Campaign Slug'] || campaign.slug, + title: campaign['Campaign Title'] || campaign.title, + description: campaign['Description'] || campaign.description, + email_subject: campaign['Email Subject'] || campaign.email_subject, + email_body: campaign['Email Body'] || campaign.email_body, + call_to_action: campaign['Call to Action'] || campaign.call_to_action, + status: campaign['Status'] || campaign.status, + allow_smtp_email: campaign['Allow SMTP Email'] || campaign.allow_smtp_email, + allow_mailto_link: campaign['Allow Mailto Link'] || campaign.allow_mailto_link, + collect_user_info: campaign['Collect User Info'] || campaign.collect_user_info, + show_email_count: campaign['Show Email Count'] || campaign.show_email_count, + target_government_levels: campaign['Target Government Levels'] || campaign.target_government_levels, + created_at: campaign.CreatedAt || campaign.created_at, + updated_at: campaign.UpdatedAt || campaign.updated_at, emailCount } }); @@ -87,7 +115,8 @@ class CampaignsController { }); } - if (campaign.status !== 'active') { + const campaignStatus = campaign['Status'] || campaign.status; + if (campaignStatus !== 'active') { return res.status(403).json({ success: false, error: 'Campaign is not currently active' @@ -96,7 +125,8 @@ class CampaignsController { // Get email count if enabled let emailCount = null; - if (campaign.show_email_count) { + const showEmailCount = campaign['Show Email Count'] || campaign.show_email_count; + if (showEmailCount) { const id = campaign.Id ?? campaign.id; if (id != null) { emailCount = await nocoDB.getCampaignEmailCount(id); @@ -106,21 +136,21 @@ class CampaignsController { res.json({ success: true, campaign: { - id: campaign.id, - slug: campaign.slug, - title: campaign.title, - description: campaign.description, - call_to_action: campaign.call_to_action, - email_subject: campaign.email_subject, - email_body: campaign.email_body, - allow_smtp_email: campaign.allow_smtp_email, - allow_mailto_link: campaign.allow_mailto_link, - collect_user_info: campaign.collect_user_info, - show_email_count: campaign.show_email_count, - target_government_levels: Array.isArray(campaign.target_government_levels) - ? campaign.target_government_levels - : (typeof campaign.target_government_levels === 'string' && campaign.target_government_levels.length > 0 - ? campaign.target_government_levels.split(',').map(s => s.trim()) + id: campaign.Id || campaign.id, + slug: campaign['Campaign Slug'] || campaign.slug, + title: campaign['Campaign Title'] || campaign.title, + description: campaign['Description'] || campaign.description, + call_to_action: campaign['Call to Action'] || campaign.call_to_action, + email_subject: campaign['Email Subject'] || campaign.email_subject, + email_body: campaign['Email Body'] || campaign.email_body, + allow_smtp_email: campaign['Allow SMTP Email'] || campaign.allow_smtp_email, + allow_mailto_link: campaign['Allow Mailto Link'] || campaign.allow_mailto_link, + collect_user_info: campaign['Collect User Info'] || campaign.collect_user_info, + show_email_count: campaign['Show Email Count'] || campaign.show_email_count, + target_government_levels: Array.isArray(campaign['Target Government Levels'] || campaign.target_government_levels) + ? (campaign['Target Government Levels'] || campaign.target_government_levels) + : (typeof (campaign['Target Government Levels'] || campaign.target_government_levels) === 'string' && (campaign['Target Government Levels'] || campaign.target_government_levels).length > 0 + ? (campaign['Target Government Levels'] || campaign.target_government_levels).split(',').map(s => s.trim()) : []), emailCount } @@ -185,11 +215,25 @@ class CampaignsController { const campaign = await nocoDB.createCampaign(campaignData); + // Normalize the created campaign data res.status(201).json({ success: true, campaign: { id: campaign.Id ?? campaign.id, - ...campaign + slug: campaign['Campaign Slug'] || campaign.slug, + title: campaign['Campaign Title'] || campaign.title, + description: campaign['Description'] || campaign.description, + email_subject: campaign['Email Subject'] || campaign.email_subject, + email_body: campaign['Email Body'] || campaign.email_body, + call_to_action: campaign['Call to Action'] || campaign.call_to_action, + status: campaign['Status'] || campaign.status, + allow_smtp_email: campaign['Allow SMTP Email'] || campaign.allow_smtp_email, + allow_mailto_link: campaign['Allow Mailto Link'] || campaign.allow_mailto_link, + collect_user_info: campaign['Collect User Info'] || campaign.collect_user_info, + show_email_count: campaign['Show Email Count'] || campaign.show_email_count, + target_government_levels: campaign['Target Government Levels'] || campaign.target_government_levels, + created_at: campaign.CreatedAt || campaign.created_at, + updated_at: campaign.UpdatedAt || campaign.updated_at } }); } catch (error) { @@ -215,7 +259,8 @@ class CampaignsController { // Ensure slug is unique (but allow current campaign to keep its slug) const existingCampaign = await nocoDB.getCampaignBySlug(slug); - if (existingCampaign && existingCampaign.id !== parseInt(id)) { + const existingId = existingCampaign ? (existingCampaign.Id || existingCampaign.id) : null; + if (existingCampaign && String(existingId) !== String(id)) { let counter = 1; let originalSlug = slug; while (await nocoDB.getCampaignBySlug(slug)) { @@ -239,11 +284,25 @@ class CampaignsController { const campaign = await nocoDB.updateCampaign(id, updates); + // Normalize the updated campaign data res.json({ success: true, campaign: { id: campaign.Id ?? campaign.id ?? id, - ...campaign + slug: campaign['Campaign Slug'] || campaign.slug, + title: campaign['Campaign Title'] || campaign.title, + description: campaign['Description'] || campaign.description, + email_subject: campaign['Email Subject'] || campaign.email_subject, + email_body: campaign['Email Body'] || campaign.email_body, + call_to_action: campaign['Call to Action'] || campaign.call_to_action, + status: campaign['Status'] || campaign.status, + allow_smtp_email: campaign['Allow SMTP Email'] || campaign.allow_smtp_email, + allow_mailto_link: campaign['Allow Mailto Link'] || campaign.allow_mailto_link, + collect_user_info: campaign['Collect User Info'] || campaign.collect_user_info, + show_email_count: campaign['Show Email Count'] || campaign.show_email_count, + target_government_levels: campaign['Target Government Levels'] || campaign.target_government_levels, + created_at: campaign.CreatedAt || campaign.created_at, + updated_at: campaign.UpdatedAt || campaign.updated_at } }); } catch (error) { @@ -413,7 +472,8 @@ class CampaignsController { }); } - if (campaign.status !== 'active') { + const campaignStatus = campaign['Status'] || campaign.status; + if (campaignStatus !== 'active') { return res.status(403).json({ success: false, error: 'Campaign is not currently active' @@ -423,18 +483,40 @@ class CampaignsController { // Get representatives const result = await representAPI.getRepresentativesByPostalCode(postalCode); - if (!result.success) { - return res.status(result.status || 500).json(result); + // Process representatives from both concordance and centroid + let representatives = []; + + // Add concordance representatives (if any) + if (result.representatives_concordance && result.representatives_concordance.length > 0) { + representatives = representatives.concat(result.representatives_concordance); + } + + // Add centroid representatives (if any) - these are the actual elected officials + if (result.representatives_centroid && result.representatives_centroid.length > 0) { + representatives = representatives.concat(result.representatives_centroid); + } + + if (representatives.length === 0) { + return res.json({ + success: false, + message: 'No representatives found for this postal code', + representatives: [], + location: { + city: result.city, + province: result.province + } + }); } // Filter representatives by target government levels - const targetLevels = Array.isArray(campaign.target_government_levels) - ? campaign.target_government_levels - : (typeof campaign.target_government_levels === 'string' && campaign.target_government_levels.length > 0 - ? campaign.target_government_levels.split(',').map(level => level.trim()) + const targetGovernmentLevels = campaign['Target Government Levels'] || campaign.target_government_levels; + const targetLevels = Array.isArray(targetGovernmentLevels) + ? targetGovernmentLevels + : (typeof targetGovernmentLevels === 'string' && targetGovernmentLevels.length > 0 + ? targetGovernmentLevels.split(',').map(level => level.trim()) : ['Federal', 'Provincial', 'Municipal']); - const filteredRepresentatives = result.representatives.filter(rep => { + const filteredRepresentatives = representatives.filter(rep => { const repLevel = rep.elected_office ? rep.elected_office.toLowerCase() : 'other'; return targetLevels.some(targetLevel => { @@ -460,7 +542,10 @@ class CampaignsController { res.json({ success: true, representatives: filteredRepresentatives, - location: result.location + location: { + city: result.city, + province: result.province + } }); } catch (error) { diff --git a/influence/app/public/admin.html.broken b/influence/app/public/admin.html.broken deleted file mode 100644 index 33d9a63..0000000 --- a/influence/app/public/admin.html.broken +++ /dev/null @@ -1,636 +0,0 @@ - - -
- - -Manage your influence campaigns and track engagement
-No campaigns found. Create your first campaign
'; - return; - } - - list.innerHTML = this.campaigns.map(campaign => ` -${campaign.description || 'No description'}
-
- Campaign URL: /campaign/${campaign.slug}
-