From 157d69c21c0ec87c5248b2c3924ed50b7351cdd7 Mon Sep 17 00:00:00 2001 From: suddenlyoranges Date: Thu, 9 Apr 2026 15:29:29 +0100 Subject: [PATCH] Add global events, map, cache and leaderboard screens Introduce four new screens for global events: GlobalEventsScreen (lists public events and handles joining), GlobalMapScreen (map/list view of event caches with user location via expo-location and markers using react-native-maps), GlobalCacheViewScreen (cache detail view with ability to log discoveries), and GlobalLeaderboardScreen (rankings and recent finds). Screens use existing global hooks and SessionStore for fetching/joining events, caches, finds and for storing current global player context; they include loading/error states and navigation between screens. Also add simple tab components, styling, and refresh actions. --- .gitignore | 4 + .../screens/global/GlobalCacheViewScreen.js | 177 +++++++++++++ .../screens/global/GlobalEventsScreen.js | 140 ++++++++++ .../screens/global/GlobalLeaderboardScreen.js | 249 ++++++++++++++++++ .../screens/global/GlobalMapScreen.js | 230 ++++++++++++++++ 5 files changed, 800 insertions(+) create mode 100644 src/components/screens/global/GlobalCacheViewScreen.js create mode 100644 src/components/screens/global/GlobalEventsScreen.js create mode 100644 src/components/screens/global/GlobalLeaderboardScreen.js create mode 100644 src/components/screens/global/GlobalMapScreen.js diff --git a/.gitignore b/.gitignore index c4fcf5f..9069e79 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,9 @@ # Learn more https://docs.github.com/en/get-started/getting-started-with-git/ignoring-files +# Environment variables (contains secrets) +.env +.env.local + # dependencies node_modules/ diff --git a/src/components/screens/global/GlobalCacheViewScreen.js b/src/components/screens/global/GlobalCacheViewScreen.js new file mode 100644 index 0000000..1e76668 --- /dev/null +++ b/src/components/screens/global/GlobalCacheViewScreen.js @@ -0,0 +1,177 @@ +import { useEffect, useState } from "react"; +import { ActivityIndicator, Alert, StyleSheet, Text, View } from "react-native"; +import Screen from "../../layout/Screen"; +import { Button, ButtonTray } from "../../UI/Button"; +import Card from "../../UI/Card"; +import useGlobalHook from "../../../hooks/useGlobalHook"; +import { getSession } from "../../../hooks/SessionStore"; + +const GlobalCacheViewScreen = ({ navigation, route }) => { + // Initialisations --------------------- + + const { cache, isFound: initIsFound, onFindLogged } = route.params; + const { logFind } = useGlobalHook(); + const session = getSession(); + + // State ------------------------------- + + const [isFound, setIsFound] = useState(initIsFound); + const [isLogging, setIsLogging] = useState(false); + + // Handlers ---------------------------- + + const handleLogFind = async () => { + if (!session.currentGlobalPlayerId) { + Alert.alert( + "Not joined", + "You must join the event before logging a find.", + ); + return; + } + + Alert.alert( + "Log Discovery", + `Record that you found "${cache.CacheName}" and earn ${cache.CachePoints ?? 0} points?`, + [ + { text: "Cancel", style: "cancel" }, + { + text: "Log Find", + onPress: async () => { + setIsLogging(true); + const result = await logFind({ + FindPlayerID: session.currentGlobalPlayerId, + FindCacheID: cache.CacheID, + FindDatetime: new Date().toISOString(), + }); + setIsLogging(false); + if (result) { + setIsFound(true); + if (onFindLogged) onFindLogged(); + Alert.alert( + "Discovery logged!", + `+${cache.CachePoints ?? 0} points earned.`, + ); + } else { + Alert.alert("Error", "Could not log find. Please try again."); + } + }, + }, + ], + ); + }; + + // View -------------------------------- + + return ( + + + + {cache.CacheName} + + + + {isFound ? "Already Found" : "Not Yet Found"} + + + + + Points + {cache.CachePoints ?? 0} + + + {cache.CacheDescription ? ( + + Description + {cache.CacheDescription} + + ) : null} + + {cache.CacheClue ? ( + + Clue + {cache.CacheClue} + + ) : null} + + + {isLogging ? ( + + ) : ( + + {!isFound && ( +