From 4edd0c69de7ff1b499e154f0f4bc774ab937339b Mon Sep 17 00:00:00 2001 From: Sharon Dcruz Date: Tue, 12 Aug 2025 11:12:08 +0530 Subject: [PATCH 01/52] Changes Updated --- .../membershipStatusNotifications.ts | 116 +++++++++++------- 1 file changed, 74 insertions(+), 42 deletions(-) diff --git a/functions/src/notifications/membershipStatusNotifications.ts b/functions/src/notifications/membershipStatusNotifications.ts index 3b0b61b..1c01fff 100644 --- a/functions/src/notifications/membershipStatusNotifications.ts +++ b/functions/src/notifications/membershipStatusNotifications.ts @@ -63,10 +63,18 @@ export const checkExpiredMemberships = onSchedule( expiringMemberships.map((m) => processExpiringMembership(m.id, m.data)) ); - const expiredSuccessful = expiredResults.filter((r) => r.status === "fulfilled").length; - const expiredFailed = expiredResults.filter((r) => r.status === "rejected").length; - const expiringSuccessful = expiringResults.filter((r) => r.status === "fulfilled").length; - const expiringFailed = expiringResults.filter((r) => r.status === "rejected").length; + const expiredSuccessful = expiredResults.filter( + (r) => r.status === "fulfilled" + ).length; + const expiredFailed = expiredResults.filter( + (r) => r.status === "rejected" + ).length; + const expiringSuccessful = expiringResults.filter( + (r) => r.status === "fulfilled" + ).length; + const expiringFailed = expiringResults.filter( + (r) => r.status === "rejected" + ).length; logger.info( `Completed processing. Expired - Success: ${expiredSuccessful}, Failed: ${expiredFailed}. Expiring - Success: ${expiringSuccessful}, Failed: ${expiringFailed}` @@ -139,7 +147,10 @@ async function findMembershipsExpiringIn10Days(): Promise< const batchResults = await Promise.allSettled( batch.map(async (doc) => { const data = doc.data() as MembershipData; - const isExpiringIn10Days = await checkIfMembershipExpiringIn10Days(doc.id, data); + const isExpiringIn10Days = await checkIfMembershipExpiringIn10Days( + doc.id, + data + ); if (isExpiringIn10Days) { return { id: doc.id, data }; } @@ -241,11 +252,11 @@ async function checkIfMembershipExpiringIn10Days( startDate, data.subscription.frequency ); - + const now = new Date(); const tenDaysFromNow = new Date(); tenDaysFromNow.setDate(now.getDate() + 10); - + const isExpiringIn10Days = expiryDate > now && expiryDate <= tenDaysFromNow; if (isExpiringIn10Days) { @@ -381,7 +392,10 @@ async function processExpiringMembership( logger.info(`Processing expiring membership ${membershipId}`); await sendPlanExpiringNotification(membershipId, membershipData); } catch (error) { - logger.error(`Error processing expiring membership ${membershipId}:`, error); + logger.error( + `Error processing expiring membership ${membershipId}:`, + error + ); } } @@ -394,19 +408,6 @@ async function sendPlanExpiredNotification( const gymOwnerId = await getGymOwnerId(membershipData.gymId); const gymName = await getGymName(membershipData.gymId); - const existing = await app - .firestore() - .collection("notifications") - .where("type", "==", "plan_expired") - .where("data.membershipId", "==", membershipId) - .limit(1) - .get(); - - if (!existing.empty) { - logger.info(`Notification already sent for ${membershipId}, skipping...`); - return; - } - let expiryDate: Date | undefined; let formattedDate = "Unknown Date"; @@ -422,7 +423,26 @@ async function sendPlanExpiredNotification( month: "long", day: "numeric", }); - + } + + const existing = await app + .firestore() + .collection("notifications") + .where("type", "==", "plan_expired") + .where("data.membershipId", "==", membershipId) + .where( + "data.expiryDate", + "==", + expiryDate + ? admin.firestore.Timestamp.fromDate(expiryDate) + : admin.firestore.Timestamp.fromDate(new Date()) + ) + .limit(1) + .get(); + + if (!existing.empty) { + logger.info(`Notification already sent for ${membershipId}, skipping...`); + return; } await app @@ -435,13 +455,13 @@ async function sendPlanExpiredNotification( notificationSent: false, timestamp: admin.firestore.FieldValue.serverTimestamp(), read: false, - readBy: [], + readBy: [], data: { planName: membershipData.subscription?.name || "Unknown Plan", clientName, membershipId, gymName, - ownerId: gymOwnerId, + ownerId: gymOwnerId, formattedExpiryDate: formattedDate, expiryDate: expiryDate ? admin.firestore.Timestamp.fromDate(expiryDate) @@ -466,19 +486,6 @@ async function sendPlanExpiringNotification( const gymOwnerId = await getGymOwnerId(membershipData.gymId); const gymName = await getGymName(membershipData.gymId); - const existing = await app - .firestore() - .collection("notifications") - .where("type", "==", "plan_expiring_soon") - .where("data.membershipId", "==", membershipId) - .limit(1) - .get(); - - if (!existing.empty) { - logger.info(`Expiring notification already sent for ${membershipId}, skipping...`); - return; - } - let expiryDate: Date | undefined; let formattedDate = "Unknown Date"; let daysUntilExpiry = 10; @@ -495,12 +502,34 @@ async function sendPlanExpiringNotification( month: "long", day: "numeric", }); - + const now = new Date(); const timeDiff = expiryDate.getTime() - now.getTime(); daysUntilExpiry = Math.ceil(timeDiff / (1000 * 3600 * 24)); } + const existing = await app + .firestore() + .collection("notifications") + .where("type", "==", "plan_expiring_soon") + .where("data.membershipId", "==", membershipId) + .where( + "data.expiryDate", + "==", + expiryDate + ? admin.firestore.Timestamp.fromDate(expiryDate) + : admin.firestore.Timestamp.fromDate(new Date()) + ) + .limit(1) + .get(); + + if (!existing.empty) { + logger.info( + `Expiring notification already sent for ${membershipId}, skipping...` + ); + return; + } + await app .firestore() .collection("notifications") @@ -511,13 +540,13 @@ async function sendPlanExpiringNotification( notificationSent: false, timestamp: admin.firestore.FieldValue.serverTimestamp(), read: false, - readBy: [], + readBy: [], data: { planName: membershipData.subscription?.name || "Unknown Plan", clientName, membershipId, gymName, - ownerId: gymOwnerId, + ownerId: gymOwnerId, formattedExpiryDate: formattedDate, expiryDate: expiryDate ? admin.firestore.Timestamp.fromDate(expiryDate) @@ -530,7 +559,10 @@ async function sendPlanExpiringNotification( `Expiring notification sent for membership ${membershipId} (expires on ${formattedDate}, ${daysUntilExpiry} days remaining)` ); } catch (error) { - logger.error(`Error sending expiring notification for ${membershipId}:`, error); + logger.error( + `Error sending expiring notification for ${membershipId}:`, + error + ); } } @@ -577,4 +609,4 @@ async function getGymName(gymId: string): Promise { logger.error(`Error getting gym name for gym ${gymId}:`, error); return "Unknown Gym"; } -} \ No newline at end of file +} -- 2.43.0 From b59e0033db675ace5bbf18fe4f0abf8f848fa9f1 Mon Sep 17 00:00:00 2001 From: Sharon Dcruz Date: Wed, 13 Aug 2025 12:08:05 +0530 Subject: [PATCH 02/52] Changes Updated --- functions/src/notifications/processNotification.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/functions/src/notifications/processNotification.ts b/functions/src/notifications/processNotification.ts index 3cc4811..2efed4c 100644 --- a/functions/src/notifications/processNotification.ts +++ b/functions/src/notifications/processNotification.ts @@ -180,7 +180,7 @@ function prepareNotificationMessage( case "trainer_response": title = notification.data?.title || - (notification.data?.status === "accepted" + (notification.data?.status === "Accepted" ? "Trainer Request Accepted" : "Trainer Request Update"); body = -- 2.43.0 From 57a4fab6c8b2b0d6cbc9883f284f84be2ef20b96 Mon Sep 17 00:00:00 2001 From: Sharon Dcruz Date: Wed, 13 Aug 2025 13:31:42 +0530 Subject: [PATCH 03/52] Changes Updated --- firestore.indexes.json | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/firestore.indexes.json b/firestore.indexes.json index 4e84252..2016f51 100644 --- a/firestore.indexes.json +++ b/firestore.indexes.json @@ -166,6 +166,20 @@ } ] }, + { + "collectionGroup": "notifications", + "queryScope": "COLLECTION", + "fields": [ + { + "fieldPath": "recipientId", + "order": "ASCENDING" + }, + { + "fieldPath": "timestamp", + "order": "DESCENDING" + } + ] + }, { "collectionGroup": "workout_logs", "queryScope": "COLLECTION", -- 2.43.0 From d7bf910baa60a84c7da8bc65bcbb95fb32ed3250 Mon Sep 17 00:00:00 2001 From: Sharon Dcruz Date: Wed, 13 Aug 2025 18:44:51 +0530 Subject: [PATCH 04/52] Changes Updated --- .../membershipStatusNotifications.ts | 192 +++++++++++++++++- .../src/notifications/processNotification.ts | 20 +- 2 files changed, 208 insertions(+), 4 deletions(-) diff --git a/functions/src/notifications/membershipStatusNotifications.ts b/functions/src/notifications/membershipStatusNotifications.ts index 1c01fff..7dd0541 100644 --- a/functions/src/notifications/membershipStatusNotifications.ts +++ b/functions/src/notifications/membershipStatusNotifications.ts @@ -33,6 +33,15 @@ interface PaymentData { discount?: number; } +interface PersonalTrainerAssign { + id: string; + ownerId: string; + trainerId?: string; + clientId: string; + membershipId: string; + gymId: string; +} + export const checkExpiredMemberships = onSchedule( { schedule: "*/5 * * * *", @@ -367,6 +376,66 @@ function calculateRenewalDateFromPayment( return renewalDate; } +async function getTrainerAssignmentsForMembership( + membershipId: string +): Promise { + try { + const querySnapshot = await app + .firestore() + .collection("personal_trainer_assignments") + .where("membershipId", "==", membershipId) + .get(); + + return querySnapshot.docs.map((doc) => ({ + id: doc.id, + ...doc.data(), + })) as PersonalTrainerAssign[]; + } catch (error) { + logger.error( + `Error getting trainer assignments for membership ${membershipId}:`, + error + ); + return []; + } +} + +async function getTrainerName(trainerId: string): Promise { + try { + const doc = await app + .firestore() + .collection("trainer_profiles") + .doc(trainerId) + .get(); + + if (!doc.exists) { + const userDoc = await app + .firestore() + .collection("users") + .doc(trainerId) + .get(); + + if (userDoc.exists) { + const userData = userDoc.data(); + return userData?.name || userData?.displayName || "Unknown Trainer"; + } + return "Unknown Trainer"; + } + + const data = doc.data(); + const fields = data?.fields; + if (fields) { + const firstName = fields["first-name"] || ""; + const lastName = fields["last-name"] || ""; + return `${firstName} ${lastName}`.trim() || "Unknown Trainer"; + } + + return data?.name || data?.displayName || "Unknown Trainer"; + } catch (error) { + logger.error(`Error getting trainer name for ${trainerId}:`, error); + return "Unknown Trainer"; + } +} + async function processExpiredMembership( membershipId: string, membershipData: MembershipData @@ -378,7 +447,10 @@ async function processExpiredMembership( }); logger.info(`Marked membership ${membershipId} as EXPIRED`); + await sendPlanExpiredNotification(membershipId, membershipData); + + await sendTrainerNotifications(membershipId, membershipData, "expired"); } catch (error) { logger.error(`Error processing membership ${membershipId}:`, error); } @@ -390,7 +462,10 @@ async function processExpiringMembership( ): Promise { try { logger.info(`Processing expiring membership ${membershipId}`); + await sendPlanExpiringNotification(membershipId, membershipData); + + await sendTrainerNotifications(membershipId, membershipData, "expiring"); } catch (error) { logger.error( `Error processing expiring membership ${membershipId}:`, @@ -399,6 +474,121 @@ async function processExpiringMembership( } } +async function sendTrainerNotifications( + membershipId: string, + membershipData: MembershipData, + notificationType: "expired" | "expiring" +): Promise { + try { + const trainerAssignments = await getTrainerAssignmentsForMembership(membershipId); + + if (trainerAssignments.length === 0) { + logger.info(`No trainer assignments found for membership ${membershipId}`); + return; + } + + const clientName = await getClientName(membershipId, membershipData.userId); + const gymName = await getGymName(membershipData.gymId); + + let expiryDate: Date | undefined; + let formattedDate = "Unknown Date"; + let daysUntilExpiry = 0; + + const payments = await getPaymentsForMembership(membershipId); + if (payments.length > 0) { + const latestPayment = payments[0]; + expiryDate = calculateRenewalDateFromPayment( + membershipData.subscription, + latestPayment.dateTimestamp + ); + formattedDate = expiryDate.toLocaleDateString("en-US", { + year: "numeric", + month: "long", + day: "numeric", + }); + + if (notificationType === "expiring") { + const now = new Date(); + const timeDiff = expiryDate.getTime() - now.getTime(); + daysUntilExpiry = Math.ceil(timeDiff / (1000 * 3600 * 24)); + } + } + + for (const assignment of trainerAssignments) { + if (!assignment.trainerId) continue; + + try { + const trainerName = await getTrainerName(assignment.trainerId); + + const notifType = notificationType === "expired" ? "trainer_client_plan_expired" : "trainer_client_plan_expiring"; + const existing = await app + .firestore() + .collection("notifications") + .where("type", "==", notifType) + .where("recipientId", "==", assignment.trainerId) + .where("data.membershipId", "==", membershipId) + .where( + "data.expiryDate", + "==", + expiryDate + ? admin.firestore.Timestamp.fromDate(expiryDate) + : admin.firestore.Timestamp.fromDate(new Date()) + ) + .limit(1) + .get(); + + if (!existing.empty) { + logger.info( + `${notificationType} notification already sent to trainer ${assignment.trainerId} for membership ${membershipId}, skipping...` + ); + continue; + } + + const notificationData: any = { + senderId: "system", + recipientId: assignment.trainerId, + type: notifType, + notificationSent: false, + timestamp: admin.firestore.FieldValue.serverTimestamp(), + read: false, + readBy: [], + data: { + planName: membershipData.subscription?.name || "Unknown Plan", + clientName, + membershipId, + gymName, + assignmentId: assignment.id, + formattedExpiryDate: formattedDate, + expiryDate: expiryDate + ? admin.firestore.Timestamp.fromDate(expiryDate) + : admin.firestore.Timestamp.fromDate(new Date()), + }, + }; + + if (notificationType === "expiring") { + notificationData.data.daysUntilExpiry = daysUntilExpiry; + } + + await app.firestore().collection("notifications").add(notificationData); + + logger.info( + `${notificationType} notification sent to trainer ${assignment.trainerId} (${trainerName}) for client ${clientName}'s membership ${membershipId}` + ); + } catch (trainerError) { + logger.error( + `Error sending notification to trainer ${assignment.trainerId} for membership ${membershipId}:`, + trainerError + ); + } + } + } catch (error) { + logger.error( + `Error sending trainer notifications for membership ${membershipId}:`, + error + ); + } +} + async function sendPlanExpiredNotification( membershipId: string, membershipData: MembershipData @@ -609,4 +799,4 @@ async function getGymName(gymId: string): Promise { logger.error(`Error getting gym name for gym ${gymId}:`, error); return "Unknown Gym"; } -} +} \ No newline at end of file diff --git a/functions/src/notifications/processNotification.ts b/functions/src/notifications/processNotification.ts index 2efed4c..d8edce7 100644 --- a/functions/src/notifications/processNotification.ts +++ b/functions/src/notifications/processNotification.ts @@ -180,7 +180,7 @@ function prepareNotificationMessage( case "trainer_response": title = notification.data?.title || - (notification.data?.status === "Accepted" + (notification.data?.status === "accepted" ? "Trainer Request Accepted" : "Trainer Request Update"); body = @@ -240,14 +240,28 @@ function prepareNotificationMessage( title = notification.data?.title || "Plan Expired"; body = notification.data?.message || - `${notification.data?.clientName}'s membership subscription for ${notification.data?.planName} has expired.`; + `${notification.data?.clientName}'s membership for ${notification.data?.planName} has expired.`; break; case "plan_expiring_soon": title = notification.data?.title || "Plan Expiring Soon"; body = notification.data?.message || - `${notification.data?.clientName}'s membership subscription for ${notification.data?.planName} will expire on ${notification.data?.formattedExpiryDate}.`; + `${notification.data?.clientName}'s membership for ${notification.data?.planName} will expire on ${notification.data?.formattedExpiryDate}.`; + break; + + case "trainer_client_plan_expired": + title = notification.data?.title || "Client Plan Expired"; + body = + notification.data?.message || + `${notification.data?.clientName}'s membership for ${notification.data?.planName} has expired.`; + break; + + case "trainer_client_plan_expiring": + title = notification.data?.title || "Client Plan Expiring Soon"; + body = + notification.data?.message || + `${notification.data?.clientName}'s membership for ${notification.data?.planName} will expire on ${notification.data?.formattedExpiryDate}.`; break; case "schedule_update": -- 2.43.0 From ded8e1591854006a82bb87e81e7a5d596a259d9b Mon Sep 17 00:00:00 2001 From: Sharon Dcruz Date: Thu, 14 Aug 2025 12:07:04 +0530 Subject: [PATCH 05/52] Changed TrainerId to TraineruserId --- .../membershipStatusNotifications.ts | 62 ++++++++++++++----- 1 file changed, 47 insertions(+), 15 deletions(-) diff --git a/functions/src/notifications/membershipStatusNotifications.ts b/functions/src/notifications/membershipStatusNotifications.ts index 7dd0541..9067c77 100644 --- a/functions/src/notifications/membershipStatusNotifications.ts +++ b/functions/src/notifications/membershipStatusNotifications.ts @@ -406,14 +406,14 @@ async function getTrainerName(trainerId: string): Promise { .collection("trainer_profiles") .doc(trainerId) .get(); - + if (!doc.exists) { const userDoc = await app .firestore() .collection("users") .doc(trainerId) .get(); - + if (userDoc.exists) { const userData = userDoc.data(); return userData?.name || userData?.displayName || "Unknown Trainer"; @@ -428,7 +428,7 @@ async function getTrainerName(trainerId: string): Promise { const lastName = fields["last-name"] || ""; return `${firstName} ${lastName}`.trim() || "Unknown Trainer"; } - + return data?.name || data?.displayName || "Unknown Trainer"; } catch (error) { logger.error(`Error getting trainer name for ${trainerId}:`, error); @@ -447,9 +447,9 @@ async function processExpiredMembership( }); logger.info(`Marked membership ${membershipId} as EXPIRED`); - + await sendPlanExpiredNotification(membershipId, membershipData); - + await sendTrainerNotifications(membershipId, membershipData, "expired"); } catch (error) { logger.error(`Error processing membership ${membershipId}:`, error); @@ -462,9 +462,9 @@ async function processExpiringMembership( ): Promise { try { logger.info(`Processing expiring membership ${membershipId}`); - + await sendPlanExpiringNotification(membershipId, membershipData); - + await sendTrainerNotifications(membershipId, membershipData, "expiring"); } catch (error) { logger.error( @@ -474,16 +474,44 @@ async function processExpiringMembership( } } +async function getTrainerUserId(trainerId: string): Promise { + try { + const trainerDoc = await app + .firestore() + .collection("trainer_profiles") + .doc(trainerId) + .get(); + + if (!trainerDoc.exists) { + throw new Error(`Trainer profile not found for ID: ${trainerId}`); + } + + const trainerData = trainerDoc.data(); + if (!trainerData?.userId) { + throw new Error(`userId not found in trainer profile: ${trainerId}`); + } + + return trainerData.userId; + } catch (error) { + logger.error(`Error getting userId for trainer ${trainerId}:`, error); + return trainerId; + } +} + async function sendTrainerNotifications( membershipId: string, membershipData: MembershipData, notificationType: "expired" | "expiring" ): Promise { try { - const trainerAssignments = await getTrainerAssignmentsForMembership(membershipId); - + const trainerAssignments = await getTrainerAssignmentsForMembership( + membershipId + ); + if (trainerAssignments.length === 0) { - logger.info(`No trainer assignments found for membership ${membershipId}`); + logger.info( + `No trainer assignments found for membership ${membershipId}` + ); return; } @@ -519,13 +547,17 @@ async function sendTrainerNotifications( try { const trainerName = await getTrainerName(assignment.trainerId); - - const notifType = notificationType === "expired" ? "trainer_client_plan_expired" : "trainer_client_plan_expiring"; + const trainerUserId = await getTrainerUserId(assignment.trainerId); + + const notifType = + notificationType === "expired" + ? "trainer_client_plan_expired" + : "trainer_client_plan_expiring"; const existing = await app .firestore() .collection("notifications") .where("type", "==", notifType) - .where("recipientId", "==", assignment.trainerId) + .where("recipientId", "==", trainerUserId) .where("data.membershipId", "==", membershipId) .where( "data.expiryDate", @@ -546,7 +578,7 @@ async function sendTrainerNotifications( const notificationData: any = { senderId: "system", - recipientId: assignment.trainerId, + recipientId: trainerUserId, type: notifType, notificationSent: false, timestamp: admin.firestore.FieldValue.serverTimestamp(), @@ -799,4 +831,4 @@ async function getGymName(gymId: string): Promise { logger.error(`Error getting gym name for gym ${gymId}:`, error); return "Unknown Gym"; } -} \ No newline at end of file +} -- 2.43.0 From e1822f925797cb179d38df1d92e64defd79c637c Mon Sep 17 00:00:00 2001 From: Sharon Dcruz Date: Thu, 14 Aug 2025 12:47:03 +0530 Subject: [PATCH 06/52] Added role to navigate to notification screen --- functions/src/notifications/membershipStatusNotifications.ts | 1 + functions/src/notifications/processNotification.ts | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/functions/src/notifications/membershipStatusNotifications.ts b/functions/src/notifications/membershipStatusNotifications.ts index 8d25206..4a99688 100644 --- a/functions/src/notifications/membershipStatusNotifications.ts +++ b/functions/src/notifications/membershipStatusNotifications.ts @@ -588,6 +588,7 @@ async function sendTrainerNotifications( gymName, assignmentId: assignment.id, formattedExpiryDate: formattedDate, + role: 'Trainer', expiryDate: expiryDate ? admin.firestore.Timestamp.fromDate(expiryDate) : admin.firestore.Timestamp.fromDate(new Date()), diff --git a/functions/src/notifications/processNotification.ts b/functions/src/notifications/processNotification.ts index d8edce7..fe7ce6a 100644 --- a/functions/src/notifications/processNotification.ts +++ b/functions/src/notifications/processNotification.ts @@ -181,8 +181,8 @@ function prepareNotificationMessage( title = notification.data?.title || (notification.data?.status === "accepted" - ? "Trainer Request Accepted" - : "Trainer Request Update"); + ? "Trainer Invitation Accepted" + : "Trainer Invitation Update"); body = notification.data?.message || `${ -- 2.43.0 From bdd94264a69fa028021a1ebaf3a6563e5a1fd7c7 Mon Sep 17 00:00:00 2001 From: Sharon Dcruz Date: Thu, 14 Aug 2025 14:01:53 +0530 Subject: [PATCH 07/52] Added role --- functions/src/notifications/membershipStatusNotifications.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/functions/src/notifications/membershipStatusNotifications.ts b/functions/src/notifications/membershipStatusNotifications.ts index 4a99688..218ff95 100644 --- a/functions/src/notifications/membershipStatusNotifications.ts +++ b/functions/src/notifications/membershipStatusNotifications.ts @@ -545,6 +545,7 @@ async function sendTrainerNotifications( try { const trainerName = await getTrainerName(assignment.trainerId); const trainerUserId = await getTrainerUserId(assignment.trainerId); + const kTrainerRole = 'Trainer'; const notifType = notificationType === "expired" @@ -588,7 +589,7 @@ async function sendTrainerNotifications( gymName, assignmentId: assignment.id, formattedExpiryDate: formattedDate, - role: 'Trainer', + role: kTrainerRole, expiryDate: expiryDate ? admin.firestore.Timestamp.fromDate(expiryDate) : admin.firestore.Timestamp.fromDate(new Date()), -- 2.43.0 From 59d8df180eb8351e180bc67f447fcc2ff5dece23 Mon Sep 17 00:00:00 2001 From: Sharon Dcruz Date: Thu, 14 Aug 2025 14:03:35 +0530 Subject: [PATCH 08/52] updated --- functions/src/notifications/membershipStatusNotifications.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/functions/src/notifications/membershipStatusNotifications.ts b/functions/src/notifications/membershipStatusNotifications.ts index 218ff95..2ed768f 100644 --- a/functions/src/notifications/membershipStatusNotifications.ts +++ b/functions/src/notifications/membershipStatusNotifications.ts @@ -4,6 +4,7 @@ import * as admin from "firebase-admin"; const app = getAdmin(); const logger = getLogger(); +const kTrainerRole = 'Trainer'; interface MembershipData { id?: string; @@ -545,7 +546,7 @@ async function sendTrainerNotifications( try { const trainerName = await getTrainerName(assignment.trainerId); const trainerUserId = await getTrainerUserId(assignment.trainerId); - const kTrainerRole = 'Trainer'; + const notifType = notificationType === "expired" -- 2.43.0 From 3e989493b08011c6315181e3cbc20bed004032b9 Mon Sep 17 00:00:00 2001 From: Sharon Dcruz Date: Thu, 14 Aug 2025 18:40:41 +0530 Subject: [PATCH 09/52] Gym index added --- firestore.indexes.json | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/firestore.indexes.json b/firestore.indexes.json index 2016f51..0530c8b 100644 --- a/firestore.indexes.json +++ b/firestore.indexes.json @@ -28,6 +28,34 @@ } ] }, + { + "collectionGroup": "gyms", + "queryScope": "COLLECTION_GROUP", + "fields": [ + { + "fieldPath": "userId", + "order": "ASCENDING" + }, + { + "fieldPath": "createdAt", + "order": "DESCENDING" + } + ] + }, + { + "collectionGroup": "gyms", + "queryScope": "COLLECTION_GROUP", + "fields": [ + { + "fieldPath": "isApproved", + "order": "ASCENDING" + }, + { + "fieldPath": "createdAt", + "order": "ASCENDING" + } + ] + }, { "collectionGroup": "gyms", "queryScope": "COLLECTION_GROUP", -- 2.43.0 From d15c04fc910f145cee58e1e736a2f9bc4ea8f380 Mon Sep 17 00:00:00 2001 From: Sharon Dcruz Date: Mon, 18 Aug 2025 19:07:45 +0530 Subject: [PATCH 10/52] Changes Updated --- .../membershipStatusNotifications.ts | 50 ++++++++++++++++--- 1 file changed, 42 insertions(+), 8 deletions(-) diff --git a/functions/src/notifications/membershipStatusNotifications.ts b/functions/src/notifications/membershipStatusNotifications.ts index 2ed768f..a26f9eb 100644 --- a/functions/src/notifications/membershipStatusNotifications.ts +++ b/functions/src/notifications/membershipStatusNotifications.ts @@ -4,7 +4,7 @@ import * as admin from "firebase-admin"; const app = getAdmin(); const logger = getLogger(); -const kTrainerRole = 'Trainer'; +const kTrainerRole = "Trainer"; interface MembershipData { id?: string; @@ -439,15 +439,33 @@ async function processExpiredMembership( membershipData: MembershipData ): Promise { try { - await app.firestore().collection("memberships").doc(membershipId).update({ - status: "EXPIRED", - updatedAt: admin.firestore.FieldValue.serverTimestamp(), - }); + const payments = await getPaymentsForMembership(membershipId); + if (payments.length > 0) { + const latestPayment = payments[0]; + const expiryDate = calculateExpiryDate( + latestPayment.dateTimestamp, + membershipData.subscription?.frequency || "monthly" + ); + + await app + .firestore() + .collection("memberships") + .doc(membershipId) + .update({ + expirationDate: admin.firestore.Timestamp.fromDate(expiryDate), + status: "EXPIRED", + updatedAt: admin.firestore.FieldValue.serverTimestamp(), + }); + } else { + await app.firestore().collection("memberships").doc(membershipId).update({ + status: "EXPIRED", + updatedAt: admin.firestore.FieldValue.serverTimestamp(), + }); + } logger.info(`Marked membership ${membershipId} as EXPIRED`); await sendPlanExpiredNotification(membershipId, membershipData); - await sendTrainerNotifications(membershipId, membershipData, "expired"); } catch (error) { logger.error(`Error processing membership ${membershipId}:`, error); @@ -461,8 +479,25 @@ async function processExpiringMembership( try { logger.info(`Processing expiring membership ${membershipId}`); - await sendPlanExpiringNotification(membershipId, membershipData); + const payments = await getPaymentsForMembership(membershipId); + if (payments.length > 0) { + const latestPayment = payments[0]; + const expiryDate = calculateExpiryDate( + latestPayment.dateTimestamp, + membershipData.subscription?.frequency || "monthly" + ); + await app + .firestore() + .collection("memberships") + .doc(membershipId) + .update({ + expirationDate: admin.firestore.Timestamp.fromDate(expiryDate), + updatedAt: admin.firestore.FieldValue.serverTimestamp(), + }); + } + + await sendPlanExpiringNotification(membershipId, membershipData); await sendTrainerNotifications(membershipId, membershipData, "expiring"); } catch (error) { logger.error( @@ -546,7 +581,6 @@ async function sendTrainerNotifications( try { const trainerName = await getTrainerName(assignment.trainerId); const trainerUserId = await getTrainerUserId(assignment.trainerId); - const notifType = notificationType === "expired" -- 2.43.0 From 25f77d2fec2fa4be31be68860ebed7971de2e451 Mon Sep 17 00:00:00 2001 From: Sharon Dcruz Date: Mon, 18 Aug 2025 23:21:09 +0530 Subject: [PATCH 11/52] Changes updated --- firestore.indexes.json | 15 +-------------- 1 file changed, 1 insertion(+), 14 deletions(-) diff --git a/firestore.indexes.json b/firestore.indexes.json index 0530c8b..c1c2245 100644 --- a/firestore.indexes.json +++ b/firestore.indexes.json @@ -56,20 +56,7 @@ } ] }, - { - "collectionGroup": "gyms", - "queryScope": "COLLECTION_GROUP", - "fields": [ - { - "fieldPath": "userId", - "order": "ASCENDING" - }, - { - "fieldPath": "createdAt", - "order": "ASCENDING" - } - ] - }, + { "collectionGroup": "gyms", "queryScope": "COLLECTION", -- 2.43.0 From 559997a16e9bd26cbc7972992f767e027ec3f40a Mon Sep 17 00:00:00 2001 From: Sharon Dcruz Date: Tue, 19 Aug 2025 09:53:01 +0530 Subject: [PATCH 12/52] Changes Updated --- firestore.indexes.json | 14 --- .../membershipStatusNotifications.ts | 96 +++++++++++++++++++ 2 files changed, 96 insertions(+), 14 deletions(-) diff --git a/firestore.indexes.json b/firestore.indexes.json index c1c2245..2d8dc7b 100644 --- a/firestore.indexes.json +++ b/firestore.indexes.json @@ -57,20 +57,6 @@ ] }, - { - "collectionGroup": "gyms", - "queryScope": "COLLECTION", - "fields": [ - { - "fieldPath": "userId", - "order": "ASCENDING" - }, - { - "fieldPath": "name", - "order": "ASCENDING" - } - ] - }, { "collectionGroup": "memberships", "queryScope": "COLLECTION", diff --git a/functions/src/notifications/membershipStatusNotifications.ts b/functions/src/notifications/membershipStatusNotifications.ts index a26f9eb..ba73340 100644 --- a/functions/src/notifications/membershipStatusNotifications.ts +++ b/functions/src/notifications/membershipStatusNotifications.ts @@ -53,6 +53,8 @@ export const checkExpiredMemberships = onSchedule( logger.info("Starting scheduled membership expiry check..."); try { + + await updateDaysUntilExpiryForAllMemberships(); const expiredMemberships = await findExpiredMemberships(); const expiringMemberships = await findMembershipsExpiringIn10Days(); @@ -377,6 +379,100 @@ function calculateRenewalDateFromPayment( return renewalDate; } +async function updateDaysUntilExpiryForAllMemberships(): Promise { + try { + logger.info("Starting to update daysUntilExpiry for all active memberships..."); + + const snapshot = await app + .firestore() + .collection("memberships") + .where("status", "==", "ACTIVE") + .get(); + + const batchSize = 10; + const docs = snapshot.docs; + let updatedCount = 0; + + for (let i = 0; i < docs.length; i += batchSize) { + const batch = docs.slice(i, i + batchSize); + const batchResults = await Promise.allSettled( + batch.map(async (doc) => { + const data = doc.data() as MembershipData; + const daysUntilExpiry = await calculateDaysUntilExpiry(doc.id, data); + + if (daysUntilExpiry !== null) { + await app + .firestore() + .collection("memberships") + .doc(doc.id) + .update({ + daysUntilExpiry: daysUntilExpiry, + updatedAt: admin.firestore.FieldValue.serverTimestamp(), + }); + return doc.id; + } + return null; + }) + ); + + batchResults.forEach((result) => { + if (result.status === "fulfilled" && result.value) { + updatedCount++; + } + }); + } + + logger.info(`Updated daysUntilExpiry for ${updatedCount} memberships`); + } catch (error) { + logger.error("Error updating daysUntilExpiry for memberships:", error); + throw error; + } +} + + +async function calculateDaysUntilExpiry( + membershipId: string, + data: MembershipData +): Promise { + try { + if (!data.subscription || !data.subscription.frequency) { + logger.warn( + `Skipping expiry calculation for membership ${membershipId} with missing subscription data.` + ); + return null; + } + + const payments = await getPaymentsForMembership(membershipId); + if (payments.length === 0) { + logger.warn( + `No payments found for membership ${membershipId}, cannot determine expiry` + ); + return null; + } + + const latestPayment = payments[0]; + const startDate = latestPayment.dateTimestamp; + + const expiryDate = calculateExpiryDate( + startDate, + data.subscription.frequency + ); + + const now = new Date(); + const timeDiff = expiryDate.getTime() - now.getTime(); + const daysUntilExpiry = Math.ceil(timeDiff / (1000 * 3600 * 24)); + + return daysUntilExpiry; + } catch (error) { + logger.error( + `Error calculating daysUntilExpiry for membership ${membershipId}:`, + error + ); + return null; + } +} + + async function getTrainerAssignmentsForMembership( membershipId: string ): Promise { -- 2.43.0 From 2987a8c15999d6bb1dd60407cc0602d0bfaa858a Mon Sep 17 00:00:00 2001 From: Sharon Dcruz Date: Tue, 19 Aug 2025 10:16:27 +0530 Subject: [PATCH 13/52] Index Updated --- firestore.indexes.json | 15 --------------- 1 file changed, 15 deletions(-) diff --git a/firestore.indexes.json b/firestore.indexes.json index 2d8dc7b..0bae7a0 100644 --- a/firestore.indexes.json +++ b/firestore.indexes.json @@ -1,19 +1,5 @@ { "indexes": [ - { - "collectionGroup": "day_pass_bookings", - "queryScope": "COLLECTION", - "fields": [ - { - "fieldPath": "userId", - "order": "ASCENDING" - }, - { - "fieldPath": "createdAt", - "order": "DESCENDING" - } - ] - }, { "collectionGroup": "day_pass_entries", "queryScope": "COLLECTION", @@ -56,7 +42,6 @@ } ] }, - { "collectionGroup": "memberships", "queryScope": "COLLECTION", -- 2.43.0 From 0f3c2909f84ad51fb3ab5bbb4f8c360befdc2f26 Mon Sep 17 00:00:00 2001 From: Sharon Dcruz Date: Tue, 19 Aug 2025 10:24:23 +0530 Subject: [PATCH 14/52] index changed --- firestore.indexes.json | 22 ++++++++++++++++++---- 1 file changed, 18 insertions(+), 4 deletions(-) diff --git a/firestore.indexes.json b/firestore.indexes.json index 0bae7a0..2016f51 100644 --- a/firestore.indexes.json +++ b/firestore.indexes.json @@ -1,5 +1,19 @@ { "indexes": [ + { + "collectionGroup": "day_pass_bookings", + "queryScope": "COLLECTION", + "fields": [ + { + "fieldPath": "userId", + "order": "ASCENDING" + }, + { + "fieldPath": "createdAt", + "order": "DESCENDING" + } + ] + }, { "collectionGroup": "day_pass_entries", "queryScope": "COLLECTION", @@ -24,20 +38,20 @@ }, { "fieldPath": "createdAt", - "order": "DESCENDING" + "order": "ASCENDING" } ] }, { "collectionGroup": "gyms", - "queryScope": "COLLECTION_GROUP", + "queryScope": "COLLECTION", "fields": [ { - "fieldPath": "isApproved", + "fieldPath": "userId", "order": "ASCENDING" }, { - "fieldPath": "createdAt", + "fieldPath": "name", "order": "ASCENDING" } ] -- 2.43.0 From 9f01685278b1126a8e111c9043795a1904a36eda Mon Sep 17 00:00:00 2001 From: Sharon Dcruz Date: Tue, 19 Aug 2025 10:42:12 +0530 Subject: [PATCH 15/52] Added New Index --- firestore.indexes.json | 42 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 42 insertions(+) diff --git a/firestore.indexes.json b/firestore.indexes.json index ef951a9..da30ef2 100644 --- a/firestore.indexes.json +++ b/firestore.indexes.json @@ -1,5 +1,19 @@ { "indexes": [ + { + "collectionGroup": "day_pass_bookings", + "queryScope": "COLLECTION", + "fields": [ + { + "fieldPath": "userId", + "order": "ASCENDING" + }, + { + "fieldPath": "createdAt", + "order": "DESCENDING" + } + ] + }, { "collectionGroup": "day_pass_entries", "queryScope": "COLLECTION", @@ -42,6 +56,34 @@ } ] }, + { + "collectionGroup": "gyms", + "queryScope": "COLLECTION", + "fields": [ + { + "fieldPath": "isApproved", + "order": "ASCENDING" + }, + { + "fieldPath": "createdAt", + "order": "ASCENDING" + } + ] + }, + { + "collectionGroup": "gyms", + "queryScope": "COLLECTION_GROUP", + "fields": [ + { + "fieldPath": "userId", + "order": "ASCENDING" + }, + { + "fieldPath": "createdAt", + "order": "DESCENDING" + } + ] + }, { "collectionGroup": "memberships", "queryScope": "COLLECTION", -- 2.43.0 From beffe778e6cd2761c408f724c35e53f0f541f36f Mon Sep 17 00:00:00 2001 From: Sharon Dcruz Date: Tue, 19 Aug 2025 10:57:30 +0530 Subject: [PATCH 16/52] Updated Index file --- firestore.indexes.json | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/firestore.indexes.json b/firestore.indexes.json index 4aa6594..c305011 100644 --- a/firestore.indexes.json +++ b/firestore.indexes.json @@ -56,20 +56,6 @@ } ] }, - { - "collectionGroup": "gyms", - "queryScope": "COLLECTION", - "fields": [ - { - "fieldPath": "userId", - "order": "ASCENDING" - }, - { - "fieldPath": "name", - "order": "ASCENDING" - } - ] - }, { "collectionGroup": "gyms", "queryScope": "COLLECTION_GROUP", @@ -84,6 +70,20 @@ } ] }, + { + "collectionGroup": "gyms", + "queryScope": "COLLECTION_GROUP", + "fields": [ + { + "fieldPath": "isApproved", + "order": "ASCENDING" + }, + { + "fieldPath": "createdAt", + "order": "ASCENDING" + } + ] + }, { "collectionGroup": "memberships", "queryScope": "COLLECTION", -- 2.43.0 From 1abf6b3d58a35dbbcd04e296017aae49956ad619 Mon Sep 17 00:00:00 2001 From: Sharon Dcruz Date: Tue, 19 Aug 2025 11:06:23 +0530 Subject: [PATCH 17/52] Changes done for index --- firestore.indexes.json | 14 -------------- 1 file changed, 14 deletions(-) diff --git a/firestore.indexes.json b/firestore.indexes.json index c305011..887fe07 100644 --- a/firestore.indexes.json +++ b/firestore.indexes.json @@ -28,20 +28,6 @@ } ] }, - { - "collectionGroup": "gyms", - "queryScope": "COLLECTION_GROUP", - "fields": [ - { - "fieldPath": "userId", - "order": "ASCENDING" - }, - { - "fieldPath": "createdAt", - "order": "ASCENDING" - } - ] - }, { "collectionGroup": "gyms", "queryScope": "COLLECTION", -- 2.43.0 From 2467e71ec0ce4aa97fb30fae549617f16c30655a Mon Sep 17 00:00:00 2001 From: Sharon Dcruz Date: Tue, 19 Aug 2025 11:08:39 +0530 Subject: [PATCH 18/52] Updated --- firestore.indexes.json | 28 ---------------------------- 1 file changed, 28 deletions(-) diff --git a/firestore.indexes.json b/firestore.indexes.json index 887fe07..c4bf41d 100644 --- a/firestore.indexes.json +++ b/firestore.indexes.json @@ -1,33 +1,5 @@ { "indexes": [ - { - "collectionGroup": "day_pass_bookings", - "queryScope": "COLLECTION", - "fields": [ - { - "fieldPath": "userId", - "order": "ASCENDING" - }, - { - "fieldPath": "createdAt", - "order": "DESCENDING" - } - ] - }, - { - "collectionGroup": "day_pass_entries", - "queryScope": "COLLECTION", - "fields": [ - { - "fieldPath": "bookingId", - "order": "ASCENDING" - }, - { - "fieldPath": "entryDate", - "order": "ASCENDING" - } - ] - }, { "collectionGroup": "gyms", "queryScope": "COLLECTION", -- 2.43.0 From 1e80333bc5103316157de524767b179e1a9b5c1b Mon Sep 17 00:00:00 2001 From: Sharon Dcruz Date: Tue, 19 Aug 2025 11:51:03 +0530 Subject: [PATCH 19/52] Index file rremoved --- firestore.indexes.json | 231 ----------------------------------------- 1 file changed, 231 deletions(-) diff --git a/firestore.indexes.json b/firestore.indexes.json index c4bf41d..e69de29 100644 --- a/firestore.indexes.json +++ b/firestore.indexes.json @@ -1,231 +0,0 @@ -{ - "indexes": [ - { - "collectionGroup": "gyms", - "queryScope": "COLLECTION", - "fields": [ - { - "fieldPath": "userId", - "order": "ASCENDING" - }, - { - "fieldPath": "name", - "order": "ASCENDING" - } - ] - }, - { - "collectionGroup": "gyms", - "queryScope": "COLLECTION_GROUP", - "fields": [ - { - "fieldPath": "userId", - "order": "ASCENDING" - }, - { - "fieldPath": "createdAt", - "order": "DESCENDING" - } - ] - }, - { - "collectionGroup": "gyms", - "queryScope": "COLLECTION_GROUP", - "fields": [ - { - "fieldPath": "isApproved", - "order": "ASCENDING" - }, - { - "fieldPath": "createdAt", - "order": "ASCENDING" - } - ] - }, - { - "collectionGroup": "memberships", - "queryScope": "COLLECTION", - "fields": [ - { - "fieldPath": "gymId", - "order": "ASCENDING" - }, - { - "fieldPath": "createdAt", - "order": "DESCENDING" - } - ] - }, - { - "collectionGroup": "notifications", - "queryScope": "COLLECTION", - "fields": [ - { - "fieldPath": "data.clientId", - "order": "ASCENDING" - }, - { - "fieldPath": "timestamp", - "order": "DESCENDING" - } - ] - }, - { - "collectionGroup": "notifications", - "queryScope": "COLLECTION", - "fields": [ - { - "fieldPath": "data.clientId", - "order": "ASCENDING" - }, - { - "fieldPath": "type", - "order": "ASCENDING" - }, - { - "fieldPath": "timestamp", - "order": "DESCENDING" - } - ] - }, - { - "collectionGroup": "notifications", - "queryScope": "COLLECTION", - "fields": [ - { - "fieldPath": "type", - "order": "ASCENDING" - }, - { - "fieldPath": "userId", - "order": "ASCENDING" - }, - { - "fieldPath": "timestamp", - "order": "DESCENDING" - } - ] - }, - { - "collectionGroup": "notifications", - "queryScope": "COLLECTION", - "fields": [ - { - "fieldPath": "data.ownerId", - "order": "ASCENDING" - }, - { - "fieldPath": "timestamp", - "order": "DESCENDING" - } - ] - }, - { - "collectionGroup": "notifications", - "queryScope": "COLLECTION", - "fields": [ - { - "fieldPath": "data.ownerId", - "order": "ASCENDING" - }, - { - "fieldPath": "type", - "order": "ASCENDING" - }, - { - "fieldPath": "timestamp", - "order": "DESCENDING" - } - ] - }, - { - "collectionGroup": "notifications", - "queryScope": "COLLECTION", - "fields": [ - { - "fieldPath": "data.trainerId", - "order": "ASCENDING" - }, - { - "fieldPath": "timestamp", - "order": "DESCENDING" - } - ] - }, - { - "collectionGroup": "notifications", - "queryScope": "COLLECTION", - "fields": [ - { - "fieldPath": "recipientId", - "order": "ASCENDING" - }, - { - "fieldPath": "timestamp", - "order": "DESCENDING" - } - ] - }, - { - "collectionGroup": "workout_logs", - "queryScope": "COLLECTION", - "fields": [ - { - "fieldPath": "user_id", - "order": "ASCENDING" - }, - { - "fieldPath": "date", - "order": "DESCENDING" - } - ] - }, - { - "collectionGroup": "workout_logs", - "queryScope": "COLLECTION", - "fields": [ - { - "fieldPath": "user_id", - "order": "ASCENDING" - }, - { - "fieldPath": "date", - "order": "ASCENDING" - } - ] - }, - { - "collectionGroup": "workout_logs", - "queryScope": "COLLECTION", - "fields": [ - { - "fieldPath": "user_id", - "order": "ASCENDING" - }, - { - "fieldPath": "start_time", - "order": "ASCENDING" - }, - { - "fieldPath": "date", - "order": "ASCENDING" - } - ] - }, - { - "collectionGroup": "terms_and_conditions", - "queryScope": "COLLECTION", - "fields": [ - { - "fieldPath": "normalizedName", - "order": "ASCENDING" - }, - { - "fieldPath": "userUid", - "order": "ASCENDING" - } - ] - } - ], - "fieldOverrides": [] -} \ No newline at end of file -- 2.43.0 From 83cb1d83fae85585a2c93d63ecd7cb1417a80df2 Mon Sep 17 00:00:00 2001 From: Sharon Dcruz Date: Tue, 19 Aug 2025 12:07:32 +0530 Subject: [PATCH 20/52] Changes done for index --- firestore.indexes.json | 259 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 259 insertions(+) diff --git a/firestore.indexes.json b/firestore.indexes.json index e69de29..887fe07 100644 --- a/firestore.indexes.json +++ b/firestore.indexes.json @@ -0,0 +1,259 @@ +{ + "indexes": [ + { + "collectionGroup": "day_pass_bookings", + "queryScope": "COLLECTION", + "fields": [ + { + "fieldPath": "userId", + "order": "ASCENDING" + }, + { + "fieldPath": "createdAt", + "order": "DESCENDING" + } + ] + }, + { + "collectionGroup": "day_pass_entries", + "queryScope": "COLLECTION", + "fields": [ + { + "fieldPath": "bookingId", + "order": "ASCENDING" + }, + { + "fieldPath": "entryDate", + "order": "ASCENDING" + } + ] + }, + { + "collectionGroup": "gyms", + "queryScope": "COLLECTION", + "fields": [ + { + "fieldPath": "userId", + "order": "ASCENDING" + }, + { + "fieldPath": "name", + "order": "ASCENDING" + } + ] + }, + { + "collectionGroup": "gyms", + "queryScope": "COLLECTION_GROUP", + "fields": [ + { + "fieldPath": "userId", + "order": "ASCENDING" + }, + { + "fieldPath": "createdAt", + "order": "DESCENDING" + } + ] + }, + { + "collectionGroup": "gyms", + "queryScope": "COLLECTION_GROUP", + "fields": [ + { + "fieldPath": "isApproved", + "order": "ASCENDING" + }, + { + "fieldPath": "createdAt", + "order": "ASCENDING" + } + ] + }, + { + "collectionGroup": "memberships", + "queryScope": "COLLECTION", + "fields": [ + { + "fieldPath": "gymId", + "order": "ASCENDING" + }, + { + "fieldPath": "createdAt", + "order": "DESCENDING" + } + ] + }, + { + "collectionGroup": "notifications", + "queryScope": "COLLECTION", + "fields": [ + { + "fieldPath": "data.clientId", + "order": "ASCENDING" + }, + { + "fieldPath": "timestamp", + "order": "DESCENDING" + } + ] + }, + { + "collectionGroup": "notifications", + "queryScope": "COLLECTION", + "fields": [ + { + "fieldPath": "data.clientId", + "order": "ASCENDING" + }, + { + "fieldPath": "type", + "order": "ASCENDING" + }, + { + "fieldPath": "timestamp", + "order": "DESCENDING" + } + ] + }, + { + "collectionGroup": "notifications", + "queryScope": "COLLECTION", + "fields": [ + { + "fieldPath": "type", + "order": "ASCENDING" + }, + { + "fieldPath": "userId", + "order": "ASCENDING" + }, + { + "fieldPath": "timestamp", + "order": "DESCENDING" + } + ] + }, + { + "collectionGroup": "notifications", + "queryScope": "COLLECTION", + "fields": [ + { + "fieldPath": "data.ownerId", + "order": "ASCENDING" + }, + { + "fieldPath": "timestamp", + "order": "DESCENDING" + } + ] + }, + { + "collectionGroup": "notifications", + "queryScope": "COLLECTION", + "fields": [ + { + "fieldPath": "data.ownerId", + "order": "ASCENDING" + }, + { + "fieldPath": "type", + "order": "ASCENDING" + }, + { + "fieldPath": "timestamp", + "order": "DESCENDING" + } + ] + }, + { + "collectionGroup": "notifications", + "queryScope": "COLLECTION", + "fields": [ + { + "fieldPath": "data.trainerId", + "order": "ASCENDING" + }, + { + "fieldPath": "timestamp", + "order": "DESCENDING" + } + ] + }, + { + "collectionGroup": "notifications", + "queryScope": "COLLECTION", + "fields": [ + { + "fieldPath": "recipientId", + "order": "ASCENDING" + }, + { + "fieldPath": "timestamp", + "order": "DESCENDING" + } + ] + }, + { + "collectionGroup": "workout_logs", + "queryScope": "COLLECTION", + "fields": [ + { + "fieldPath": "user_id", + "order": "ASCENDING" + }, + { + "fieldPath": "date", + "order": "DESCENDING" + } + ] + }, + { + "collectionGroup": "workout_logs", + "queryScope": "COLLECTION", + "fields": [ + { + "fieldPath": "user_id", + "order": "ASCENDING" + }, + { + "fieldPath": "date", + "order": "ASCENDING" + } + ] + }, + { + "collectionGroup": "workout_logs", + "queryScope": "COLLECTION", + "fields": [ + { + "fieldPath": "user_id", + "order": "ASCENDING" + }, + { + "fieldPath": "start_time", + "order": "ASCENDING" + }, + { + "fieldPath": "date", + "order": "ASCENDING" + } + ] + }, + { + "collectionGroup": "terms_and_conditions", + "queryScope": "COLLECTION", + "fields": [ + { + "fieldPath": "normalizedName", + "order": "ASCENDING" + }, + { + "fieldPath": "userUid", + "order": "ASCENDING" + } + ] + } + ], + "fieldOverrides": [] +} \ No newline at end of file -- 2.43.0 From d27d41318b44865183701b0cab12acfcdf3fabc5 Mon Sep 17 00:00:00 2001 From: Sharon Dcruz Date: Tue, 19 Aug 2025 12:19:52 +0530 Subject: [PATCH 21/52] updated --- firestore.indexes.json | 88 ------------------------------------------ 1 file changed, 88 deletions(-) diff --git a/firestore.indexes.json b/firestore.indexes.json index 9e692cc..53cc445 100644 --- a/firestore.indexes.json +++ b/firestore.indexes.json @@ -165,94 +165,6 @@ "order": "DESCENDING" } ] - }, - { - "collectionGroup": "notifications", - "queryScope": "COLLECTION", - "fields": [ - { - "fieldPath": "data.trainerId", - "order": "ASCENDING" - }, - { - "fieldPath": "timestamp", - "order": "DESCENDING" - } - ] - }, - { - "collectionGroup": "notifications", - "queryScope": "COLLECTION", - "fields": [ - { - "fieldPath": "recipientId", - "order": "ASCENDING" - }, - { - "fieldPath": "timestamp", - "order": "DESCENDING" - } - ] - }, - { - "collectionGroup": "workout_logs", - "queryScope": "COLLECTION", - "fields": [ - { - "fieldPath": "user_id", - "order": "ASCENDING" - }, - { - "fieldPath": "date", - "order": "DESCENDING" - } - ] - }, - { - "collectionGroup": "workout_logs", - "queryScope": "COLLECTION", - "fields": [ - { - "fieldPath": "user_id", - "order": "ASCENDING" - }, - { - "fieldPath": "date", - "order": "ASCENDING" - } - ] - }, - { - "collectionGroup": "workout_logs", - "queryScope": "COLLECTION", - "fields": [ - { - "fieldPath": "user_id", - "order": "ASCENDING" - }, - { - "fieldPath": "start_time", - "order": "ASCENDING" - }, - { - "fieldPath": "date", - "order": "ASCENDING" - } - ] - }, - { - "collectionGroup": "terms_and_conditions", - "queryScope": "COLLECTION", - "fields": [ - { - "fieldPath": "normalizedName", - "order": "ASCENDING" - }, - { - "fieldPath": "userUid", - "order": "ASCENDING" - } - ] } ], "fieldOverrides": [] -- 2.43.0 From 5e2aacab581b90b90e7209cba66f9d69e331a635 Mon Sep 17 00:00:00 2001 From: Sharon Dcruz Date: Tue, 19 Aug 2025 12:23:28 +0530 Subject: [PATCH 22/52] updated --- firestore.indexes.json | 136 +++++++++-------------------------------- 1 file changed, 29 insertions(+), 107 deletions(-) diff --git a/firestore.indexes.json b/firestore.indexes.json index 53cc445..980f655 100644 --- a/firestore.indexes.json +++ b/firestore.indexes.json @@ -1,95 +1,11 @@ { "indexes": [ - { - "collectionGroup": "day_pass_bookings", - "queryScope": "COLLECTION", - "fields": [ - { - "fieldPath": "userId", - "order": "ASCENDING" - }, - { - "fieldPath": "createdAt", - "order": "DESCENDING" - } - ] - }, - { - "collectionGroup": "day_pass_entries", - "queryScope": "COLLECTION", - "fields": [ - { - "fieldPath": "bookingId", - "order": "ASCENDING" - }, - { - "fieldPath": "entryDate", - "order": "ASCENDING" - } - ] - }, - { - "collectionGroup": "gyms", - "queryScope": "COLLECTION", - "fields": [ - { - "fieldPath": "userId", - "order": "ASCENDING" - }, - { - "fieldPath": "name", - "order": "ASCENDING" - } - ] - }, - { - "collectionGroup": "gyms", - "queryScope": "COLLECTION_GROUP", - "fields": [ - { - "fieldPath": "userId", - "order": "ASCENDING" - }, - { - "fieldPath": "createdAt", - "order": "DESCENDING" - } - ] - }, - { - "collectionGroup": "gyms", - "queryScope": "COLLECTION_GROUP", - "fields": [ - { - "fieldPath": "isApproved", - "order": "ASCENDING" - }, - { - "fieldPath": "createdAt", - "order": "ASCENDING" - } - ] - }, - { - "collectionGroup": "memberships", - "queryScope": "COLLECTION", - "fields": [ - { - "fieldPath": "gymId", - "order": "ASCENDING" - }, - { - "fieldPath": "createdAt", - "order": "DESCENDING" - } - ] - }, - { +{ "collectionGroup": "notifications", "queryScope": "COLLECTION", "fields": [ { - "fieldPath": "data.clientId", + "fieldPath": "data.trainerId", "order": "ASCENDING" }, { @@ -103,11 +19,7 @@ "queryScope": "COLLECTION", "fields": [ { - "fieldPath": "data.clientId", - "order": "ASCENDING" - }, - { - "fieldPath": "type", + "fieldPath": "recipientId", "order": "ASCENDING" }, { @@ -117,52 +29,62 @@ ] }, { - "collectionGroup": "notifications", + "collectionGroup": "workout_logs", "queryScope": "COLLECTION", "fields": [ { - "fieldPath": "type", + "fieldPath": "user_id", "order": "ASCENDING" }, { - "fieldPath": "userId", - "order": "ASCENDING" - }, - { - "fieldPath": "timestamp", + "fieldPath": "date", "order": "DESCENDING" } ] }, { - "collectionGroup": "notifications", + "collectionGroup": "workout_logs", "queryScope": "COLLECTION", "fields": [ { - "fieldPath": "data.ownerId", + "fieldPath": "user_id", "order": "ASCENDING" }, { - "fieldPath": "timestamp", - "order": "DESCENDING" + "fieldPath": "date", + "order": "ASCENDING" } ] }, { - "collectionGroup": "notifications", + "collectionGroup": "workout_logs", "queryScope": "COLLECTION", "fields": [ { - "fieldPath": "data.ownerId", + "fieldPath": "user_id", "order": "ASCENDING" }, { - "fieldPath": "type", + "fieldPath": "start_time", "order": "ASCENDING" }, { - "fieldPath": "timestamp", - "order": "DESCENDING" + "fieldPath": "date", + "order": "ASCENDING" + } + ] + }, + { + "collectionGroup": "terms_and_conditions", + "queryScope": "COLLECTION", + "fields": [ + { + "fieldPath": "normalizedName", + "order": "ASCENDING" + }, + { + "fieldPath": "userUid", + "order": "ASCENDING" } ] } -- 2.43.0 From fb6141f0b35047fc7fa56d2e867685f338b5d36c Mon Sep 17 00:00:00 2001 From: Sharon Dcruz Date: Tue, 19 Aug 2025 12:35:02 +0530 Subject: [PATCH 23/52] Changes Updated --- firestore.indexes.json | 110 +++++++++++++++++++++++++++++++++++++++-- 1 file changed, 107 insertions(+), 3 deletions(-) diff --git a/firestore.indexes.json b/firestore.indexes.json index 980f655..ae7170d 100644 --- a/firestore.indexes.json +++ b/firestore.indexes.json @@ -1,11 +1,114 @@ { "indexes": [ -{ + { + "collectionGroup": "day_pass_bookings", + "queryScope": "COLLECTION", + "fields": [ + { + "fieldPath": "userId", + "order": "ASCENDING" + }, + { + "fieldPath": "createdAt", + "order": "DESCENDING" + } + ] + }, + { + "collectionGroup": "day_pass_entries", + "queryScope": "COLLECTION", + "fields": [ + { + "fieldPath": "bookingId", + "order": "ASCENDING" + }, + { + "fieldPath": "entryDate", + "order": "ASCENDING" + } + ] + }, + { + "collectionGroup": "gyms", + "queryScope": "COLLECTION", + "fields": [ + { + "fieldPath": "userId", + "order": "ASCENDING" + }, + { + "fieldPath": "name", + "order": "ASCENDING" + } + ] + }, + { + "collectionGroup": "gyms", + "queryScope": "COLLECTION_GROUP", + "fields": [ + { + "fieldPath": "userId", + "order": "ASCENDING" + }, + { + "fieldPath": "createdAt", + "order": "DESCENDING" + } + ] + }, + { + "collectionGroup": "gyms", + "queryScope": "COLLECTION_GROUP", + "fields": [ + { + "fieldPath": "userId", + "order": "ASCENDING" + }, + { + "fieldPath": "createdAt", + "order": "ASCENDING" + } + ] + }, + { + "collectionGroup": "gyms", + "queryScope": "COLLECTION_GROUP", + "fields": [ + { + "fieldPath": "isApproved", + "order": "ASCENDING" + }, + { + "fieldPath": "createdAt", + "order": "ASCENDING" + } + ] + }, + { + "collectionGroup": "memberships", + "queryScope": "COLLECTION", + "fields": [ + { + "fieldPath": "gymId", + "order": "ASCENDING" + }, + { + "fieldPath": "createdAt", + "order": "DESCENDING" + } + ] + }, + + { "collectionGroup": "notifications", "queryScope": "COLLECTION", "fields": [ { - "fieldPath": "data.trainerId", + "fieldPath": "type", + "order": "ASCENDING" + }, + { + "fieldPath": "userId", "order": "ASCENDING" }, { @@ -14,6 +117,7 @@ } ] }, + { "collectionGroup": "notifications", "queryScope": "COLLECTION", @@ -90,4 +194,4 @@ } ], "fieldOverrides": [] -} +} \ No newline at end of file -- 2.43.0 From b51f4d81f0bdc8d41664541746fbd923ed78dcb8 Mon Sep 17 00:00:00 2001 From: Sharon Dcruz Date: Tue, 19 Aug 2025 12:40:32 +0530 Subject: [PATCH 24/52] Changed --- firestore.indexes.json | 1 + 1 file changed, 1 insertion(+) diff --git a/firestore.indexes.json b/firestore.indexes.json index 6f214a4..2ffd217 100644 --- a/firestore.indexes.json +++ b/firestore.indexes.json @@ -189,5 +189,6 @@ ] } ], + "fieldOverrides": [] } \ No newline at end of file -- 2.43.0 From 99fed340aa559f5f789059748682a021676c81e0 Mon Sep 17 00:00:00 2001 From: Sharon Dcruz Date: Tue, 19 Aug 2025 12:49:47 +0530 Subject: [PATCH 25/52] updated --- firestore.indexes.json | 143 ++++------------------------------------- 1 file changed, 14 insertions(+), 129 deletions(-) diff --git a/firestore.indexes.json b/firestore.indexes.json index 2ffd217..f39047e 100644 --- a/firestore.indexes.json +++ b/firestore.indexes.json @@ -1,133 +1,5 @@ { "indexes": [ - { - "collectionGroup": "day_pass_bookings", - "queryScope": "COLLECTION", - "fields": [ - { - "fieldPath": "userId", - "order": "ASCENDING" - }, - { - "fieldPath": "createdAt", - "order": "DESCENDING" - } - ] - }, - { - "collectionGroup": "day_pass_entries", - "queryScope": "COLLECTION", - "fields": [ - { - "fieldPath": "bookingId", - "order": "ASCENDING" - }, - { - "fieldPath": "entryDate", - "order": "ASCENDING" - } - ] - }, - { - "collectionGroup": "gyms", - "queryScope": "COLLECTION", - "fields": [ - { - "fieldPath": "userId", - "order": "ASCENDING" - }, - { - "fieldPath": "name", - "order": "ASCENDING" - } - ] - }, - { - "collectionGroup": "gyms", - "queryScope": "COLLECTION_GROUP", - "fields": [ - { - "fieldPath": "userId", - "order": "ASCENDING" - }, - { - "fieldPath": "createdAt", - "order": "DESCENDING" - } - ] - }, - { - "collectionGroup": "gyms", - "queryScope": "COLLECTION_GROUP", - "fields": [ - { - "fieldPath": "userId", - "order": "ASCENDING" - }, - { - "fieldPath": "createdAt", - "order": "ASCENDING" - } - ] - }, - { - "collectionGroup": "gyms", - "queryScope": "COLLECTION_GROUP", - "fields": [ - { - "fieldPath": "isApproved", - "order": "ASCENDING" - }, - { - "fieldPath": "createdAt", - "order": "ASCENDING" - } - ] - }, - { - "collectionGroup": "memberships", - "queryScope": "COLLECTION", - "fields": [ - { - "fieldPath": "gymId", - "order": "ASCENDING" - }, - { - "fieldPath": "createdAt", - "order": "DESCENDING" - } - ] - }, - - { - "collectionGroup": "workout_logs", - "queryScope": "COLLECTION", - "fields": [ - { - "fieldPath": "user_id", - "order": "ASCENDING" - }, - { - "fieldPath": "date", - "order": "DESCENDING" - } - ] - }, - - { - "collectionGroup": "workout_logs", - "queryScope": "COLLECTION", - "fields": [ - { - "fieldPath": "recipientId", - "order": "ASCENDING" - }, - { - "fieldPath": "date", - "order": "ASCENDING" - } - ] - }, { "collectionGroup": "workout_logs", "queryScope": "COLLECTION", @@ -187,8 +59,21 @@ "order": "ASCENDING" } ] + }, + { + "collectionGroup": "notifications", + "queryScope": "COLLECTION", + "fields": [ + { + "fieldPath": "recipientId", + "order": "ASCENDING" + }, + { + "fieldPath": "timestamp", + "order": "DESCENDING" + } + ] } ], - "fieldOverrides": [] } \ No newline at end of file -- 2.43.0 From 9f8ea011c192230a828a673df6107bdbb47fc384 Mon Sep 17 00:00:00 2001 From: Sharon Dcruz Date: Tue, 19 Aug 2025 15:11:59 +0530 Subject: [PATCH 26/52] Updated --- firestore.indexes.json | 121 ++++++++++++++++++++++++++++++++++++----- 1 file changed, 107 insertions(+), 14 deletions(-) diff --git a/firestore.indexes.json b/firestore.indexes.json index f39047e..d2b6856 100644 --- a/firestore.indexes.json +++ b/firestore.indexes.json @@ -1,5 +1,112 @@ { "indexes": [ + { + "collectionGroup": "day_pass_bookings", + "queryScope": "COLLECTION", + "fields": [ + { + "fieldPath": "userId", + "order": "ASCENDING" + }, + { + "fieldPath": "createdAt", + "order": "DESCENDING" + } + ] + }, + { + "collectionGroup": "day_pass_entries", + "queryScope": "COLLECTION", + "fields": [ + { + "fieldPath": "bookingId", + "order": "ASCENDING" + }, + { + "fieldPath": "entryDate", + "order": "ASCENDING" + } + ] + }, + { + "collectionGroup": "gyms", + "queryScope": "COLLECTION_GROUP", + "fields": [ + { + "fieldPath": "userId", + "order": "ASCENDING" + }, + { + "fieldPath": "createdAt", + "order": "ASCENDING" + } + ] + }, + { + "collectionGroup": "gyms", + "queryScope": "COLLECTION", + "fields": [ + { + "fieldPath": "userId", + "order": "ASCENDING" + }, + { + "fieldPath": "name", + "order": "ASCENDING" + } + ] + }, + { + "collectionGroup": "memberships", + "queryScope": "COLLECTION", + "fields": [ + { + "fieldPath": "gymId", + "order": "ASCENDING" + }, + { + "fieldPath": "createdAt", + "order": "DESCENDING" + } + ] + }, + + + { + "collectionGroup": "notifications", + "queryScope": "COLLECTION", + "fields": [ + { + "fieldPath": "type", + "order": "ASCENDING" + }, + { + "fieldPath": "userId", + "order": "ASCENDING" + }, + { + "fieldPath": "timestamp", + "order": "DESCENDING" + } + ] + }, + + + + { + "collectionGroup": "notifications", + "queryScope": "COLLECTION", + "fields": [ + { + "fieldPath": "recipientId", + "order": "ASCENDING" + }, + { + "fieldPath": "timestamp", + "order": "DESCENDING" + } + ] + }, { "collectionGroup": "workout_logs", "queryScope": "COLLECTION", @@ -59,20 +166,6 @@ "order": "ASCENDING" } ] - }, - { - "collectionGroup": "notifications", - "queryScope": "COLLECTION", - "fields": [ - { - "fieldPath": "recipientId", - "order": "ASCENDING" - }, - { - "fieldPath": "timestamp", - "order": "DESCENDING" - } - ] } ], "fieldOverrides": [] -- 2.43.0 From 1bd8d24df6af35637a6cab2bd4336b14c8938a77 Mon Sep 17 00:00:00 2001 From: Sharon Dcruz Date: Tue, 19 Aug 2025 15:21:12 +0530 Subject: [PATCH 27/52] Updated --- firestore.indexes.json | 185 +---------------------------------------- 1 file changed, 1 insertion(+), 184 deletions(-) diff --git a/firestore.indexes.json b/firestore.indexes.json index 077a143..2ddb5ce 100644 --- a/firestore.indexes.json +++ b/firestore.indexes.json @@ -1,187 +1,4 @@ { - "indexes": [ - { - "collectionGroup": "day_pass_bookings", - "queryScope": "COLLECTION", - "fields": [ - { - "fieldPath": "userId", - "order": "ASCENDING" - }, - { - "fieldPath": "createdAt", - "order": "DESCENDING" - } - ] - }, - { - "collectionGroup": "day_pass_entries", - "queryScope": "COLLECTION", - "fields": [ - { - "fieldPath": "bookingId", - "order": "ASCENDING" - }, - { - "fieldPath": "entryDate", - "order": "ASCENDING" - } - ] - }, - { - "collectionGroup": "gyms", - "queryScope": "COLLECTION_GROUP", - "fields": [ - { - "fieldPath": "userId", - "order": "ASCENDING" - }, - { - "fieldPath": "createdAt", - "order": "ASCENDING" - } - ] - }, - { - "collectionGroup": "gyms", - "queryScope": "COLLECTION", - "fields": [ - { - "fieldPath": "userId", - "order": "ASCENDING" - }, - { - "fieldPath": "name", - "order": "ASCENDING" - } - ] - }, - { - "collectionGroup": "memberships", - "queryScope": "COLLECTION", - "fields": [ - { - "fieldPath": "gymId", - "order": "ASCENDING" - }, - { - "fieldPath": "createdAt", - "order": "DESCENDING" - } - ] - }, - - - { - "collectionGroup": "notifications", - "queryScope": "COLLECTION", - "fields": [ - { - "fieldPath": "type", - "order": "ASCENDING" - }, - { - "fieldPath": "userId", - "order": "ASCENDING" - }, - { - "fieldPath": "timestamp", - "order": "DESCENDING" - } - ] - }, - - - - { - "collectionGroup": "notifications", - "queryScope": "COLLECTION", - "fields": [ - { - "fieldPath": "recipientId", - "order": "ASCENDING" - }, - { - "fieldPath": "timestamp", - "order": "DESCENDING" - } - ] - }, - { - "collectionGroup": "workout_logs", - "queryScope": "COLLECTION", - "fields": [ - { - "fieldPath": "user_id", - "order": "ASCENDING" - }, - { - "fieldPath": "date", - "order": "DESCENDING" - } - ] - }, - { - "collectionGroup": "workout_logs", - "queryScope": "COLLECTION", - "fields": [ - { - "fieldPath": "user_id", - "order": "ASCENDING" - }, - { - "fieldPath": "date", - "order": "ASCENDING" - } - ] - }, - { - "collectionGroup": "workout_logs", - "queryScope": "COLLECTION", - "fields": [ - { - "fieldPath": "user_id", - "order": "ASCENDING" - }, - { - "fieldPath": "start_time", - "order": "ASCENDING" - }, - { - "fieldPath": "date", - "order": "ASCENDING" - } - ] - }, - { - "collectionGroup": "terms_and_conditions", - "queryScope": "COLLECTION", - "fields": [ - { - "fieldPath": "normalizedName", - "order": "ASCENDING" - }, - { - "fieldPath": "userUid", - "order": "ASCENDING" - } - ] - }, - { - "collectionGroup": "notifications", - "queryScope": "COLLECTION", - "fields": [ - { - "fieldPath": "recipientId", - "order": "ASCENDING" - }, - { - "fieldPath": "timestamp", - "order": "DESCENDING" - } - ] - } - ], - + "indexes": [], "fieldOverrides": [] } \ No newline at end of file -- 2.43.0 From 86b2073e8e562cf69294384e5dd1e407616b07a2 Mon Sep 17 00:00:00 2001 From: Sharon Dcruz Date: Tue, 19 Aug 2025 15:49:09 +0530 Subject: [PATCH 28/52] Done --- firestore.indexes.json | 165 ++++++++++++++++++++++++++++++++++++++++- 1 file changed, 164 insertions(+), 1 deletion(-) diff --git a/firestore.indexes.json b/firestore.indexes.json index 2ddb5ce..054170d 100644 --- a/firestore.indexes.json +++ b/firestore.indexes.json @@ -1,4 +1,167 @@ { - "indexes": [], + "indexes": [ + { + "collectionGroup": "day_pass_bookings", + "queryScope": "COLLECTION", + "fields": [ + { + "fieldPath": "userId", + "order": "ASCENDING" + }, + { + "fieldPath": "createdAt", + "order": "DESCENDING" + } + ] + }, + { + "collectionGroup": "day_pass_entries", + "queryScope": "COLLECTION", + "fields": [ + { + "fieldPath": "bookingId", + "order": "ASCENDING" + }, + { + "fieldPath": "entryDate", + "order": "ASCENDING" + } + ] + }, + { + "collectionGroup": "gyms", + "queryScope": "COLLECTION_GROUP", + "fields": [ + { + "fieldPath": "userId", + "order": "ASCENDING" + }, + { + "fieldPath": "createdAt", + "order": "ASCENDING" + } + ] + }, + { + "collectionGroup": "gyms", + "queryScope": "COLLECTION", + "fields": [ + { + "fieldPath": "userId", + "order": "ASCENDING" + }, + { + "fieldPath": "name", + "order": "ASCENDING" + } + ] + }, + { + "collectionGroup": "memberships", + "queryScope": "COLLECTION", + "fields": [ + { + "fieldPath": "gymId", + "order": "ASCENDING" + }, + { + "fieldPath": "createdAt", + "order": "DESCENDING" + } + ] + }, + { + "collectionGroup": "notifications", + "queryScope": "COLLECTION", + "fields": [ + { + "fieldPath": "type", + "order": "ASCENDING" + }, + { + "fieldPath": "userId", + "order": "ASCENDING" + }, + { + "fieldPath": "timestamp", + "order": "DESCENDING" + } + ] + }, + { + "collectionGroup": "notifications", + "queryScope": "COLLECTION", + "fields": [ + { + "fieldPath": "recipientId", + "order": "ASCENDING" + }, + { + "fieldPath": "timestamp", + "order": "DESCENDING" + } + ] + }, + { + "collectionGroup": "workout_logs", + "queryScope": "COLLECTION", + "fields": [ + { + "fieldPath": "user_id", + "order": "ASCENDING" + }, + { + "fieldPath": "date", + "order": "DESCENDING" + } + ] + }, + { + "collectionGroup": "workout_logs", + "queryScope": "COLLECTION", + "fields": [ + { + "fieldPath": "user_id", + "order": "ASCENDING" + }, + { + "fieldPath": "date", + "order": "ASCENDING" + } + ] + }, + { + "collectionGroup": "workout_logs", + "queryScope": "COLLECTION", + "fields": [ + { + "fieldPath": "user_id", + "order": "ASCENDING" + }, + { + "fieldPath": "start_time", + "order": "ASCENDING" + }, + { + "fieldPath": "date", + "order": "ASCENDING" + } + ] + }, + { + "collectionGroup": "terms_and_conditions", + "queryScope": "COLLECTION", + "fields": [ + { + "fieldPath": "normalizedName", + "order": "ASCENDING" + }, + { + "fieldPath": "userUid", + "order": "ASCENDING" + } + ] + } + ], "fieldOverrides": [] } \ No newline at end of file -- 2.43.0 From a62db929aa5df4cbfac576f85f30093782082be8 Mon Sep 17 00:00:00 2001 From: Sharon Dcruz Date: Tue, 19 Aug 2025 16:25:16 +0530 Subject: [PATCH 29/52] Changes Updated --- .../membershipStatusNotifications.ts | 34 +++++++++++++------ 1 file changed, 23 insertions(+), 11 deletions(-) diff --git a/functions/src/notifications/membershipStatusNotifications.ts b/functions/src/notifications/membershipStatusNotifications.ts index ba73340..7e1b88e 100644 --- a/functions/src/notifications/membershipStatusNotifications.ts +++ b/functions/src/notifications/membershipStatusNotifications.ts @@ -53,7 +53,6 @@ export const checkExpiredMemberships = onSchedule( logger.info("Starting scheduled membership expiry check..."); try { - await updateDaysUntilExpiryForAllMemberships(); const expiredMemberships = await findExpiredMemberships(); const expiringMemberships = await findMembershipsExpiringIn10Days(); @@ -381,8 +380,10 @@ function calculateRenewalDateFromPayment( async function updateDaysUntilExpiryForAllMemberships(): Promise { try { - logger.info("Starting to update daysUntilExpiry for all active memberships..."); - + logger.info( + "Starting to update daysUntilExpiry for all active memberships..." + ); + const snapshot = await app .firestore() .collection("memberships") @@ -399,16 +400,22 @@ async function updateDaysUntilExpiryForAllMemberships(): Promise { batch.map(async (doc) => { const data = doc.data() as MembershipData; const daysUntilExpiry = await calculateDaysUntilExpiry(doc.id, data); - + if (daysUntilExpiry !== null) { + const updateData: any = { + daysUntilExpiry: daysUntilExpiry, + updatedAt: admin.firestore.FieldValue.serverTimestamp(), + }; + await app .firestore() .collection("memberships") .doc(doc.id) - .update({ - daysUntilExpiry: daysUntilExpiry, - updatedAt: admin.firestore.FieldValue.serverTimestamp(), - }); + .update(updateData); + + logger.info( + `Updated membership ${doc.id} with daysUntilExpiry: ${daysUntilExpiry}` + ); return doc.id; } return null; @@ -429,7 +436,6 @@ async function updateDaysUntilExpiryForAllMemberships(): Promise { } } - async function calculateDaysUntilExpiry( membershipId: string, data: MembershipData @@ -459,7 +465,14 @@ async function calculateDaysUntilExpiry( ); const now = new Date(); - const timeDiff = expiryDate.getTime() - now.getTime(); + const today = new Date(now.getFullYear(), now.getMonth(), now.getDate()); + const expiryDateOnly = new Date( + expiryDate.getFullYear(), + expiryDate.getMonth(), + expiryDate.getDate() + ); + + const timeDiff = expiryDateOnly.getTime() - today.getTime(); const daysUntilExpiry = Math.ceil(timeDiff / (1000 * 3600 * 24)); return daysUntilExpiry; @@ -472,7 +485,6 @@ async function calculateDaysUntilExpiry( } } - async function getTrainerAssignmentsForMembership( membershipId: string ): Promise { -- 2.43.0 From 33ada04122a27503c27ea89c1a0b01278cfe27b8 Mon Sep 17 00:00:00 2001 From: Sharon Dcruz Date: Tue, 19 Aug 2025 17:10:55 +0530 Subject: [PATCH 30/52] Removed --- firestore.indexes.json | 165 +---------------------------------------- 1 file changed, 1 insertion(+), 164 deletions(-) diff --git a/firestore.indexes.json b/firestore.indexes.json index 054170d..2ddb5ce 100644 --- a/firestore.indexes.json +++ b/firestore.indexes.json @@ -1,167 +1,4 @@ { - "indexes": [ - { - "collectionGroup": "day_pass_bookings", - "queryScope": "COLLECTION", - "fields": [ - { - "fieldPath": "userId", - "order": "ASCENDING" - }, - { - "fieldPath": "createdAt", - "order": "DESCENDING" - } - ] - }, - { - "collectionGroup": "day_pass_entries", - "queryScope": "COLLECTION", - "fields": [ - { - "fieldPath": "bookingId", - "order": "ASCENDING" - }, - { - "fieldPath": "entryDate", - "order": "ASCENDING" - } - ] - }, - { - "collectionGroup": "gyms", - "queryScope": "COLLECTION_GROUP", - "fields": [ - { - "fieldPath": "userId", - "order": "ASCENDING" - }, - { - "fieldPath": "createdAt", - "order": "ASCENDING" - } - ] - }, - { - "collectionGroup": "gyms", - "queryScope": "COLLECTION", - "fields": [ - { - "fieldPath": "userId", - "order": "ASCENDING" - }, - { - "fieldPath": "name", - "order": "ASCENDING" - } - ] - }, - { - "collectionGroup": "memberships", - "queryScope": "COLLECTION", - "fields": [ - { - "fieldPath": "gymId", - "order": "ASCENDING" - }, - { - "fieldPath": "createdAt", - "order": "DESCENDING" - } - ] - }, - { - "collectionGroup": "notifications", - "queryScope": "COLLECTION", - "fields": [ - { - "fieldPath": "type", - "order": "ASCENDING" - }, - { - "fieldPath": "userId", - "order": "ASCENDING" - }, - { - "fieldPath": "timestamp", - "order": "DESCENDING" - } - ] - }, - { - "collectionGroup": "notifications", - "queryScope": "COLLECTION", - "fields": [ - { - "fieldPath": "recipientId", - "order": "ASCENDING" - }, - { - "fieldPath": "timestamp", - "order": "DESCENDING" - } - ] - }, - { - "collectionGroup": "workout_logs", - "queryScope": "COLLECTION", - "fields": [ - { - "fieldPath": "user_id", - "order": "ASCENDING" - }, - { - "fieldPath": "date", - "order": "DESCENDING" - } - ] - }, - { - "collectionGroup": "workout_logs", - "queryScope": "COLLECTION", - "fields": [ - { - "fieldPath": "user_id", - "order": "ASCENDING" - }, - { - "fieldPath": "date", - "order": "ASCENDING" - } - ] - }, - { - "collectionGroup": "workout_logs", - "queryScope": "COLLECTION", - "fields": [ - { - "fieldPath": "user_id", - "order": "ASCENDING" - }, - { - "fieldPath": "start_time", - "order": "ASCENDING" - }, - { - "fieldPath": "date", - "order": "ASCENDING" - } - ] - }, - { - "collectionGroup": "terms_and_conditions", - "queryScope": "COLLECTION", - "fields": [ - { - "fieldPath": "normalizedName", - "order": "ASCENDING" - }, - { - "fieldPath": "userUid", - "order": "ASCENDING" - } - ] - } - ], + "indexes": [], "fieldOverrides": [] } \ No newline at end of file -- 2.43.0 From a0cd3fa4873788b85416fef64086e2bf62fb9deb Mon Sep 17 00:00:00 2001 From: Sharon Dcruz Date: Tue, 19 Aug 2025 17:12:12 +0530 Subject: [PATCH 31/52] Removed indexes --- firestore.indexes.json | 165 +---------------------------------------- 1 file changed, 1 insertion(+), 164 deletions(-) diff --git a/firestore.indexes.json b/firestore.indexes.json index 054170d..2ddb5ce 100644 --- a/firestore.indexes.json +++ b/firestore.indexes.json @@ -1,167 +1,4 @@ { - "indexes": [ - { - "collectionGroup": "day_pass_bookings", - "queryScope": "COLLECTION", - "fields": [ - { - "fieldPath": "userId", - "order": "ASCENDING" - }, - { - "fieldPath": "createdAt", - "order": "DESCENDING" - } - ] - }, - { - "collectionGroup": "day_pass_entries", - "queryScope": "COLLECTION", - "fields": [ - { - "fieldPath": "bookingId", - "order": "ASCENDING" - }, - { - "fieldPath": "entryDate", - "order": "ASCENDING" - } - ] - }, - { - "collectionGroup": "gyms", - "queryScope": "COLLECTION_GROUP", - "fields": [ - { - "fieldPath": "userId", - "order": "ASCENDING" - }, - { - "fieldPath": "createdAt", - "order": "ASCENDING" - } - ] - }, - { - "collectionGroup": "gyms", - "queryScope": "COLLECTION", - "fields": [ - { - "fieldPath": "userId", - "order": "ASCENDING" - }, - { - "fieldPath": "name", - "order": "ASCENDING" - } - ] - }, - { - "collectionGroup": "memberships", - "queryScope": "COLLECTION", - "fields": [ - { - "fieldPath": "gymId", - "order": "ASCENDING" - }, - { - "fieldPath": "createdAt", - "order": "DESCENDING" - } - ] - }, - { - "collectionGroup": "notifications", - "queryScope": "COLLECTION", - "fields": [ - { - "fieldPath": "type", - "order": "ASCENDING" - }, - { - "fieldPath": "userId", - "order": "ASCENDING" - }, - { - "fieldPath": "timestamp", - "order": "DESCENDING" - } - ] - }, - { - "collectionGroup": "notifications", - "queryScope": "COLLECTION", - "fields": [ - { - "fieldPath": "recipientId", - "order": "ASCENDING" - }, - { - "fieldPath": "timestamp", - "order": "DESCENDING" - } - ] - }, - { - "collectionGroup": "workout_logs", - "queryScope": "COLLECTION", - "fields": [ - { - "fieldPath": "user_id", - "order": "ASCENDING" - }, - { - "fieldPath": "date", - "order": "DESCENDING" - } - ] - }, - { - "collectionGroup": "workout_logs", - "queryScope": "COLLECTION", - "fields": [ - { - "fieldPath": "user_id", - "order": "ASCENDING" - }, - { - "fieldPath": "date", - "order": "ASCENDING" - } - ] - }, - { - "collectionGroup": "workout_logs", - "queryScope": "COLLECTION", - "fields": [ - { - "fieldPath": "user_id", - "order": "ASCENDING" - }, - { - "fieldPath": "start_time", - "order": "ASCENDING" - }, - { - "fieldPath": "date", - "order": "ASCENDING" - } - ] - }, - { - "collectionGroup": "terms_and_conditions", - "queryScope": "COLLECTION", - "fields": [ - { - "fieldPath": "normalizedName", - "order": "ASCENDING" - }, - { - "fieldPath": "userUid", - "order": "ASCENDING" - } - ] - } - ], + "indexes": [], "fieldOverrides": [] } \ No newline at end of file -- 2.43.0 From b3ea601a0f8c978cf1fb7f1b146103bc44fca1b7 Mon Sep 17 00:00:00 2001 From: Sharon Dcruz Date: Tue, 19 Aug 2025 17:19:25 +0530 Subject: [PATCH 32/52] Added Index --- firestore.indexes.json | 165 ++++++++++++++++++++++++++++++++++++++++- 1 file changed, 164 insertions(+), 1 deletion(-) diff --git a/firestore.indexes.json b/firestore.indexes.json index 2ddb5ce..054170d 100644 --- a/firestore.indexes.json +++ b/firestore.indexes.json @@ -1,4 +1,167 @@ { - "indexes": [], + "indexes": [ + { + "collectionGroup": "day_pass_bookings", + "queryScope": "COLLECTION", + "fields": [ + { + "fieldPath": "userId", + "order": "ASCENDING" + }, + { + "fieldPath": "createdAt", + "order": "DESCENDING" + } + ] + }, + { + "collectionGroup": "day_pass_entries", + "queryScope": "COLLECTION", + "fields": [ + { + "fieldPath": "bookingId", + "order": "ASCENDING" + }, + { + "fieldPath": "entryDate", + "order": "ASCENDING" + } + ] + }, + { + "collectionGroup": "gyms", + "queryScope": "COLLECTION_GROUP", + "fields": [ + { + "fieldPath": "userId", + "order": "ASCENDING" + }, + { + "fieldPath": "createdAt", + "order": "ASCENDING" + } + ] + }, + { + "collectionGroup": "gyms", + "queryScope": "COLLECTION", + "fields": [ + { + "fieldPath": "userId", + "order": "ASCENDING" + }, + { + "fieldPath": "name", + "order": "ASCENDING" + } + ] + }, + { + "collectionGroup": "memberships", + "queryScope": "COLLECTION", + "fields": [ + { + "fieldPath": "gymId", + "order": "ASCENDING" + }, + { + "fieldPath": "createdAt", + "order": "DESCENDING" + } + ] + }, + { + "collectionGroup": "notifications", + "queryScope": "COLLECTION", + "fields": [ + { + "fieldPath": "type", + "order": "ASCENDING" + }, + { + "fieldPath": "userId", + "order": "ASCENDING" + }, + { + "fieldPath": "timestamp", + "order": "DESCENDING" + } + ] + }, + { + "collectionGroup": "notifications", + "queryScope": "COLLECTION", + "fields": [ + { + "fieldPath": "recipientId", + "order": "ASCENDING" + }, + { + "fieldPath": "timestamp", + "order": "DESCENDING" + } + ] + }, + { + "collectionGroup": "workout_logs", + "queryScope": "COLLECTION", + "fields": [ + { + "fieldPath": "user_id", + "order": "ASCENDING" + }, + { + "fieldPath": "date", + "order": "DESCENDING" + } + ] + }, + { + "collectionGroup": "workout_logs", + "queryScope": "COLLECTION", + "fields": [ + { + "fieldPath": "user_id", + "order": "ASCENDING" + }, + { + "fieldPath": "date", + "order": "ASCENDING" + } + ] + }, + { + "collectionGroup": "workout_logs", + "queryScope": "COLLECTION", + "fields": [ + { + "fieldPath": "user_id", + "order": "ASCENDING" + }, + { + "fieldPath": "start_time", + "order": "ASCENDING" + }, + { + "fieldPath": "date", + "order": "ASCENDING" + } + ] + }, + { + "collectionGroup": "terms_and_conditions", + "queryScope": "COLLECTION", + "fields": [ + { + "fieldPath": "normalizedName", + "order": "ASCENDING" + }, + { + "fieldPath": "userUid", + "order": "ASCENDING" + } + ] + } + ], "fieldOverrides": [] } \ No newline at end of file -- 2.43.0 From 4385d4579d06627280d03affc435f5be8888f55d Mon Sep 17 00:00:00 2001 From: Sharon Dcruz Date: Tue, 19 Aug 2025 17:20:27 +0530 Subject: [PATCH 33/52] Added Index --- firestore.indexes.json | 165 ++++++++++++++++++++++++++++++++++++++++- 1 file changed, 164 insertions(+), 1 deletion(-) diff --git a/firestore.indexes.json b/firestore.indexes.json index 2ddb5ce..054170d 100644 --- a/firestore.indexes.json +++ b/firestore.indexes.json @@ -1,4 +1,167 @@ { - "indexes": [], + "indexes": [ + { + "collectionGroup": "day_pass_bookings", + "queryScope": "COLLECTION", + "fields": [ + { + "fieldPath": "userId", + "order": "ASCENDING" + }, + { + "fieldPath": "createdAt", + "order": "DESCENDING" + } + ] + }, + { + "collectionGroup": "day_pass_entries", + "queryScope": "COLLECTION", + "fields": [ + { + "fieldPath": "bookingId", + "order": "ASCENDING" + }, + { + "fieldPath": "entryDate", + "order": "ASCENDING" + } + ] + }, + { + "collectionGroup": "gyms", + "queryScope": "COLLECTION_GROUP", + "fields": [ + { + "fieldPath": "userId", + "order": "ASCENDING" + }, + { + "fieldPath": "createdAt", + "order": "ASCENDING" + } + ] + }, + { + "collectionGroup": "gyms", + "queryScope": "COLLECTION", + "fields": [ + { + "fieldPath": "userId", + "order": "ASCENDING" + }, + { + "fieldPath": "name", + "order": "ASCENDING" + } + ] + }, + { + "collectionGroup": "memberships", + "queryScope": "COLLECTION", + "fields": [ + { + "fieldPath": "gymId", + "order": "ASCENDING" + }, + { + "fieldPath": "createdAt", + "order": "DESCENDING" + } + ] + }, + { + "collectionGroup": "notifications", + "queryScope": "COLLECTION", + "fields": [ + { + "fieldPath": "type", + "order": "ASCENDING" + }, + { + "fieldPath": "userId", + "order": "ASCENDING" + }, + { + "fieldPath": "timestamp", + "order": "DESCENDING" + } + ] + }, + { + "collectionGroup": "notifications", + "queryScope": "COLLECTION", + "fields": [ + { + "fieldPath": "recipientId", + "order": "ASCENDING" + }, + { + "fieldPath": "timestamp", + "order": "DESCENDING" + } + ] + }, + { + "collectionGroup": "workout_logs", + "queryScope": "COLLECTION", + "fields": [ + { + "fieldPath": "user_id", + "order": "ASCENDING" + }, + { + "fieldPath": "date", + "order": "DESCENDING" + } + ] + }, + { + "collectionGroup": "workout_logs", + "queryScope": "COLLECTION", + "fields": [ + { + "fieldPath": "user_id", + "order": "ASCENDING" + }, + { + "fieldPath": "date", + "order": "ASCENDING" + } + ] + }, + { + "collectionGroup": "workout_logs", + "queryScope": "COLLECTION", + "fields": [ + { + "fieldPath": "user_id", + "order": "ASCENDING" + }, + { + "fieldPath": "start_time", + "order": "ASCENDING" + }, + { + "fieldPath": "date", + "order": "ASCENDING" + } + ] + }, + { + "collectionGroup": "terms_and_conditions", + "queryScope": "COLLECTION", + "fields": [ + { + "fieldPath": "normalizedName", + "order": "ASCENDING" + }, + { + "fieldPath": "userUid", + "order": "ASCENDING" + } + ] + } + ], "fieldOverrides": [] } \ No newline at end of file -- 2.43.0 From f1976f12b687035caff02b83ee8ed3e4c62851f8 Mon Sep 17 00:00:00 2001 From: Sharon Dcruz Date: Wed, 20 Aug 2025 13:37:22 +0530 Subject: [PATCH 34/52] Changes Updated for days until expiry --- .../membershipStatusNotifications.ts | 17 +++++------------ 1 file changed, 5 insertions(+), 12 deletions(-) diff --git a/functions/src/notifications/membershipStatusNotifications.ts b/functions/src/notifications/membershipStatusNotifications.ts index 7e1b88e..85799cf 100644 --- a/functions/src/notifications/membershipStatusNotifications.ts +++ b/functions/src/notifications/membershipStatusNotifications.ts @@ -465,17 +465,11 @@ async function calculateDaysUntilExpiry( ); const now = new Date(); - const today = new Date(now.getFullYear(), now.getMonth(), now.getDate()); - const expiryDateOnly = new Date( - expiryDate.getFullYear(), - expiryDate.getMonth(), - expiryDate.getDate() - ); - const timeDiff = expiryDateOnly.getTime() - today.getTime(); - const daysUntilExpiry = Math.ceil(timeDiff / (1000 * 3600 * 24)); + const timeDiff = expiryDate.getTime() - now.getTime(); + const daysUntilExpiry = Math.floor(timeDiff / (1000 * 3600 * 24)); - return daysUntilExpiry; + return Math.max(0, daysUntilExpiry); } catch (error) { logger.error( `Error calculating daysUntilExpiry for membership ${membershipId}:`, @@ -679,7 +673,7 @@ async function sendTrainerNotifications( if (notificationType === "expiring") { const now = new Date(); const timeDiff = expiryDate.getTime() - now.getTime(); - daysUntilExpiry = Math.ceil(timeDiff / (1000 * 3600 * 24)); + daysUntilExpiry = Math.floor(timeDiff / (1000 * 3600 * 24)); } } @@ -869,7 +863,7 @@ async function sendPlanExpiringNotification( const now = new Date(); const timeDiff = expiryDate.getTime() - now.getTime(); - daysUntilExpiry = Math.ceil(timeDiff / (1000 * 3600 * 24)); + daysUntilExpiry = Math.floor(timeDiff / (1000 * 3600 * 24)); } const existing = await app @@ -929,7 +923,6 @@ async function sendPlanExpiringNotification( ); } } - async function getClientName( membershipId: string, clientId: string -- 2.43.0 From 687d9716b38bf8376ca34b02de304a6f8949087c Mon Sep 17 00:00:00 2001 From: Sharon Dcruz Date: Wed, 20 Aug 2025 13:58:09 +0530 Subject: [PATCH 35/52] new Index added --- firestore.indexes.json | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/firestore.indexes.json b/firestore.indexes.json index 054170d..54f5709 100644 --- a/firestore.indexes.json +++ b/firestore.indexes.json @@ -56,6 +56,34 @@ } ] }, + { + "collectionGroup": "gyms", + "queryScope": "COLLECTION", + "fields": [ + { + "fieldPath": "userId", + "order": "ASCENDING" + }, + { + "fieldPath": "createdAt", + "order": "DESCENDING" + } + ] + }, + { + "collectionGroup": "gyms", + "queryScope": "COLLECTION", + "fields": [ + { + "fieldPath": "isApproved", + "order": "ASCENDING" + }, + { + "fieldPath": "createdAt", + "order": "ASCENDING" + } + ] + }, { "collectionGroup": "memberships", "queryScope": "COLLECTION", -- 2.43.0 From 64db7d11afd6d755fd0c5aedf00cdb365cb342ba Mon Sep 17 00:00:00 2001 From: Sharon Dcruz Date: Wed, 20 Aug 2025 18:56:02 +0530 Subject: [PATCH 36/52] Updated --- firestore.indexes.json | 193 +---------------------------------------- 1 file changed, 1 insertion(+), 192 deletions(-) diff --git a/firestore.indexes.json b/firestore.indexes.json index 54f5709..2ddb5ce 100644 --- a/firestore.indexes.json +++ b/firestore.indexes.json @@ -1,195 +1,4 @@ { - "indexes": [ - { - "collectionGroup": "day_pass_bookings", - "queryScope": "COLLECTION", - "fields": [ - { - "fieldPath": "userId", - "order": "ASCENDING" - }, - { - "fieldPath": "createdAt", - "order": "DESCENDING" - } - ] - }, - { - "collectionGroup": "day_pass_entries", - "queryScope": "COLLECTION", - "fields": [ - { - "fieldPath": "bookingId", - "order": "ASCENDING" - }, - { - "fieldPath": "entryDate", - "order": "ASCENDING" - } - ] - }, - { - "collectionGroup": "gyms", - "queryScope": "COLLECTION_GROUP", - "fields": [ - { - "fieldPath": "userId", - "order": "ASCENDING" - }, - { - "fieldPath": "createdAt", - "order": "ASCENDING" - } - ] - }, - { - "collectionGroup": "gyms", - "queryScope": "COLLECTION", - "fields": [ - { - "fieldPath": "userId", - "order": "ASCENDING" - }, - { - "fieldPath": "name", - "order": "ASCENDING" - } - ] - }, - { - "collectionGroup": "gyms", - "queryScope": "COLLECTION", - "fields": [ - { - "fieldPath": "userId", - "order": "ASCENDING" - }, - { - "fieldPath": "createdAt", - "order": "DESCENDING" - } - ] - }, - { - "collectionGroup": "gyms", - "queryScope": "COLLECTION", - "fields": [ - { - "fieldPath": "isApproved", - "order": "ASCENDING" - }, - { - "fieldPath": "createdAt", - "order": "ASCENDING" - } - ] - }, - { - "collectionGroup": "memberships", - "queryScope": "COLLECTION", - "fields": [ - { - "fieldPath": "gymId", - "order": "ASCENDING" - }, - { - "fieldPath": "createdAt", - "order": "DESCENDING" - } - ] - }, - { - "collectionGroup": "notifications", - "queryScope": "COLLECTION", - "fields": [ - { - "fieldPath": "type", - "order": "ASCENDING" - }, - { - "fieldPath": "userId", - "order": "ASCENDING" - }, - { - "fieldPath": "timestamp", - "order": "DESCENDING" - } - ] - }, - { - "collectionGroup": "notifications", - "queryScope": "COLLECTION", - "fields": [ - { - "fieldPath": "recipientId", - "order": "ASCENDING" - }, - { - "fieldPath": "timestamp", - "order": "DESCENDING" - } - ] - }, - { - "collectionGroup": "workout_logs", - "queryScope": "COLLECTION", - "fields": [ - { - "fieldPath": "user_id", - "order": "ASCENDING" - }, - { - "fieldPath": "date", - "order": "DESCENDING" - } - ] - }, - { - "collectionGroup": "workout_logs", - "queryScope": "COLLECTION", - "fields": [ - { - "fieldPath": "user_id", - "order": "ASCENDING" - }, - { - "fieldPath": "date", - "order": "ASCENDING" - } - ] - }, - { - "collectionGroup": "workout_logs", - "queryScope": "COLLECTION", - "fields": [ - { - "fieldPath": "user_id", - "order": "ASCENDING" - }, - { - "fieldPath": "start_time", - "order": "ASCENDING" - }, - { - "fieldPath": "date", - "order": "ASCENDING" - } - ] - }, - { - "collectionGroup": "terms_and_conditions", - "queryScope": "COLLECTION", - "fields": [ - { - "fieldPath": "normalizedName", - "order": "ASCENDING" - }, - { - "fieldPath": "userUid", - "order": "ASCENDING" - } - ] - } - ], + "indexes": [], "fieldOverrides": [] } \ No newline at end of file -- 2.43.0 From e4fe538dd3bd0e801b2a7634bd2b811df68703a3 Mon Sep 17 00:00:00 2001 From: Sharon Dcruz Date: Wed, 20 Aug 2025 19:04:51 +0530 Subject: [PATCH 37/52] added --- firestore.indexes.json | 193 ++++++++++++++++++++++++++++++++++++++++- 1 file changed, 192 insertions(+), 1 deletion(-) diff --git a/firestore.indexes.json b/firestore.indexes.json index 2ddb5ce..54f5709 100644 --- a/firestore.indexes.json +++ b/firestore.indexes.json @@ -1,4 +1,195 @@ { - "indexes": [], + "indexes": [ + { + "collectionGroup": "day_pass_bookings", + "queryScope": "COLLECTION", + "fields": [ + { + "fieldPath": "userId", + "order": "ASCENDING" + }, + { + "fieldPath": "createdAt", + "order": "DESCENDING" + } + ] + }, + { + "collectionGroup": "day_pass_entries", + "queryScope": "COLLECTION", + "fields": [ + { + "fieldPath": "bookingId", + "order": "ASCENDING" + }, + { + "fieldPath": "entryDate", + "order": "ASCENDING" + } + ] + }, + { + "collectionGroup": "gyms", + "queryScope": "COLLECTION_GROUP", + "fields": [ + { + "fieldPath": "userId", + "order": "ASCENDING" + }, + { + "fieldPath": "createdAt", + "order": "ASCENDING" + } + ] + }, + { + "collectionGroup": "gyms", + "queryScope": "COLLECTION", + "fields": [ + { + "fieldPath": "userId", + "order": "ASCENDING" + }, + { + "fieldPath": "name", + "order": "ASCENDING" + } + ] + }, + { + "collectionGroup": "gyms", + "queryScope": "COLLECTION", + "fields": [ + { + "fieldPath": "userId", + "order": "ASCENDING" + }, + { + "fieldPath": "createdAt", + "order": "DESCENDING" + } + ] + }, + { + "collectionGroup": "gyms", + "queryScope": "COLLECTION", + "fields": [ + { + "fieldPath": "isApproved", + "order": "ASCENDING" + }, + { + "fieldPath": "createdAt", + "order": "ASCENDING" + } + ] + }, + { + "collectionGroup": "memberships", + "queryScope": "COLLECTION", + "fields": [ + { + "fieldPath": "gymId", + "order": "ASCENDING" + }, + { + "fieldPath": "createdAt", + "order": "DESCENDING" + } + ] + }, + { + "collectionGroup": "notifications", + "queryScope": "COLLECTION", + "fields": [ + { + "fieldPath": "type", + "order": "ASCENDING" + }, + { + "fieldPath": "userId", + "order": "ASCENDING" + }, + { + "fieldPath": "timestamp", + "order": "DESCENDING" + } + ] + }, + { + "collectionGroup": "notifications", + "queryScope": "COLLECTION", + "fields": [ + { + "fieldPath": "recipientId", + "order": "ASCENDING" + }, + { + "fieldPath": "timestamp", + "order": "DESCENDING" + } + ] + }, + { + "collectionGroup": "workout_logs", + "queryScope": "COLLECTION", + "fields": [ + { + "fieldPath": "user_id", + "order": "ASCENDING" + }, + { + "fieldPath": "date", + "order": "DESCENDING" + } + ] + }, + { + "collectionGroup": "workout_logs", + "queryScope": "COLLECTION", + "fields": [ + { + "fieldPath": "user_id", + "order": "ASCENDING" + }, + { + "fieldPath": "date", + "order": "ASCENDING" + } + ] + }, + { + "collectionGroup": "workout_logs", + "queryScope": "COLLECTION", + "fields": [ + { + "fieldPath": "user_id", + "order": "ASCENDING" + }, + { + "fieldPath": "start_time", + "order": "ASCENDING" + }, + { + "fieldPath": "date", + "order": "ASCENDING" + } + ] + }, + { + "collectionGroup": "terms_and_conditions", + "queryScope": "COLLECTION", + "fields": [ + { + "fieldPath": "normalizedName", + "order": "ASCENDING" + }, + { + "fieldPath": "userUid", + "order": "ASCENDING" + } + ] + } + ], "fieldOverrides": [] } \ No newline at end of file -- 2.43.0 From ddc7cf272e8b0ae4406e6372aeaa450ac9b5e4e4 Mon Sep 17 00:00:00 2001 From: Sharon Dcruz Date: Wed, 20 Aug 2025 19:05:36 +0530 Subject: [PATCH 38/52] Added Index --- firestore.indexes.json | 193 ++++++++++++++++++++++++++++++++++++++++- 1 file changed, 192 insertions(+), 1 deletion(-) diff --git a/firestore.indexes.json b/firestore.indexes.json index 2ddb5ce..54f5709 100644 --- a/firestore.indexes.json +++ b/firestore.indexes.json @@ -1,4 +1,195 @@ { - "indexes": [], + "indexes": [ + { + "collectionGroup": "day_pass_bookings", + "queryScope": "COLLECTION", + "fields": [ + { + "fieldPath": "userId", + "order": "ASCENDING" + }, + { + "fieldPath": "createdAt", + "order": "DESCENDING" + } + ] + }, + { + "collectionGroup": "day_pass_entries", + "queryScope": "COLLECTION", + "fields": [ + { + "fieldPath": "bookingId", + "order": "ASCENDING" + }, + { + "fieldPath": "entryDate", + "order": "ASCENDING" + } + ] + }, + { + "collectionGroup": "gyms", + "queryScope": "COLLECTION_GROUP", + "fields": [ + { + "fieldPath": "userId", + "order": "ASCENDING" + }, + { + "fieldPath": "createdAt", + "order": "ASCENDING" + } + ] + }, + { + "collectionGroup": "gyms", + "queryScope": "COLLECTION", + "fields": [ + { + "fieldPath": "userId", + "order": "ASCENDING" + }, + { + "fieldPath": "name", + "order": "ASCENDING" + } + ] + }, + { + "collectionGroup": "gyms", + "queryScope": "COLLECTION", + "fields": [ + { + "fieldPath": "userId", + "order": "ASCENDING" + }, + { + "fieldPath": "createdAt", + "order": "DESCENDING" + } + ] + }, + { + "collectionGroup": "gyms", + "queryScope": "COLLECTION", + "fields": [ + { + "fieldPath": "isApproved", + "order": "ASCENDING" + }, + { + "fieldPath": "createdAt", + "order": "ASCENDING" + } + ] + }, + { + "collectionGroup": "memberships", + "queryScope": "COLLECTION", + "fields": [ + { + "fieldPath": "gymId", + "order": "ASCENDING" + }, + { + "fieldPath": "createdAt", + "order": "DESCENDING" + } + ] + }, + { + "collectionGroup": "notifications", + "queryScope": "COLLECTION", + "fields": [ + { + "fieldPath": "type", + "order": "ASCENDING" + }, + { + "fieldPath": "userId", + "order": "ASCENDING" + }, + { + "fieldPath": "timestamp", + "order": "DESCENDING" + } + ] + }, + { + "collectionGroup": "notifications", + "queryScope": "COLLECTION", + "fields": [ + { + "fieldPath": "recipientId", + "order": "ASCENDING" + }, + { + "fieldPath": "timestamp", + "order": "DESCENDING" + } + ] + }, + { + "collectionGroup": "workout_logs", + "queryScope": "COLLECTION", + "fields": [ + { + "fieldPath": "user_id", + "order": "ASCENDING" + }, + { + "fieldPath": "date", + "order": "DESCENDING" + } + ] + }, + { + "collectionGroup": "workout_logs", + "queryScope": "COLLECTION", + "fields": [ + { + "fieldPath": "user_id", + "order": "ASCENDING" + }, + { + "fieldPath": "date", + "order": "ASCENDING" + } + ] + }, + { + "collectionGroup": "workout_logs", + "queryScope": "COLLECTION", + "fields": [ + { + "fieldPath": "user_id", + "order": "ASCENDING" + }, + { + "fieldPath": "start_time", + "order": "ASCENDING" + }, + { + "fieldPath": "date", + "order": "ASCENDING" + } + ] + }, + { + "collectionGroup": "terms_and_conditions", + "queryScope": "COLLECTION", + "fields": [ + { + "fieldPath": "normalizedName", + "order": "ASCENDING" + }, + { + "fieldPath": "userUid", + "order": "ASCENDING" + } + ] + } + ], "fieldOverrides": [] } \ No newline at end of file -- 2.43.0 From 1f5889627829ffaced32f01ce8dfe1e32ff3aecf Mon Sep 17 00:00:00 2001 From: Sharon Dcruz Date: Fri, 22 Aug 2025 16:40:05 +0530 Subject: [PATCH 39/52] removed --- firestore.indexes.json | 193 +---------------------------------------- 1 file changed, 1 insertion(+), 192 deletions(-) diff --git a/firestore.indexes.json b/firestore.indexes.json index 54f5709..2ddb5ce 100644 --- a/firestore.indexes.json +++ b/firestore.indexes.json @@ -1,195 +1,4 @@ { - "indexes": [ - { - "collectionGroup": "day_pass_bookings", - "queryScope": "COLLECTION", - "fields": [ - { - "fieldPath": "userId", - "order": "ASCENDING" - }, - { - "fieldPath": "createdAt", - "order": "DESCENDING" - } - ] - }, - { - "collectionGroup": "day_pass_entries", - "queryScope": "COLLECTION", - "fields": [ - { - "fieldPath": "bookingId", - "order": "ASCENDING" - }, - { - "fieldPath": "entryDate", - "order": "ASCENDING" - } - ] - }, - { - "collectionGroup": "gyms", - "queryScope": "COLLECTION_GROUP", - "fields": [ - { - "fieldPath": "userId", - "order": "ASCENDING" - }, - { - "fieldPath": "createdAt", - "order": "ASCENDING" - } - ] - }, - { - "collectionGroup": "gyms", - "queryScope": "COLLECTION", - "fields": [ - { - "fieldPath": "userId", - "order": "ASCENDING" - }, - { - "fieldPath": "name", - "order": "ASCENDING" - } - ] - }, - { - "collectionGroup": "gyms", - "queryScope": "COLLECTION", - "fields": [ - { - "fieldPath": "userId", - "order": "ASCENDING" - }, - { - "fieldPath": "createdAt", - "order": "DESCENDING" - } - ] - }, - { - "collectionGroup": "gyms", - "queryScope": "COLLECTION", - "fields": [ - { - "fieldPath": "isApproved", - "order": "ASCENDING" - }, - { - "fieldPath": "createdAt", - "order": "ASCENDING" - } - ] - }, - { - "collectionGroup": "memberships", - "queryScope": "COLLECTION", - "fields": [ - { - "fieldPath": "gymId", - "order": "ASCENDING" - }, - { - "fieldPath": "createdAt", - "order": "DESCENDING" - } - ] - }, - { - "collectionGroup": "notifications", - "queryScope": "COLLECTION", - "fields": [ - { - "fieldPath": "type", - "order": "ASCENDING" - }, - { - "fieldPath": "userId", - "order": "ASCENDING" - }, - { - "fieldPath": "timestamp", - "order": "DESCENDING" - } - ] - }, - { - "collectionGroup": "notifications", - "queryScope": "COLLECTION", - "fields": [ - { - "fieldPath": "recipientId", - "order": "ASCENDING" - }, - { - "fieldPath": "timestamp", - "order": "DESCENDING" - } - ] - }, - { - "collectionGroup": "workout_logs", - "queryScope": "COLLECTION", - "fields": [ - { - "fieldPath": "user_id", - "order": "ASCENDING" - }, - { - "fieldPath": "date", - "order": "DESCENDING" - } - ] - }, - { - "collectionGroup": "workout_logs", - "queryScope": "COLLECTION", - "fields": [ - { - "fieldPath": "user_id", - "order": "ASCENDING" - }, - { - "fieldPath": "date", - "order": "ASCENDING" - } - ] - }, - { - "collectionGroup": "workout_logs", - "queryScope": "COLLECTION", - "fields": [ - { - "fieldPath": "user_id", - "order": "ASCENDING" - }, - { - "fieldPath": "start_time", - "order": "ASCENDING" - }, - { - "fieldPath": "date", - "order": "ASCENDING" - } - ] - }, - { - "collectionGroup": "terms_and_conditions", - "queryScope": "COLLECTION", - "fields": [ - { - "fieldPath": "normalizedName", - "order": "ASCENDING" - }, - { - "fieldPath": "userUid", - "order": "ASCENDING" - } - ] - } - ], + "indexes": [], "fieldOverrides": [] } \ No newline at end of file -- 2.43.0 From 1c33794af4d1e15adff50cdfbc9ced1723a98851 Mon Sep 17 00:00:00 2001 From: Sharon Dcruz Date: Fri, 22 Aug 2025 17:29:05 +0530 Subject: [PATCH 40/52] Indexes added --- firestore.indexes.json | 193 ++++++++++++++++++++++++++++++++++++++++- 1 file changed, 192 insertions(+), 1 deletion(-) diff --git a/firestore.indexes.json b/firestore.indexes.json index 2ddb5ce..54f5709 100644 --- a/firestore.indexes.json +++ b/firestore.indexes.json @@ -1,4 +1,195 @@ { - "indexes": [], + "indexes": [ + { + "collectionGroup": "day_pass_bookings", + "queryScope": "COLLECTION", + "fields": [ + { + "fieldPath": "userId", + "order": "ASCENDING" + }, + { + "fieldPath": "createdAt", + "order": "DESCENDING" + } + ] + }, + { + "collectionGroup": "day_pass_entries", + "queryScope": "COLLECTION", + "fields": [ + { + "fieldPath": "bookingId", + "order": "ASCENDING" + }, + { + "fieldPath": "entryDate", + "order": "ASCENDING" + } + ] + }, + { + "collectionGroup": "gyms", + "queryScope": "COLLECTION_GROUP", + "fields": [ + { + "fieldPath": "userId", + "order": "ASCENDING" + }, + { + "fieldPath": "createdAt", + "order": "ASCENDING" + } + ] + }, + { + "collectionGroup": "gyms", + "queryScope": "COLLECTION", + "fields": [ + { + "fieldPath": "userId", + "order": "ASCENDING" + }, + { + "fieldPath": "name", + "order": "ASCENDING" + } + ] + }, + { + "collectionGroup": "gyms", + "queryScope": "COLLECTION", + "fields": [ + { + "fieldPath": "userId", + "order": "ASCENDING" + }, + { + "fieldPath": "createdAt", + "order": "DESCENDING" + } + ] + }, + { + "collectionGroup": "gyms", + "queryScope": "COLLECTION", + "fields": [ + { + "fieldPath": "isApproved", + "order": "ASCENDING" + }, + { + "fieldPath": "createdAt", + "order": "ASCENDING" + } + ] + }, + { + "collectionGroup": "memberships", + "queryScope": "COLLECTION", + "fields": [ + { + "fieldPath": "gymId", + "order": "ASCENDING" + }, + { + "fieldPath": "createdAt", + "order": "DESCENDING" + } + ] + }, + { + "collectionGroup": "notifications", + "queryScope": "COLLECTION", + "fields": [ + { + "fieldPath": "type", + "order": "ASCENDING" + }, + { + "fieldPath": "userId", + "order": "ASCENDING" + }, + { + "fieldPath": "timestamp", + "order": "DESCENDING" + } + ] + }, + { + "collectionGroup": "notifications", + "queryScope": "COLLECTION", + "fields": [ + { + "fieldPath": "recipientId", + "order": "ASCENDING" + }, + { + "fieldPath": "timestamp", + "order": "DESCENDING" + } + ] + }, + { + "collectionGroup": "workout_logs", + "queryScope": "COLLECTION", + "fields": [ + { + "fieldPath": "user_id", + "order": "ASCENDING" + }, + { + "fieldPath": "date", + "order": "DESCENDING" + } + ] + }, + { + "collectionGroup": "workout_logs", + "queryScope": "COLLECTION", + "fields": [ + { + "fieldPath": "user_id", + "order": "ASCENDING" + }, + { + "fieldPath": "date", + "order": "ASCENDING" + } + ] + }, + { + "collectionGroup": "workout_logs", + "queryScope": "COLLECTION", + "fields": [ + { + "fieldPath": "user_id", + "order": "ASCENDING" + }, + { + "fieldPath": "start_time", + "order": "ASCENDING" + }, + { + "fieldPath": "date", + "order": "ASCENDING" + } + ] + }, + { + "collectionGroup": "terms_and_conditions", + "queryScope": "COLLECTION", + "fields": [ + { + "fieldPath": "normalizedName", + "order": "ASCENDING" + }, + { + "fieldPath": "userUid", + "order": "ASCENDING" + } + ] + } + ], "fieldOverrides": [] } \ No newline at end of file -- 2.43.0 From ef8c4433844debee0f861673a6eec15c83678f01 Mon Sep 17 00:00:00 2001 From: Sharon Dcruz Date: Fri, 22 Aug 2025 17:29:35 +0530 Subject: [PATCH 41/52] Indexes added --- firestore.indexes.json | 193 ++++++++++++++++++++++++++++++++++++++++- 1 file changed, 192 insertions(+), 1 deletion(-) diff --git a/firestore.indexes.json b/firestore.indexes.json index 2ddb5ce..54f5709 100644 --- a/firestore.indexes.json +++ b/firestore.indexes.json @@ -1,4 +1,195 @@ { - "indexes": [], + "indexes": [ + { + "collectionGroup": "day_pass_bookings", + "queryScope": "COLLECTION", + "fields": [ + { + "fieldPath": "userId", + "order": "ASCENDING" + }, + { + "fieldPath": "createdAt", + "order": "DESCENDING" + } + ] + }, + { + "collectionGroup": "day_pass_entries", + "queryScope": "COLLECTION", + "fields": [ + { + "fieldPath": "bookingId", + "order": "ASCENDING" + }, + { + "fieldPath": "entryDate", + "order": "ASCENDING" + } + ] + }, + { + "collectionGroup": "gyms", + "queryScope": "COLLECTION_GROUP", + "fields": [ + { + "fieldPath": "userId", + "order": "ASCENDING" + }, + { + "fieldPath": "createdAt", + "order": "ASCENDING" + } + ] + }, + { + "collectionGroup": "gyms", + "queryScope": "COLLECTION", + "fields": [ + { + "fieldPath": "userId", + "order": "ASCENDING" + }, + { + "fieldPath": "name", + "order": "ASCENDING" + } + ] + }, + { + "collectionGroup": "gyms", + "queryScope": "COLLECTION", + "fields": [ + { + "fieldPath": "userId", + "order": "ASCENDING" + }, + { + "fieldPath": "createdAt", + "order": "DESCENDING" + } + ] + }, + { + "collectionGroup": "gyms", + "queryScope": "COLLECTION", + "fields": [ + { + "fieldPath": "isApproved", + "order": "ASCENDING" + }, + { + "fieldPath": "createdAt", + "order": "ASCENDING" + } + ] + }, + { + "collectionGroup": "memberships", + "queryScope": "COLLECTION", + "fields": [ + { + "fieldPath": "gymId", + "order": "ASCENDING" + }, + { + "fieldPath": "createdAt", + "order": "DESCENDING" + } + ] + }, + { + "collectionGroup": "notifications", + "queryScope": "COLLECTION", + "fields": [ + { + "fieldPath": "type", + "order": "ASCENDING" + }, + { + "fieldPath": "userId", + "order": "ASCENDING" + }, + { + "fieldPath": "timestamp", + "order": "DESCENDING" + } + ] + }, + { + "collectionGroup": "notifications", + "queryScope": "COLLECTION", + "fields": [ + { + "fieldPath": "recipientId", + "order": "ASCENDING" + }, + { + "fieldPath": "timestamp", + "order": "DESCENDING" + } + ] + }, + { + "collectionGroup": "workout_logs", + "queryScope": "COLLECTION", + "fields": [ + { + "fieldPath": "user_id", + "order": "ASCENDING" + }, + { + "fieldPath": "date", + "order": "DESCENDING" + } + ] + }, + { + "collectionGroup": "workout_logs", + "queryScope": "COLLECTION", + "fields": [ + { + "fieldPath": "user_id", + "order": "ASCENDING" + }, + { + "fieldPath": "date", + "order": "ASCENDING" + } + ] + }, + { + "collectionGroup": "workout_logs", + "queryScope": "COLLECTION", + "fields": [ + { + "fieldPath": "user_id", + "order": "ASCENDING" + }, + { + "fieldPath": "start_time", + "order": "ASCENDING" + }, + { + "fieldPath": "date", + "order": "ASCENDING" + } + ] + }, + { + "collectionGroup": "terms_and_conditions", + "queryScope": "COLLECTION", + "fields": [ + { + "fieldPath": "normalizedName", + "order": "ASCENDING" + }, + { + "fieldPath": "userUid", + "order": "ASCENDING" + } + ] + } + ], "fieldOverrides": [] } \ No newline at end of file -- 2.43.0 From 05912a1c325f496fde5b06afc210e4babef5012f Mon Sep 17 00:00:00 2001 From: Sharon Dcruz Date: Mon, 25 Aug 2025 07:03:33 +0530 Subject: [PATCH 42/52] Changes Updated For expirydate --- .../membershipStatusNotifications.ts | 102 +++++++++++++++--- 1 file changed, 85 insertions(+), 17 deletions(-) diff --git a/functions/src/notifications/membershipStatusNotifications.ts b/functions/src/notifications/membershipStatusNotifications.ts index 85799cf..e8c3b01 100644 --- a/functions/src/notifications/membershipStatusNotifications.ts +++ b/functions/src/notifications/membershipStatusNotifications.ts @@ -11,6 +11,7 @@ interface MembershipData { userId: string; gymId: string; status: string; + expirationDate?: admin.firestore.Timestamp; subscription?: { name: string; frequency: string; @@ -56,14 +57,16 @@ export const checkExpiredMemberships = onSchedule( await updateDaysUntilExpiryForAllMemberships(); const expiredMemberships = await findExpiredMemberships(); const expiringMemberships = await findMembershipsExpiringIn10Days(); + + const expiredMembershipsWithoutExpiryDate = await findExpiredMembershipsWithoutExpiryDate(); - if (expiredMemberships.length === 0 && expiringMemberships.length === 0) { - logger.info("No expired or expiring memberships found."); + if (expiredMemberships.length === 0 && expiringMemberships.length === 0 && expiredMembershipsWithoutExpiryDate.length === 0) { + logger.info("No expired, expiring, or unprocessed expired memberships found."); return; } logger.info( - `Found ${expiredMemberships.length} expired memberships and ${expiringMemberships.length} memberships expiring in 10 days to process.` + `Found ${expiredMemberships.length} expired memberships, ${expiringMemberships.length} memberships expiring in 10 days, and ${expiredMembershipsWithoutExpiryDate.length} expired memberships without expiry dates to process.` ); const expiredResults = await Promise.allSettled( @@ -74,21 +77,19 @@ export const checkExpiredMemberships = onSchedule( expiringMemberships.map((m) => processExpiringMembership(m.id, m.data)) ); - const expiredSuccessful = expiredResults.filter( - (r) => r.status === "fulfilled" - ).length; - const expiredFailed = expiredResults.filter( - (r) => r.status === "rejected" - ).length; - const expiringSuccessful = expiringResults.filter( - (r) => r.status === "fulfilled" - ).length; - const expiringFailed = expiringResults.filter( - (r) => r.status === "rejected" - ).length; + const updateResults = await Promise.allSettled( + expiredMembershipsWithoutExpiryDate.map((m) => updateExpiryDateForExpiredMembership(m.id, m.data)) + ); + + const expiredSuccessful = expiredResults.filter(r => r.status === "fulfilled").length; + const expiredFailed = expiredResults.filter(r => r.status === "rejected").length; + const expiringSuccessful = expiringResults.filter(r => r.status === "fulfilled").length; + const expiringFailed = expiringResults.filter(r => r.status === "rejected").length; + const updateSuccessful = updateResults.filter(r => r.status === "fulfilled").length; + const updateFailed = updateResults.filter(r => r.status === "rejected").length; logger.info( - `Completed processing. Expired - Success: ${expiredSuccessful}, Failed: ${expiredFailed}. Expiring - Success: ${expiringSuccessful}, Failed: ${expiringFailed}` + `Completed processing. Expired - Success: ${expiredSuccessful}, Failed: ${expiredFailed}. Expiring - Success: ${expiringSuccessful}, Failed: ${expiringFailed}. Updates - Success: ${updateSuccessful}, Failed: ${updateFailed}` ); } catch (error) { logger.error("Error in scheduled membership expiry check:", error); @@ -96,6 +97,72 @@ export const checkExpiredMemberships = onSchedule( } ); + + + +async function findExpiredMembershipsWithoutExpiryDate(): Promise< + Array<{ id: string; data: MembershipData }> +> { + try { + const snapshot = await app + .firestore() + .collection("memberships") + .where("status", "==", "EXPIRED") + .get(); + + const membershipsWithoutExpiryDate: Array<{ id: string; data: MembershipData }> = []; + + snapshot.docs.forEach((doc) => { + const data = doc.data() as MembershipData; + if (!data.expirationDate) { + membershipsWithoutExpiryDate.push({ id: doc.id, data }); + } + }); + + return membershipsWithoutExpiryDate; + } catch (error) { + logger.error("Error finding expired memberships without expiry date:", error); + throw error; + } +} +async function updateExpiryDateForExpiredMembership( + membershipId: string, + membershipData: MembershipData +): Promise { + try { + if (!membershipData.subscription || !membershipData.subscription.frequency) { + logger.warn(`Skipping membership ${membershipId} - no subscription data`); + return; + } + + const payments = await getPaymentsForMembership(membershipId); + if (payments.length === 0) { + logger.warn(`No payments found for membership ${membershipId}`); + return; + } + + const latestPayment = payments[0]; + const expiryDate = calculateExpiryDate( + latestPayment.dateTimestamp, + membershipData.subscription.frequency + ); + + await app + .firestore() + .collection("memberships") + .doc(membershipId) + .update({ + expirationDate: admin.firestore.Timestamp.fromDate(expiryDate), + updatedAt: admin.firestore.FieldValue.serverTimestamp(), + }); + + logger.info(`Updated expiry date for expired membership ${membershipId}: ${expiryDate.toISOString()}`); + } catch (error) { + logger.error(`Error updating expiry date for membership ${membershipId}:`, error); + throw error; + } +} + async function findExpiredMemberships(): Promise< Array<{ id: string; data: MembershipData }> > { @@ -923,6 +990,7 @@ async function sendPlanExpiringNotification( ); } } + async function getClientName( membershipId: string, clientId: string @@ -966,4 +1034,4 @@ async function getGymName(gymId: string): Promise { logger.error(`Error getting gym name for gym ${gymId}:`, error); return "Unknown Gym"; } -} +} \ No newline at end of file -- 2.43.0 From b61003e185b4d235471857593ff27ded51a2c57f Mon Sep 17 00:00:00 2001 From: Sharon Dcruz Date: Mon, 25 Aug 2025 07:05:18 +0530 Subject: [PATCH 43/52] Removed Indexes --- firestore.indexes.json | 193 +---------------------------------------- 1 file changed, 1 insertion(+), 192 deletions(-) diff --git a/firestore.indexes.json b/firestore.indexes.json index 54f5709..2ddb5ce 100644 --- a/firestore.indexes.json +++ b/firestore.indexes.json @@ -1,195 +1,4 @@ { - "indexes": [ - { - "collectionGroup": "day_pass_bookings", - "queryScope": "COLLECTION", - "fields": [ - { - "fieldPath": "userId", - "order": "ASCENDING" - }, - { - "fieldPath": "createdAt", - "order": "DESCENDING" - } - ] - }, - { - "collectionGroup": "day_pass_entries", - "queryScope": "COLLECTION", - "fields": [ - { - "fieldPath": "bookingId", - "order": "ASCENDING" - }, - { - "fieldPath": "entryDate", - "order": "ASCENDING" - } - ] - }, - { - "collectionGroup": "gyms", - "queryScope": "COLLECTION_GROUP", - "fields": [ - { - "fieldPath": "userId", - "order": "ASCENDING" - }, - { - "fieldPath": "createdAt", - "order": "ASCENDING" - } - ] - }, - { - "collectionGroup": "gyms", - "queryScope": "COLLECTION", - "fields": [ - { - "fieldPath": "userId", - "order": "ASCENDING" - }, - { - "fieldPath": "name", - "order": "ASCENDING" - } - ] - }, - { - "collectionGroup": "gyms", - "queryScope": "COLLECTION", - "fields": [ - { - "fieldPath": "userId", - "order": "ASCENDING" - }, - { - "fieldPath": "createdAt", - "order": "DESCENDING" - } - ] - }, - { - "collectionGroup": "gyms", - "queryScope": "COLLECTION", - "fields": [ - { - "fieldPath": "isApproved", - "order": "ASCENDING" - }, - { - "fieldPath": "createdAt", - "order": "ASCENDING" - } - ] - }, - { - "collectionGroup": "memberships", - "queryScope": "COLLECTION", - "fields": [ - { - "fieldPath": "gymId", - "order": "ASCENDING" - }, - { - "fieldPath": "createdAt", - "order": "DESCENDING" - } - ] - }, - { - "collectionGroup": "notifications", - "queryScope": "COLLECTION", - "fields": [ - { - "fieldPath": "type", - "order": "ASCENDING" - }, - { - "fieldPath": "userId", - "order": "ASCENDING" - }, - { - "fieldPath": "timestamp", - "order": "DESCENDING" - } - ] - }, - { - "collectionGroup": "notifications", - "queryScope": "COLLECTION", - "fields": [ - { - "fieldPath": "recipientId", - "order": "ASCENDING" - }, - { - "fieldPath": "timestamp", - "order": "DESCENDING" - } - ] - }, - { - "collectionGroup": "workout_logs", - "queryScope": "COLLECTION", - "fields": [ - { - "fieldPath": "user_id", - "order": "ASCENDING" - }, - { - "fieldPath": "date", - "order": "DESCENDING" - } - ] - }, - { - "collectionGroup": "workout_logs", - "queryScope": "COLLECTION", - "fields": [ - { - "fieldPath": "user_id", - "order": "ASCENDING" - }, - { - "fieldPath": "date", - "order": "ASCENDING" - } - ] - }, - { - "collectionGroup": "workout_logs", - "queryScope": "COLLECTION", - "fields": [ - { - "fieldPath": "user_id", - "order": "ASCENDING" - }, - { - "fieldPath": "start_time", - "order": "ASCENDING" - }, - { - "fieldPath": "date", - "order": "ASCENDING" - } - ] - }, - { - "collectionGroup": "terms_and_conditions", - "queryScope": "COLLECTION", - "fields": [ - { - "fieldPath": "normalizedName", - "order": "ASCENDING" - }, - { - "fieldPath": "userUid", - "order": "ASCENDING" - } - ] - } - ], + "indexes": [], "fieldOverrides": [] } \ No newline at end of file -- 2.43.0 From 6f2d12c802797963c75f8316d17b65a032147dfb Mon Sep 17 00:00:00 2001 From: Sharon Dcruz Date: Mon, 25 Aug 2025 12:36:59 +0530 Subject: [PATCH 44/52] Added Filtering logic --- .../src/notifications/filterMembersRequest.ts | 453 ++++++++++++++++++ 1 file changed, 453 insertions(+) create mode 100644 functions/src/notifications/filterMembersRequest.ts diff --git a/functions/src/notifications/filterMembersRequest.ts b/functions/src/notifications/filterMembersRequest.ts new file mode 100644 index 0000000..0b4e610 --- /dev/null +++ b/functions/src/notifications/filterMembersRequest.ts @@ -0,0 +1,453 @@ +import { onCall } from "firebase-functions/v2/https"; +import { getLogger, getAdmin } from "../shared/config"; + +const app = getAdmin(); +const logger = getLogger(); + +interface FilterMembersRequest { + gymId: string; + filter: string; + sortBy: string; + sortAscending: boolean; + searchQuery?: string; + limit?: number; + lastDocumentId?: string; + role?: string; + trainerAssignedMembershipIds?: string[]; +} + +interface MembershipWithDetails { + membershipId: string; + memberData: any; + fields: { [key: string]: string }; + renewalDate?: string; + daysUntilExpiry?: number; + hasPersonalTraining: boolean; + trainerAssignments?: any[]; + timeSlots?: any[]; +} + +interface FilterMembersResponse { + members: MembershipWithDetails[]; + hasMore: boolean; + lastDocumentId?: string; + totalCount: number; +} + +export const filterMembers = onCall( + { + region: "#{SERVICES_RGN}#", + cors: true, + }, + async (request): Promise => { + try { + const { + gymId, + filter, + sortBy, + sortAscending, + searchQuery, + limit = 20, + lastDocumentId, + role, + trainerAssignedMembershipIds, + } = request.data as FilterMembersRequest; + + logger.info(`Filtering members for gym ${gymId} with filter: ${filter}`); + + if (!gymId) { + throw new Error("gymId is required"); + } + + let query = app + .firestore() + .collection("memberships") + .where("gymId", "==", gymId); + + if (filter === "Active") { + query = query.where("status", "==", "ACTIVE"); + } else if (filter === "Pending") { + query = query.where("status", "==", "PENDING"); + } else if (filter === "Expired") { + query = query.where("status", "==", "EXPIRED"); + } + + let orderByField = "createdAt"; + let orderByDirection: "asc" | "desc" = sortAscending ? "asc" : "desc"; + + switch (sortBy) { + case "Name": + orderByField = "createdAt"; + break; + case "Expiry Date": + orderByField = "expirationDate"; + break; + case "Join Date": + orderByField = "createdAt"; + break; + default: + orderByField = "createdAt"; + } + + query = query.orderBy(orderByField, orderByDirection); + + if (lastDocumentId) { + const lastDoc = await app + .firestore() + .collection("memberships") + .doc(lastDocumentId) + .get(); + if (lastDoc.exists) { + query = query.startAfter(lastDoc); + } + } + + const fetchLimit = ["All", "Active", "Pending", "Expired"].includes( + filter + ) + ? limit + : limit * 3; + query = query.limit(fetchLimit); + + const snapshot = await query.get(); + const allMembers: MembershipWithDetails[] = []; + + const batchSize = 10; + const docs = snapshot.docs; + + for (let i = 0; i < docs.length; i += batchSize) { + const batch = docs.slice(i, i + batchSize); + const batchResults = await Promise.allSettled( + batch.map(async (doc) => { + const memberData = doc.data(); + const membershipId = doc.id; + + const fields = await getClientFieldsByMembershipId(membershipId); + + let renewalDate: Date | undefined; + let daysUntilExpiry: number | undefined; + + if (memberData.subscription) { + const payments = await getPaymentsForMembership(membershipId); + if (payments.length > 0) { + const latestPayment = payments[0]; + renewalDate = calculateRenewalDateFromPayment( + memberData.subscription, + latestPayment.dateTimestamp + ); + + if (memberData.status === "ACTIVE") { + const now = new Date(); + const timeDiff = renewalDate.getTime() - now.getTime(); + daysUntilExpiry = Math.max( + 0, + Math.floor(timeDiff / (1000 * 3600 * 24)) + ); + } + } + } + + const hasPersonalTraining = + memberData.subscription?.hasPersonalTraining === true; + + let trainerAssignments: any[] = []; + let timeSlots: any[] = []; + + if (hasPersonalTraining) { + trainerAssignments = await getTrainerAssignmentsForMembership( + membershipId + ); + + if (trainerAssignments.length > 0) { + const latestAssignment = trainerAssignments[0]; + timeSlots = latestAssignment.timeSlot || []; + } + } + + return { + membershipId, + memberData, + fields, + renewalDate: renewalDate?.toISOString(), + daysUntilExpiry, + hasPersonalTraining, + trainerAssignments, + timeSlots, + }; + }) + ); + + batchResults.forEach((result) => { + if (result.status === "fulfilled" && result.value) { + allMembers.push(result.value); + } + }); + } + + let filteredMembers = allMembers; + if (role === "Trainer" && trainerAssignedMembershipIds) { + filteredMembers = allMembers.filter((member) => + trainerAssignedMembershipIds.includes(member.membershipId) + ); + } + + if (searchQuery && searchQuery.length >= 2) { + const searchLower = searchQuery.toLowerCase(); + filteredMembers = filteredMembers.filter((member) => { + const firstName = member.fields["first-name"]?.toLowerCase() || ""; + const lastName = member.fields["last-name"]?.toLowerCase() || ""; + const phone = member.fields["phone-number"]?.toLowerCase() || ""; + const email = member.fields["email"]?.toLowerCase() || ""; + + return ( + firstName.includes(searchLower) || + lastName.includes(searchLower) || + phone.includes(searchLower) || + email.includes(searchLower) + ); + }); + } + + if ( + filter !== "All" && + filter !== "Active" && + filter !== "Pending" && + filter !== "Expired" + ) { + filteredMembers = filteredMembers.filter((member) => { + switch (filter) { + case "Personal Training": + return member.hasPersonalTraining; + + case "Expiring in 10 Days": + return ( + member.memberData.status === "ACTIVE" && + member.daysUntilExpiry != null && + member.daysUntilExpiry > 0 && + member.daysUntilExpiry <= 10 + ); + + case "Expiring in 30 Days": + return ( + member.memberData.status === "ACTIVE" && + member.daysUntilExpiry != null && + member.daysUntilExpiry > 10 && + member.daysUntilExpiry <= 30 + ); + + case "Expired in 30 days": + return applyExpiredDateFilter(member.memberData, 30); + + case "Expired in 60 days": + return applyExpiredDateFilter(member.memberData, 60); + + default: + return true; + } + }); + } + + if (sortBy === "Name") { + filteredMembers.sort((a, b) => { + const aName = `${a.fields["first-name"] || ""} ${ + a.fields["last-name"] || "" + }`.trim(); + const bName = `${b.fields["first-name"] || ""} ${ + b.fields["last-name"] || "" + }`.trim(); + const comparison = aName.localeCompare(bName); + return sortAscending ? comparison : -comparison; + }); + } else if (sortBy === "Expiry Date") { + filteredMembers.sort((a, b) => { + const aDate = a.renewalDate ? new Date(a.renewalDate) : new Date(0); + const bDate = b.renewalDate ? new Date(b.renewalDate) : new Date(0); + const comparison = aDate.getTime() - bDate.getTime(); + return sortAscending ? comparison : -comparison; + }); + } + + const startIndex = 0; + const endIndex = Math.min(startIndex + limit, filteredMembers.length); + const paginatedMembers = filteredMembers.slice(startIndex, endIndex); + + const hasMore = endIndex < filteredMembers.length; + const lastMember = + paginatedMembers.length > 0 + ? paginatedMembers[paginatedMembers.length - 1] + : null; + + logger.info( + `Returning ${paginatedMembers.length} members out of ${filteredMembers.length} filtered` + ); + + return { + members: paginatedMembers, + hasMore, + lastDocumentId: lastMember?.membershipId, + totalCount: filteredMembers.length, + }; + } catch (error) { + logger.error("Error filtering members:", error); + throw new Error( + `Failed to filter members: ${ + error instanceof Error ? error.message : "Unknown error" + }` + ); + } + } +); + +async function getClientFieldsByMembershipId( + membershipId: string +): Promise<{ [key: string]: string }> { + try { + const membershipDoc = await app + .firestore() + .collection("memberships") + .doc(membershipId) + .get(); + + if (!membershipDoc.exists) { + return {}; + } + + const membershipData = membershipDoc.data(); + const userId = membershipData?.userId; + + if (!userId) { + return {}; + } + + const clientDoc = await app + .firestore() + .collection("client_profiles") + .doc(userId) + .get(); + + if (!clientDoc.exists) { + return {}; + } + + return clientDoc.data()?.fields || {}; + } catch (error) { + logger.error( + `Error getting client fields for membership ${membershipId}:`, + error + ); + return {}; + } +} + +async function getPaymentsForMembership(membershipId: string): Promise { + try { + const docSnapshot = await app + .firestore() + .collection("membership_payments") + .doc(membershipId) + .get(); + + if (!docSnapshot.exists) { + return []; + } + + const data = docSnapshot.data(); + const paymentsData = data?.payments || []; + + const payments = paymentsData.map((payment: any) => ({ + ...payment, + dateTimestamp: payment.dateTimestamp.toDate + ? payment.dateTimestamp.toDate() + : new Date(payment.dateTimestamp), + createdAt: payment.createdAt.toDate + ? payment.createdAt.toDate() + : new Date(payment.createdAt), + })); + + payments.sort( + (a: any, b: any) => b.createdAt.getTime() - a.createdAt.getTime() + ); + return payments; + } catch (error) { + logger.error( + `Error getting payments for membership ${membershipId}:`, + error + ); + return []; + } +} + +function calculateRenewalDateFromPayment( + subscription: any, + paymentDate: Date +): Date { + const renewalDate = new Date(paymentDate); + const frequency = subscription.frequency || "Monthly"; + + switch (frequency.toLowerCase()) { + case "monthly": + renewalDate.setMonth(renewalDate.getMonth() + 1); + break; + case "quarterly": + renewalDate.setMonth(renewalDate.getMonth() + 3); + break; + case "half-yearly": + renewalDate.setMonth(renewalDate.getMonth() + 6); + break; + case "yearly": + renewalDate.setFullYear(renewalDate.getFullYear() + 1); + break; + default: + renewalDate.setMonth(renewalDate.getMonth() + 1); + } + + return renewalDate; +} + +async function getTrainerAssignmentsForMembership( + membershipId: string +): Promise { + try { + const querySnapshot = await app + .firestore() + .collection("personal_trainer_assignments") + .where("membershipId", "==", membershipId) + .get(); + + return querySnapshot.docs.map((doc) => ({ + id: doc.id, + ...doc.data(), + })); + } catch (error) { + logger.error( + `Error getting trainer assignments for membership ${membershipId}:`, + error + ); + return []; + } +} + +function applyExpiredDateFilter(memberData: any, days: number): boolean { + const status = memberData.status; + const expirationDate = memberData.expirationDate; + + if (status !== "EXPIRED" || !expirationDate) { + return false; + } + + try { + const expiredDate = expirationDate.toDate + ? expirationDate.toDate() + : new Date(expirationDate); + const now = new Date(); + const targetDaysAgo = new Date(now.getTime() - days * 24 * 60 * 60 * 1000); + + return ( + expiredDate.getTime() < now.getTime() && + expiredDate.getTime() > targetDaysAgo.getTime() + ); + } catch (error) { + logger.error("Error parsing expiration date:", error); + return false; + } +} -- 2.43.0 From 02a8c1187aa6934c719ddb39e9698167794ee0d4 Mon Sep 17 00:00:00 2001 From: Sharon Dcruz Date: Mon, 25 Aug 2025 12:38:45 +0530 Subject: [PATCH 45/52] Updated --- functions/src/index.ts | 2 +- functions/src/notifications/index.ts | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/functions/src/index.ts b/functions/src/index.ts index 625c6d7..750b059 100644 --- a/functions/src/index.ts +++ b/functions/src/index.ts @@ -13,7 +13,7 @@ export * from './shared/config'; export { sendEmailSES } from './email'; export { sendSMSMessage } from './sms'; export { accessFile } from './storage'; -export { processNotificationOnCreate,checkExpiredMemberships } from './notifications'; +export { processNotificationOnCreate,checkExpiredMemberships,filterMembers } from './notifications'; export * from './payments'; export { getPlaceDetails, getPlacesAutocomplete } from './places'; export { registerClient } from './users'; diff --git a/functions/src/notifications/index.ts b/functions/src/notifications/index.ts index 9e40bc5..3f42ba1 100644 --- a/functions/src/notifications/index.ts +++ b/functions/src/notifications/index.ts @@ -1,3 +1,4 @@ export { processNotificationOnCreate } from './processNotification'; export { checkExpiredMemberships } from "./membershipStatusNotifications"; +export { filterMembers } from "./filterMembersRequest"; -- 2.43.0 From 371620d228810ded7c8e7577ba60e03884e7b7c3 Mon Sep 17 00:00:00 2001 From: Sharon Dcruz Date: Mon, 25 Aug 2025 13:23:32 +0530 Subject: [PATCH 46/52] Updated --- functions/src/index.ts | 2 +- .../src/notifications/filterMembersRequest.ts | 453 ------------------ functions/src/notifications/index.ts | 1 - 3 files changed, 1 insertion(+), 455 deletions(-) delete mode 100644 functions/src/notifications/filterMembersRequest.ts diff --git a/functions/src/index.ts b/functions/src/index.ts index 750b059..625c6d7 100644 --- a/functions/src/index.ts +++ b/functions/src/index.ts @@ -13,7 +13,7 @@ export * from './shared/config'; export { sendEmailSES } from './email'; export { sendSMSMessage } from './sms'; export { accessFile } from './storage'; -export { processNotificationOnCreate,checkExpiredMemberships,filterMembers } from './notifications'; +export { processNotificationOnCreate,checkExpiredMemberships } from './notifications'; export * from './payments'; export { getPlaceDetails, getPlacesAutocomplete } from './places'; export { registerClient } from './users'; diff --git a/functions/src/notifications/filterMembersRequest.ts b/functions/src/notifications/filterMembersRequest.ts deleted file mode 100644 index 0b4e610..0000000 --- a/functions/src/notifications/filterMembersRequest.ts +++ /dev/null @@ -1,453 +0,0 @@ -import { onCall } from "firebase-functions/v2/https"; -import { getLogger, getAdmin } from "../shared/config"; - -const app = getAdmin(); -const logger = getLogger(); - -interface FilterMembersRequest { - gymId: string; - filter: string; - sortBy: string; - sortAscending: boolean; - searchQuery?: string; - limit?: number; - lastDocumentId?: string; - role?: string; - trainerAssignedMembershipIds?: string[]; -} - -interface MembershipWithDetails { - membershipId: string; - memberData: any; - fields: { [key: string]: string }; - renewalDate?: string; - daysUntilExpiry?: number; - hasPersonalTraining: boolean; - trainerAssignments?: any[]; - timeSlots?: any[]; -} - -interface FilterMembersResponse { - members: MembershipWithDetails[]; - hasMore: boolean; - lastDocumentId?: string; - totalCount: number; -} - -export const filterMembers = onCall( - { - region: "#{SERVICES_RGN}#", - cors: true, - }, - async (request): Promise => { - try { - const { - gymId, - filter, - sortBy, - sortAscending, - searchQuery, - limit = 20, - lastDocumentId, - role, - trainerAssignedMembershipIds, - } = request.data as FilterMembersRequest; - - logger.info(`Filtering members for gym ${gymId} with filter: ${filter}`); - - if (!gymId) { - throw new Error("gymId is required"); - } - - let query = app - .firestore() - .collection("memberships") - .where("gymId", "==", gymId); - - if (filter === "Active") { - query = query.where("status", "==", "ACTIVE"); - } else if (filter === "Pending") { - query = query.where("status", "==", "PENDING"); - } else if (filter === "Expired") { - query = query.where("status", "==", "EXPIRED"); - } - - let orderByField = "createdAt"; - let orderByDirection: "asc" | "desc" = sortAscending ? "asc" : "desc"; - - switch (sortBy) { - case "Name": - orderByField = "createdAt"; - break; - case "Expiry Date": - orderByField = "expirationDate"; - break; - case "Join Date": - orderByField = "createdAt"; - break; - default: - orderByField = "createdAt"; - } - - query = query.orderBy(orderByField, orderByDirection); - - if (lastDocumentId) { - const lastDoc = await app - .firestore() - .collection("memberships") - .doc(lastDocumentId) - .get(); - if (lastDoc.exists) { - query = query.startAfter(lastDoc); - } - } - - const fetchLimit = ["All", "Active", "Pending", "Expired"].includes( - filter - ) - ? limit - : limit * 3; - query = query.limit(fetchLimit); - - const snapshot = await query.get(); - const allMembers: MembershipWithDetails[] = []; - - const batchSize = 10; - const docs = snapshot.docs; - - for (let i = 0; i < docs.length; i += batchSize) { - const batch = docs.slice(i, i + batchSize); - const batchResults = await Promise.allSettled( - batch.map(async (doc) => { - const memberData = doc.data(); - const membershipId = doc.id; - - const fields = await getClientFieldsByMembershipId(membershipId); - - let renewalDate: Date | undefined; - let daysUntilExpiry: number | undefined; - - if (memberData.subscription) { - const payments = await getPaymentsForMembership(membershipId); - if (payments.length > 0) { - const latestPayment = payments[0]; - renewalDate = calculateRenewalDateFromPayment( - memberData.subscription, - latestPayment.dateTimestamp - ); - - if (memberData.status === "ACTIVE") { - const now = new Date(); - const timeDiff = renewalDate.getTime() - now.getTime(); - daysUntilExpiry = Math.max( - 0, - Math.floor(timeDiff / (1000 * 3600 * 24)) - ); - } - } - } - - const hasPersonalTraining = - memberData.subscription?.hasPersonalTraining === true; - - let trainerAssignments: any[] = []; - let timeSlots: any[] = []; - - if (hasPersonalTraining) { - trainerAssignments = await getTrainerAssignmentsForMembership( - membershipId - ); - - if (trainerAssignments.length > 0) { - const latestAssignment = trainerAssignments[0]; - timeSlots = latestAssignment.timeSlot || []; - } - } - - return { - membershipId, - memberData, - fields, - renewalDate: renewalDate?.toISOString(), - daysUntilExpiry, - hasPersonalTraining, - trainerAssignments, - timeSlots, - }; - }) - ); - - batchResults.forEach((result) => { - if (result.status === "fulfilled" && result.value) { - allMembers.push(result.value); - } - }); - } - - let filteredMembers = allMembers; - if (role === "Trainer" && trainerAssignedMembershipIds) { - filteredMembers = allMembers.filter((member) => - trainerAssignedMembershipIds.includes(member.membershipId) - ); - } - - if (searchQuery && searchQuery.length >= 2) { - const searchLower = searchQuery.toLowerCase(); - filteredMembers = filteredMembers.filter((member) => { - const firstName = member.fields["first-name"]?.toLowerCase() || ""; - const lastName = member.fields["last-name"]?.toLowerCase() || ""; - const phone = member.fields["phone-number"]?.toLowerCase() || ""; - const email = member.fields["email"]?.toLowerCase() || ""; - - return ( - firstName.includes(searchLower) || - lastName.includes(searchLower) || - phone.includes(searchLower) || - email.includes(searchLower) - ); - }); - } - - if ( - filter !== "All" && - filter !== "Active" && - filter !== "Pending" && - filter !== "Expired" - ) { - filteredMembers = filteredMembers.filter((member) => { - switch (filter) { - case "Personal Training": - return member.hasPersonalTraining; - - case "Expiring in 10 Days": - return ( - member.memberData.status === "ACTIVE" && - member.daysUntilExpiry != null && - member.daysUntilExpiry > 0 && - member.daysUntilExpiry <= 10 - ); - - case "Expiring in 30 Days": - return ( - member.memberData.status === "ACTIVE" && - member.daysUntilExpiry != null && - member.daysUntilExpiry > 10 && - member.daysUntilExpiry <= 30 - ); - - case "Expired in 30 days": - return applyExpiredDateFilter(member.memberData, 30); - - case "Expired in 60 days": - return applyExpiredDateFilter(member.memberData, 60); - - default: - return true; - } - }); - } - - if (sortBy === "Name") { - filteredMembers.sort((a, b) => { - const aName = `${a.fields["first-name"] || ""} ${ - a.fields["last-name"] || "" - }`.trim(); - const bName = `${b.fields["first-name"] || ""} ${ - b.fields["last-name"] || "" - }`.trim(); - const comparison = aName.localeCompare(bName); - return sortAscending ? comparison : -comparison; - }); - } else if (sortBy === "Expiry Date") { - filteredMembers.sort((a, b) => { - const aDate = a.renewalDate ? new Date(a.renewalDate) : new Date(0); - const bDate = b.renewalDate ? new Date(b.renewalDate) : new Date(0); - const comparison = aDate.getTime() - bDate.getTime(); - return sortAscending ? comparison : -comparison; - }); - } - - const startIndex = 0; - const endIndex = Math.min(startIndex + limit, filteredMembers.length); - const paginatedMembers = filteredMembers.slice(startIndex, endIndex); - - const hasMore = endIndex < filteredMembers.length; - const lastMember = - paginatedMembers.length > 0 - ? paginatedMembers[paginatedMembers.length - 1] - : null; - - logger.info( - `Returning ${paginatedMembers.length} members out of ${filteredMembers.length} filtered` - ); - - return { - members: paginatedMembers, - hasMore, - lastDocumentId: lastMember?.membershipId, - totalCount: filteredMembers.length, - }; - } catch (error) { - logger.error("Error filtering members:", error); - throw new Error( - `Failed to filter members: ${ - error instanceof Error ? error.message : "Unknown error" - }` - ); - } - } -); - -async function getClientFieldsByMembershipId( - membershipId: string -): Promise<{ [key: string]: string }> { - try { - const membershipDoc = await app - .firestore() - .collection("memberships") - .doc(membershipId) - .get(); - - if (!membershipDoc.exists) { - return {}; - } - - const membershipData = membershipDoc.data(); - const userId = membershipData?.userId; - - if (!userId) { - return {}; - } - - const clientDoc = await app - .firestore() - .collection("client_profiles") - .doc(userId) - .get(); - - if (!clientDoc.exists) { - return {}; - } - - return clientDoc.data()?.fields || {}; - } catch (error) { - logger.error( - `Error getting client fields for membership ${membershipId}:`, - error - ); - return {}; - } -} - -async function getPaymentsForMembership(membershipId: string): Promise { - try { - const docSnapshot = await app - .firestore() - .collection("membership_payments") - .doc(membershipId) - .get(); - - if (!docSnapshot.exists) { - return []; - } - - const data = docSnapshot.data(); - const paymentsData = data?.payments || []; - - const payments = paymentsData.map((payment: any) => ({ - ...payment, - dateTimestamp: payment.dateTimestamp.toDate - ? payment.dateTimestamp.toDate() - : new Date(payment.dateTimestamp), - createdAt: payment.createdAt.toDate - ? payment.createdAt.toDate() - : new Date(payment.createdAt), - })); - - payments.sort( - (a: any, b: any) => b.createdAt.getTime() - a.createdAt.getTime() - ); - return payments; - } catch (error) { - logger.error( - `Error getting payments for membership ${membershipId}:`, - error - ); - return []; - } -} - -function calculateRenewalDateFromPayment( - subscription: any, - paymentDate: Date -): Date { - const renewalDate = new Date(paymentDate); - const frequency = subscription.frequency || "Monthly"; - - switch (frequency.toLowerCase()) { - case "monthly": - renewalDate.setMonth(renewalDate.getMonth() + 1); - break; - case "quarterly": - renewalDate.setMonth(renewalDate.getMonth() + 3); - break; - case "half-yearly": - renewalDate.setMonth(renewalDate.getMonth() + 6); - break; - case "yearly": - renewalDate.setFullYear(renewalDate.getFullYear() + 1); - break; - default: - renewalDate.setMonth(renewalDate.getMonth() + 1); - } - - return renewalDate; -} - -async function getTrainerAssignmentsForMembership( - membershipId: string -): Promise { - try { - const querySnapshot = await app - .firestore() - .collection("personal_trainer_assignments") - .where("membershipId", "==", membershipId) - .get(); - - return querySnapshot.docs.map((doc) => ({ - id: doc.id, - ...doc.data(), - })); - } catch (error) { - logger.error( - `Error getting trainer assignments for membership ${membershipId}:`, - error - ); - return []; - } -} - -function applyExpiredDateFilter(memberData: any, days: number): boolean { - const status = memberData.status; - const expirationDate = memberData.expirationDate; - - if (status !== "EXPIRED" || !expirationDate) { - return false; - } - - try { - const expiredDate = expirationDate.toDate - ? expirationDate.toDate() - : new Date(expirationDate); - const now = new Date(); - const targetDaysAgo = new Date(now.getTime() - days * 24 * 60 * 60 * 1000); - - return ( - expiredDate.getTime() < now.getTime() && - expiredDate.getTime() > targetDaysAgo.getTime() - ); - } catch (error) { - logger.error("Error parsing expiration date:", error); - return false; - } -} diff --git a/functions/src/notifications/index.ts b/functions/src/notifications/index.ts index 3f42ba1..9e40bc5 100644 --- a/functions/src/notifications/index.ts +++ b/functions/src/notifications/index.ts @@ -1,4 +1,3 @@ export { processNotificationOnCreate } from './processNotification'; export { checkExpiredMemberships } from "./membershipStatusNotifications"; -export { filterMembers } from "./filterMembersRequest"; -- 2.43.0 From 87b31096f5feeabc32626187b5d2d6cc3a1652e0 Mon Sep 17 00:00:00 2001 From: Sharon Dcruz Date: Mon, 25 Aug 2025 15:19:27 +0530 Subject: [PATCH 47/52] Removed Indexes --- firestore.indexes.json | 193 +---------------------------------------- 1 file changed, 1 insertion(+), 192 deletions(-) diff --git a/firestore.indexes.json b/firestore.indexes.json index 54f5709..2ddb5ce 100644 --- a/firestore.indexes.json +++ b/firestore.indexes.json @@ -1,195 +1,4 @@ { - "indexes": [ - { - "collectionGroup": "day_pass_bookings", - "queryScope": "COLLECTION", - "fields": [ - { - "fieldPath": "userId", - "order": "ASCENDING" - }, - { - "fieldPath": "createdAt", - "order": "DESCENDING" - } - ] - }, - { - "collectionGroup": "day_pass_entries", - "queryScope": "COLLECTION", - "fields": [ - { - "fieldPath": "bookingId", - "order": "ASCENDING" - }, - { - "fieldPath": "entryDate", - "order": "ASCENDING" - } - ] - }, - { - "collectionGroup": "gyms", - "queryScope": "COLLECTION_GROUP", - "fields": [ - { - "fieldPath": "userId", - "order": "ASCENDING" - }, - { - "fieldPath": "createdAt", - "order": "ASCENDING" - } - ] - }, - { - "collectionGroup": "gyms", - "queryScope": "COLLECTION", - "fields": [ - { - "fieldPath": "userId", - "order": "ASCENDING" - }, - { - "fieldPath": "name", - "order": "ASCENDING" - } - ] - }, - { - "collectionGroup": "gyms", - "queryScope": "COLLECTION", - "fields": [ - { - "fieldPath": "userId", - "order": "ASCENDING" - }, - { - "fieldPath": "createdAt", - "order": "DESCENDING" - } - ] - }, - { - "collectionGroup": "gyms", - "queryScope": "COLLECTION", - "fields": [ - { - "fieldPath": "isApproved", - "order": "ASCENDING" - }, - { - "fieldPath": "createdAt", - "order": "ASCENDING" - } - ] - }, - { - "collectionGroup": "memberships", - "queryScope": "COLLECTION", - "fields": [ - { - "fieldPath": "gymId", - "order": "ASCENDING" - }, - { - "fieldPath": "createdAt", - "order": "DESCENDING" - } - ] - }, - { - "collectionGroup": "notifications", - "queryScope": "COLLECTION", - "fields": [ - { - "fieldPath": "type", - "order": "ASCENDING" - }, - { - "fieldPath": "userId", - "order": "ASCENDING" - }, - { - "fieldPath": "timestamp", - "order": "DESCENDING" - } - ] - }, - { - "collectionGroup": "notifications", - "queryScope": "COLLECTION", - "fields": [ - { - "fieldPath": "recipientId", - "order": "ASCENDING" - }, - { - "fieldPath": "timestamp", - "order": "DESCENDING" - } - ] - }, - { - "collectionGroup": "workout_logs", - "queryScope": "COLLECTION", - "fields": [ - { - "fieldPath": "user_id", - "order": "ASCENDING" - }, - { - "fieldPath": "date", - "order": "DESCENDING" - } - ] - }, - { - "collectionGroup": "workout_logs", - "queryScope": "COLLECTION", - "fields": [ - { - "fieldPath": "user_id", - "order": "ASCENDING" - }, - { - "fieldPath": "date", - "order": "ASCENDING" - } - ] - }, - { - "collectionGroup": "workout_logs", - "queryScope": "COLLECTION", - "fields": [ - { - "fieldPath": "user_id", - "order": "ASCENDING" - }, - { - "fieldPath": "start_time", - "order": "ASCENDING" - }, - { - "fieldPath": "date", - "order": "ASCENDING" - } - ] - }, - { - "collectionGroup": "terms_and_conditions", - "queryScope": "COLLECTION", - "fields": [ - { - "fieldPath": "normalizedName", - "order": "ASCENDING" - }, - { - "fieldPath": "userUid", - "order": "ASCENDING" - } - ] - } - ], + "indexes": [], "fieldOverrides": [] } \ No newline at end of file -- 2.43.0 From 7b04a0e2bb8ca3b97faecc97fdaba7f1719c5be2 Mon Sep 17 00:00:00 2001 From: Sharon Dcruz Date: Mon, 25 Aug 2025 15:25:10 +0530 Subject: [PATCH 48/52] Indexes Added --- firestore.indexes.json | 193 ++++++++++++++++++++++++++++++++++++++++- 1 file changed, 192 insertions(+), 1 deletion(-) diff --git a/firestore.indexes.json b/firestore.indexes.json index 2ddb5ce..54f5709 100644 --- a/firestore.indexes.json +++ b/firestore.indexes.json @@ -1,4 +1,195 @@ { - "indexes": [], + "indexes": [ + { + "collectionGroup": "day_pass_bookings", + "queryScope": "COLLECTION", + "fields": [ + { + "fieldPath": "userId", + "order": "ASCENDING" + }, + { + "fieldPath": "createdAt", + "order": "DESCENDING" + } + ] + }, + { + "collectionGroup": "day_pass_entries", + "queryScope": "COLLECTION", + "fields": [ + { + "fieldPath": "bookingId", + "order": "ASCENDING" + }, + { + "fieldPath": "entryDate", + "order": "ASCENDING" + } + ] + }, + { + "collectionGroup": "gyms", + "queryScope": "COLLECTION_GROUP", + "fields": [ + { + "fieldPath": "userId", + "order": "ASCENDING" + }, + { + "fieldPath": "createdAt", + "order": "ASCENDING" + } + ] + }, + { + "collectionGroup": "gyms", + "queryScope": "COLLECTION", + "fields": [ + { + "fieldPath": "userId", + "order": "ASCENDING" + }, + { + "fieldPath": "name", + "order": "ASCENDING" + } + ] + }, + { + "collectionGroup": "gyms", + "queryScope": "COLLECTION", + "fields": [ + { + "fieldPath": "userId", + "order": "ASCENDING" + }, + { + "fieldPath": "createdAt", + "order": "DESCENDING" + } + ] + }, + { + "collectionGroup": "gyms", + "queryScope": "COLLECTION", + "fields": [ + { + "fieldPath": "isApproved", + "order": "ASCENDING" + }, + { + "fieldPath": "createdAt", + "order": "ASCENDING" + } + ] + }, + { + "collectionGroup": "memberships", + "queryScope": "COLLECTION", + "fields": [ + { + "fieldPath": "gymId", + "order": "ASCENDING" + }, + { + "fieldPath": "createdAt", + "order": "DESCENDING" + } + ] + }, + { + "collectionGroup": "notifications", + "queryScope": "COLLECTION", + "fields": [ + { + "fieldPath": "type", + "order": "ASCENDING" + }, + { + "fieldPath": "userId", + "order": "ASCENDING" + }, + { + "fieldPath": "timestamp", + "order": "DESCENDING" + } + ] + }, + { + "collectionGroup": "notifications", + "queryScope": "COLLECTION", + "fields": [ + { + "fieldPath": "recipientId", + "order": "ASCENDING" + }, + { + "fieldPath": "timestamp", + "order": "DESCENDING" + } + ] + }, + { + "collectionGroup": "workout_logs", + "queryScope": "COLLECTION", + "fields": [ + { + "fieldPath": "user_id", + "order": "ASCENDING" + }, + { + "fieldPath": "date", + "order": "DESCENDING" + } + ] + }, + { + "collectionGroup": "workout_logs", + "queryScope": "COLLECTION", + "fields": [ + { + "fieldPath": "user_id", + "order": "ASCENDING" + }, + { + "fieldPath": "date", + "order": "ASCENDING" + } + ] + }, + { + "collectionGroup": "workout_logs", + "queryScope": "COLLECTION", + "fields": [ + { + "fieldPath": "user_id", + "order": "ASCENDING" + }, + { + "fieldPath": "start_time", + "order": "ASCENDING" + }, + { + "fieldPath": "date", + "order": "ASCENDING" + } + ] + }, + { + "collectionGroup": "terms_and_conditions", + "queryScope": "COLLECTION", + "fields": [ + { + "fieldPath": "normalizedName", + "order": "ASCENDING" + }, + { + "fieldPath": "userUid", + "order": "ASCENDING" + } + ] + } + ], "fieldOverrides": [] } \ No newline at end of file -- 2.43.0 From 9bc89f28c39bf9be8f75ddd2ae6f8b14955e5d15 Mon Sep 17 00:00:00 2001 From: Sharon Dcruz Date: Tue, 26 Aug 2025 11:52:09 +0530 Subject: [PATCH 49/52] Updated --- functions/src/notifications/processNotification.ts | 9 --------- 1 file changed, 9 deletions(-) diff --git a/functions/src/notifications/processNotification.ts b/functions/src/notifications/processNotification.ts index fe7ce6a..6398419 100644 --- a/functions/src/notifications/processNotification.ts +++ b/functions/src/notifications/processNotification.ts @@ -82,15 +82,6 @@ async function getUserAndFCMToken( if (notification.recipientId) { targetUserId = notification.recipientId; logger.info(`Using top-level recipientId: ${targetUserId}`); - } else if (notification.data?.userId) { - targetUserId = notification.data.userId; - logger.info(`Using data.userId: ${targetUserId}`); - } else if (notification.data?.clientId) { - targetUserId = notification.data.clientId; - logger.info(`Using data.clientId: ${targetUserId}`); - } else if (notification.data?.invitorId) { - targetUserId = notification.data.invitorId; - logger.info(`Using data.invitorId: ${targetUserId}`); } else if (notification.data?.phoneNumber) { logger.info( `Looking up user by phone number from data: ${notification.data.phoneNumber}` -- 2.43.0 From 65e7c7039feb5a65ccee68617769b4b3f2322d38 Mon Sep 17 00:00:00 2001 From: Sharon Dcruz Date: Tue, 9 Sep 2025 14:00:36 +0530 Subject: [PATCH 50/52] Updated Schedue to run once in a day --- .../membershipStatusNotifications.ts | 74 +++++++++++++------ 1 file changed, 53 insertions(+), 21 deletions(-) diff --git a/functions/src/notifications/membershipStatusNotifications.ts b/functions/src/notifications/membershipStatusNotifications.ts index e8c3b01..9238024 100644 --- a/functions/src/notifications/membershipStatusNotifications.ts +++ b/functions/src/notifications/membershipStatusNotifications.ts @@ -46,7 +46,7 @@ interface PersonalTrainerAssign { export const checkExpiredMemberships = onSchedule( { - schedule: "*/5 * * * *", + schedule: "0 0 * * *", timeZone: "UTC", region: "#{SERVICES_RGN}#", }, @@ -57,11 +57,18 @@ export const checkExpiredMemberships = onSchedule( await updateDaysUntilExpiryForAllMemberships(); const expiredMemberships = await findExpiredMemberships(); const expiringMemberships = await findMembershipsExpiringIn10Days(); - - const expiredMembershipsWithoutExpiryDate = await findExpiredMembershipsWithoutExpiryDate(); - if (expiredMemberships.length === 0 && expiringMemberships.length === 0 && expiredMembershipsWithoutExpiryDate.length === 0) { - logger.info("No expired, expiring, or unprocessed expired memberships found."); + const expiredMembershipsWithoutExpiryDate = + await findExpiredMembershipsWithoutExpiryDate(); + + if ( + expiredMemberships.length === 0 && + expiringMemberships.length === 0 && + expiredMembershipsWithoutExpiryDate.length === 0 + ) { + logger.info( + "No expired, expiring, or unprocessed expired memberships found." + ); return; } @@ -78,15 +85,29 @@ export const checkExpiredMemberships = onSchedule( ); const updateResults = await Promise.allSettled( - expiredMembershipsWithoutExpiryDate.map((m) => updateExpiryDateForExpiredMembership(m.id, m.data)) + expiredMembershipsWithoutExpiryDate.map((m) => + updateExpiryDateForExpiredMembership(m.id, m.data) + ) ); - const expiredSuccessful = expiredResults.filter(r => r.status === "fulfilled").length; - const expiredFailed = expiredResults.filter(r => r.status === "rejected").length; - const expiringSuccessful = expiringResults.filter(r => r.status === "fulfilled").length; - const expiringFailed = expiringResults.filter(r => r.status === "rejected").length; - const updateSuccessful = updateResults.filter(r => r.status === "fulfilled").length; - const updateFailed = updateResults.filter(r => r.status === "rejected").length; + const expiredSuccessful = expiredResults.filter( + (r) => r.status === "fulfilled" + ).length; + const expiredFailed = expiredResults.filter( + (r) => r.status === "rejected" + ).length; + const expiringSuccessful = expiringResults.filter( + (r) => r.status === "fulfilled" + ).length; + const expiringFailed = expiringResults.filter( + (r) => r.status === "rejected" + ).length; + const updateSuccessful = updateResults.filter( + (r) => r.status === "fulfilled" + ).length; + const updateFailed = updateResults.filter( + (r) => r.status === "rejected" + ).length; logger.info( `Completed processing. Expired - Success: ${expiredSuccessful}, Failed: ${expiredFailed}. Expiring - Success: ${expiringSuccessful}, Failed: ${expiringFailed}. Updates - Success: ${updateSuccessful}, Failed: ${updateFailed}` @@ -97,9 +118,6 @@ export const checkExpiredMemberships = onSchedule( } ); - - - async function findExpiredMembershipsWithoutExpiryDate(): Promise< Array<{ id: string; data: MembershipData }> > { @@ -110,7 +128,10 @@ async function findExpiredMembershipsWithoutExpiryDate(): Promise< .where("status", "==", "EXPIRED") .get(); - const membershipsWithoutExpiryDate: Array<{ id: string; data: MembershipData }> = []; + const membershipsWithoutExpiryDate: Array<{ + id: string; + data: MembershipData; + }> = []; snapshot.docs.forEach((doc) => { const data = doc.data() as MembershipData; @@ -121,7 +142,10 @@ async function findExpiredMembershipsWithoutExpiryDate(): Promise< return membershipsWithoutExpiryDate; } catch (error) { - logger.error("Error finding expired memberships without expiry date:", error); + logger.error( + "Error finding expired memberships without expiry date:", + error + ); throw error; } } @@ -130,7 +154,10 @@ async function updateExpiryDateForExpiredMembership( membershipData: MembershipData ): Promise { try { - if (!membershipData.subscription || !membershipData.subscription.frequency) { + if ( + !membershipData.subscription || + !membershipData.subscription.frequency + ) { logger.warn(`Skipping membership ${membershipId} - no subscription data`); return; } @@ -156,9 +183,14 @@ async function updateExpiryDateForExpiredMembership( updatedAt: admin.firestore.FieldValue.serverTimestamp(), }); - logger.info(`Updated expiry date for expired membership ${membershipId}: ${expiryDate.toISOString()}`); + logger.info( + `Updated expiry date for expired membership ${membershipId}: ${expiryDate.toISOString()}` + ); } catch (error) { - logger.error(`Error updating expiry date for membership ${membershipId}:`, error); + logger.error( + `Error updating expiry date for membership ${membershipId}:`, + error + ); throw error; } } @@ -1034,4 +1066,4 @@ async function getGymName(gymId: string): Promise { logger.error(`Error getting gym name for gym ${gymId}:`, error); return "Unknown Gym"; } -} \ No newline at end of file +} -- 2.43.0 From a19803fcee8e92924bf4c9e9409225cd021df6c8 Mon Sep 17 00:00:00 2001 From: Sharon Dcruz Date: Tue, 9 Sep 2025 14:34:38 +0530 Subject: [PATCH 51/52] Updated --- functions/src/notifications/membershipStatusNotifications.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/functions/src/notifications/membershipStatusNotifications.ts b/functions/src/notifications/membershipStatusNotifications.ts index 9238024..40b5666 100644 --- a/functions/src/notifications/membershipStatusNotifications.ts +++ b/functions/src/notifications/membershipStatusNotifications.ts @@ -46,7 +46,7 @@ interface PersonalTrainerAssign { export const checkExpiredMemberships = onSchedule( { - schedule: "0 0 * * *", + schedule: "0 0,12 * * *", timeZone: "UTC", region: "#{SERVICES_RGN}#", }, -- 2.43.0 From 8252651e33e07510ee8ee3244f759018dba8bde3 Mon Sep 17 00:00:00 2001 From: Sharon Dcruz Date: Thu, 11 Sep 2025 09:49:51 +0530 Subject: [PATCH 52/52] Schedule Updated --- functions/src/notifications/membershipStatusNotifications.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/functions/src/notifications/membershipStatusNotifications.ts b/functions/src/notifications/membershipStatusNotifications.ts index 40b5666..cc4f5ae 100644 --- a/functions/src/notifications/membershipStatusNotifications.ts +++ b/functions/src/notifications/membershipStatusNotifications.ts @@ -46,10 +46,11 @@ interface PersonalTrainerAssign { export const checkExpiredMemberships = onSchedule( { - schedule: "0 0,12 * * *", + schedule: "0 8,14,20 * * *", timeZone: "UTC", region: "#{SERVICES_RGN}#", }, + async (event) => { logger.info("Starting scheduled membership expiry check..."); -- 2.43.0