created endpoint for notifying clients and owners when a trainer updates his profile
This commit is contained in:
parent
ba0f28d1db
commit
d8686f3b8b
@ -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
2592
package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load Diff
5
package.json
Normal file
5
package.json
Normal file
@ -0,0 +1,5 @@
|
||||
{
|
||||
"dependencies": {
|
||||
"firebase-functions": "^6.3.2"
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user