From 9111b387080695f76895f8394d76eafa3586a0f5 Mon Sep 17 00:00:00 2001 From: suddenlyoranges Date: Thu, 9 Apr 2026 16:48:13 +0100 Subject: [PATCH] Added global gameplay screens and API hook fixed routings to global game screen. Fixed navbar layouts on the screen. Updated api keys to use private key and added .env file. Configured useGlobalHook to use api from env variable. --- App.js | 30 +++++ src/components/layout/BottomNavbar.js | 10 ++ src/components/layout/Screen.js | 4 + src/components/screens/GameSelectionScreen.js | 2 +- src/hooks/SessionStore.js | 34 +++++- src/hooks/useGlobalHook.js | 103 ++++++++++++++++++ 6 files changed, 179 insertions(+), 4 deletions(-) create mode 100644 src/hooks/useGlobalHook.js diff --git a/App.js b/App.js index 1ba19b5..542d48d 100644 --- a/App.js +++ b/App.js @@ -12,6 +12,10 @@ import GameSettingsScreen from "./src/components/screens/GameSettingsScreen"; import PlayersScreen from "./src/components/screens/PlayersScreen"; import ExpandedMapScreen from "./src/components/screens/ExpandedMapScreen"; import GameSelectionScreen from "./src/components/screens/GameSelectionScreen"; +import GlobalEventsScreen from "./src/components/screens/global/GlobalEventsScreen"; +import GlobalMapScreen from "./src/components/screens/global/GlobalMapScreen"; +import GlobalCacheViewScreen from "./src/components/screens/global/GlobalCacheViewScreen"; +import GlobalLeaderboardScreen from "./src/components/screens/global/GlobalLeaderboardScreen"; import { loadSession } from "./src/hooks/SessionStore"; const RootStack = createNativeStackNavigator(); @@ -50,6 +54,19 @@ const GameStack = () => ( name="ExpandedMapScreen" component={ExpandedMapScreen} /> + + + + ); @@ -74,6 +91,19 @@ const AdminStack = () => ( component={ExpandedMapScreen} /> + + + + ); diff --git a/src/components/layout/BottomNavbar.js b/src/components/layout/BottomNavbar.js index 0e68805..5e210c0 100644 --- a/src/components/layout/BottomNavbar.js +++ b/src/components/layout/BottomNavbar.js @@ -35,6 +35,11 @@ const BottomNavbar = ({ navigation, routeName }) => { route: "GameSelectionScreen", onPress: () => navigation.navigate("GameSelectionScreen"), }, + { + label: "Global", + route: "GlobalEventsScreen", + onPress: () => navigation.navigate("GlobalEventsScreen"), + }, ]; const playerTabs = [ @@ -58,6 +63,11 @@ const BottomNavbar = ({ navigation, routeName }) => { route: "GameSelectionScreen", onPress: () => navigation.navigate("GameSelectionScreen"), }, + { + label: "Global", + route: "GlobalEventsScreen", + onPress: () => navigation.navigate("GlobalEventsScreen"), + }, { label: "Leave", route: "__leave__", onPress: () => handleLeaveGame() }, ]; diff --git a/src/components/layout/Screen.js b/src/components/layout/Screen.js index 25ffb0a..9342601 100644 --- a/src/components/layout/Screen.js +++ b/src/components/layout/Screen.js @@ -20,6 +20,10 @@ const Screen = ({ children, style, showBack = false }) => { GameSelectionScreen: "Games", PlayersScreen: "Players", ExpandedMapScreen: "Map View", + GlobalEventsScreen: "Global Events", + GlobalMapScreen: "Global Map", + GlobalCacheViewScreen: "Cache Details", + GlobalLeaderboardScreen: "Global Leaderboard", }; // State ---------------------- diff --git a/src/components/screens/GameSelectionScreen.js b/src/components/screens/GameSelectionScreen.js index 5377e5c..969d70a 100644 --- a/src/components/screens/GameSelectionScreen.js +++ b/src/components/screens/GameSelectionScreen.js @@ -35,7 +35,7 @@ const GameSelectionScreen = ({ navigation }) => { }; const handleExplore = () => { - navigation.navigate("MapScreen"); + navigation.navigate("GlobalEventsScreen"); }; // View -------------------------------- diff --git a/src/hooks/SessionStore.js b/src/hooks/SessionStore.js index a3e3774..341b68d 100644 --- a/src/hooks/SessionStore.js +++ b/src/hooks/SessionStore.js @@ -1,8 +1,8 @@ // --- Session Store (with AsyncStorage persistence) --- -import AsyncStorage from '@react-native-async-storage/async-storage'; +import AsyncStorage from "@react-native-async-storage/async-storage"; -const STORAGE_KEY = '@mad_session'; +const STORAGE_KEY = "@mad_session"; const session = { currentUid: null, @@ -12,6 +12,9 @@ const session = { isBusiness: null, isAcceptedAdmin: false, teamsEnabled: false, + // Global gameplay + currentGlobalEventId: null, + currentGlobalPlayerId: null, }; // --- Handlers --- @@ -46,6 +49,18 @@ const setSessionTeamsEnabled = (val) => { const getSession = () => ({ ...session }); +const setGlobalSession = (eventId, playerId) => { + session.currentGlobalEventId = eventId ?? null; + session.currentGlobalPlayerId = playerId ?? null; + persistSession(); +}; + +const clearGlobalSession = () => { + session.currentGlobalEventId = null; + session.currentGlobalPlayerId = null; + persistSession(); +}; + const clearSession = () => { session.currentUid = null; session.currentGid = null; @@ -53,6 +68,8 @@ const clearSession = () => { session.currentTid = null; session.isBusiness = null; session.isAcceptedAdmin = false; + session.currentGlobalEventId = null; + session.currentGlobalPlayerId = null; AsyncStorage.removeItem(STORAGE_KEY).catch(() => {}); }; @@ -85,4 +102,15 @@ const loadSession = async () => { return { ...session }; }; -export { setSessionUser, setSessionGroup, setSessionTeam, setSessionTeamsEnabled, getSession, clearSession, clearGameSession, loadSession }; +export { + setSessionUser, + setSessionGroup, + setSessionTeam, + setSessionTeamsEnabled, + getSession, + clearSession, + clearGameSession, + loadSession, + setGlobalSession, + clearGlobalSession, +}; diff --git a/src/hooks/useGlobalHook.js b/src/hooks/useGlobalHook.js new file mode 100644 index 0000000..734c824 --- /dev/null +++ b/src/hooks/useGlobalHook.js @@ -0,0 +1,103 @@ +import API from "../components/API/API"; + +const GLOBAL_BASE = process.env.EXPO_PUBLIC_GLOBAL_API_BASE; +const GLOBAL_KEY = process.env.EXPO_PUBLIC_GLOBAL_API_KEY; + +// Appends the API key as a query param to any URL +const withKey = (url) => { + const separator = url.includes("?") ? "&" : "?"; + return `${url}${separator}key=${GLOBAL_KEY}`; +}; + +const useGlobalHook = () => { + // Initialisations --------------------- + + const eventsEndpoint = `${GLOBAL_BASE}/api/events`; + const playersEndpoint = `${GLOBAL_BASE}/api/players`; + const cachesEndpoint = `${GLOBAL_BASE}/api/caches`; + const findsEndpoint = `${GLOBAL_BASE}/api/finds`; + const usersEndpoint = `${GLOBAL_BASE}/api/users`; + + // Handlers ---------------------------- + + // Events + const getPublicEvents = async () => { + const response = await API.get(withKey(eventsEndpoint)); + if (!response.isSuccess) return []; + return response.result.filter((e) => e.EventIspublic); + }; + + const getEvent = async (eventId) => { + const response = await API.get(withKey(`${eventsEndpoint}/${eventId}`)); + return response.isSuccess ? response.result : null; + }; + + // Players + const getPlayersByEvent = async (eventId) => { + const response = await API.get( + withKey(`${playersEndpoint}/events/${eventId}`), + ); + return response.isSuccess ? response.result : []; + }; + + const joinEvent = async (data) => { + const response = await API.post(withKey(playersEndpoint), data); + return response.isSuccess ? response.result : null; + }; + + // Caches + const getCachesByEvent = async (eventId) => { + const response = await API.get( + withKey(`${cachesEndpoint}/events/${eventId}`), + ); + return response.isSuccess ? response.result : []; + }; + + const getCache = async (cacheId) => { + const response = await API.get(withKey(`${cachesEndpoint}/${cacheId}`)); + return response.isSuccess ? response.result : null; + }; + + // Finds + const getFindsByEvent = async (eventId) => { + const response = await API.get( + withKey(`${findsEndpoint}/events/${eventId}`), + ); + return response.isSuccess ? response.result : []; + }; + + const getFindsByPlayer = async (playerId) => { + const response = await API.get( + withKey(`${findsEndpoint}/players/${playerId}`), + ); + return response.isSuccess ? response.result : []; + }; + + const logFind = async (data) => { + const response = await API.post(withKey(findsEndpoint), data); + return response.isSuccess ? response.result : null; + }; + + // Users + const getUser = async (userId) => { + const response = await API.get(withKey(`${usersEndpoint}/${userId}`)); + return response.isSuccess ? response.result : null; + }; + + // Return -------------------------------- + + return { + getPublicEvents, + getEvent, + getPlayersByEvent, + joinEvent, + getCachesByEvent, + getCache, + getFindsByEvent, + getFindsByPlayer, + logFind, + getUser, + }; +}; + +export default useGlobalHook;