From 5c81ae30161b86bf0caf2464601aee344a4c03e3 Mon Sep 17 00:00:00 2001 From: Sharon Dcruz Date: Fri, 1 Aug 2025 12:24:04 +0530 Subject: [PATCH 01/10] Changes Updated --- functions/src/index.ts | 2 +- functions/src/notifications/index.ts | 2 + .../membershipStatusNotifications.ts | 178 ++++++++++++++++++ .../src/notifications/processNotification.ts | 2 +- 4 files changed, 182 insertions(+), 2 deletions(-) create mode 100644 functions/src/notifications/membershipStatusNotifications.ts diff --git a/functions/src/index.ts b/functions/src/index.ts index 1156209..fb48fbe 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 } from './notifications'; +export { processNotificationOnCreate,processMembershipStatusChange } 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 c9fed3e..eb9cb4d 100644 --- a/functions/src/notifications/index.ts +++ b/functions/src/notifications/index.ts @@ -1 +1,3 @@ export { processNotificationOnCreate } from './processNotification'; +export { processMembershipStatusChange } from "./membershipStatusNotifications"; + diff --git a/functions/src/notifications/membershipStatusNotifications.ts b/functions/src/notifications/membershipStatusNotifications.ts new file mode 100644 index 0000000..21b7a79 --- /dev/null +++ b/functions/src/notifications/membershipStatusNotifications.ts @@ -0,0 +1,178 @@ +import { onDocumentUpdated } from "firebase-functions/v2/firestore"; +import { getLogger } from "../shared/config"; +import { getAdmin } from "../shared/config"; +import * as admin from "firebase-admin"; + +const app = getAdmin(); +const logger = getLogger(); + +interface MembershipData { + id?: string; + userId: string; + gymId: string; + status: string; + subscription?: { + name: string; + duration: number; + }; + createdAt: admin.firestore.FieldValue; + updatedAt: admin.firestore.FieldValue; +} + +interface ClientFields { + [key: string]: string | undefined; + 'first-name'?: string; +} + +export const processMembershipStatusChange = onDocumentUpdated( + { + region: "#{SERVICES_RGN}#", + document: "memberships/{membershipId}", + }, + async (event) => { + try { + const membershipId = event.params.membershipId; + const beforeData = event.data?.before?.data() as MembershipData; + const afterData = event.data?.after?.data() as MembershipData; + + if (!beforeData || !afterData) { + logger.error(`No data found for membership ${membershipId}`); + return; + } + + // Check if status changed to EXPIRED + if (beforeData.status !== "EXPIRED" && afterData.status === "EXPIRED") { + logger.info(`Membership ${membershipId} status changed to EXPIRED. Sending notification...`); + + await sendPlanExpiredNotification(membershipId, afterData); + } + + } catch (error) { + logger.error("Error processing membership status change:", error); + } + } +); + +async function sendPlanExpiredNotification( + membershipId: string, + membershipData: MembershipData +): Promise { + try { + const clientName = await getClientName(membershipId, membershipData.userId); + + const gymOwnerId = await getGymOwnerId(membershipData.gymId); + + const gymName = await getGymName(membershipData.gymId); + + const expiryDate = new Date(); + const formattedExpiryDate = expiryDate.toLocaleDateString('en-US', { + year: 'numeric', + month: 'long', + day: 'numeric' + }); + + // Create notification document + const notificationData = { + senderId: "system", + recipientId: gymOwnerId, + type: "plan_expired", + notificationSent: false, + timestamp: admin.firestore.FieldValue.serverTimestamp(), + read: false, + data: { + title: "Plan Expired", + message: `The plan ${membershipData.subscription?.name || 'Unknown Plan'} for client ${clientName} has expired.`, + planName: membershipData.subscription?.name || 'Unknown Plan', + clientName: clientName, + membershipId: membershipId, + gymName: gymName, + formattedExpiryDate: formattedExpiryDate, + expiryDate: admin.firestore.Timestamp.fromDate(expiryDate), + }, + }; + + const notificationRef = await app + .firestore() + .collection("notifications") + .add(notificationData); + + logger.info(`Plan expired notification created with ID: ${notificationRef.id} for gym owner ${gymOwnerId}, membership ${membershipId}`); + } catch (error) { + logger.error(`Error sending plan expired notification for membership ${membershipId}:`, error); + throw error; + } +} + +async function getClientName(membershipId: string, clientId: string): Promise { + try { + const clientProfileDoc = await app + .firestore() + .collection("client_profiles") + .doc(clientId) + .get(); + + if (!clientProfileDoc.exists) { + logger.warn(`Client profile not found for clientId: ${clientId}`); + return "Unknown Client"; + } + + const clientData = clientProfileDoc.data(); + const fields = clientData?.fields as ClientFields; + + if (fields) { + const firstName = fields['first-name'] || ''; + return firstName || "Unknown Client"; + } + + return "Unknown Client"; + } catch (error) { + logger.error(`Error getting client name for membership ${membershipId}:`, error); + return "Unknown Client"; + } +} + +async function getGymOwnerId(gymId: string): Promise { + try { + const gymDoc = await app + .firestore() + .collection("gyms") + .doc(gymId) + .get(); + + if (!gymDoc.exists) { + throw new Error(`Gym not found: ${gymId}`); + } + + const gymData = gymDoc.data(); + const userId = gymData?.userId; + + if (!userId) { + throw new Error(`No userId found in gym document: ${gymId}`); + } + + return userId; + } catch (error) { + logger.error(`Error getting gym owner ID for gym ${gymId}:`, error); + throw error; + } +} + +async function getGymName(gymId: string): Promise { + try { + const gymDoc = await app + .firestore() + .collection("gyms") + .doc(gymId) + .get(); + + if (!gymDoc.exists) { + return "Unknown Gym"; + } + + const gymData = gymDoc.data(); + return gymData?.name || gymData?.gymName || "Unknown Gym"; + } catch (error) { + logger.error(`Error getting gym name for gym ${gymId}:`, error); + return "Unknown Gym"; + } +} diff --git a/functions/src/notifications/processNotification.ts b/functions/src/notifications/processNotification.ts index 5d3c9b0..d232395 100644 --- a/functions/src/notifications/processNotification.ts +++ b/functions/src/notifications/processNotification.ts @@ -240,7 +240,7 @@ function prepareNotificationMessage( title = notification.data?.title || "Plan Expired"; body = notification.data?.message || - `The plan ${notification.data?.planName} for client ${notification.data?.clientName} expired on ${notification.data?.formattedExpiryDate}.`; + `The plan ${notification.data?.planName} for client ${notification.data?.clientName} has expired.`; break; case "schedule_update": -- 2.43.0 From adec108f8a75a43b0a1cbe387ce4febd2e9b249c Mon Sep 17 00:00:00 2001 From: Sharon Dcruz Date: Fri, 1 Aug 2025 18:25:39 +0530 Subject: [PATCH 02/10] Changes Updated --- functions/src/index.ts | 4 +- functions/src/notifications/index.ts | 2 +- .../membershipStatusNotifications.ts | 297 ++++++++++++------ 3 files changed, 198 insertions(+), 105 deletions(-) diff --git a/functions/src/index.ts b/functions/src/index.ts index fb48fbe..625c6d7 100644 --- a/functions/src/index.ts +++ b/functions/src/index.ts @@ -7,13 +7,13 @@ setGlobalOptions({ minInstances: 0, maxInstances: 10, concurrency: 80 -}); +}); export * from './shared/config'; export { sendEmailSES } from './email'; export { sendSMSMessage } from './sms'; export { accessFile } from './storage'; -export { processNotificationOnCreate,processMembershipStatusChange } 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/index.ts b/functions/src/notifications/index.ts index eb9cb4d..9e40bc5 100644 --- a/functions/src/notifications/index.ts +++ b/functions/src/notifications/index.ts @@ -1,3 +1,3 @@ export { processNotificationOnCreate } from './processNotification'; -export { processMembershipStatusChange } from "./membershipStatusNotifications"; +export { checkExpiredMemberships } from "./membershipStatusNotifications"; diff --git a/functions/src/notifications/membershipStatusNotifications.ts b/functions/src/notifications/membershipStatusNotifications.ts index 21b7a79..17d108d 100644 --- a/functions/src/notifications/membershipStatusNotifications.ts +++ b/functions/src/notifications/membershipStatusNotifications.ts @@ -1,6 +1,5 @@ -import { onDocumentUpdated } from "firebase-functions/v2/firestore"; -import { getLogger } from "../shared/config"; -import { getAdmin } from "../shared/config"; +import { onSchedule } from "firebase-functions/v2/scheduler"; +import { getLogger, getAdmin } from "../shared/config"; import * as admin from "firebase-admin"; const app = getAdmin(); @@ -14,143 +13,246 @@ interface MembershipData { subscription?: { name: string; duration: number; + frequency: string; + assignedAt: admin.firestore.Timestamp; }; - createdAt: admin.firestore.FieldValue; - updatedAt: admin.firestore.FieldValue; } interface ClientFields { [key: string]: string | undefined; - 'first-name'?: string; + "first-name"?: string; + "last-name"?: string; } -export const processMembershipStatusChange = onDocumentUpdated( +export const checkExpiredMemberships = onSchedule( { + schedule: "0 8,14,20 * * *", + timeZone: "UTC", region: "#{SERVICES_RGN}#", - document: "memberships/{membershipId}", }, async (event) => { - try { - const membershipId = event.params.membershipId; - const beforeData = event.data?.before?.data() as MembershipData; - const afterData = event.data?.after?.data() as MembershipData; + logger.info("Starting scheduled membership expiry check..."); - if (!beforeData || !afterData) { - logger.error(`No data found for membership ${membershipId}`); + try { + const expiredMemberships = await findExpiredMemberships(); + + if (expiredMemberships.length === 0) { + logger.info("No expired memberships found."); return; } - // Check if status changed to EXPIRED - if (beforeData.status !== "EXPIRED" && afterData.status === "EXPIRED") { - logger.info(`Membership ${membershipId} status changed to EXPIRED. Sending notification...`); - - await sendPlanExpiredNotification(membershipId, afterData); - } + logger.info( + `Found ${expiredMemberships.length} expired memberships to process.` + ); + const results = await Promise.allSettled( + expiredMemberships.map((m) => processExpiredMembership(m.id, m.data)) + ); + + const successful = results.filter((r) => r.status === "fulfilled").length; + const failed = results.filter((r) => r.status === "rejected").length; + + logger.info( + `Completed processing. Success: ${successful}, Failed: ${failed}` + ); } catch (error) { - logger.error("Error processing membership status change:", error); + logger.error("Error in scheduled membership expiry check:", error); } } ); +async function findExpiredMemberships(): Promise< + Array<{ id: string; data: MembershipData }> +> { + try { + const snapshot = await app + .firestore() + .collection("memberships") + .where("status", "==", "ACTIVE") + .get(); + + const expired: Array<{ id: string; data: MembershipData }> = []; + + snapshot.docs.forEach((doc) => { + const data = doc.data() as MembershipData; + const isExpired = checkIfMembershipExpired(data); + if (isExpired) expired.push({ id: doc.id, data }); + }); + + return expired; + } catch (error) { + logger.error("Error finding expired memberships:", error); + throw error; + } +} + +function checkIfMembershipExpired(data: MembershipData): boolean { + try { + // Critical update: Use the assignedAt timestamp from the subscription object + if ( + !data.subscription || + !data.subscription.duration || + !data.subscription.frequency || + !data.subscription.assignedAt + ) { + logger.warn( + `Skipping expiry check for membership ${data.id} with missing subscription data.` + ); + return false; + } + + const startDate = ( + data.subscription.assignedAt as admin.firestore.Timestamp + ).toDate(); + const expiryDate = calculateExpiryDate( + startDate, + data.subscription.duration, + data.subscription.frequency + ); + const now = new Date(); + + return now > expiryDate; + } catch (error) { + logger.error(`Error checking expiry for membership ${data.id}:`, error); + return false; + } +} + +function calculateExpiryDate( + startDate: Date, + duration: number, + frequency: string +): Date { + const expiry = new Date(startDate); + switch (frequency.toLowerCase()) { + case "monthly": + expiry.setMonth(expiry.getMonth() + duration); + break; + case "quarterly": + expiry.setMonth(expiry.getMonth() + 3 * duration); + break; + case "half-yearly": + expiry.setMonth(expiry.getMonth() + 6 * duration); + break; + case "yearly": + expiry.setFullYear(expiry.getFullYear() + duration); + break; + default: + expiry.setMonth(expiry.getMonth() + duration); + } + return expiry; +} + +async function processExpiredMembership( + membershipId: string, + membershipData: MembershipData +): Promise { + try { + 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); + } catch (error) { + logger.error(`Error processing membership ${membershipId}:`, error); + } +} + async function sendPlanExpiredNotification( membershipId: string, membershipData: MembershipData ): Promise { try { const clientName = await getClientName(membershipId, membershipData.userId); - const gymOwnerId = await getGymOwnerId(membershipData.gymId); - const gymName = await getGymName(membershipData.gymId); - const expiryDate = new Date(); - const formattedExpiryDate = expiryDate.toLocaleDateString('en-US', { - year: 'numeric', - month: 'long', - day: 'numeric' - }); - - // Create notification document - const notificationData = { - senderId: "system", - recipientId: gymOwnerId, - type: "plan_expired", - notificationSent: false, - timestamp: admin.firestore.FieldValue.serverTimestamp(), - read: false, - data: { - title: "Plan Expired", - message: `The plan ${membershipData.subscription?.name || 'Unknown Plan'} for client ${clientName} has expired.`, - planName: membershipData.subscription?.name || 'Unknown Plan', - clientName: clientName, - membershipId: membershipId, - gymName: gymName, - formattedExpiryDate: formattedExpiryDate, - expiryDate: admin.firestore.Timestamp.fromDate(expiryDate), - }, - }; - - const notificationRef = await app + const existing = await app .firestore() .collection("notifications") - .add(notificationData); + .where("type", "==", "plan_expired") + .where("data.membershipId", "==", membershipId) + .limit(1) + .get(); - logger.info(`Plan expired notification created with ID: ${notificationRef.id} for gym owner ${gymOwnerId}, membership ${membershipId}`); + if (!existing.empty) { + logger.info(`Notification already sent for ${membershipId}, skipping...`); + return; + } + + const expiryDate = membershipData.subscription?.assignedAt?.toDate(); + const formattedDate = expiryDate + ? expiryDate.toLocaleDateString("en-US", { + year: "numeric", + month: "long", + day: "numeric", + }) + : "Unknown Date"; + + await app + .firestore() + .collection("notifications") + .add({ + senderId: "system", + recipientId: gymOwnerId, + type: "plan_expired", + notificationSent: false, + timestamp: admin.firestore.FieldValue.serverTimestamp(), + read: false, + data: { + title: "Plan Expired", + message: `The plan ${ + membershipData.subscription?.name || "Unknown Plan" + } for client ${clientName} has expired.`, + planName: membershipData.subscription?.name || "Unknown Plan", + clientName, + membershipId, + gymName, + formattedExpiryDate: formattedDate, + expiryDate: + membershipData.subscription?.assignedAt || + admin.firestore.Timestamp.fromDate(new Date()), + }, + }); + + logger.info( + `Notification sent for expired plan of membership ${membershipId}` + ); } catch (error) { - logger.error(`Error sending plan expired notification for membership ${membershipId}:`, error); - throw error; + logger.error(`Error sending notification for ${membershipId}:`, error); } } -async function getClientName(membershipId: string, clientId: string): Promise { +async function getClientName( + membershipId: string, + clientId: string +): Promise { try { - const clientProfileDoc = await app + const doc = await app .firestore() .collection("client_profiles") .doc(clientId) .get(); + if (!doc.exists) return "Unknown Client"; - if (!clientProfileDoc.exists) { - logger.warn(`Client profile not found for clientId: ${clientId}`); - return "Unknown Client"; - } - - const clientData = clientProfileDoc.data(); - const fields = clientData?.fields as ClientFields; - - if (fields) { - const firstName = fields['first-name'] || ''; - return firstName || "Unknown Client"; - } - - return "Unknown Client"; + const fields = doc.data()?.fields as ClientFields; + const firstName = fields?.["first-name"] || ""; + const lastName = fields?.["last-name"] || ""; + return `${firstName} ${lastName}`.trim() || "Unknown Client"; } catch (error) { - logger.error(`Error getting client name for membership ${membershipId}:`, error); + logger.error(`Error getting client name for ${membershipId}:`, error); return "Unknown Client"; } } async function getGymOwnerId(gymId: string): Promise { try { - const gymDoc = await app - .firestore() - .collection("gyms") - .doc(gymId) - .get(); - - if (!gymDoc.exists) { - throw new Error(`Gym not found: ${gymId}`); - } - - const gymData = gymDoc.data(); - const userId = gymData?.userId; - - if (!userId) { - throw new Error(`No userId found in gym document: ${gymId}`); - } - - return userId; + const doc = await app.firestore().collection("gyms").doc(gymId).get(); + const data = doc.data(); + if (!data?.userId) throw new Error(`userId not found for gym ${gymId}`); + return data.userId; } catch (error) { logger.error(`Error getting gym owner ID for gym ${gymId}:`, error); throw error; @@ -159,18 +261,9 @@ async function getGymOwnerId(gymId: string): Promise { async function getGymName(gymId: string): Promise { try { - const gymDoc = await app - .firestore() - .collection("gyms") - .doc(gymId) - .get(); - - if (!gymDoc.exists) { - return "Unknown Gym"; - } - - const gymData = gymDoc.data(); - return gymData?.name || gymData?.gymName || "Unknown Gym"; + const doc = await app.firestore().collection("gyms").doc(gymId).get(); + const data = doc.data(); + return data?.name || data?.gymName || "Unknown Gym"; } catch (error) { logger.error(`Error getting gym name for gym ${gymId}:`, error); return "Unknown Gym"; -- 2.43.0 From 764c79e1ec1c381399b4f302e23c15f5323ff1f6 Mon Sep 17 00:00:00 2001 From: Sharon Dcruz Date: Fri, 1 Aug 2025 21:09:52 +0530 Subject: [PATCH 03/10] Changes UPdated --- firestore.indexes.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/firestore.indexes.json b/firestore.indexes.json index def7a3d..7308d4d 100644 --- a/firestore.indexes.json +++ b/firestore.indexes.json @@ -107,7 +107,7 @@ "queryScope": "COLLECTION", "fields": [ { - "fieldPath": "ownerId", + "fieldPath": "data.ownerId", "order": "ASCENDING" }, { @@ -121,7 +121,7 @@ "queryScope": "COLLECTION", "fields": [ { - "fieldPath": "ownerId", + "fieldPath": "data.ownerId", "order": "ASCENDING" }, { @@ -139,7 +139,7 @@ "queryScope": "COLLECTION", "fields": [ { - "fieldPath": "trainerId", + "fieldPath": "data.trainerId", "order": "ASCENDING" }, { -- 2.43.0 From 9327da361cea25806f9526677cc3117d89a9b529 Mon Sep 17 00:00:00 2001 From: Sharon Dcruz Date: Mon, 4 Aug 2025 10:02:29 +0530 Subject: [PATCH 04/10] Changes Updated --- firestore.indexes.json | 62 +----------------------------------------- 1 file changed, 1 insertion(+), 61 deletions(-) diff --git a/firestore.indexes.json b/firestore.indexes.json index 7308d4d..49c7af5 100644 --- a/firestore.indexes.json +++ b/firestore.indexes.json @@ -75,21 +75,7 @@ "queryScope": "COLLECTION", "fields": [ { - "fieldPath": "clientId", - "order": "ASCENDING" - }, - { - "fieldPath": "timestamp", - "order": "DESCENDING" - } - ] - }, - { - "collectionGroup": "notifications", - "queryScope": "COLLECTION", - "fields": [ - { - "fieldPath": "clientId", + "fieldPath": "data.clientId", "order": "ASCENDING" }, { @@ -102,52 +88,6 @@ } ] }, - { - "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", -- 2.43.0 From d76c84418bef2a5fb32310c484cb4a4431ad599d Mon Sep 17 00:00:00 2001 From: Sharon Dcruz Date: Mon, 4 Aug 2025 10:29:00 +0530 Subject: [PATCH 05/10] Changes Updated --- firestore.indexes.json | 20 +------------------- 1 file changed, 1 insertion(+), 19 deletions(-) diff --git a/firestore.indexes.json b/firestore.indexes.json index 49c7af5..f609f3d 100644 --- a/firestore.indexes.json +++ b/firestore.indexes.json @@ -78,30 +78,12 @@ "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", + "fieldPath": "__name__", "order": "DESCENDING" } ] -- 2.43.0 From 7fbab4cded6f13b35f6b202fc52c606aad9e17b4 Mon Sep 17 00:00:00 2001 From: Sharon Dcruz Date: Mon, 4 Aug 2025 10:35:48 +0530 Subject: [PATCH 06/10] Updated --- firestore.indexes.json | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/firestore.indexes.json b/firestore.indexes.json index f609f3d..d8e0d35 100644 --- a/firestore.indexes.json +++ b/firestore.indexes.json @@ -77,6 +77,10 @@ { "fieldPath": "data.clientId", "order": "ASCENDING" + }, + { + "fieldPath": "type", + "order": "ASCENDING" }, { "fieldPath": "timestamp", @@ -95,6 +99,10 @@ { "fieldPath": "data.ownerId", "order": "ASCENDING" + }, + { + "fieldPath": "type", + "order": "ASCENDING" }, { "fieldPath": "timestamp", @@ -113,6 +121,10 @@ { "fieldPath": "data.trainerId", "order": "ASCENDING" + }, + { + "fieldPath": "type", + "order": "ASCENDING" }, { "fieldPath": "timestamp", -- 2.43.0 From 4d61f72cd8e84c638f92055190a9213e1ef007df Mon Sep 17 00:00:00 2001 From: Sharon Dcruz Date: Mon, 4 Aug 2025 10:47:22 +0530 Subject: [PATCH 07/10] Updated --- firestore.indexes.json | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/firestore.indexes.json b/firestore.indexes.json index d8e0d35..2c5a656 100644 --- a/firestore.indexes.json +++ b/firestore.indexes.json @@ -85,10 +85,6 @@ { "fieldPath": "timestamp", "order": "DESCENDING" - }, - { - "fieldPath": "__name__", - "order": "DESCENDING" } ] }, @@ -107,10 +103,6 @@ { "fieldPath": "timestamp", "order": "DESCENDING" - }, - { - "fieldPath": "__name__", - "order": "DESCENDING" } ] }, @@ -129,10 +121,6 @@ { "fieldPath": "timestamp", "order": "DESCENDING" - }, - { - "fieldPath": "__name__", - "order": "DESCENDING" } ] }, -- 2.43.0 From 3f4974a74c9f0e6143435b2f204d789c13c55a3d Mon Sep 17 00:00:00 2001 From: Sharon Dcruz Date: Mon, 4 Aug 2025 11:02:41 +0530 Subject: [PATCH 08/10] Chnages Updated --- firestore.indexes.json | 25 ++++++++++++++++++++++--- 1 file changed, 22 insertions(+), 3 deletions(-) diff --git a/firestore.indexes.json b/firestore.indexes.json index 2c5a656..913b031 100644 --- a/firestore.indexes.json +++ b/firestore.indexes.json @@ -78,7 +78,7 @@ "fieldPath": "data.clientId", "order": "ASCENDING" }, - { + { "fieldPath": "type", "order": "ASCENDING" }, @@ -96,7 +96,7 @@ "fieldPath": "data.ownerId", "order": "ASCENDING" }, - { + { "fieldPath": "type", "order": "ASCENDING" }, @@ -114,7 +114,7 @@ "fieldPath": "data.trainerId", "order": "ASCENDING" }, - { + { "fieldPath": "type", "order": "ASCENDING" }, @@ -124,6 +124,25 @@ } ] }, + { + "collectionGroup": "notifications", + "queryScope": "COLLECTION", + "fields": [ + { + "fieldPath": "type", + "order": "ASCENDING" + }, + { + "fieldPath": "recipientId", + "order": "ASCENDING" + }, + { + "fieldPath": "timestamp", + "order": "DESCENDING" + } + ] + }, + { "collectionGroup": "workout_logs", "queryScope": "COLLECTION", -- 2.43.0 From e13fdf2a0dbffcdeb5a235cbc4e389c899ec2580 Mon Sep 17 00:00:00 2001 From: Sharon Dcruz Date: Mon, 4 Aug 2025 11:09:51 +0530 Subject: [PATCH 09/10] Updated --- firestore.indexes.json | 107 ++++++++++++++++++++++++++++++----------- 1 file changed, 79 insertions(+), 28 deletions(-) diff --git a/firestore.indexes.json b/firestore.indexes.json index 913b031..150acf4 100644 --- a/firestore.indexes.json +++ b/firestore.indexes.json @@ -75,7 +75,21 @@ "queryScope": "COLLECTION", "fields": [ { - "fieldPath": "data.clientId", + "fieldPath": "clientId", + "order": "ASCENDING" + }, + { + "fieldPath": "timestamp", + "order": "DESCENDING" + } + ] + }, + { + "collectionGroup": "notifications", + "queryScope": "COLLECTION", + "fields": [ + { + "fieldPath": "clientId", "order": "ASCENDING" }, { @@ -88,6 +102,70 @@ } ] }, + { + "collectionGroup": "notifications", + "queryScope": "COLLECTION", + "fields": [ + { + "fieldPath": "ownerId", + "order": "ASCENDING" + }, + { + "fieldPath": "timestamp", + "order": "DESCENDING" + } + ] + }, + { + "collectionGroup": "notifications", + "queryScope": "COLLECTION", + "fields": [ + { + "fieldPath": "ownerId", + "order": "ASCENDING" + }, + { + "fieldPath": "type", + "order": "ASCENDING" + }, + { + "fieldPath": "timestamp", + "order": "DESCENDING" + } + ] + }, + { + "collectionGroup": "notifications", + "queryScope": "COLLECTION", + "fields": [ + { + "fieldPath": "trainerId", + "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", @@ -96,10 +174,6 @@ "fieldPath": "data.ownerId", "order": "ASCENDING" }, - { - "fieldPath": "type", - "order": "ASCENDING" - }, { "fieldPath": "timestamp", "order": "DESCENDING" @@ -114,35 +188,12 @@ "fieldPath": "data.trainerId", "order": "ASCENDING" }, - { - "fieldPath": "type", - "order": "ASCENDING" - }, { "fieldPath": "timestamp", "order": "DESCENDING" } ] }, - { - "collectionGroup": "notifications", - "queryScope": "COLLECTION", - "fields": [ - { - "fieldPath": "type", - "order": "ASCENDING" - }, - { - "fieldPath": "recipientId", - "order": "ASCENDING" - }, - { - "fieldPath": "timestamp", - "order": "DESCENDING" - } - ] - }, - { "collectionGroup": "workout_logs", "queryScope": "COLLECTION", -- 2.43.0 From 14b190f8918e4e0aa175e0ee939ac02fecf702b3 Mon Sep 17 00:00:00 2001 From: Sharon Dcruz Date: Mon, 4 Aug 2025 11:13:42 +0530 Subject: [PATCH 10/10] Changes Updated --- firestore.indexes.json | 68 +++++++++++++----------------------------- 1 file changed, 20 insertions(+), 48 deletions(-) diff --git a/firestore.indexes.json b/firestore.indexes.json index 150acf4..4e84252 100644 --- a/firestore.indexes.json +++ b/firestore.indexes.json @@ -75,7 +75,7 @@ "queryScope": "COLLECTION", "fields": [ { - "fieldPath": "clientId", + "fieldPath": "data.clientId", "order": "ASCENDING" }, { @@ -89,7 +89,7 @@ "queryScope": "COLLECTION", "fields": [ { - "fieldPath": "clientId", + "fieldPath": "data.clientId", "order": "ASCENDING" }, { @@ -102,52 +102,6 @@ } ] }, - { - "collectionGroup": "notifications", - "queryScope": "COLLECTION", - "fields": [ - { - "fieldPath": "ownerId", - "order": "ASCENDING" - }, - { - "fieldPath": "timestamp", - "order": "DESCENDING" - } - ] - }, - { - "collectionGroup": "notifications", - "queryScope": "COLLECTION", - "fields": [ - { - "fieldPath": "ownerId", - "order": "ASCENDING" - }, - { - "fieldPath": "type", - "order": "ASCENDING" - }, - { - "fieldPath": "timestamp", - "order": "DESCENDING" - } - ] - }, - { - "collectionGroup": "notifications", - "queryScope": "COLLECTION", - "fields": [ - { - "fieldPath": "trainerId", - "order": "ASCENDING" - }, - { - "fieldPath": "timestamp", - "order": "DESCENDING" - } - ] - }, { "collectionGroup": "notifications", "queryScope": "COLLECTION", @@ -180,6 +134,24 @@ } ] }, + { + "collectionGroup": "notifications", + "queryScope": "COLLECTION", + "fields": [ + { + "fieldPath": "data.ownerId", + "order": "ASCENDING" + }, + { + "fieldPath": "type", + "order": "ASCENDING" + }, + { + "fieldPath": "timestamp", + "order": "DESCENDING" + } + ] + }, { "collectionGroup": "notifications", "queryScope": "COLLECTION", -- 2.43.0