mirror of
https://github.com/urosran/cally.git
synced 2025-11-26 16:34:54 +00:00
Syncing rework
This commit is contained in:
@ -3,10 +3,16 @@ import { useAuthContext } from "@/contexts/AuthContext";
|
||||
import { useAtomValue } from "jotai";
|
||||
import { useFetchAndSaveGoogleEvents } from "./useFetchAndSaveGoogleEvents";
|
||||
import { useFetchAndSaveAppleEvents } from "./useFetchAndSaveAppleEvents";
|
||||
import { useFetchAndSaveOutlookEvents } from "./useFetchAndSaveOutlookEvents";
|
||||
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);
|
||||
@ -15,12 +21,18 @@ export const useSyncEvents = () => {
|
||||
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(null);
|
||||
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 } = useFetchAndSaveOutlookEvents();
|
||||
const { mutateAsync: fetchAndSaveOutlookEvents } = useFetchAndSaveMicrosoftEvents();
|
||||
const { mutateAsync: fetchAndSaveAppleEvents } = useFetchAndSaveAppleEvents();
|
||||
|
||||
const generateRangeKey = (startDate: Date, endDate: Date) => {
|
||||
@ -41,26 +53,71 @@ export const useSyncEvents = () => {
|
||||
}
|
||||
|
||||
if (isBefore(selectedDate, lowerBoundDate) || isAfter(selectedDate, upperBoundDate)) {
|
||||
const results: SyncResponse[] = [];
|
||||
const stats = { total: 0, success: 0, failed: 0, events: 0 };
|
||||
|
||||
try {
|
||||
const googleEvents = Object.entries(profileData?.googleAccounts || {}).map(([email, { accessToken }]) =>
|
||||
fetchAndSaveGoogleEvents({ token: accessToken, email, date: selectedDate })
|
||||
);
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const outlookEvents = Object.entries(profileData?.microsoftAccounts || {}).map(([email, token]) =>
|
||||
fetchAndSaveOutlookEvents({ token, email, date: selectedDate })
|
||||
);
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const appleEvents = Object.entries(profileData?.appleAccounts || {}).map(([email, token]) =>
|
||||
fetchAndSaveAppleEvents({ token, email, date: selectedDate })
|
||||
);
|
||||
|
||||
await Promise.all([...googleEvents, ...outlookEvents, ...appleEvents]);
|
||||
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);
|
||||
} catch (err) {
|
||||
|
||||
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 {
|
||||
@ -69,7 +126,16 @@ export const useSyncEvents = () => {
|
||||
} else {
|
||||
setIsSyncing(false);
|
||||
}
|
||||
}, [selectedDate, lowerBoundDate, upperBoundDate, profileData, fetchAndSaveGoogleEvents, fetchAndSaveOutlookEvents, fetchAndSaveAppleEvents, syncedRanges]);
|
||||
}, [
|
||||
selectedDate,
|
||||
lowerBoundDate,
|
||||
upperBoundDate,
|
||||
profileData,
|
||||
fetchAndSaveGoogleEvents,
|
||||
fetchAndSaveOutlookEvents,
|
||||
fetchAndSaveAppleEvents,
|
||||
syncedRanges
|
||||
]);
|
||||
|
||||
useEffect(() => {
|
||||
syncEvents();
|
||||
@ -81,5 +147,6 @@ export const useSyncEvents = () => {
|
||||
lastSyncDate,
|
||||
lowerBoundDate,
|
||||
upperBoundDate,
|
||||
syncStats,
|
||||
};
|
||||
};
|
||||
Reference in New Issue
Block a user