feat: Upgrade Firebase Functions dependencies, enhance notification service with APNS support and FCM

This commit is contained in:
Van Leemput Dayron
2025-11-28 20:18:24 +01:00
parent 68f546d0e8
commit b4bcc8f498
14 changed files with 7101 additions and 4405 deletions

2
functions/.gitignore vendored Normal file
View File

@@ -0,0 +1,2 @@
node_modules/
*.local

View File

@@ -1,27 +1,14 @@
const functions = require("firebase-functions");
const functions = require("firebase-functions/v1");
const admin = require("firebase-admin");
admin.initializeApp();
// Helper function to send notifications
async function sendNotificationToTripParticipants(tripId, title, body, excludeUserId) {
// Helper function to send notifications to a list of users
async function sendNotificationToUsers(userIds, title, body, excludeUserId, data = {}) {
try {
const tripDoc = await admin.firestore().collection("trips").doc(tripId).get();
if (!tripDoc.exists) {
console.log(`Trip ${tripId} not found`);
return;
}
const trip = tripDoc.data();
const participants = trip.participants || [];
// Add creator if not in participants list (though usually they are)
if (trip.createdBy && !participants.includes(trip.createdBy)) {
participants.push(trip.createdBy);
}
const tokens = [];
for (const userId of participants) {
for (const userId of userIds) {
if (userId === excludeUserId) continue;
const userDoc = await admin.firestore().collection("users").doc(userId).get();
@@ -41,8 +28,8 @@ async function sendNotificationToTripParticipants(tripId, title, body, excludeUs
},
tokens: tokens,
data: {
tripId: tripId,
click_action: "FLUTTER_NOTIFICATION_CLICK",
...data
},
};
@@ -55,13 +42,31 @@ async function sendNotificationToTripParticipants(tripId, title, body, excludeUs
}
exports.onActivityCreated = functions.firestore
.document("trips/{tripId}/activities/{activityId}")
.document("activities/{activityId}")
.onCreate(async (snapshot, context) => {
const activity = snapshot.data();
const tripId = context.params.tripId;
const createdBy = activity.createdBy || "Unknown"; // Assuming createdBy field exists
const tripId = activity.tripId;
const createdBy = activity.createdBy || "Unknown";
// Fetch creator name if possible, otherwise use generic message
if (!tripId) {
console.log("No tripId found in activity");
return;
}
// Fetch trip to get participants
const tripDoc = await admin.firestore().collection("trips").doc(tripId).get();
if (!tripDoc.exists) {
console.log(`Trip ${tripId} not found`);
return;
}
const trip = tripDoc.data();
const participants = trip.participants || [];
if (trip.createdBy && !participants.includes(trip.createdBy)) {
participants.push(trip.createdBy);
}
// Fetch creator name
let creatorName = "Quelqu'un";
if (createdBy !== "Unknown") {
const userDoc = await admin.firestore().collection("users").doc(createdBy).get();
@@ -70,56 +75,72 @@ exports.onActivityCreated = functions.firestore
}
}
await sendNotificationToTripParticipants(
tripId,
await sendNotificationToUsers(
participants,
"Nouvelle activité !",
`${creatorName} a ajouté une nouvelle activité : ${activity.title}`,
createdBy
`${creatorName} a ajouté une nouvelle activité : ${activity.name || activity.title}`,
createdBy,
{ tripId: tripId }
);
});
exports.onMessageCreated = functions.firestore
.document("trips/{tripId}/messages/{messageId}")
.document("groups/{groupId}/messages/{messageId}")
.onCreate(async (snapshot, context) => {
const message = snapshot.data();
const tripId = context.params.tripId;
const groupId = context.params.groupId;
const senderId = message.senderId;
let senderName = "Quelqu'un";
if (senderId) {
const userDoc = await admin.firestore().collection("users").doc(senderId).get();
if (userDoc.exists) {
senderName = userDoc.data().prenom || "Quelqu'un";
}
// Fetch group to get members
const groupDoc = await admin.firestore().collection("groups").doc(groupId).get();
if (!groupDoc.exists) {
console.log(`Group ${groupId} not found`);
return;
}
await sendNotificationToTripParticipants(
tripId,
const group = groupDoc.data();
const memberIds = group.memberIds || [];
let senderName = message.senderName || "Quelqu'un";
await sendNotificationToUsers(
memberIds,
"Nouveau message",
`${senderName} : ${message.content}`,
senderId
`${senderName} : ${message.text}`,
senderId,
{ groupId: groupId }
);
});
exports.onExpenseCreated = functions.firestore
.document("trips/{tripId}/expenses/{expenseId}")
.document("expenses/{expenseId}")
.onCreate(async (snapshot, context) => {
const expense = snapshot.data();
const tripId = context.params.tripId;
const paidBy = expense.paidBy;
const groupId = expense.groupId;
const paidBy = expense.paidById || expense.paidBy;
let payerName = "Quelqu'un";
if (paidBy) {
const userDoc = await admin.firestore().collection("users").doc(paidBy).get();
if (userDoc.exists) {
payerName = userDoc.data().prenom || "Quelqu'un";
}
if (!groupId) {
console.log("No groupId found in expense");
return;
}
await sendNotificationToTripParticipants(
tripId,
// Fetch group to get members
const groupDoc = await admin.firestore().collection("groups").doc(groupId).get();
if (!groupDoc.exists) {
console.log(`Group ${groupId} not found`);
return;
}
const group = groupDoc.data();
const memberIds = group.memberIds || [];
let payerName = expense.paidByName || "Quelqu'un";
await sendNotificationToUsers(
memberIds,
"Nouvelle dépense",
`${payerName} a ajouté une dépense : ${expense.amount} ${expense.currency || '€'}`,
paidBy
paidBy,
{ groupId: groupId }
);
});

11099
functions/package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -1,25 +1,23 @@
{
"name": "functions",
"description": "Cloud Functions for Travel Mate",
"scripts": {
"lint": "eslint .",
"serve": "firebase emulators:start --only functions",
"shell": "firebase functions:shell",
"start": "npm run shell",
"deploy": "firebase deploy --only functions",
"logs": "firebase functions:log"
},
"engines": {
"node": "18"
},
"main": "index.js",
"dependencies": {
"firebase-admin": "^11.8.0",
"firebase-functions": "^4.3.1"
},
"devDependencies": {
"eslint": "^8.15.0",
"eslint-config-google": "^0.14.0"
},
"private": true
"name": "functions",
"description": "Cloud Functions for Firebase",
"scripts": {
"serve": "firebase emulators:start --only functions",
"shell": "firebase functions:shell",
"start": "npm run shell",
"deploy": "firebase deploy --only functions",
"logs": "firebase functions:log"
},
"engines": {
"node": "20"
},
"main": "index.js",
"dependencies": {
"firebase-admin": "^13.6.0",
"firebase-functions": "^7.0.0"
},
"devDependencies": {
"firebase-functions-test": "^3.4.1"
},
"private": true
}