tonne of imporvements, debugs, new ui
This commit is contained in:
@@ -80,18 +80,13 @@ class NocoDBService {
|
||||
// Create record
|
||||
async create(tableId, data) {
|
||||
try {
|
||||
// Clean data to prevent ID conflicts
|
||||
const cleanData = { ...data };
|
||||
delete cleanData.ID;
|
||||
delete cleanData.id;
|
||||
delete cleanData.Id;
|
||||
|
||||
// Remove undefined values
|
||||
Object.keys(cleanData).forEach(key => {
|
||||
if (cleanData[key] === undefined) {
|
||||
delete cleanData[key];
|
||||
// Clean the data to remove any null values which can cause NocoDB issues
|
||||
const cleanData = Object.keys(data).reduce((clean, key) => {
|
||||
if (data[key] !== null && data[key] !== undefined) {
|
||||
clean[key] = data[key];
|
||||
}
|
||||
});
|
||||
return clean;
|
||||
}, {});
|
||||
|
||||
const url = this.getTableUrl(tableId);
|
||||
const response = await this.client.post(url, cleanData);
|
||||
@@ -102,6 +97,26 @@ class NocoDBService {
|
||||
}
|
||||
}
|
||||
|
||||
// Update record
|
||||
async update(tableId, recordId, data) {
|
||||
try {
|
||||
// Clean the data to remove any null values which can cause NocoDB issues
|
||||
const cleanData = Object.keys(data).reduce((clean, key) => {
|
||||
if (data[key] !== null && data[key] !== undefined) {
|
||||
clean[key] = data[key];
|
||||
}
|
||||
return clean;
|
||||
}, {});
|
||||
|
||||
const url = `${this.getTableUrl(tableId)}/${recordId}`;
|
||||
const response = await this.client.patch(url, cleanData);
|
||||
return response.data;
|
||||
} catch (error) {
|
||||
console.error('Error updating record:', error);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
async storeRepresentatives(postalCode, representatives) {
|
||||
@@ -110,16 +125,16 @@ class NocoDBService {
|
||||
|
||||
for (const rep of representatives) {
|
||||
const record = {
|
||||
postal_code: postalCode,
|
||||
name: rep.name || '',
|
||||
email: rep.email || '',
|
||||
district_name: rep.district_name || '',
|
||||
elected_office: rep.elected_office || '',
|
||||
party_name: rep.party_name || '',
|
||||
representative_set_name: rep.representative_set_name || '',
|
||||
url: rep.url || '',
|
||||
photo_url: rep.photo_url || '',
|
||||
cached_at: new Date().toISOString()
|
||||
'Postal Code': postalCode,
|
||||
'Name': rep.name || '',
|
||||
'Email': rep.email || '',
|
||||
'District Name': rep.district_name || '',
|
||||
'Elected Office': rep.elected_office || '',
|
||||
'Party Name': rep.party_name || '',
|
||||
'Representative Set Name': rep.representative_set_name || '',
|
||||
'Profile URL': rep.url || '',
|
||||
'Photo URL': rep.photo_url || '',
|
||||
'Cached At': new Date().toISOString()
|
||||
};
|
||||
|
||||
const result = await this.create(this.tableIds.representatives, record);
|
||||
@@ -181,13 +196,13 @@ class NocoDBService {
|
||||
async logEmailSend(emailData) {
|
||||
try {
|
||||
const record = {
|
||||
recipient_email: emailData.recipientEmail,
|
||||
sender_name: emailData.senderName,
|
||||
sender_email: emailData.senderEmail,
|
||||
subject: emailData.subject,
|
||||
postal_code: emailData.postalCode,
|
||||
status: emailData.status,
|
||||
sent_at: emailData.timestamp
|
||||
'Recipient Email': emailData.recipientEmail,
|
||||
'Sender Name': emailData.senderName,
|
||||
'Sender Email': emailData.senderEmail,
|
||||
'Subject': emailData.subject,
|
||||
'Postal Code': emailData.postalCode,
|
||||
'Status': emailData.status,
|
||||
'Sent At': emailData.timestamp
|
||||
};
|
||||
|
||||
await this.create(this.tableIds.emails, record);
|
||||
@@ -233,7 +248,13 @@ class NocoDBService {
|
||||
|
||||
async storePostalCodeInfo(postalCodeData) {
|
||||
try {
|
||||
const response = await this.create(this.tableIds.postalCodes, postalCodeData);
|
||||
// Map fields to NocoDB column titles
|
||||
const mappedData = {
|
||||
'Postal Code': postalCodeData.postal_code,
|
||||
'City': postalCodeData.city,
|
||||
'Province': postalCodeData.province
|
||||
};
|
||||
const response = await this.create(this.tableIds.postalCodes, mappedData);
|
||||
return response;
|
||||
} catch (error) {
|
||||
// Don't throw error for postal code caching failures
|
||||
@@ -347,7 +368,25 @@ class NocoDBService {
|
||||
// Campaign email tracking methods
|
||||
async logCampaignEmail(emailData) {
|
||||
try {
|
||||
const response = await this.create(this.tableIds.campaignEmails, emailData);
|
||||
// Map fields to NocoDB column titles
|
||||
const mappedData = {
|
||||
'Campaign ID': emailData.campaign_id,
|
||||
'Campaign Slug': emailData.campaign_slug,
|
||||
'User Email': emailData.user_email,
|
||||
'User Name': emailData.user_name,
|
||||
'User Postal Code': emailData.user_postal_code,
|
||||
'Recipient Email': emailData.recipient_email,
|
||||
'Recipient Name': emailData.recipient_name,
|
||||
'Recipient Title': emailData.recipient_title,
|
||||
'Government Level': emailData.recipient_level,
|
||||
'Email Method': emailData.email_method,
|
||||
'Subject': emailData.subject,
|
||||
'Message': emailData.message,
|
||||
'Status': emailData.status
|
||||
// Note: 'Sent At' has default value of now() so we don't need to set it
|
||||
};
|
||||
|
||||
const response = await this.create(this.tableIds.campaignEmails, mappedData);
|
||||
return response;
|
||||
} catch (error) {
|
||||
console.error('Log campaign email failed:', error);
|
||||
@@ -358,7 +397,7 @@ class NocoDBService {
|
||||
async getCampaignEmailCount(campaignId) {
|
||||
try {
|
||||
const response = await this.getAll(this.tableIds.campaignEmails, {
|
||||
where: `(campaign_id,eq,${campaignId})`,
|
||||
where: `(Campaign ID,eq,${campaignId})`,
|
||||
limit: 1000 // Get enough to count
|
||||
});
|
||||
return response.pageInfo ? response.pageInfo.totalRows : (response.list ? response.list.length : 0);
|
||||
@@ -371,7 +410,7 @@ class NocoDBService {
|
||||
async getCampaignAnalytics(campaignId) {
|
||||
try {
|
||||
const response = await this.getAll(this.tableIds.campaignEmails, {
|
||||
where: `(campaign_id,eq,${campaignId})`,
|
||||
where: `(Campaign ID,eq,${campaignId})`,
|
||||
limit: 1000
|
||||
});
|
||||
|
||||
@@ -379,32 +418,36 @@ class NocoDBService {
|
||||
|
||||
const analytics = {
|
||||
totalEmails: emails.length,
|
||||
smtpEmails: emails.filter(e => e.email_method === 'smtp').length,
|
||||
mailtoClicks: emails.filter(e => e.email_method === 'mailto').length,
|
||||
successfulEmails: emails.filter(e => e.status === 'sent' || e.status === 'clicked').length,
|
||||
failedEmails: emails.filter(e => e.status === 'failed').length,
|
||||
smtpEmails: emails.filter(e => (e['Email Method'] || e.email_method) === 'smtp').length,
|
||||
mailtoClicks: emails.filter(e => (e['Email Method'] || e.email_method) === 'mailto').length,
|
||||
successfulEmails: emails.filter(e => {
|
||||
const status = e['Status'] || e.status;
|
||||
return status === 'sent' || status === 'clicked';
|
||||
}).length,
|
||||
failedEmails: emails.filter(e => (e['Status'] || e.status) === 'failed').length,
|
||||
byLevel: {},
|
||||
byDate: {},
|
||||
recentEmails: emails.slice(0, 10).map(email => ({
|
||||
timestamp: email.timestamp,
|
||||
user_name: email.user_name,
|
||||
recipient_name: email.recipient_name,
|
||||
recipient_level: email.recipient_level,
|
||||
email_method: email.email_method,
|
||||
status: email.status
|
||||
timestamp: email['Sent At'] || email.timestamp || email.sent_at,
|
||||
user_name: email['User Name'] || email.user_name,
|
||||
recipient_name: email['Recipient Name'] || email.recipient_name,
|
||||
recipient_level: email['Government Level'] || email.recipient_level,
|
||||
email_method: email['Email Method'] || email.email_method,
|
||||
status: email['Status'] || email.status
|
||||
}))
|
||||
};
|
||||
|
||||
// Group by government level
|
||||
emails.forEach(email => {
|
||||
const level = email.recipient_level || 'Other';
|
||||
const level = email['Government Level'] || email.recipient_level || 'Other';
|
||||
analytics.byLevel[level] = (analytics.byLevel[level] || 0) + 1;
|
||||
});
|
||||
|
||||
// Group by date
|
||||
emails.forEach(email => {
|
||||
if (email.timestamp) {
|
||||
const date = email.timestamp.split('T')[0]; // Get date part
|
||||
const timestamp = email['Sent At'] || email.timestamp || email.sent_at;
|
||||
if (timestamp) {
|
||||
const date = timestamp.split('T')[0]; // Get date part
|
||||
analytics.byDate[date] = (analytics.byDate[date] || 0) + 1;
|
||||
}
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user