mirror of
https://github.com/urosran/cally.git
synced 2025-07-15 17:47:08 +00:00
Functions update
This commit is contained in:
@ -17,8 +17,21 @@ export const useCalendarControls = (events: any[]) => {
|
|||||||
|
|
||||||
const handlePressEvent = useCallback((event: any) => {
|
const handlePressEvent = useCallback((event: any) => {
|
||||||
const foundEvent = events?.find(x => x.id === event.id);
|
const foundEvent = events?.find(x => x.id === event.id);
|
||||||
|
|
||||||
|
if (foundEvent) {
|
||||||
|
const processedEvent = {
|
||||||
|
...foundEvent,
|
||||||
|
startDate: foundEvent.startDate?.seconds ?
|
||||||
|
new Date(foundEvent.startDate.seconds * 1000) :
|
||||||
|
new Date(foundEvent.start),
|
||||||
|
endDate: foundEvent.endDate?.seconds ?
|
||||||
|
new Date(foundEvent.endDate.seconds * 1000) :
|
||||||
|
new Date(foundEvent.end)
|
||||||
|
};
|
||||||
|
|
||||||
setEditVisible(true);
|
setEditVisible(true);
|
||||||
setEventForEdit(foundEvent!);
|
setEventForEdit(processedEvent);
|
||||||
|
}
|
||||||
}, [events, setEditVisible, setEventForEdit]);
|
}, [events, setEditVisible, setEventForEdit]);
|
||||||
|
|
||||||
const handlePressCell = useCallback((date: DateOrDateTime) => {
|
const handlePressCell = useCallback((date: DateOrDateTime) => {
|
||||||
|
@ -313,18 +313,22 @@ exports.checkUpcomingEvents = functions.pubsub
|
|||||||
.schedule("every 5 minutes")
|
.schedule("every 5 minutes")
|
||||||
.onRun(async (context) => {
|
.onRun(async (context) => {
|
||||||
const now = Timestamp.now();
|
const now = Timestamp.now();
|
||||||
|
const tenMinutesFromNow = new Date(now.toDate().getTime() + 10 * 60 * 1000);
|
||||||
|
|
||||||
const eventsSnapshot = await db.collection("Events")
|
const eventsSnapshot = await db.collection("Events")
|
||||||
.where("startDate", ">=", now)
|
.where("startDate", ">=", now)
|
||||||
|
.where("startDate", "<=", Timestamp.fromDate(tenMinutesFromNow))
|
||||||
.get();
|
.get();
|
||||||
|
|
||||||
await Promise.all(eventsSnapshot.docs.map(async (doc) => {
|
await Promise.all(eventsSnapshot.docs.map(async (doc) => {
|
||||||
const event = doc.data();
|
const event = doc.data();
|
||||||
if (!event?.startDate) return;
|
if (!event?.startDate) return;
|
||||||
const { familyId, title, allDay } = event;
|
const { familyId, title, allDay } = event;
|
||||||
try {
|
try {
|
||||||
const familyDoc = await db.collection("Families").doc(familyId).get();
|
const familyDoc = await db.collection("Households").doc(familyId).get();
|
||||||
if (!familyDoc.exists) return;
|
if (!familyDoc.exists) return;
|
||||||
const familySettings = familyDoc.data()?.settings || {};
|
const familySettings = familyDoc.data()?.settings || {};
|
||||||
const reminderTime = familySettings.defaultReminderTime || 15;
|
const reminderTime = familySettings.defaultReminderTime || 5;
|
||||||
const eventTime = event.startDate.toDate();
|
const eventTime = event.startDate.toDate();
|
||||||
const reminderThreshold = new Date(now.toDate().getTime() + reminderTime * 60 * 1000);
|
const reminderThreshold = new Date(now.toDate().getTime() + reminderTime * 60 * 1000);
|
||||||
if (allDay) {
|
if (allDay) {
|
||||||
@ -460,6 +464,13 @@ exports.syncNewEventToGoogle = functions.firestore
|
|||||||
.onCreate(async (snapshot, context) => {
|
.onCreate(async (snapshot, context) => {
|
||||||
const newEvent = snapshot.data();
|
const newEvent = snapshot.data();
|
||||||
const eventId = context.params.eventId;
|
const eventId = context.params.eventId;
|
||||||
|
|
||||||
|
await snapshot.ref.update({
|
||||||
|
reminderSent: false,
|
||||||
|
eveningReminderSent: false,
|
||||||
|
notifiedAt: null
|
||||||
|
});
|
||||||
|
|
||||||
if (newEvent.externalOrigin === "google") {
|
if (newEvent.externalOrigin === "google") {
|
||||||
logger.info("[GOOGLE_SYNC] Skipping sync for Google-originated event", eventId);
|
logger.info("[GOOGLE_SYNC] Skipping sync for Google-originated event", eventId);
|
||||||
return;
|
return;
|
||||||
@ -1132,19 +1143,19 @@ exports.notifyOnEventUpdate = functions.firestore
|
|||||||
───────────────────────────────── */
|
───────────────────────────────── */
|
||||||
// We keep the reminder scheduler mostly as-is but ensure that once a notification is sent, the event is updated
|
// We keep the reminder scheduler mostly as-is but ensure that once a notification is sent, the event is updated
|
||||||
exports.checkUpcomingEvents = functions.pubsub
|
exports.checkUpcomingEvents = functions.pubsub
|
||||||
.schedule("every 5 minutes") // Run more frequently to catch reminders
|
.schedule("every 5 minutes")
|
||||||
.onRun(async (context) => {
|
.onRun(async (context) => {
|
||||||
const now = Timestamp.now();
|
const now = Timestamp.now();
|
||||||
const thirtyMinutesFromNow = new Date(now.toDate().getTime() + 30 * 60 * 1000);
|
const thirtyMinutesFromNow = new Date(now.toDate().getTime() + 30 * 60 * 1000);
|
||||||
|
|
||||||
// Query only events starting in the next 30 minutes that haven't been reminded
|
logger.info(`Running check at ${now.toDate().toISOString()}`);
|
||||||
|
|
||||||
const eventsSnapshot = await db.collection("Events")
|
const eventsSnapshot = await db.collection("Events")
|
||||||
.where("startDate", ">=", now)
|
.where("startDate", ">=", now)
|
||||||
.where("startDate", "<=", thirtyMinutesFromNow)
|
.where("startDate", "<=", Timestamp.fromDate(thirtyMinutesFromNow))
|
||||||
.where("reminderSent", "==", false) // Only get events that haven't been reminded
|
|
||||||
.get();
|
.get();
|
||||||
|
|
||||||
const batch = db.batch(); // Batch our updates
|
const batch = db.batch();
|
||||||
const notificationPromises = [];
|
const notificationPromises = [];
|
||||||
|
|
||||||
for (const doc of eventsSnapshot.docs) {
|
for (const doc of eventsSnapshot.docs) {
|
||||||
@ -1152,64 +1163,65 @@ exports.checkUpcomingEvents = functions.pubsub
|
|||||||
if (!event?.startDate) continue;
|
if (!event?.startDate) continue;
|
||||||
|
|
||||||
const { familyId, title, allDay } = event;
|
const { familyId, title, allDay } = event;
|
||||||
|
|
||||||
|
// Skip if reminder already sent
|
||||||
|
if (event.reminderSent) {
|
||||||
|
logger.info(`Reminder already sent for event: ${title}`);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const familyDoc = await db.collection("Families").doc(familyId).get();
|
const familyDoc = await db.collection("Families").doc(familyId).get();
|
||||||
if (!familyDoc.exists) continue;
|
if (!familyDoc.exists) continue;
|
||||||
|
|
||||||
const familySettings = familyDoc.data()?.settings || {};
|
const familySettings = familyDoc.data()?.settings || {};
|
||||||
const reminderTime = familySettings.defaultReminderTime || 10; // Default to 10 minutes
|
const reminderTime = familySettings.defaultReminderTime || 10;
|
||||||
const eventTime = event.startDate.toDate();
|
|
||||||
const reminderThreshold = new Date(now.toDate().getTime() + reminderTime * 60 * 1000);
|
|
||||||
|
|
||||||
// Check if we're within the reminder window
|
const eventTime = event.startDate.toDate();
|
||||||
const timeUntilEvent = eventTime.getTime() - now.toDate().getTime();
|
const timeUntilEvent = eventTime.getTime() - now.toDate().getTime();
|
||||||
const minutesUntilEvent = Math.floor(timeUntilEvent / (60 * 1000));
|
const minutesUntilEvent = Math.floor(timeUntilEvent / (60 * 1000));
|
||||||
|
|
||||||
|
logger.info(`Checking event: "${title}"`, {
|
||||||
|
minutesUntilEvent,
|
||||||
|
reminderTime,
|
||||||
|
eventTime: eventTime.toISOString()
|
||||||
|
});
|
||||||
|
|
||||||
|
// Modified timing logic: Send reminder when we're close to the reminder time
|
||||||
|
// This ensures we don't miss the window between function executions
|
||||||
if (minutesUntilEvent <= reminderTime && minutesUntilEvent > 0) {
|
if (minutesUntilEvent <= reminderTime && minutesUntilEvent > 0) {
|
||||||
notificationPromises.push(async () => {
|
logger.info(`Preparing to send reminder for: ${title}`);
|
||||||
const pushTokens = await getPushTokensForFamily(familyId);
|
const pushTokens = await getPushTokensForFamily(familyId);
|
||||||
|
|
||||||
if (pushTokens.length) {
|
if (pushTokens.length) {
|
||||||
await sendNotifications(pushTokens, {
|
await sendNotifications(pushTokens, {
|
||||||
title: "Upcoming Event",
|
title: "Upcoming Event",
|
||||||
body: `In ${minutesUntilEvent} minutes: ${title}`,
|
body: `In ${minutesUntilEvent} minutes: ${title}`,
|
||||||
data: { type: 'event_reminder', eventId: doc.id }
|
data: { type: 'event_reminder', eventId: doc.id }
|
||||||
});
|
});
|
||||||
batch.update(doc.ref, { reminderSent: true });
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
// Handle all-day events separately
|
batch.update(doc.ref, {
|
||||||
if (allDay && !event.eveningReminderSent) {
|
reminderSent: true,
|
||||||
const eveningBefore = new Date(eventTime);
|
lastReminderSent: Timestamp.now()
|
||||||
eveningBefore.setDate(eveningBefore.getDate() - 1);
|
});
|
||||||
eveningBefore.setHours(20, 0, 0, 0);
|
|
||||||
|
|
||||||
if (now.toDate() >= eveningBefore) {
|
logger.info(`Reminder sent for: ${title}`);
|
||||||
notificationPromises.push(async () => {
|
|
||||||
const pushTokens = await getPushTokensForFamily(familyId);
|
|
||||||
if (pushTokens.length) {
|
|
||||||
await sendNotifications(pushTokens, {
|
|
||||||
title: "Tomorrow's All-Day Event",
|
|
||||||
body: `Tomorrow: ${title}`,
|
|
||||||
data: { type: 'event_reminder', eventId: doc.id }
|
|
||||||
});
|
|
||||||
batch.update(doc.ref, { eveningReminderSent: true });
|
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
logger.info(`Not yet time for reminder: ${title}`, {
|
||||||
|
minutesUntilEvent,
|
||||||
|
reminderTime
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
logger.error(`Error processing reminder for event ${doc.id}:`, error);
|
logger.error(`Error processing reminder for event ${doc.id}:`, error);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Execute all notifications
|
// Commit batch if there are any operations
|
||||||
await Promise.all(notificationPromises.map(fn => fn()));
|
|
||||||
|
|
||||||
// Commit all updates in one batch
|
|
||||||
if (batch._ops.length > 0) {
|
if (batch._ops.length > 0) {
|
||||||
await batch.commit();
|
await batch.commit();
|
||||||
|
logger.info(`Committed ${batch._ops.length} updates`);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user