import React, { createContext, useContext, useEffect, useState, ReactNode } from "react"; import AsyncStorage from "@react-native-async-storage/async-storage"; import { AppState } from "react-native"; import { v4 as uuidv4 } from "uuid"; import axios from "axios"; import log from "@/util/log" export const API_URL = process.env.EXPO_PUBLIC_API_URL; // Define context type interface UserContextType { isProfileActive: boolean; setProfileActive: (active: boolean) => void; isMenuActive: boolean; setMenuActive: (active: boolean) => void; isAboutActive: boolean; setAboutActive: (active: boolean) => void; isPrivacyActive: boolean; setPrivacyActive: (active: boolean) => void; isBugActive: boolean; setBugActive: (active: boolean) => void; isLocationActive: boolean; setLocationActive: (active: boolean) => void; userId: string; userName: string; setUserName: (name: string) => void; userImage: string; setUserImage: (image: string) => void; park: string; setPark: (park: string) => void; userStatus: string; setUserStatus: (status: string) => void; setUserDataChanged: (changed: boolean) => void; isLoading: boolean; currentTheme: string; setTheme: (theme: string) => void; } // Create context with default values const UserContext = createContext(undefined); // Define provider props type interface UserProviderProps { children: ReactNode; } export const UserProvider: React.FC = ({ children }) => { const [isProfileActive, setProfileActive] = useState(false); const [isMenuActive, setMenuActive] = useState(false); const [isAboutActive, setAboutActive] = useState(false); const [isPrivacyActive, setPrivacyActive] = useState(false); const [isBugActive, setBugActive] = useState(false); const [isLocationActive, setLocationActive] = useState(false); const [userId, setUserId] = useState(""); const [userName, setUserName] = useState(""); const [userImage, setUserImage] = useState(""); const [park, setPark] = useState(""); const [userStatus, setUserStatus] = useState("none"); const [userDataChanged, setUserDataChanged] = useState(false); const [isLoading, setIsLoading] = useState(true); const [appState, setAppState] = useState(AppState.currentState); const [currentTheme, setTheme] = useState(""); useEffect(() => { const loadUserData = async () => { try { const storedUserId = await AsyncStorage.getItem("userId"); const storedUserName = await AsyncStorage.getItem("userName"); const storedUserImage = await AsyncStorage.getItem("userImage"); const storedUserTheme = await AsyncStorage.getItem("theme"); const storedPark = await AsyncStorage.getItem("park"); log.debug("Stored park: ", storedPark); if (storedUserId) { setUserId(storedUserId); setUserName(storedUserName || ""); setUserImage(storedUserImage || ""); setTheme(storedUserTheme || "blue"); setProfileActive(false); } else { setUserId(uuidv4()); setUserName(""); setUserImage(""); setTheme("blue") setProfileActive(true); } if(storedPark) { setPark(storedPark); setLocationActive(false); } else { setPark(""); setLocationActive(true); } } catch (error) { log.error("Error loading user data:", error); } finally { setIsLoading(false); } }; void loadUserData(); }, []); useEffect(() => { if (!userDataChanged) return; const saveUserData = async () => { try { await AsyncStorage.setItem("userId", userId); await AsyncStorage.setItem("userName", userName); await AsyncStorage.setItem("userImage", userImage); await AsyncStorage.setItem("theme", currentTheme); await AsyncStorage.setItem("park", park); log.debug("Current park: ", park); setUserDataChanged(false); } catch (error) { log.error("Error saving user data:", error); } }; void saveUserData(); }, [userDataChanged]); useEffect(() => { const handleAppStateChange = (nextAppState: string) => { if (appState.match(/inactive|background/) && nextAppState === "active") { if (!isLoading) { void fetchCurrentStatus(); } else { log.debug("Waiting for loading to complete before fetching status..."); } } setAppState(AppState.currentState); }; const listener = AppState.addEventListener("change", handleAppStateChange); return () => { listener.remove(); }; }, [appState]); const fetchCurrentStatus = async () => { try { const response = await axios.post(API_URL + "/get", { id: userId }); if (response.data?.status) { setTimeout(() => { setUserStatus("none"); }, 0); } } catch (error) { log.error("Error fetching status:", error); } }; return ( {children} ); }; // Custom hook to use context export const useUser = (): UserContextType => { const context = useContext(UserContext); if (!context) { throw new Error("useUser must be used within a UserProvider"); } return context; };