mirror of
https://github.com/urosran/cally.git
synced 2025-07-10 07:07:16 +00:00
144 lines
5.1 KiB
TypeScript
144 lines
5.1 KiB
TypeScript
import { useMutation, useQueryClient } from "@tanstack/react-query";
|
|
import { useAuthContext } from "@/contexts/AuthContext";
|
|
import { useSetUserData } from "@/hooks/firebase/useSetUserData";
|
|
import functions from '@react-native-firebase/functions';
|
|
import * as AuthSession from 'expo-auth-session';
|
|
|
|
interface SyncResponse {
|
|
success: boolean;
|
|
eventCount: number;
|
|
message?: string;
|
|
}
|
|
|
|
interface SyncError extends Error {
|
|
code?: string;
|
|
details?: {
|
|
requiresReauth?: boolean;
|
|
message?: string;
|
|
};
|
|
}
|
|
|
|
const microsoftConfig = {
|
|
clientId: "13c79071-1066-40a9-9f71-b8c4b138b4af",
|
|
scopes: [
|
|
"openid",
|
|
"profile",
|
|
"email",
|
|
"offline_access",
|
|
"Calendars.ReadWrite",
|
|
"User.Read",
|
|
],
|
|
redirectUri: AuthSession.makeRedirectUri({path: "settings"})
|
|
};
|
|
|
|
export const useFetchAndSaveMicrosoftEvents = () => {
|
|
const queryClient = useQueryClient();
|
|
const { profileData } = useAuthContext();
|
|
const { mutateAsync: setUserData } = useSetUserData();
|
|
|
|
const handleReauth = async (email: string) => {
|
|
try {
|
|
const authRequest = new AuthSession.AuthRequest({
|
|
clientId: microsoftConfig.clientId,
|
|
scopes: microsoftConfig.scopes,
|
|
redirectUri: microsoftConfig.redirectUri,
|
|
responseType: AuthSession.ResponseType.Code,
|
|
usePKCE: true,
|
|
});
|
|
|
|
const result = await authRequest.promptAsync({
|
|
authorizationEndpoint: 'https://login.microsoftonline.com/common/oauth2/v2.0/authorize',
|
|
});
|
|
|
|
if (result.type === 'success' && result.params?.code) {
|
|
const tokenResponse = await fetch('https://login.microsoftonline.com/common/oauth2/v2.0/token', {
|
|
method: 'POST',
|
|
headers: {
|
|
'Content-Type': 'application/x-www-form-urlencoded',
|
|
},
|
|
body: new URLSearchParams({
|
|
client_id: microsoftConfig.clientId,
|
|
scope: microsoftConfig.scopes.join(' '),
|
|
code: result.params.code,
|
|
redirect_uri: microsoftConfig.redirectUri,
|
|
grant_type: 'authorization_code',
|
|
code_verifier: authRequest.codeVerifier || '',
|
|
}),
|
|
});
|
|
|
|
const tokens = await tokenResponse.json();
|
|
|
|
await setUserData({
|
|
newUserData: {
|
|
microsoftAccounts: {
|
|
...profileData?.microsoftAccounts,
|
|
[email]: {
|
|
accessToken: tokens.access_token,
|
|
refreshToken: tokens.refresh_token,
|
|
email,
|
|
}
|
|
}
|
|
}
|
|
});
|
|
|
|
return true;
|
|
}
|
|
return false;
|
|
} catch (error) {
|
|
console.error('Microsoft reauth error:', error);
|
|
return false;
|
|
}
|
|
};
|
|
|
|
return useMutation<SyncResponse, SyncError, { email?: string }>({
|
|
mutationKey: ["fetchAndSaveOutlookEvents", "sync"],
|
|
mutationFn: async ({ email }: { email?: string }) => {
|
|
if (!email) {
|
|
throw new Error("Email is required");
|
|
}
|
|
|
|
if (!profileData?.microsoftAccounts?.[email]) {
|
|
throw new Error("No valid Microsoft account found");
|
|
}
|
|
|
|
try {
|
|
const response = await functions()
|
|
.httpsCallable('triggerMicrosoftSync')({ email });
|
|
|
|
return response.data as SyncResponse;
|
|
} catch (error: any) {
|
|
console.error("Microsoft sync error:", error);
|
|
|
|
// Check if we need to reauthenticate
|
|
if (error.details?.requiresReauth ||
|
|
error.code === 'functions/failed-precondition' ||
|
|
error.code === 'functions/unauthenticated') {
|
|
|
|
console.log('Attempting Microsoft reauth...');
|
|
const reauthSuccessful = await handleReauth(email);
|
|
|
|
if (reauthSuccessful) {
|
|
// Retry the sync with new tokens
|
|
console.log('Retrying sync after reauth...');
|
|
const retryResponse = await functions()
|
|
.httpsCallable('triggerMicrosoftSync')({ email });
|
|
return retryResponse.data as SyncResponse;
|
|
}
|
|
}
|
|
|
|
throw error;
|
|
}
|
|
},
|
|
onSuccess: (data) => {
|
|
queryClient.invalidateQueries({queryKey: ["events"]});
|
|
console.log(`Successfully synced ${data.eventCount} Microsoft events`);
|
|
},
|
|
onError: (error) => {
|
|
console.error('Microsoft sync failed:', {
|
|
message: error.message,
|
|
code: error.code,
|
|
details: error.details
|
|
});
|
|
}
|
|
});
|
|
}; |