Files
cally/hooks/useFetchAndSaveOutlookEvents.ts
Milan Paunovic c411990312 Fixes
2024-12-15 16:46:26 +01:00

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
});
}
});
};