Files
cally/hooks/useSyncOnScroll.ts
Milan Paunovic f2af60111b Syncing rework
2024-11-26 21:13:54 +01:00

152 lines
5.7 KiB
TypeScript

import { useState, useEffect, useCallback } from "react";
import { useAuthContext } from "@/contexts/AuthContext";
import { useAtomValue } from "jotai";
import { useFetchAndSaveGoogleEvents } from "./useFetchAndSaveGoogleEvents";
import { useFetchAndSaveAppleEvents } from "./useFetchAndSaveAppleEvents";
import { useFetchAndSaveMicrosoftEvents } from "./useFetchAndSaveOutlookEvents";
import { selectedDateAtom } from "@/components/pages/calendar/atoms";
import { addDays, subDays, isBefore, isAfter, format } from "date-fns";
interface SyncResponse {
success: boolean;
eventCount?: number;
error?: string;
}
export const useSyncEvents = () => {
const { profileData } = useAuthContext();
const selectedDate = useAtomValue(selectedDateAtom);
const [lastSyncDate, setLastSyncDate] = useState<Date>(selectedDate);
const [lowerBoundDate, setLowerBoundDate] = useState<Date>(subDays(selectedDate, 6 * 30));
const [upperBoundDate, setUpperBoundDate] = useState<Date>(addDays(selectedDate, 6 * 30));
const [isSyncing, setIsSyncing] = useState(false);
const [error, setError] = useState<Error | null>(null);
const [syncStats, setSyncStats] = useState<{
total: number;
success: number;
failed: number;
events: number;
}>({ total: 0, success: 0, failed: 0, events: 0 });
const syncedRanges = useState<Set<string>>(new Set())[0];
const { mutateAsync: fetchAndSaveGoogleEvents } = useFetchAndSaveGoogleEvents();
const { mutateAsync: fetchAndSaveOutlookEvents } = useFetchAndSaveMicrosoftEvents();
const { mutateAsync: fetchAndSaveAppleEvents } = useFetchAndSaveAppleEvents();
const generateRangeKey = (startDate: Date, endDate: Date) => {
return `${format(startDate, "yyyy-MM-dd")}_${format(endDate, "yyyy-MM-dd")}`;
};
const syncEvents = useCallback(async () => {
setIsSyncing(true);
setError(null);
const newLowerBound = subDays(selectedDate, 6 * 30);
const newUpperBound = addDays(selectedDate, 6 * 30);
const rangeKey = generateRangeKey(newLowerBound, newUpperBound);
if (syncedRanges.has(rangeKey)) {
setIsSyncing(false);
return;
}
if (isBefore(selectedDate, lowerBoundDate) || isAfter(selectedDate, upperBoundDate)) {
const results: SyncResponse[] = [];
const stats = { total: 0, success: 0, failed: 0, events: 0 };
try {
if (profileData?.googleAccounts) {
for (const [email] of Object.entries(profileData.googleAccounts)) {
try {
stats.total++;
const result = await fetchAndSaveGoogleEvents({ email }) as SyncResponse;
if (result.success) {
stats.success++;
stats.events += result.eventCount || 0;
} else {
stats.failed++;
}
results.push(result);
} catch (err) {
stats.failed++;
console.error(`Failed to sync Google calendar for ${email}:`, err);
}
}
}
if (profileData?.microsoftAccounts) {
for (const [email] of Object.entries(profileData.microsoftAccounts)) {
try {
stats.total++;
const result = await fetchAndSaveOutlookEvents({ email });
if (result.success) {
stats.success++;
stats.events += result.eventCount || 0;
} else {
stats.failed++;
}
results.push(result);
} catch (err) {
stats.failed++;
console.error(`Failed to sync Microsoft calendar for ${email}:`, err);
}
}
}
if (profileData?.appleAccounts) {
for (const [email] of Object.entries(profileData.appleAccounts)) {
try {
stats.total++;
const result = await fetchAndSaveAppleEvents({ email });
} catch (err) {
stats.failed++;
console.error(`Failed to sync Apple calendar for ${email}:`, err);
}
}
}
setSyncStats(stats);
setLastSyncDate(selectedDate);
setLowerBoundDate(newLowerBound);
setUpperBoundDate(newUpperBound);
syncedRanges.add(rangeKey);
if (stats.failed > 0) {
throw new Error(`Failed to sync ${stats.failed} calendars`);
}
} catch (err: any) {
console.error("Error syncing events:", err);
setError(err);
} finally {
setIsSyncing(false);
}
} else {
setIsSyncing(false);
}
}, [
selectedDate,
lowerBoundDate,
upperBoundDate,
profileData,
fetchAndSaveGoogleEvents,
fetchAndSaveOutlookEvents,
fetchAndSaveAppleEvents,
syncedRanges
]);
useEffect(() => {
syncEvents();
}, [selectedDate, syncEvents]);
return {
isSyncing,
error,
lastSyncDate,
lowerBoundDate,
upperBoundDate,
syncStats,
};
};