import cacheAssetsAsync from "@/utils/assetsCache"; import authenticateUser, { parseAuthicationErrors } from "@/utils/requests/authenticateUser"; import type { IuserInformations } from "@/utils/requests/types"; import getUserInformations, { parseUserInformationsErrors, } from "@/utils/requests/userInformations"; import ErrorModal from "@components/modals/ErrorModal"; import { LOG } from "@logger"; import AsyncStorage from "@react-native-async-storage/async-storage"; // import { type NavigationProp, useNavigation } from "@react-navigation/native"; import { useMutation } from "@tanstack/react-query"; import * as SplashScreen from "expo-splash-screen"; import { createContext, useCallback, useContext, useEffect, useState } from "react"; import { useModalsManagerContext } from "./ModalsManagerContext"; import type { IauthenticationData } from "./Types"; const log = LOG.extend("UserAuthenticationContext"); SplashScreen.preventAutoHideAsync(); export interface UserAuthenticationContextProps { isAuthenticated: boolean; setIsAuthenticated: React.Dispatch>; setAuthenticationData: React.Dispatch>; userInformations: IuserInformations; setUserInformations: React.Dispatch>; login: (email: string, password: string) => void; isAuthenticating: boolean; logout: () => void; } export const UserAuthenticationContext = createContext({ isAuthenticated: false, setIsAuthenticated: () => {}, setAuthenticationData: () => {}, userInformations: { username: "", email: "", // biome-ignore lint/style/useNamingConvention: first_name: "", // biome-ignore lint/style/useNamingConvention: last_name: "", marchand: { // biome-ignore lint/style/useNamingConvention: marchand_id: "", nom: "", code: "", adresse: "", // biome-ignore lint/style/useNamingConvention: url_succes: "", // biome-ignore lint/style/useNamingConvention: url_echec: "", entreprise: 0, user: 0, }, }, setUserInformations: () => {}, login: () => {}, isAuthenticating: false, logout: () => {}, }); export const UserAuthenticationContextProvider = ({ children }: { children: React.ReactNode }) => { // States const [isAuthenticated, setIsAuthenticated] = useState(false); const [isAuthenticating, setIsAuthenticating] = useState(false); const [authenticationData, setAuthenticationData] = useState({ access: "", refresh: "", }); const [error, setError] = useState(""); const [userInformations, setUserInformations] = useState({ username: "JohnDoe", email: "JohnDoe@example.com", // biome-ignore lint/style/useNamingConvention: first_name: "John", // biome-ignore lint/style/useNamingConvention: last_name: "Doe", marchand: { // biome-ignore lint/style/useNamingConvention: marchand_id: "id123", nom: "Beasy", code: "BEASY-EXAMPLE-1", adresse: "Plateau 2, 1023, Immeuble Chardy", // biome-ignore lint/style/useNamingConvention: url_succes: "https://example.com/success", // biome-ignore lint/style/useNamingConvention: url_echec: "https://example.com/echec", entreprise: 0, user: 0, }, }); // Hoooks const { showModal } = useModalsManagerContext(); // const navigation = useNavigation>(); // Mutations const authenticationMutation = useMutation({ mutationFn: authenticateUser, onMutate: () => { setIsAuthenticating(true); setError(""); }, onSuccess: (data) => { setAuthenticationData(data); log.info("Receive data from authenticateUser, running getUserInformations..."); userInformationsMutation.mutate(data.access); }, onError: (error: unknown) => { const errorString = parseAuthicationErrors(error); showModal(); }, onSettled: () => { setIsAuthenticating(false); }, }); const userInformationsMutation = useMutation({ mutationFn: (userAccessToken: string) => getUserInformations(userAccessToken), onMutate: () => { setIsAuthenticating(true); setError(""); }, onSettled: () => { setIsAuthenticating(false); }, onSuccess: (userInformations) => { log.info("getUserInformations request was a success, navigating to homepage"); setUserInformations(userInformations); setIsAuthenticated(true); storeAuthenticationData(authenticationData); storeUserInformations(userInformations); // navigation.navigate("appBottomTabsNavigator"); }, onError: (error) => { log.error("userInformationsMutation", error); const errorString = parseUserInformationsErrors(error); showModal(); clearStorages(); }, }); // Methods const login = useCallback( (email: string, password: string) => { authenticationMutation.mutate({ username: email, password: password, }); }, [authenticationMutation], ); const logout = useCallback(() => { (async () => { setIsAuthenticated(false); setAuthenticationData({ access: "", refresh: "", }); setUserInformations({ username: "", email: "", // biome-ignore lint/style/useNamingConvention: first_name: "", // biome-ignore lint/style/useNamingConvention: last_name: "", marchand: { // biome-ignore lint/style/useNamingConvention: marchand_id: "", nom: "", code: "", adresse: "", // biome-ignore lint/style/useNamingConvention: url_succes: "", // biome-ignore lint/style/useNamingConvention: url_echec: "", entreprise: 0, user: 0, }, }); await clearStorages(); })(); }, []); // Storages const storeAuthenticationData = async (authenticationData: IauthenticationData) => { try { await AsyncStorage.setItem("authenticationData", JSON.stringify(authenticationData)); } catch (error) { log.error("storeAuthenticationData |", JSON.stringify(error, null, 2)); // saving error } }; const storeUserInformations = async (userInformations: IuserInformations) => { try { await AsyncStorage.setItem("userInformations", JSON.stringify(userInformations)); } catch (error) { log.error("storeUserInformations |", JSON.stringify(error, null, 2)); // saving error } }; const clearStorages = async () => { try { await AsyncStorage.clear(); } catch (error) { log.error("clearStorages |", JSON.stringify(error, null, 2)); // saving error } }; const loadAuthenticationData = async () => { log.debug("loadAuthenticationData | Loading authentication data"); const jsonRepresentation = await AsyncStorage.getItem("authenticationData"); return jsonRepresentation ? JSON.parse(jsonRepresentation) : null; }; const loadUserInformations = async () => { log.debug("loadUserInformations | Loading user informations"); const jsonRepresentation = await AsyncStorage.getItem("userInformations"); return jsonRepresentation ? JSON.parse(jsonRepresentation) : null; }; // biome-ignore lint/correctness/useExhaustiveDependencies: useEffect(() => { log.debug("UserAuthenticationContext | App Startup | loading saved user data."); (async () => { try { // await loadAssetsAsync(); await cacheAssetsAsync({ images: [ "../assets/background_default.png", "../assets/beasy_default.png", "../assets/beasy_background.png", "../assets/background_content_white2.png", "../../assets/background.png", ], }); const authenticationData = await loadAuthenticationData(); const userInformations = await loadUserInformations(); if (authenticationData && userInformations) { setAuthenticationData(authenticationData); setUserInformations(userInformations); setIsAuthenticated(true); } } catch (error) { log.error( "UserAuthenticationContext | App Startup | error during retrieval of stored data |", JSON.stringify(error, null, 2), ); } finally { setTimeout(async () => await SplashScreen.hideAsync(), 500); } })(); }, []); return ( {children} ); }; export const useUserAuthenticationContext = () => { return useContext(UserAuthenticationContext); };