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;