refactored the notification function
This commit is contained in:
parent
d8686f3b8b
commit
883813a589
@ -1,6 +1,7 @@
|
|||||||
{
|
{
|
||||||
"projects": {
|
"projects": {
|
||||||
"debug": "fitlien-dev",
|
"debug": "fitlien-dev",
|
||||||
"release": "fitlien"
|
"release": "fitlien",
|
||||||
|
"default": "fitlien-dev"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,5 +1,6 @@
|
|||||||
{
|
{
|
||||||
"firestore": {
|
"firestore": {
|
||||||
|
"enabled": false,
|
||||||
"rules": "firestore.rules",
|
"rules": "firestore.rules",
|
||||||
"indexes": "firestore.indexes.json"
|
"indexes": "firestore.indexes.json"
|
||||||
},
|
},
|
||||||
@ -14,8 +15,7 @@
|
|||||||
"firebase-debug.*.log",
|
"firebase-debug.*.log",
|
||||||
"*.local"
|
"*.local"
|
||||||
],
|
],
|
||||||
"predeploy": [
|
"predeploy": []
|
||||||
]
|
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"storage": {
|
"storage": {
|
||||||
@ -23,5 +23,20 @@
|
|||||||
},
|
},
|
||||||
"remoteconfig": {
|
"remoteconfig": {
|
||||||
"template": "remoteconfig.template.json"
|
"template": "remoteconfig.template.json"
|
||||||
|
},
|
||||||
|
"emulators": {
|
||||||
|
"functions": {
|
||||||
|
"port": 5001
|
||||||
|
},
|
||||||
|
"firestore": {
|
||||||
|
"port": 8080
|
||||||
|
},
|
||||||
|
"storage": {
|
||||||
|
"port": 9199
|
||||||
|
},
|
||||||
|
"ui": {
|
||||||
|
"enabled": true
|
||||||
|
},
|
||||||
|
"singleProjectMode": true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
12
functions/.runtimeconfig.json
Normal file
12
functions/.runtimeconfig.json
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
{
|
||||||
|
"mailgun": {
|
||||||
|
"api_key": "a4540f0b68d40922a8ee203a44ec880c-623424ea-7d804677",
|
||||||
|
"server": "fitlien.cosqnet.com",
|
||||||
|
"from_address": "postmaster@fitlien.cosqnet.com"
|
||||||
|
},
|
||||||
|
"twilio": {
|
||||||
|
"account_sid": "AC5cfaae728ba68fb1aa6756d973b6e32b",
|
||||||
|
"auth_token": "886ed704c7918078f361f5f88b42ffc0",
|
||||||
|
"phone_number": "+12315005309"
|
||||||
|
}
|
||||||
|
}
|
||||||
12
functions/package-lock.json
generated
12
functions/package-lock.json
generated
@ -8,6 +8,7 @@
|
|||||||
"name": "functions",
|
"name": "functions",
|
||||||
"version": "0.0.0",
|
"version": "0.0.0",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"dotenv": "^16.4.7",
|
||||||
"firebase-admin": "^12.6.0",
|
"firebase-admin": "^12.6.0",
|
||||||
"firebase-functions": "^6.0.1",
|
"firebase-functions": "^6.0.1",
|
||||||
"form-data": "^4.0.1",
|
"form-data": "^4.0.1",
|
||||||
@ -2341,6 +2342,17 @@
|
|||||||
"url": "https://github.com/fb55/domutils?sponsor=1"
|
"url": "https://github.com/fb55/domutils?sponsor=1"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/dotenv": {
|
||||||
|
"version": "16.4.7",
|
||||||
|
"resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.4.7.tgz",
|
||||||
|
"integrity": "sha512-47qPchRCykZC03FhkYAhrvwU4xDBFIj1QPqaarj6mdM/hgUzfPHcpkHJOn3mJAufFeeAxAzeGsr5X0M4k6fLZQ==",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=12"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://dotenvx.com"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/dunder-proto": {
|
"node_modules/dunder-proto": {
|
||||||
"version": "1.0.1",
|
"version": "1.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz",
|
||||||
|
|||||||
@ -15,6 +15,7 @@
|
|||||||
},
|
},
|
||||||
"main": "lib/index.js",
|
"main": "lib/index.js",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"dotenv": "^16.4.7",
|
||||||
"firebase-admin": "^12.6.0",
|
"firebase-admin": "^12.6.0",
|
||||||
"firebase-functions": "^6.0.1",
|
"firebase-functions": "^6.0.1",
|
||||||
"form-data": "^4.0.1",
|
"form-data": "^4.0.1",
|
||||||
|
|||||||
@ -5,17 +5,23 @@ import { Message } from "firebase-admin/messaging";
|
|||||||
import * as express from "express";
|
import * as express from "express";
|
||||||
import * as logger from "firebase-functions/logger";
|
import * as logger from "firebase-functions/logger";
|
||||||
import { onDocumentCreated } from "firebase-functions/firestore";
|
import { onDocumentCreated } from "firebase-functions/firestore";
|
||||||
|
// import * as dotenv from 'dotenv';
|
||||||
|
import * as functions from "firebase-functions";
|
||||||
|
|
||||||
|
// dotenv.config();
|
||||||
|
|
||||||
|
admin.initializeApp();
|
||||||
const formData = require('form-data');
|
const formData = require('form-data');
|
||||||
const Mailgun = require('mailgun.js');
|
const Mailgun = require('mailgun.js');
|
||||||
const { convert } = require('html-to-text');
|
const { convert } = require('html-to-text');
|
||||||
const twilio = require('twilio')
|
const twilio = require('twilio')
|
||||||
|
|
||||||
|
|
||||||
export const sendEmailMessage = onRequest({
|
export const sendEmailMessage = onRequest({
|
||||||
region: '#{SERVICES_RGN}#'
|
region: '#{SERVICES_RGN}#'
|
||||||
}, (request: Request, response: express.Response) => {
|
}, (request: Request, response: express.Response) => {
|
||||||
const mailgun = new Mailgun(formData);
|
const mailgun = new Mailgun(formData);
|
||||||
const mailGunClient = mailgun.client({ username: 'api', key: process.env.MAILGUN_API_KEY });
|
const mailGunClient = mailgun.client({ username: 'api', key: functions.config().MAILGUN_API_KEY });
|
||||||
|
|
||||||
const toAddress = request.body.toAddress;
|
const toAddress = request.body.toAddress;
|
||||||
const subject = request.body.subject;
|
const subject = request.body.subject;
|
||||||
@ -25,8 +31,8 @@ export const sendEmailMessage = onRequest({
|
|||||||
};
|
};
|
||||||
|
|
||||||
const textMessage = convert(message, options);
|
const textMessage = convert(message, options);
|
||||||
mailGunClient.messages.create(process.env.MAILGUN_SERVER, {
|
mailGunClient.messages.create(functions.config().MAILGUN_SERVER, {
|
||||||
from: process.env.MAILGUN_FROM_ADDRESS,
|
from: functions.config().MAILGUN_FROM_ADDRESS,
|
||||||
to: toAddress,
|
to: toAddress,
|
||||||
subject: subject,
|
subject: subject,
|
||||||
text: textMessage,
|
text: textMessage,
|
||||||
@ -43,12 +49,12 @@ export const sendEmailMessage = onRequest({
|
|||||||
export const sendSMSMessage = onRequest({
|
export const sendSMSMessage = onRequest({
|
||||||
region: '#{SERVICES_RGN}#'
|
region: '#{SERVICES_RGN}#'
|
||||||
}, (request: Request, response: express.Response) => {
|
}, (request: Request, response: express.Response) => {
|
||||||
const client = twilio(process.env.TWILIO_ACCOUNT_SID, process.env.TWILIO_AUTH_TOKEN);
|
const client = twilio(functions.config().TWILIO_ACCOUNT_SID, functions.config().TWILIO_AUTH_TOKEN);
|
||||||
const { to, body } = request.body;
|
const { to, body } = request.body;
|
||||||
client.messages
|
client.messages
|
||||||
.create({
|
.create({
|
||||||
body: body,
|
body: body,
|
||||||
from: process.env.TWILIO_PHONE_NUMBER,
|
from: functions.config().TWILIO_PHONE_NUMBER,
|
||||||
to: to
|
to: to
|
||||||
})
|
})
|
||||||
.then((message: any) => {
|
.then((message: any) => {
|
||||||
@ -144,29 +150,35 @@ export const notifyTrainerUpdate = onRequest(
|
|||||||
},
|
},
|
||||||
async (request: Request, response: express.Response) => {
|
async (request: Request, response: express.Response) => {
|
||||||
try {
|
try {
|
||||||
const { trainerId, section, trainerName, changedFields} = request.body;
|
const { trainerId, originalProfile,section,changedFields} = request.body;
|
||||||
|
|
||||||
if (!trainerId || !section || !trainerName || !changedFields) {
|
if (!trainerId || !originalProfile || !section || !changedFields) {
|
||||||
response.status(400).json({ success: false, error: 'Missing required parameters' });
|
response.status(400).json({ success: false, error: 'Missing required parameters' });
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
const trainerData = originalProfile;
|
||||||
|
|
||||||
|
const trainerName=trainerData["normalizedName"]
|
||||||
|
|
||||||
let changesTable = '<table border="1" cellpadding="5" style="border-collapse: collapse;">';
|
let changesTable = '<table border="1" cellpadding="5" style="border-collapse: collapse;">';
|
||||||
changesTable += '<tr><th>Field</th><th>New Value</th></tr>';
|
changesTable += '<tr><th>Field</th><th>Old Value</th><th>New Value</th></tr>';
|
||||||
|
|
||||||
if (changedFields && typeof changedFields === 'object') {
|
if (changedFields && typeof changedFields === 'object') {
|
||||||
for (const [field, value] of Object.entries(changedFields)) {
|
for (const [field, newValue] of Object.entries(changedFields)) {
|
||||||
changesTable += '<tr>';
|
changesTable += '<tr>';
|
||||||
changesTable += `<td>${field}</td>`;
|
changesTable += `<td>${formatFieldName(field)}</td>`;
|
||||||
|
|
||||||
// Handle different types of values (strings, arrays, objects)
|
const oldValue = field.includes('.')
|
||||||
if (Array.isArray(value)) {
|
? field.split('.').reduce((obj, key) => obj && obj[key], trainerData)
|
||||||
changesTable += `<td>${value.join(', ')}</td>`;
|
: trainerData[field];
|
||||||
} else if (typeof value === 'object' && value !== null) {
|
|
||||||
changesTable += `<td>${JSON.stringify(value)}</td>`;
|
const formattedOldValue = formatValueForEmail(oldValue);
|
||||||
} else {
|
const formattedNewValue = formatValueForEmail(newValue);
|
||||||
changesTable += `<td>${value}</td>`;
|
|
||||||
}
|
changesTable += `<td>${formattedOldValue}</td>`;
|
||||||
|
changesTable += `<td>${formattedNewValue}</td>`;
|
||||||
|
|
||||||
changesTable += '</tr>';
|
changesTable += '</tr>';
|
||||||
}
|
}
|
||||||
@ -174,6 +186,21 @@ export const notifyTrainerUpdate = onRequest(
|
|||||||
|
|
||||||
changesTable += '</table>';
|
changesTable += '</table>';
|
||||||
|
|
||||||
|
const emailContent = `
|
||||||
|
<h2>Trainer Profile Update</h2>
|
||||||
|
<p>Your trainer ${trainerName} has updated their ${section}.</p>
|
||||||
|
<h3>Changes Made:</h3>
|
||||||
|
${changesTable}
|
||||||
|
`;
|
||||||
|
|
||||||
|
const mailgun = new Mailgun(formData);
|
||||||
|
const mailGunClient = mailgun.client({ username: 'api', key: functions.config().mailgun.api_key});
|
||||||
|
|
||||||
|
const options = { wordwrap: 130 };
|
||||||
|
const textMessage = convert(emailContent, options);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
const memberships = await admin
|
const memberships = await admin
|
||||||
.firestore()
|
.firestore()
|
||||||
.collection('memberships')
|
.collection('memberships')
|
||||||
@ -219,55 +246,44 @@ export const notifyTrainerUpdate = onRequest(
|
|||||||
const clientEmail = clientData.email;
|
const clientEmail = clientData.email;
|
||||||
|
|
||||||
if (fcmToken) {
|
if (fcmToken) {
|
||||||
const message : Message ={
|
// const message : Message ={
|
||||||
notification: {
|
// notification: {
|
||||||
title: 'Trainer Profile Update',
|
// title: 'Trainer Profile Update',
|
||||||
body: `${trainerName} has updated their ${section}`,
|
// body: `${trainerName} has updated their ${section}`,
|
||||||
},
|
// },
|
||||||
data: {
|
// data: {
|
||||||
type: 'trainer_profile_update',
|
// type: 'trainer_profile_update',
|
||||||
trainerId: trainerId,
|
// trainerId: trainerId,
|
||||||
section: section,
|
// section: section,
|
||||||
trainerName: trainerName,
|
// trainerName: trainerName,
|
||||||
},
|
// },
|
||||||
android: {
|
// android: {
|
||||||
priority: 'high',
|
// priority: 'high',
|
||||||
notification: {
|
// notification: {
|
||||||
channelId: 'trainer_updates_channel',
|
// channelId: 'trainer_updates_channel',
|
||||||
priority: 'high',
|
// priority: 'high',
|
||||||
defaultSound: true,
|
// defaultSound: true,
|
||||||
defaultVibrateTimings: true,
|
// defaultVibrateTimings: true,
|
||||||
icon: '@mipmap/ic_launcher',
|
// icon: '@mipmap/ic_launcher',
|
||||||
clickAction: 'FLUTTER_NOTIFICATION_CLICK',
|
// clickAction: 'FLUTTER_NOTIFICATION_CLICK',
|
||||||
},
|
// },
|
||||||
},
|
// },
|
||||||
token: fcmToken,
|
// token: fcmToken,
|
||||||
};
|
// };
|
||||||
|
const message = generateTrainerUpdateMessage(trainerId,section,trainerName,fcmToken);
|
||||||
notificationPromises.push(admin.messaging().send(message));
|
notificationPromises.push(admin.messaging().send(message));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (clientEmail) {
|
if (clientEmail) {
|
||||||
const emailContent = `
|
|
||||||
<h2>Trainer Profile Update</h2>
|
|
||||||
<p>Your trainer ${trainerName} has updated their ${section}.</p>
|
|
||||||
<h3>Changes Made:</h3>
|
|
||||||
${changesTable}
|
|
||||||
`;
|
|
||||||
|
|
||||||
const mailgun = new Mailgun(formData);
|
// const emailPromise = mailGunClient.messages.create(functions.config().mailgun.server, {
|
||||||
const mailGunClient = mailgun.client({ username: 'api', key: process.env.MAILGUN_API_KEY });
|
// from: functions.config().mailgun.from_address,
|
||||||
|
// to: clientEmail,
|
||||||
const options = { wordwrap: 130 };
|
// subject: `Your trainer ${trainerName} has updated their profile`,
|
||||||
const textMessage = convert(emailContent, options);
|
// text: textMessage,
|
||||||
|
// html: emailContent
|
||||||
const emailPromise = mailGunClient.messages.create(process.env.MAILGUN_SERVER, {
|
// });
|
||||||
from: process.env.MAILGUN_FROM_ADDRESS,
|
const emailPromise = generateTrainerUpdateMail(mailGunClient,textMessage,emailContent,trainerName,clientEmail);
|
||||||
to: clientEmail,
|
|
||||||
subject: `Your trainer ${trainerName} has updated their profile`,
|
|
||||||
text: textMessage,
|
|
||||||
html: emailContent
|
|
||||||
});
|
|
||||||
|
|
||||||
emailPromises.push(emailPromise);
|
emailPromises.push(emailPromise);
|
||||||
}
|
}
|
||||||
@ -293,7 +309,162 @@ export const notifyTrainerUpdate = onRequest(
|
|||||||
const gymEmail = gymData.email;
|
const gymEmail = gymData.email;
|
||||||
|
|
||||||
if (fcmToken) {
|
if (fcmToken) {
|
||||||
const message :Message={
|
// const message :Message={
|
||||||
|
// notification: {
|
||||||
|
// title: 'Trainer Profile Update',
|
||||||
|
// body: `${trainerName} has updated their ${section}`,
|
||||||
|
// },
|
||||||
|
// data: {
|
||||||
|
// type: 'trainer_profile_update',
|
||||||
|
// trainerId: trainerId,
|
||||||
|
// section: section,
|
||||||
|
// trainerName: trainerName,
|
||||||
|
// },
|
||||||
|
// android: {
|
||||||
|
// priority: 'high',
|
||||||
|
// notification: {
|
||||||
|
// channelId: 'trainer_updates_channel',
|
||||||
|
// priority: 'high',
|
||||||
|
// defaultSound: true,
|
||||||
|
// defaultVibrateTimings: true,
|
||||||
|
// icon: '@mipmap/ic_launcher',
|
||||||
|
// clickAction: 'FLUTTER_NOTIFICATION_CLICK',
|
||||||
|
// },
|
||||||
|
// },
|
||||||
|
// token: fcmToken,
|
||||||
|
// };
|
||||||
|
|
||||||
|
const message = generateTrainerUpdateMessage(trainerId,section,trainerName,fcmToken);
|
||||||
|
|
||||||
|
notificationPromises.push(admin.messaging().send(message));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (gymEmail) {
|
||||||
|
// const emailPromise = mailGunClient.messages.create(functions.config().mailgun.server, {
|
||||||
|
// from: functions.config().mailgun.from_address,
|
||||||
|
// to: gymEmail,
|
||||||
|
// subject: `Your trainer ${trainerName} has updated their profile`,
|
||||||
|
// text: textMessage,
|
||||||
|
// html: emailContent
|
||||||
|
// });
|
||||||
|
|
||||||
|
const emailPromise = generateTrainerUpdateMail(mailGunClient,textMessage,emailContent,trainerName,gymEmail);
|
||||||
|
|
||||||
|
emailPromises.push(emailPromise);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
await Promise.all([...notificationPromises, ...emailPromises]);
|
||||||
|
|
||||||
|
logger.info(`Notifications sent to clients of trainer: ${trainerId}`);
|
||||||
|
response.json({
|
||||||
|
success: true,
|
||||||
|
message: `Notifications sent to ${notificationPromises.length} clients, Emails sent to ${emailPromises.length} clients`
|
||||||
|
});
|
||||||
|
} catch (error) {
|
||||||
|
logger.error('Error sending trainer update notifications:', error);
|
||||||
|
response.status(500).json({ success: false, error: "failed to send notifications" });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
function formatFieldName(field: string): string {
|
||||||
|
const formatted = field.replace(/([A-Z])/g, ' $1')
|
||||||
|
.replace(/^./, (str) => str.toUpperCase());
|
||||||
|
|
||||||
|
return formatted
|
||||||
|
.replace('Normalized ', '')
|
||||||
|
.replace('Work Experiences', 'Work Experience');
|
||||||
|
}
|
||||||
|
|
||||||
|
function formatValueForEmail(value: any): string {
|
||||||
|
if (value === undefined || value === null) {
|
||||||
|
return 'N/A';
|
||||||
|
}
|
||||||
|
|
||||||
|
if (typeof value === 'string') {
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (typeof value === 'number' || typeof value === 'boolean') {
|
||||||
|
return value.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (value instanceof Date) {
|
||||||
|
return value.toLocaleDateString();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Array.isArray(value)) {
|
||||||
|
if (value.length > 0 && typeof value[0] === 'object') {
|
||||||
|
let table = '<table border="1" cellpadding="3" style="border-collapse: collapse; font-size: 0.9em;">';
|
||||||
|
|
||||||
|
if (value[0].hasOwnProperty('title') && value[0].hasOwnProperty('year')) {
|
||||||
|
table += '<tr><th>Title</th><th>Year</th></tr>';
|
||||||
|
value.forEach((item: any) => {
|
||||||
|
table += `<tr><td>${item.title}</td><td>${item.year}</td></tr>`;
|
||||||
|
});
|
||||||
|
} else if (value[0].hasOwnProperty('name') && value[0].hasOwnProperty('year')) {
|
||||||
|
table += '<tr><th>Name</th><th>Year</th><th>Validity</th><th>Country</th></tr>';
|
||||||
|
value.forEach((item: any) => {
|
||||||
|
table += `<tr><td>${item.name}</td><td>${item.year}</td><td>${item.validityYear}</td><td>${item.country}</td></tr>`;
|
||||||
|
});
|
||||||
|
} else if (value[0].hasOwnProperty('organization') && value[0].hasOwnProperty('role')) {
|
||||||
|
table += '<tr><th>Organization</th><th>Role</th><th>Duration</th></tr>';
|
||||||
|
value.forEach((item: any) => {
|
||||||
|
table += `<tr><td>${item.organization}</td><td>${item.role}</td><td>${item.duration}</td></tr>`;
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
const keys = Object.keys(value[0]);
|
||||||
|
table += '<tr>' + keys.map(k => `<th>${formatFieldName(k)}</th>`).join('') + '</tr>';
|
||||||
|
value.forEach((item: any) => {
|
||||||
|
table += '<tr>' + keys.map(k => `<td>${formatValueForEmail(item[k])}</td>`).join('') + '</tr>';
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
table += '</table>';
|
||||||
|
return table;
|
||||||
|
} else {
|
||||||
|
return value.join(', ');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (typeof value === 'object') {
|
||||||
|
if (Object.keys(value).some(key => ['Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday'].includes(key))) {
|
||||||
|
let scheduleTable = '<table border="1" cellpadding="3" style="border-collapse: collapse; font-size: 0.9em;">';
|
||||||
|
scheduleTable += '<tr><th>Day</th><th>Time Slots</th></tr>';
|
||||||
|
|
||||||
|
const days = ['Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday'];
|
||||||
|
days.forEach(day => {
|
||||||
|
if (value[day] && Array.isArray(value[day])) {
|
||||||
|
const timeSlots = value[day].map((slot: string) => {
|
||||||
|
return slot.replace('TimeSlot.', '').replace(/^\w/, c => c.toUpperCase());
|
||||||
|
}).join(', ');
|
||||||
|
|
||||||
|
scheduleTable += `<tr><td>${day}</td><td>${timeSlots}</td></tr>`;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
scheduleTable += '</table>';
|
||||||
|
return scheduleTable;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
return JSON.stringify(value, null, 2)
|
||||||
|
.replace(/[{}"]/g, '')
|
||||||
|
.replace(/,\n/g, '<br>')
|
||||||
|
.replace(/:/g, ': ');
|
||||||
|
} catch (e) {
|
||||||
|
return '[Complex Object]';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return String(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function generateTrainerUpdateMessage(trainerId: string, section: string, trainerName: string, fcmToken: string) : Message {
|
||||||
|
return {
|
||||||
notification: {
|
notification: {
|
||||||
title: 'Trainer Profile Update',
|
title: 'Trainer Profile Update',
|
||||||
body: `${trainerName} has updated their ${section}`,
|
body: `${trainerName} has updated their ${section}`,
|
||||||
@ -317,47 +488,15 @@ export const notifyTrainerUpdate = onRequest(
|
|||||||
},
|
},
|
||||||
token: fcmToken,
|
token: fcmToken,
|
||||||
};
|
};
|
||||||
|
|
||||||
notificationPromises.push(admin.messaging().send(message));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (gymEmail) {
|
function generateTrainerUpdateMail(mailGunClient:any,textMessage:any,emailContent:string,trainerName: string, clientEmail: string) : Promise<any> {
|
||||||
const emailContent = `
|
return mailGunClient.messages.create(functions.config().mailgun.server, {
|
||||||
<h2>Trainer Profile Update</h2>
|
from: functions.config().mailgun.from_address,
|
||||||
<p>Your trainer ${trainerName} has updated their ${section}.</p>
|
to: clientEmail,
|
||||||
<h3>Changes Made:</h3>
|
|
||||||
${changesTable}
|
|
||||||
`;
|
|
||||||
|
|
||||||
const mailgun = new Mailgun(formData);
|
|
||||||
const mailGunClient = mailgun.client({ username: 'api', key: process.env.MAILGUN_API_KEY });
|
|
||||||
|
|
||||||
const options = { wordwrap: 130 };
|
|
||||||
const textMessage = convert(emailContent, options);
|
|
||||||
|
|
||||||
const emailPromise = mailGunClient.messages.create(process.env.MAILGUN_SERVER, {
|
|
||||||
from: process.env.MAILGUN_FROM_ADDRESS,
|
|
||||||
to: gymEmail,
|
|
||||||
subject: `Your trainer ${trainerName} has updated their profile`,
|
subject: `Your trainer ${trainerName} has updated their profile`,
|
||||||
text: textMessage,
|
text: textMessage,
|
||||||
html: emailContent
|
html: emailContent
|
||||||
});
|
});
|
||||||
|
|
||||||
emailPromises.push(emailPromise);
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
await Promise.all([...notificationPromises, ...emailPromises]);
|
|
||||||
|
|
||||||
logger.info(`Notifications sent to clients of trainer: ${trainerId}`);
|
|
||||||
response.json({
|
|
||||||
success: true,
|
|
||||||
message: `Notifications sent to ${notificationPromises.length} clients, Emails sent to ${emailPromises.length} clients`
|
|
||||||
});
|
|
||||||
} catch (error) {
|
|
||||||
logger.error('Error sending trainer update notifications:', error);
|
|
||||||
response.status(500).json({ success: false, error: "failed to send notifications" });
|
|
||||||
}
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user