notification-issue (#71)
All checks were successful
Deploy FitLien services to Dev / Deploy to Dev (push) Successful in 4m23s
All checks were successful
Deploy FitLien services to Dev / Deploy to Dev (push) Successful in 4m23s
Reviewed-on: #71 Reviewed-by: Dhansh A S <dhanshas@cosq.net> Co-authored-by: Sharon Dcruz <sharondcruz@cosq.net> Co-committed-by: Sharon Dcruz <sharondcruz@cosq.net>
This commit is contained in:
parent
9c2431fb7b
commit
3223efc392
@ -9,22 +9,12 @@ const logger = getLogger();
|
|||||||
interface NotificationData {
|
interface NotificationData {
|
||||||
senderId?: string;
|
senderId?: string;
|
||||||
recipientId?: string;
|
recipientId?: string;
|
||||||
notificationSent?: boolean;
|
ownerId?: string;
|
||||||
userId?: string;
|
|
||||||
clientId?: string;
|
|
||||||
invitorId?: string;
|
|
||||||
phoneNumber?: string;
|
|
||||||
message?: string;
|
|
||||||
type?: string;
|
type?: string;
|
||||||
status?: string;
|
notificationSent?: boolean;
|
||||||
gymName?: string;
|
timestamp?: admin.firestore.FieldValue;
|
||||||
trainerName?: string;
|
read?: boolean;
|
||||||
membershipId?: string;
|
data?: { [key: string]: any };
|
||||||
subscriptionName?: string;
|
|
||||||
name?: string;
|
|
||||||
clientEmail?: string;
|
|
||||||
invitationId?: string;
|
|
||||||
[key: string]: any;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export const processNotificationOnCreate = onDocumentCreated(
|
export const processNotificationOnCreate = onDocumentCreated(
|
||||||
@ -67,10 +57,7 @@ export const processNotificationOnCreate = onDocumentCreated(
|
|||||||
|
|
||||||
const message = prepareNotificationMessage(notification, fcmToken);
|
const message = prepareNotificationMessage(notification, fcmToken);
|
||||||
try {
|
try {
|
||||||
const fcmResponse = await app.messaging().send({
|
const fcmResponse = await app.messaging().send(message);
|
||||||
...message,
|
|
||||||
token: fcmToken,
|
|
||||||
});
|
|
||||||
|
|
||||||
logger.info(`FCM notification sent successfully: ${fcmResponse}`);
|
logger.info(`FCM notification sent successfully: ${fcmResponse}`);
|
||||||
await markNotificationAsSent(notificationId);
|
await markNotificationAsSent(notificationId);
|
||||||
@ -90,53 +77,58 @@ export const processNotificationOnCreate = onDocumentCreated(
|
|||||||
async function getUserAndFCMToken(
|
async function getUserAndFCMToken(
|
||||||
notification: NotificationData
|
notification: NotificationData
|
||||||
): Promise<{ userId: string | null; fcmToken: string | null }> {
|
): Promise<{ userId: string | null; fcmToken: string | null }> {
|
||||||
let userId: string | null = null;
|
let targetUserId: string | null = null;
|
||||||
let fcmToken: string | null = null;
|
let fcmToken: string | null = null;
|
||||||
|
|
||||||
if (notification.recipientId) {
|
if (notification.recipientId) {
|
||||||
userId = notification.recipientId;
|
targetUserId = notification.recipientId;
|
||||||
fcmToken = await getFCMTokenFromUserDoc(userId);
|
logger.info(`Using top-level recipientId: ${targetUserId}`);
|
||||||
logger.info(`Using recipientId: ${userId}`);
|
} else if (notification.ownerId) {
|
||||||
} else if (notification.userId) {
|
targetUserId = notification.ownerId;
|
||||||
userId = notification.userId;
|
logger.info(`Using top-level ownerId: ${targetUserId}`);
|
||||||
fcmToken = await getFCMTokenFromUserDoc(userId);
|
} else if (notification.data?.userId) {
|
||||||
logger.info(`Using userId: ${userId}`);
|
targetUserId = notification.data.userId;
|
||||||
} else if (notification.clientId) {
|
logger.info(`Using data.userId: ${targetUserId}`);
|
||||||
userId = notification.clientId;
|
} else if (notification.data?.clientId) {
|
||||||
fcmToken = await getFCMTokenFromUserDoc(userId);
|
targetUserId = notification.data.clientId;
|
||||||
logger.info(`Using clientId: ${userId}`);
|
logger.info(`Using data.clientId: ${targetUserId}`);
|
||||||
} else if (notification.invitorId) {
|
} else if (notification.data?.invitorId) {
|
||||||
userId = notification.invitorId;
|
targetUserId = notification.data.invitorId;
|
||||||
fcmToken = await getFCMTokenFromUserDoc(userId);
|
logger.info(`Using data.invitorId: ${targetUserId}`);
|
||||||
logger.info(`Using invitorId: ${userId}`);
|
} else if (notification.data?.phoneNumber) {
|
||||||
} else if (notification.phoneNumber) {
|
logger.info(
|
||||||
logger.info(`Looking up user by phone number: ${notification.phoneNumber}`);
|
`Looking up user by phone number from data: ${notification.data.phoneNumber}`
|
||||||
|
);
|
||||||
const userQuery = await app
|
const userQuery = await app
|
||||||
.firestore()
|
.firestore()
|
||||||
.collection("users")
|
.collection("users")
|
||||||
.where("phoneNumber", "==", notification.phoneNumber)
|
.where("phoneNumber", "==", notification.data.phoneNumber)
|
||||||
.limit(1)
|
.limit(1)
|
||||||
.get();
|
.get();
|
||||||
|
|
||||||
if (!userQuery.empty) {
|
if (!userQuery.empty) {
|
||||||
const userDoc = userQuery.docs[0];
|
const userDoc = userQuery.docs[0];
|
||||||
userId = userDoc.id;
|
targetUserId = userDoc.id;
|
||||||
fcmToken = userDoc.data()?.fcmToken;
|
fcmToken = userDoc.data()?.fcmToken;
|
||||||
logger.info(`Found user by phone: ${userId}`);
|
logger.info(`Found user by phone: ${targetUserId}`);
|
||||||
} else {
|
} else {
|
||||||
logger.warn(
|
logger.warn(
|
||||||
`No user found with phone number: ${notification.phoneNumber}`
|
`No user found with phone number from data: ${notification.data.phoneNumber}`
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
logger.error("No valid user identifier found in notification");
|
logger.error("No valid user identifier found in notification or its data");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (userId && !fcmToken) {
|
if (targetUserId && !fcmToken) {
|
||||||
logger.warn(`User ${userId} found but no FCM token available`);
|
fcmToken = await getFCMTokenFromUserDoc(targetUserId);
|
||||||
}
|
}
|
||||||
|
|
||||||
return { userId, fcmToken };
|
if (targetUserId && !fcmToken) {
|
||||||
|
logger.warn(`User ${targetUserId} found but no FCM token available`);
|
||||||
|
}
|
||||||
|
|
||||||
|
return { userId: targetUserId, fcmToken };
|
||||||
}
|
}
|
||||||
|
|
||||||
async function getFCMTokenFromUserDoc(userId: string): Promise<string | null> {
|
async function getFCMTokenFromUserDoc(userId: string): Promise<string | null> {
|
||||||
@ -162,142 +154,164 @@ async function getFCMTokenFromUserDoc(userId: string): Promise<string | null> {
|
|||||||
function prepareNotificationMessage(
|
function prepareNotificationMessage(
|
||||||
notification: NotificationData,
|
notification: NotificationData,
|
||||||
fcmToken: string
|
fcmToken: string
|
||||||
): admin.messaging.Message {
|
): admin.messaging.TokenMessage {
|
||||||
let title = "New Notification";
|
let title = notification.data?.title || "New Notification";
|
||||||
let body = notification.message || "You have a new notification";
|
let body = notification.data?.message || "You have a new notification";
|
||||||
let data: Record<string, string> = {
|
|
||||||
|
let fcmData: Record<string, string> = {
|
||||||
type: notification.type || "general",
|
type: notification.type || "general",
|
||||||
notificationId: "notification_" + Date.now(),
|
notificationId: "notification_" + Date.now().toString(),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
if (notification.senderId) fcmData.senderId = notification.senderId;
|
||||||
|
if (notification.recipientId) fcmData.recipientId = notification.recipientId;
|
||||||
|
if (notification.ownerId) fcmData.ownerId = notification.ownerId;
|
||||||
|
if (notification.read !== undefined) fcmData.read = String(notification.read);
|
||||||
|
|
||||||
|
if (notification.data) {
|
||||||
|
for (const key in notification.data) {
|
||||||
|
if (Object.prototype.hasOwnProperty.call(notification.data, key)) {
|
||||||
|
const value = notification.data[key];
|
||||||
|
if (typeof value === "object" && value !== null) {
|
||||||
|
fcmData[key] = JSON.stringify(value);
|
||||||
|
} else {
|
||||||
|
fcmData[key] = String(value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
switch (notification.type) {
|
switch (notification.type) {
|
||||||
case "trainer_response":
|
case "trainer_response":
|
||||||
title =
|
title =
|
||||||
notification.status === "ACCEPTED"
|
notification.data?.title ||
|
||||||
|
(notification.data?.status === "ACCEPTED"
|
||||||
? "Trainer Request Accepted"
|
? "Trainer Request Accepted"
|
||||||
: "Trainer Request Update";
|
: "Trainer Request Update");
|
||||||
body =
|
body =
|
||||||
notification.message ||
|
notification.data?.message ||
|
||||||
`${
|
`${
|
||||||
notification.trainerName
|
notification.data?.trainerName
|
||||||
} has ${notification.status?.toLowerCase()} your request`;
|
} has ${notification.data?.status?.toLowerCase()} your request`;
|
||||||
data.trainerName = notification.trainerName || "";
|
|
||||||
data.status = notification.status || "";
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case "trainer_assignment":
|
case "trainer_assignment":
|
||||||
title = "New Client Assignment";
|
title = notification.data?.title || "New Client Assignment";
|
||||||
body =
|
body =
|
||||||
notification.message ||
|
notification.data?.message ||
|
||||||
`You have been assigned to ${notification.name}`;
|
`You have been assigned to ${notification.data?.name}`;
|
||||||
data.clientName = notification.name || "";
|
|
||||||
data.membershipId = notification.membershipId || "";
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case "trainer_assigned_to_client":
|
case "trainer_assigned_to_client":
|
||||||
title = "Trainer Assigned";
|
title = notification.data?.title || "Trainer Assigned";
|
||||||
body =
|
body =
|
||||||
notification.message ||
|
notification.data?.message ||
|
||||||
`${notification.trainerName} has been assigned as your trainer`;
|
`${notification.data?.trainerName} has been assigned as your trainer`;
|
||||||
data.trainerName = notification.trainerName || "";
|
|
||||||
data.membershipId = notification.membershipId || "";
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case "trainer_update_owner":
|
case "trainer_update_owner":
|
||||||
title = "Trainer Schedule Update";
|
title = notification.data?.title || "Trainer Schedule Update";
|
||||||
body = notification.message || "A trainer has updated their schedule";
|
body =
|
||||||
data.membershipId = notification.membershipId || "";
|
notification.data?.message || "A trainer has updated their schedule";
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case "trainer_update_client":
|
case "trainer_update_client":
|
||||||
title = "Schedule Update";
|
title = notification.data?.title || "Schedule Update";
|
||||||
body = notification.message || "Your training schedule has been updated";
|
body =
|
||||||
data.membershipId = notification.membershipId || "";
|
notification.data?.message || "Your training schedule has been updated";
|
||||||
|
if (notification.data?.oldTimeSlot && notification.data?.newTimeSlot) {
|
||||||
|
body += ` from ${notification.data.oldTimeSlot} to ${notification.data.newTimeSlot}`;
|
||||||
|
if (notification.data?.formattedDate) {
|
||||||
|
body += ` on ${notification.data.formattedDate}`;
|
||||||
|
}
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case "plan_renewal":
|
case "plan_renewal":
|
||||||
title = "Plan Renewal";
|
title = notification.data?.title || "Plan Renewal";
|
||||||
body =
|
body =
|
||||||
notification.message ||
|
notification.data?.message ||
|
||||||
`Plan ${notification.subscriptionName} has been renewed`;
|
`Plan ${notification.data?.subscriptionName} has been renewed`;
|
||||||
data.planName = notification.subscriptionName || "";
|
|
||||||
data.membershipId = notification.membershipId || "";
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case "plan_assigned":
|
case "plan_assigned":
|
||||||
title = "New Plan Assigned";
|
title = notification.data?.title || "New Plan Assigned";
|
||||||
body =
|
body =
|
||||||
notification.message ||
|
notification.data?.message ||
|
||||||
`You have been assigned ${notification.subscriptionName} at ${notification.gymName}`;
|
`You have been assigned ${notification.data?.subscriptionName} at ${notification.data?.gymName}`;
|
||||||
data.planName = notification.subscriptionName || "";
|
|
||||||
data.gymName = notification.gymName || "";
|
|
||||||
data.membershipId = notification.membershipId || "";
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case "schedule_update":
|
case "schedule_update":
|
||||||
title = "Schedule Update";
|
title = notification.data?.title || "Schedule Update";
|
||||||
body = notification.message || "Your training schedule has been updated";
|
body =
|
||||||
data.gymName = notification.gymName || "";
|
notification.data?.message || "Your training schedule has been updated";
|
||||||
|
if (notification.data?.oldTimeSlot && notification.data?.newTimeSlot) {
|
||||||
|
body += ` from ${notification.data.oldTimeSlot} to ${notification.data.newTimeSlot}`;
|
||||||
|
if (notification.data?.formattedDate) {
|
||||||
|
body += ` on ${notification.data.formattedDate}`;
|
||||||
|
}
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case "attendance_dispute":
|
case "attendance_dispute":
|
||||||
title = "Attendance Dispute";
|
title = notification.data?.title || "Attendance Dispute";
|
||||||
body =
|
body =
|
||||||
notification.message ||
|
notification.data?.message ||
|
||||||
`${notification.name} has disputed an attendance record`;
|
`${notification.data?.name} has disputed an attendance record`;
|
||||||
data.disputedBy = notification.name || "";
|
if (notification.data?.logTime) {
|
||||||
data.membershipId = notification.membershipId || "";
|
body += ` for ${notification.data.logTime}`;
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case "day_pass_entry":
|
case "day_pass_entry":
|
||||||
const isAccepted = notification.status === "ACCEPTED";
|
const isAccepted = notification.data?.status === "ACCEPTED";
|
||||||
title = isAccepted ? "Day Pass Approved" : "Day Pass Denied";
|
title =
|
||||||
|
notification.data?.title ||
|
||||||
|
(isAccepted ? "Day Pass Approved" : "Day Pass Denied");
|
||||||
body =
|
body =
|
||||||
notification.message ||
|
notification.data?.message ||
|
||||||
(isAccepted
|
(isAccepted
|
||||||
? "Your day pass has been approved"
|
? "Your day pass has been approved"
|
||||||
: "Your day pass has been denied");
|
: "Your day pass has been denied");
|
||||||
data.gymName = notification.gymName || "";
|
|
||||||
data.status = notification.status || "";
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case "client_invitations":
|
case "client_invitations":
|
||||||
if (notification.userId || notification.invitorId) {
|
if (notification.data?.userId || notification.data?.invitorId) {
|
||||||
const isAccept = notification.status === "ACCEPTED";
|
const isAccept = notification.data?.status === "ACCEPTED";
|
||||||
title = isAccept ? "Invitation Accepted" : "Invitation Rejected";
|
title =
|
||||||
|
notification.data?.title ||
|
||||||
|
(isAccept ? "Invitation Accepted" : "Invitation Rejected");
|
||||||
body =
|
body =
|
||||||
notification.message ||
|
notification.data?.message ||
|
||||||
(isAccept
|
(isAccept
|
||||||
? `The invitation for ${notification.subscriptionName} you shared with ${notification.name} has been accepted`
|
? `The invitation for ${notification.data?.subscriptionName} you shared with ${notification.data?.name} has been accepted`
|
||||||
: `The invitation for ${notification.subscriptionName} you shared with ${notification.name} has been rejected`);
|
: `The invitation for ${notification.data?.subscriptionName} you shared with ${notification.data?.name} has been rejected`);
|
||||||
} else if (notification.phoneNumber) {
|
} else if (notification.data?.phoneNumber) {
|
||||||
const invitationStatus = getInvitationStatus(notification.status);
|
const invitationStatus = getInvitationStatus(notification.data?.status);
|
||||||
title = getInvitationTitle(invitationStatus);
|
title =
|
||||||
|
notification.data?.title || getInvitationTitle(invitationStatus);
|
||||||
body =
|
body =
|
||||||
notification.message ||
|
notification.data?.message ||
|
||||||
getInvitationBody(invitationStatus, notification.name);
|
getInvitationBody(invitationStatus, notification.data?.name);
|
||||||
data.status = invitationStatus;
|
fcmData.status = invitationStatus;
|
||||||
}
|
}
|
||||||
data.gymName = notification.gymName || "";
|
|
||||||
data.clientEmail = notification.clientEmail || "";
|
|
||||||
data.clientName = notification.name || "";
|
|
||||||
data.invitationId = notification.invitationId || "";
|
|
||||||
data.subscriptionName = notification.subscriptionName || "";
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
logger.info(
|
logger.info(
|
||||||
`Using default handling for notification type: ${notification.type}`
|
`Using default handling for notification type: ${notification.type}`
|
||||||
);
|
);
|
||||||
title = notification.type
|
title =
|
||||||
? `${notification.type.replace("_", " ").toUpperCase()}`
|
notification.data?.title ||
|
||||||
: "Notification";
|
(notification.type
|
||||||
|
? `${notification.type.replace("_", " ").toUpperCase()}`
|
||||||
|
: "Notification");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
const notificationMessage: admin.messaging.Message = {
|
const notificationMessage: admin.messaging.TokenMessage = {
|
||||||
notification: { title, body },
|
notification: { title, body },
|
||||||
data,
|
data: fcmData,
|
||||||
android: {
|
android: {
|
||||||
priority: "high",
|
priority: "high",
|
||||||
notification: {
|
notification: {
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user