feature/fitlien-828 (#120)
All checks were successful
Deploy FitLien services to Dev / Deploy to Dev (push) Successful in 4m26s

Reviewed-on: #120
Reviewed-by: Dhansh A S <dhanshas@cosq.net>
Co-authored-by: Sharon Dcruz <sharondcruz@cosq.net>
Co-committed-by: Sharon Dcruz <sharondcruz@cosq.net>
This commit is contained in:
Sharon Dcruz 2025-09-22 06:26:10 +00:00 committed by Dhansh A S
parent bf94866fbf
commit b6d222f0c3

View File

@ -33,34 +33,26 @@ interface PaymentData {
[key: string]: any; [key: string]: any;
} }
interface TrainerAssignment { interface MinimalCacheEntry {
id?: string;
membershipId?: string;
timeSlot?: any[];
createdAt?: admin.firestore.Timestamp;
[key: string]: any;
}
interface CacheEntry {
userId: string;
membershipId: string; membershipId: string;
memberData: { userId: string;
daysUntilExpiry?: number | null; status: string;
hasPartialPayment: boolean; displayName: string;
createdAt?: string | null; email?: string | null;
updatedAt?: string | null; phoneNumber?: string | null;
[key: string]: any; alternateContact?: string | null;
};
fields: { [key: string]: any };
renewalDate?: string | null; renewalDate?: string | null;
trainerAssignments: any[]; createdAt?: string | null;
timeSlots: any[]; daysUntilExpiry?: number | null;
hasPersonalTraining: boolean;
hasPartialPayment: boolean;
remainingAmount: number;
lastUpdated: string; lastUpdated: string;
} }
interface JsonCacheData { interface MinimalJsonCacheData {
gymId: string; gymId: string;
members: CacheEntry[]; members: MinimalCacheEntry[];
totalMembers: number; totalMembers: number;
lastUpdated: string; lastUpdated: string;
cacheVersion: string; cacheVersion: string;
@ -104,7 +96,7 @@ export const getMemberCache = onRequest(
try { try {
const [fileBuffer] = await file.download(); const [fileBuffer] = await file.download();
const jsonData: JsonCacheData = JSON.parse(fileBuffer.toString()); const jsonData: MinimalJsonCacheData = JSON.parse(fileBuffer.toString());
logger.info( logger.info(
`Retrieved ${jsonData.totalMembers} members from cache for gym ${gymId}` `Retrieved ${jsonData.totalMembers} members from cache for gym ${gymId}`
@ -118,7 +110,7 @@ export const getMemberCache = onRequest(
members: [], members: [],
totalMembers: 0, totalMembers: 0,
lastUpdated: new Date().toISOString(), lastUpdated: new Date().toISOString(),
cacheVersion: "2.0", cacheVersion: "3.0",
}); });
} }
} catch (error) { } catch (error) {
@ -166,8 +158,8 @@ export const updateMemberCache = onRequest(
} for gym: ${gymId}` } for gym: ${gymId}`
); );
let members: CacheEntry[] = []; let members: MinimalCacheEntry[] = [];
let existingData: JsonCacheData | null = null; let existingData: MinimalJsonCacheData | null = null;
if (incrementalUpdate) { if (incrementalUpdate) {
try { try {
@ -197,15 +189,15 @@ export const updateMemberCache = onRequest(
if (incrementalUpdate && membershipIds && Array.isArray(membershipIds)) { if (incrementalUpdate && membershipIds && Array.isArray(membershipIds)) {
await updateSpecificMembers(gymId, membershipIds, members); await updateSpecificMembers(gymId, membershipIds, members);
} else { } else {
members = await fetchAllMembers(gymId); members = await fetchAllMinimalMembers(gymId);
} }
const jsonData: JsonCacheData = { const jsonData: MinimalJsonCacheData = {
gymId, gymId,
members, members,
totalMembers: members.length, totalMembers: members.length,
lastUpdated: new Date().toISOString(), lastUpdated: new Date().toISOString(),
cacheVersion: "2.0", cacheVersion: "3.0",
}; };
await saveCacheToStorage(gymId, jsonData); await saveCacheToStorage(gymId, jsonData);
@ -234,8 +226,8 @@ export const updateMemberCache = onRequest(
} }
); );
async function fetchAllMembers(gymId: string): Promise<CacheEntry[]> { async function fetchAllMinimalMembers(gymId: string): Promise<MinimalCacheEntry[]> {
const members: CacheEntry[] = []; const members: MinimalCacheEntry[] = [];
const membershipsSnapshot = await app const membershipsSnapshot = await app
.firestore() .firestore()
@ -258,7 +250,7 @@ async function fetchAllMembers(gymId: string): Promise<CacheEntry[]> {
); );
return null; return null;
} }
return await generateCacheEntry(userId, doc.id, membershipData); return await generateMinimalCacheEntry(userId, doc.id, membershipData);
} catch (error) { } catch (error) {
logger.error(`Error processing member ${doc.id}:`, error); logger.error(`Error processing member ${doc.id}:`, error);
return null; return null;
@ -267,7 +259,7 @@ async function fetchAllMembers(gymId: string): Promise<CacheEntry[]> {
const batchResults = await Promise.all(batchPromises); const batchResults = await Promise.all(batchPromises);
const validResults = batchResults.filter( const validResults = batchResults.filter(
(member): member is CacheEntry => member !== null (member): member is MinimalCacheEntry => member !== null
); );
members.push(...validResults); members.push(...validResults);
} }
@ -278,7 +270,7 @@ async function fetchAllMembers(gymId: string): Promise<CacheEntry[]> {
async function updateSpecificMembers( async function updateSpecificMembers(
gymId: string, gymId: string,
membershipIds: string[], membershipIds: string[],
existingMembers: CacheEntry[] existingMembers: MinimalCacheEntry[]
): Promise<void> { ): Promise<void> {
logger.info(`Updating ${membershipIds.length} specific members`); logger.info(`Updating ${membershipIds.length} specific members`);
@ -319,7 +311,7 @@ async function updateSpecificMembers(
); );
return null; return null;
} }
return await generateCacheEntry(userId, doc.id, membershipData); return await generateMinimalCacheEntry(userId, doc.id, membershipData);
} catch (error) { } catch (error) {
logger.error(`Error processing member ${doc.id}:`, error); logger.error(`Error processing member ${doc.id}:`, error);
return null; return null;
@ -345,7 +337,7 @@ async function updateSpecificMembers(
async function saveCacheToStorage( async function saveCacheToStorage(
gymId: string, gymId: string,
jsonData: JsonCacheData jsonData: MinimalJsonCacheData
): Promise<void> { ): Promise<void> {
const fileName = `${CACHE_FOLDER}/${gymId}.json`; const fileName = `${CACHE_FOLDER}/${gymId}.json`;
const file = app.storage().bucket().file(fileName); const file = app.storage().bucket().file(fileName);
@ -363,13 +355,18 @@ async function saveCacheToStorage(
}); });
} }
async function generateCacheEntry( async function generateMinimalCacheEntry(
userId: string, userId: string,
membershipId: string, membershipId: string,
membershipData: MembershipData membershipData: MembershipData
): Promise<CacheEntry> { ): Promise<MinimalCacheEntry> {
try { try {
let fields: { [key: string]: string } = {}; let firstName = '';
let lastName = '';
let email = '';
let phoneNumber = '';
let alternateContact = '';
try { try {
const clientFieldsSnapshot = await app const clientFieldsSnapshot = await app
.firestore() .firestore()
@ -381,12 +378,12 @@ async function generateCacheEntry(
const fieldDoc = clientFieldsSnapshot.docs[0]; const fieldDoc = clientFieldsSnapshot.docs[0];
const fieldData = fieldDoc.data() as ClientFields; const fieldData = fieldDoc.data() as ClientFields;
fields = { ...fieldData.fields }; const fields = fieldData.fields || {};
Object.keys(fieldData).forEach((key) => { firstName = fields['first-name'] || fieldData['first-name'] || '';
if (key !== "fields" && !fields[key]) { lastName = fields['last-name'] || fieldData['last-name'] || '';
fields[key] = fieldData[key]; email = fields['email'] || fieldData['email'] || '';
} phoneNumber = fields['phone-number'] || fieldData['phone-number'] || '';
}); alternateContact = fields['alternate-contact'] || fieldData['alternate-contact'] || '';
} }
} catch (error) { } catch (error) {
logger.error(`Error getting fields for user ${userId}:`, error); logger.error(`Error getting fields for user ${userId}:`, error);
@ -431,60 +428,35 @@ async function generateCacheEntry(
} }
} }
const displayName = firstName.length === 0 ? 'Unknown' :
(lastName.length === 0 ? firstName : `${firstName} ${lastName}`);
const isPartial = membershipData.isPartialPayment === true; const isPartial = membershipData.isPartialPayment === true;
const remaining = membershipData.remainingAmount || 0; const remaining = membershipData.remainingAmount || 0;
const hasPartialPayment = isPartial && remaining > 0; const hasPartialPayment = isPartial && remaining > 0;
let trainerAssignments: any[] = []; const minimalEntry: MinimalCacheEntry = {
let timeSlots: any[] = [];
if (membershipData.subscription?.hasPersonalTraining) {
try {
const assignmentsSnapshot = await app
.firestore()
.collection("personal_trainer_assignments")
.where("membershipId", "==", membershipId)
.get();
assignmentsSnapshot.docs.forEach((doc) => {
const data = doc.data() as TrainerAssignment;
if (data.timeSlot && Array.isArray(data.timeSlot)) {
timeSlots.push(...data.timeSlot);
}
trainerAssignments.push({ id: doc.id, ...data });
});
} catch (error) {
logger.error(
`Error getting trainer data for membership ${membershipId}:`,
error
);
}
}
const cacheEntry: CacheEntry = {
userId,
membershipId, membershipId,
memberData: { userId,
...membershipData, status: membershipData.status || 'N/A',
hasPartialPayment, displayName,
daysUntilExpiry, email: email || null,
createdAt: membershipData.createdAt phoneNumber: phoneNumber || null,
? membershipData.createdAt.toDate().toISOString() alternateContact: alternateContact || null,
: null,
updatedAt: membershipData.updatedAt
? membershipData.updatedAt.toDate().toISOString()
: null,
},
fields,
renewalDate: renewalDate ? renewalDate.toISOString() : null, renewalDate: renewalDate ? renewalDate.toISOString() : null,
trainerAssignments, createdAt: membershipData.createdAt
timeSlots, ? membershipData.createdAt.toDate().toISOString()
: null,
daysUntilExpiry,
hasPersonalTraining: membershipData.subscription?.hasPersonalTraining === true,
hasPartialPayment,
remainingAmount: remaining,
lastUpdated: new Date().toISOString(), lastUpdated: new Date().toISOString(),
}; };
return cacheEntry; return minimalEntry;
} catch (error) { } catch (error) {
logger.error("Error generating cache entry:", error); logger.error("Error generating minimal cache entry:", error);
throw error; throw error;
} }
} }
@ -523,4 +495,4 @@ function calculateRenewalDateTimeFromPayment(
default: default:
return new Date(Date.now() + 30 * 24 * 60 * 60 * 1000); return new Date(Date.now() + 30 * 24 * 60 * 60 * 1000);
} }
} }