mirror of
https://github.com/urosran/cally.git
synced 2025-07-10 15:17:17 +00:00
Calendar controls fix
This commit is contained in:
@ -148,7 +148,7 @@ export const ManuallyAddEventModal = () => {
|
|||||||
setIsPrivate(editEvent?.private || false);
|
setIsPrivate(editEvent?.private || false);
|
||||||
|
|
||||||
setStartTime(() => {
|
setStartTime(() => {
|
||||||
const date = initialDate ?? new Date();
|
const date = initialDate ? new Date(initialDate) : new Date();
|
||||||
date.setSeconds(0, 0);
|
date.setSeconds(0, 0);
|
||||||
return date;
|
return date;
|
||||||
});
|
});
|
||||||
|
@ -8,8 +8,8 @@ import type { AsyncPersistRetryer } from '@tanstack/query-async-storage-persiste
|
|||||||
const createQueryClient = () => new QueryClient({
|
const createQueryClient = () => new QueryClient({
|
||||||
defaultOptions: {
|
defaultOptions: {
|
||||||
queries: {
|
queries: {
|
||||||
gcTime: 1000 * 60 * 60 * 24, // 24 hours
|
gcTime: 1000 * 60 * 60 * 24,
|
||||||
staleTime: 1000 * 60 * 5, // 5 minutes
|
staleTime: 1000 * 60 * 5,
|
||||||
retry: 2,
|
retry: 2,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
const { onRequest } = require("firebase-functions/v2/https");
|
const { onRequest, onCall, HttpsError } = require("firebase-functions/v2/https");
|
||||||
const { getAuth } = require("firebase-admin/auth");
|
const { getAuth } = require("firebase-admin/auth");
|
||||||
const { getFirestore, Timestamp, FieldValue, FieldPath } = require("firebase-admin/firestore");
|
const { getFirestore, Timestamp, FieldValue, FieldPath } = require("firebase-admin/firestore");
|
||||||
const logger = require("firebase-functions/logger");
|
const logger = require("firebase-functions/logger");
|
||||||
@ -14,7 +14,7 @@ let expo = new Expo({ accessToken: process.env.EXPO_ACCESS_TOKEN });
|
|||||||
|
|
||||||
const GOOGLE_CALENDAR_ID = "primary";
|
const GOOGLE_CALENDAR_ID = "primary";
|
||||||
const CHANNEL_ID = "cally-family-calendar";
|
const CHANNEL_ID = "cally-family-calendar";
|
||||||
const WEBHOOK_URL = "https://us-central1-cally-family-calendar.cloudfunctions.net/sendSyncNotification";
|
const WEBHOOK_URL = "https://sendsyncnotification-ne4kpcdqwa-uc.a.run.app";
|
||||||
|
|
||||||
/* ─────────────────────────────────
|
/* ─────────────────────────────────
|
||||||
PUSH NOTIFICATION HELPERS
|
PUSH NOTIFICATION HELPERS
|
||||||
@ -1171,7 +1171,7 @@ exports.checkUpcomingEvents = functions.pubsub
|
|||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const familyDoc = await db.collection("Families").doc(familyId).get();
|
const familyDoc = await db.collection("Households").doc(familyId).get();
|
||||||
if (!familyDoc.exists) continue;
|
if (!familyDoc.exists) continue;
|
||||||
|
|
||||||
const familySettings = familyDoc.data()?.settings || {};
|
const familySettings = familyDoc.data()?.settings || {};
|
||||||
@ -1299,28 +1299,29 @@ exports.migrateEventNotifications = functions.https.onRequest(async (req, res) =
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
exports.sendSyncNotification = functions.https.onRequest(async (req, res) => {
|
exports.sendSyncNotification = onRequest(async (req, res) => {
|
||||||
const userId = req.query.userId;
|
const userId = req.query.userId;
|
||||||
|
|
||||||
if (!userId) {
|
if (!userId) {
|
||||||
console.error('[SYNC] Missing userId in request');
|
logger.error('[SYNC] Missing userId in request');
|
||||||
return res.status(400).send('Missing userId');
|
return res.status(400).send('Missing userId');
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const userDoc = await db.collection("Profiles").doc(userId).get();
|
const userDoc = await db.collection("Profiles").doc(userId).get();
|
||||||
if (!userDoc.exists) {
|
if (!userDoc.exists) {
|
||||||
console.error(`[SYNC] No profile found for user ${userId}`);
|
logger.error(`[SYNC] No profile found for user ${userId}`);
|
||||||
return res.status(404).send("User profile not found");
|
return res.status(404).send("User profile not found");
|
||||||
}
|
}
|
||||||
|
|
||||||
const userData = userDoc.data();
|
const userData = userDoc.data();
|
||||||
|
const familyId = userData.familyId;
|
||||||
const googleAccounts = userData.googleAccounts || {};
|
const googleAccounts = userData.googleAccounts || {};
|
||||||
|
|
||||||
// Get first Google account
|
// Get first Google account
|
||||||
const [email] = Object.keys(googleAccounts);
|
const [email] = Object.keys(googleAccounts);
|
||||||
if (!email) {
|
if (!email) {
|
||||||
console.error(`[SYNC] No Google account found for user ${userId}`);
|
logger.error(`[SYNC] No Google account found for user ${userId}`);
|
||||||
return res.status(400).send("No Google account found");
|
return res.status(400).send("No Google account found");
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1328,21 +1329,40 @@ exports.sendSyncNotification = functions.https.onRequest(async (req, res) => {
|
|||||||
const { accessToken, refreshToken } = accountData;
|
const { accessToken, refreshToken } = accountData;
|
||||||
|
|
||||||
if (!accessToken) {
|
if (!accessToken) {
|
||||||
console.error(`[SYNC] No access token for user ${userId}`);
|
logger.error(`[SYNC] No access token for user ${userId}`);
|
||||||
return res.status(400).send("No access token found");
|
return res.status(400).send("No access token found");
|
||||||
}
|
}
|
||||||
|
|
||||||
const familyId = userData.familyId;
|
|
||||||
if (!familyId) {
|
if (!familyId) {
|
||||||
console.error(`[SYNC] No family ID for user ${userId}`);
|
logger.error(`[SYNC] No family ID for user ${userId}`);
|
||||||
return res.status(400).send("No family ID found");
|
return res.status(400).send("No family ID found");
|
||||||
}
|
}
|
||||||
|
|
||||||
console.log(`[SYNC] Starting calendar sync for user ${userId}`);
|
// Check if household exists and create if it doesn't
|
||||||
|
const householdsSnapshot = await db.collection('Households')
|
||||||
|
.where("familyId", "==", familyId)
|
||||||
|
.get();
|
||||||
|
|
||||||
|
if (householdsSnapshot.empty) {
|
||||||
|
logger.info(`[SYNC] No household found for family ${familyId}, creating one`);
|
||||||
|
// Create a new household document
|
||||||
|
await db.collection('Households').add({
|
||||||
|
familyId,
|
||||||
|
createdAt: admin.firestore.FieldValue.serverTimestamp(),
|
||||||
|
createdBy: userId,
|
||||||
|
lastSyncTimestamp: admin.firestore.FieldValue.serverTimestamp(),
|
||||||
|
settings: {
|
||||||
|
defaultReminderTime: 15, // Default 15 minutes reminder
|
||||||
|
}
|
||||||
|
});
|
||||||
|
logger.info(`[SYNC] Created new household for family ${familyId}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
logger.info(`[SYNC] Starting calendar sync for user ${userId}`);
|
||||||
const syncStartTime = Date.now();
|
const syncStartTime = Date.now();
|
||||||
|
|
||||||
// Trigger immediate sync
|
// Trigger immediate sync and get event count
|
||||||
await fetchAndSaveGoogleEvents({
|
const totalEvents = await fetchAndSaveGoogleEvents({
|
||||||
token: accessToken,
|
token: accessToken,
|
||||||
refreshToken,
|
refreshToken,
|
||||||
email,
|
email,
|
||||||
@ -1350,13 +1370,13 @@ exports.sendSyncNotification = functions.https.onRequest(async (req, res) => {
|
|||||||
creatorId: userId
|
creatorId: userId
|
||||||
});
|
});
|
||||||
|
|
||||||
// Update household timestamps
|
// Update household timestamps (will now include newly created household if any)
|
||||||
const householdsSnapshot = await db.collection('Households')
|
const updatedHouseholdsSnapshot = await db.collection('Households')
|
||||||
.where("familyId", "==", familyId)
|
.where("familyId", "==", familyId)
|
||||||
.get();
|
.get();
|
||||||
|
|
||||||
const batch = db.batch();
|
const batch = db.batch();
|
||||||
householdsSnapshot.docs.forEach((doc) => {
|
updatedHouseholdsSnapshot.docs.forEach((doc) => {
|
||||||
batch.update(doc.ref, {
|
batch.update(doc.ref, {
|
||||||
lastSyncTimestamp: admin.firestore.FieldValue.serverTimestamp()
|
lastSyncTimestamp: admin.firestore.FieldValue.serverTimestamp()
|
||||||
});
|
});
|
||||||
@ -1364,10 +1384,319 @@ exports.sendSyncNotification = functions.https.onRequest(async (req, res) => {
|
|||||||
|
|
||||||
await batch.commit();
|
await batch.commit();
|
||||||
|
|
||||||
console.log(`[SYNC] Completed sync for user ${userId} in ${Date.now() - syncStartTime}ms`);
|
logger.info(`[SYNC] Completed sync for user ${userId} in ${Date.now() - syncStartTime}ms`);
|
||||||
res.status(200).send("Sync completed successfully");
|
res.status(200).send("Sync completed successfully");
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error(`[SYNC] Error in sync notification:`, error);
|
logger.error(`[SYNC] Error in sync notification:`, error);
|
||||||
res.status(500).send("Sync failed");
|
res.status(500).send("Sync failed");
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
exports.renewGoogleCalendarWatch = functions.pubsub
|
||||||
|
.schedule("every 10 minutes")
|
||||||
|
.onRun(async (context) => {
|
||||||
|
logger.info("[WATCH] Starting calendar watch renewal check");
|
||||||
|
|
||||||
|
try {
|
||||||
|
const profilesWithGoogle = await db.collection('Profiles')
|
||||||
|
.where('googleAccounts', '!=', null)
|
||||||
|
.get();
|
||||||
|
|
||||||
|
logger.info(`[WATCH] Found ${profilesWithGoogle.size} profiles with Google accounts`);
|
||||||
|
|
||||||
|
const existingWatches = await db.collection('CalendarWatches').get();
|
||||||
|
logger.info(`[WATCH] Found ${existingWatches.size} existing watches`);
|
||||||
|
|
||||||
|
const now = Date.now();
|
||||||
|
const watchMap = new Map();
|
||||||
|
existingWatches.forEach(doc => {
|
||||||
|
watchMap.set(doc.id, doc.data());
|
||||||
|
logger.debug(`[WATCH] Existing watch for ${doc.id}`, doc.data());
|
||||||
|
});
|
||||||
|
|
||||||
|
const batch = db.batch();
|
||||||
|
let processedCount = 0;
|
||||||
|
let newWatchCount = 0;
|
||||||
|
let renewalCount = 0;
|
||||||
|
|
||||||
|
for (const profile of profilesWithGoogle.docs) {
|
||||||
|
const userId = profile.id;
|
||||||
|
const userData = profile.data();
|
||||||
|
const existingWatch = watchMap.get(userId);
|
||||||
|
|
||||||
|
logger.info(`[WATCH] Processing user ${userId}`, {
|
||||||
|
hasGoogleAccounts: !!userData.googleAccounts,
|
||||||
|
accountCount: Object.keys(userData.googleAccounts || {}).length,
|
||||||
|
hasExistingWatch: !!existingWatch,
|
||||||
|
watchExpiration: existingWatch?.expiration
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!userData.googleAccounts || Object.keys(userData.googleAccounts).length === 0) {
|
||||||
|
logger.info(`[WATCH] Skipping user ${userId} - no Google accounts`);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
const firstAccount = Object.values(userData.googleAccounts)[0];
|
||||||
|
const token = firstAccount?.accessToken;
|
||||||
|
|
||||||
|
if (!token) {
|
||||||
|
logger.info(`[WATCH] No token found for user ${userId}`);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
const needsRenewal = !existingWatch ||
|
||||||
|
!existingWatch.expiration ||
|
||||||
|
existingWatch.expiration < (now + 30 * 60 * 1000);
|
||||||
|
|
||||||
|
if (!needsRenewal) {
|
||||||
|
logger.info(`[WATCH] Watch still valid for user ${userId}, skipping renewal`);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
logger.info(`[WATCH] ${existingWatch ? 'Renewing' : 'Creating new'} watch for user ${userId}`);
|
||||||
|
|
||||||
|
const url = `https://www.googleapis.com/calendar/v3/calendars/${GOOGLE_CALENDAR_ID}/events/watch`;
|
||||||
|
const watchBody = {
|
||||||
|
id: `${CHANNEL_ID}-${userId}`,
|
||||||
|
type: "web_hook",
|
||||||
|
address: `${WEBHOOK_URL}?userId=${userId}`,
|
||||||
|
params: {ttl: "604800"}
|
||||||
|
};
|
||||||
|
|
||||||
|
logger.info(`[WATCH] Making request for user ${userId}`, {
|
||||||
|
url,
|
||||||
|
watchBody,
|
||||||
|
tokenPrefix: token.substring(0, 10)
|
||||||
|
});
|
||||||
|
|
||||||
|
const response = await fetch(url, {
|
||||||
|
method: "POST",
|
||||||
|
headers: {
|
||||||
|
Authorization: `Bearer ${token}`,
|
||||||
|
"Content-Type": "application/json",
|
||||||
|
},
|
||||||
|
body: JSON.stringify(watchBody),
|
||||||
|
});
|
||||||
|
|
||||||
|
const responseText = await response.text();
|
||||||
|
logger.info(`[WATCH] Received response for ${userId}`, {
|
||||||
|
status: response.status,
|
||||||
|
response: responseText
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!response.ok) {
|
||||||
|
throw new Error(`Failed to set up watch: ${responseText}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
const result = JSON.parse(responseText);
|
||||||
|
|
||||||
|
batch.set(db.collection('CalendarWatches').doc(userId), {
|
||||||
|
watchId: result.id,
|
||||||
|
resourceId: result.resourceId,
|
||||||
|
expiration: result.expiration,
|
||||||
|
updatedAt: admin.firestore.FieldValue.serverTimestamp(),
|
||||||
|
}, {merge: true});
|
||||||
|
|
||||||
|
processedCount++;
|
||||||
|
if (existingWatch) {
|
||||||
|
renewalCount++;
|
||||||
|
} else {
|
||||||
|
newWatchCount++;
|
||||||
|
}
|
||||||
|
|
||||||
|
logger.info(`[WATCH] Successfully ${existingWatch ? 'renewed' : 'created'} watch for user ${userId}`, {
|
||||||
|
watchId: result.id,
|
||||||
|
expiration: result.expiration
|
||||||
|
});
|
||||||
|
|
||||||
|
} catch (error) {
|
||||||
|
logger.error(`[WATCH] Failed to ${existingWatch ? 'renew' : 'create'} watch for user ${userId}:`, {
|
||||||
|
error: error.message,
|
||||||
|
stack: error.stack
|
||||||
|
});
|
||||||
|
|
||||||
|
batch.set(db.collection('CalendarWatchErrors').doc(), {
|
||||||
|
userId,
|
||||||
|
error: error.message,
|
||||||
|
timestamp: admin.firestore.FieldValue.serverTimestamp(),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (processedCount > 0) {
|
||||||
|
logger.info(`[WATCH] Committing batch with ${processedCount} operations`);
|
||||||
|
await batch.commit();
|
||||||
|
}
|
||||||
|
|
||||||
|
logger.info(`[WATCH] Completed calendar watch processing`, {
|
||||||
|
totalProcessed: processedCount,
|
||||||
|
newWatches: newWatchCount,
|
||||||
|
renewals: renewalCount
|
||||||
|
});
|
||||||
|
|
||||||
|
return null;
|
||||||
|
} catch (error) {
|
||||||
|
logger.error('[WATCH] Critical error in watch renewal:', {
|
||||||
|
error: error.message,
|
||||||
|
stack: error.stack
|
||||||
|
});
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
exports.triggerGoogleSync = onCall({
|
||||||
|
memory: '256MiB',
|
||||||
|
enforceAppCheck: false,
|
||||||
|
maxInstances: 10,
|
||||||
|
region: 'us-central1',
|
||||||
|
invoker: 'public',
|
||||||
|
}, async (request) => {
|
||||||
|
if (!request.auth) {
|
||||||
|
throw new HttpsError('unauthenticated', 'Authentication required');
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
const userId = request.auth.uid;
|
||||||
|
const {email} = request.data;
|
||||||
|
|
||||||
|
logger.info("Starting manual Google sync", {userId, email});
|
||||||
|
|
||||||
|
const userDoc = await db.collection("Profiles").doc(userId).get();
|
||||||
|
const userData = userDoc.data();
|
||||||
|
|
||||||
|
if (!userData?.googleAccounts?.[email]) {
|
||||||
|
logger.error("No valid Google account found", {userId, email});
|
||||||
|
throw new HttpsError('failed-precondition', 'No valid Google account found');
|
||||||
|
}
|
||||||
|
|
||||||
|
const accountData = userData.googleAccounts[email];
|
||||||
|
const eventCount = await calendarSync({
|
||||||
|
userId,
|
||||||
|
email,
|
||||||
|
token: accountData.accessToken,
|
||||||
|
refreshToken: accountData.refreshToken,
|
||||||
|
familyId: userData.familyId
|
||||||
|
});
|
||||||
|
|
||||||
|
logger.info("Manual sync completed successfully", {userId, eventCount});
|
||||||
|
|
||||||
|
return {
|
||||||
|
success: true,
|
||||||
|
eventCount,
|
||||||
|
message: "Google calendar sync completed successfully"
|
||||||
|
};
|
||||||
|
} catch (error) {
|
||||||
|
logger.error("Manual sync failed", error);
|
||||||
|
throw new HttpsError('internal', error.message);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
exports.triggerMicrosoftSync = onCall({
|
||||||
|
memory: '256MiB',
|
||||||
|
enforceAppCheck: false,
|
||||||
|
maxInstances: 10,
|
||||||
|
region: 'us-central1',
|
||||||
|
invoker: 'public',
|
||||||
|
}, async (request) => {
|
||||||
|
if (!request.auth) {
|
||||||
|
throw new HttpsError('unauthenticated', 'Authentication required');
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
const userId = request.auth.uid;
|
||||||
|
const {email} = request.data;
|
||||||
|
|
||||||
|
if (!email) {
|
||||||
|
throw new HttpsError('invalid-argument', 'Email is required');
|
||||||
|
}
|
||||||
|
|
||||||
|
logger.info('Starting Microsoft sync', {userId, email});
|
||||||
|
|
||||||
|
const userDoc = await db.collection("Profiles").doc(userId).get();
|
||||||
|
if (!userDoc.exists) {
|
||||||
|
throw new HttpsError('not-found', 'User profile not found');
|
||||||
|
}
|
||||||
|
|
||||||
|
const userData = userDoc.data();
|
||||||
|
const accountData = userData.microsoftAccounts?.[email];
|
||||||
|
|
||||||
|
if (!accountData) {
|
||||||
|
throw new HttpsError('failed-precondition', 'Microsoft account not found');
|
||||||
|
}
|
||||||
|
|
||||||
|
let {accessToken, refreshToken} = accountData;
|
||||||
|
|
||||||
|
// Try to refresh token if it exists
|
||||||
|
if (refreshToken) {
|
||||||
|
try {
|
||||||
|
const refreshedTokens = await refreshMicrosoftToken(refreshToken);
|
||||||
|
accessToken = refreshedTokens.accessToken;
|
||||||
|
refreshToken = refreshedTokens.refreshToken || refreshToken;
|
||||||
|
|
||||||
|
// Update the stored tokens
|
||||||
|
await db.collection("Profiles").doc(userId).update({
|
||||||
|
[`microsoftAccounts.${email}`]: {
|
||||||
|
...accountData,
|
||||||
|
accessToken,
|
||||||
|
refreshToken,
|
||||||
|
lastRefresh: FieldValue.serverTimestamp()
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} catch (refreshError) {
|
||||||
|
logger.error('Token refresh failed:', refreshError);
|
||||||
|
throw new HttpsError(
|
||||||
|
'failed-precondition',
|
||||||
|
'Failed to refresh Microsoft token. Please reconnect your account.',
|
||||||
|
{requiresReauth: true}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
const eventCount = await fetchAndSaveMicrosoftEvents({
|
||||||
|
token: accessToken,
|
||||||
|
refreshToken,
|
||||||
|
email,
|
||||||
|
familyId: userData.familyId,
|
||||||
|
creatorId: userId
|
||||||
|
});
|
||||||
|
|
||||||
|
logger.info('Microsoft sync completed successfully', {eventCount});
|
||||||
|
return {
|
||||||
|
success: true,
|
||||||
|
eventCount,
|
||||||
|
message: "Microsoft calendar sync completed successfully"
|
||||||
|
};
|
||||||
|
} catch (syncError) {
|
||||||
|
if (syncError.message?.includes('401') ||
|
||||||
|
syncError.message?.includes('unauthorized') ||
|
||||||
|
syncError.message?.includes('invalid_grant')) {
|
||||||
|
throw new HttpsError(
|
||||||
|
'unauthenticated',
|
||||||
|
'Microsoft authentication expired. Please reconnect your account.',
|
||||||
|
{requiresReauth: true}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
throw new HttpsError('internal', syncError.message);
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
logger.error('Microsoft sync function error:', error);
|
||||||
|
if (error instanceof HttpsError) {
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
throw new HttpsError('internal', error.message || 'Unknown error occurred');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
exports.forceWatchRenewal = onRequest(async (req, res) => {
|
||||||
|
const batch = db.batch();
|
||||||
|
const watches = await db.collection('CalendarWatches').get();
|
||||||
|
watches.forEach(doc => {
|
||||||
|
batch.update(doc.ref, {
|
||||||
|
expiration: 0
|
||||||
|
});
|
||||||
|
});
|
||||||
|
await batch.commit();
|
||||||
|
res.status(200).send('Forced renewal of all watches');
|
||||||
|
});
|
@ -106,13 +106,13 @@ export const useGetEvents = () => {
|
|||||||
|
|
||||||
const prefetchEvents = async () => {
|
const prefetchEvents = async () => {
|
||||||
await queryClient.prefetchQuery({
|
await queryClient.prefetchQuery({
|
||||||
queryKey: ["events", user.uid, false], // Personal events
|
queryKey: ["events", user.uid, false],
|
||||||
queryFn: () => fetchEvents(user.uid, profileData, false),
|
queryFn: () => fetchEvents(user.uid, profileData, false),
|
||||||
staleTime: 5 * 60 * 1000,
|
staleTime: 5 * 60 * 1000,
|
||||||
});
|
});
|
||||||
|
|
||||||
await queryClient.prefetchQuery({
|
await queryClient.prefetchQuery({
|
||||||
queryKey: ["events", user.uid, true], // Family events
|
queryKey: ["events", user.uid, true],
|
||||||
queryFn: () => fetchEvents(user.uid, profileData, true),
|
queryFn: () => fetchEvents(user.uid, profileData, true),
|
||||||
staleTime: 5 * 60 * 1000,
|
staleTime: 5 * 60 * 1000,
|
||||||
});
|
});
|
||||||
@ -150,8 +150,8 @@ export const useGetEvents = () => {
|
|||||||
return useQuery({
|
return useQuery({
|
||||||
queryKey: ["events", user?.uid, isFamilyView],
|
queryKey: ["events", user?.uid, isFamilyView],
|
||||||
queryFn: () => fetchEvents(user?.uid!, profileData, isFamilyView),
|
queryFn: () => fetchEvents(user?.uid!, profileData, isFamilyView),
|
||||||
staleTime: Infinity,
|
staleTime: 10 * 60 * 1000,
|
||||||
gcTime: Infinity,
|
gcTime: 24 * 60 * 60 * 1000,
|
||||||
placeholderData: (previousData) => previousData,
|
placeholderData: (previousData) => previousData,
|
||||||
enabled: Boolean(user?.uid),
|
enabled: Boolean(user?.uid),
|
||||||
});
|
});
|
||||||
|
Reference in New Issue
Block a user