created endpoint for notifying clients and owners when a trainer updates his profile

This commit is contained in:
josephgladwingeorge 2025-03-25 11:11:13 +05:30
parent ba0f28d1db
commit d8686f3b8b
3 changed files with 2824 additions and 2 deletions

View File

@ -1,6 +1,7 @@
import { onRequest } from "firebase-functions/v2/https";
import { Request } from "firebase-functions/v2/https";
import * as admin from 'firebase-admin';
import { Message } from "firebase-admin/messaging";
import * as express from "express";
import * as logger from "firebase-functions/logger";
import { onDocumentCreated } from "firebase-functions/firestore";
@ -103,7 +104,7 @@ export const notifyInvitation = onDocumentCreated({
return null;
}
const message: admin.messaging.Message = {
const message: Message = {
notification: {
title: 'New Gym Invitation',
body: `${invitation.invitedByName} has invited you to join ${invitation.gymName}`,
@ -135,4 +136,228 @@ export const notifyInvitation = onDocumentCreated({
console.error('Error sending invitation notification:', error);
return null;
}
});
});
export const notifyTrainerUpdate = onRequest(
{
region: '#{SERVICES_RGN}#'
},
async (request: Request, response: express.Response) => {
try {
const { trainerId, section, trainerName, changedFields} = request.body;
if (!trainerId || !section || !trainerName || !changedFields) {
response.status(400).json({ success: false, error: 'Missing required parameters' });
return;
}
let changesTable = '<table border="1" cellpadding="5" style="border-collapse: collapse;">';
changesTable += '<tr><th>Field</th><th>New Value</th></tr>';
if (changedFields && typeof changedFields === 'object') {
for (const [field, value] of Object.entries(changedFields)) {
changesTable += '<tr>';
changesTable += `<td>${field}</td>`;
// Handle different types of values (strings, arrays, objects)
if (Array.isArray(value)) {
changesTable += `<td>${value.join(', ')}</td>`;
} else if (typeof value === 'object' && value !== null) {
changesTable += `<td>${JSON.stringify(value)}</td>`;
} else {
changesTable += `<td>${value}</td>`;
}
changesTable += '</tr>';
}
}
changesTable += '</table>';
const memberships = await admin
.firestore()
.collection('memberships')
.where('trainerId', '==', trainerId)
.get();
const userIds = memberships.docs.map((doc) => doc.data().userId);
// if (clients.empty) {
// logger.info(`No clients found for trainer: ${trainerId}`);
// response.json({ success: true, message: 'No clients to notify' });
// return;
// }
const acceptedGyms = await admin
.firestore()
.collection('traineracceptedgyms')
.where('trainerProfileId', '==', trainerId)
.get();
const gymIds = acceptedGyms.docs.map((doc) => doc.data().gymId);
const notificationPromises = [];
const emailPromises = [];
for (const userId of userIds) {
const clientQuerySnapshot = await admin
.firestore()
.collection('client_profiles')
.where('uid', '==',userId)
.limit(1)
.get();
if (clientQuerySnapshot.empty) {
console.log(`No client found with uid: ${userId}`);
continue;
}
const clientDoc = clientQuerySnapshot.docs[0];
const clientData = clientDoc.data();
const fcmToken = clientData.fcmToken;
const clientEmail = clientData.email;
if (fcmToken) {
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,
};
notificationPromises.push(admin.messaging().send(message));
}
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 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: clientEmail,
subject: `Your trainer ${trainerName} has updated their profile`,
text: textMessage,
html: emailContent
});
emailPromises.push(emailPromise);
}
}
for (const gymId of gymIds) {
const gymQuerySnapshot = await admin
.firestore()
.collection('gyms')
.where('id', '==',gymId)
.limit(1)
.get();
if (gymQuerySnapshot.empty) {
console.log(`No gym found with id: ${gymId}`);
continue;
}
const gymDoc = gymQuerySnapshot.docs[0];
const gymData = gymDoc.data();
const fcmToken = gymData.fcmToken;
const gymEmail = gymData.email;
if (fcmToken) {
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,
};
notificationPromises.push(admin.messaging().send(message));
}
if (gymEmail) {
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: 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`,
text: textMessage,
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" });
}
}
);

2592
package-lock.json generated Normal file

File diff suppressed because it is too large Load Diff

5
package.json Normal file
View File

@ -0,0 +1,5 @@
{
"dependencies": {
"firebase-functions": "^6.3.2"
}
}