pogdark-app/context/UserContext.tsx

198 lines
6.7 KiB
TypeScript
Raw Normal View History

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";
2025-03-02 20:32:39 +00:00
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;
2025-03-30 03:18:28 +00:00
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;
2025-04-28 04:05:33 +00:00
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<UserContextType | undefined>(undefined);
// Define provider props type
interface UserProviderProps {
children: ReactNode;
}
export const UserProvider: React.FC<UserProviderProps> = ({ children }) => {
const [isProfileActive, setProfileActive] = useState(false);
2025-03-30 03:18:28 +00:00
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("");
2025-04-28 04:05:33 +00:00
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");
2025-04-28 04:05:33 +00:00
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);
}
2025-04-28 04:05:33 +00:00
if(storedPark) {
setPark(storedPark);
setLocationActive(false);
} else {
setPark("");
setLocationActive(true);
}
} catch (error) {
2025-03-02 20:32:39 +00:00
log.error("Error loading user data:", error);
} finally {
setIsLoading(false);
}
};
2025-03-23 05:06:26 +00:00
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);
2025-04-28 04:05:33 +00:00
await AsyncStorage.setItem("park", park);
log.debug("Current park: ", park);
setUserDataChanged(false);
} catch (error) {
2025-03-02 20:32:39 +00:00
log.error("Error saving user data:", error);
}
};
2025-03-23 05:06:26 +00:00
void saveUserData();
}, [userDataChanged]);
useEffect(() => {
const handleAppStateChange = (nextAppState: string) => {
if (appState.match(/inactive|background/) && nextAppState === "active") {
if (!isLoading) {
2025-03-23 05:06:26 +00:00
void fetchCurrentStatus();
} else {
2025-03-02 20:32:39 +00:00
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) {
2025-03-02 20:32:39 +00:00
log.error("Error fetching status:", error);
}
};
return (
<UserContext.Provider
value={{
isProfileActive,
setProfileActive,
2025-03-30 03:18:28 +00:00
isMenuActive,
setMenuActive,
isAboutActive,
setAboutActive,
isPrivacyActive,
setPrivacyActive,
isBugActive,
setBugActive,
isLocationActive,
setLocationActive,
userId,
userName,
setUserName,
userImage,
setUserImage,
2025-04-28 04:05:33 +00:00
park,
setPark,
userStatus,
setUserStatus,
setUserDataChanged,
isLoading,
currentTheme,
setTheme,
}}
>
{children}
</UserContext.Provider>
);
};
// 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;
};