diff --git a/src/components/screens/global/GlobalCacheViewScreen.js b/src/components/screens/global/GlobalCacheViewScreen.js
index 257244c..bd8d58a 100644
--- a/src/components/screens/global/GlobalCacheViewScreen.js
+++ b/src/components/screens/global/GlobalCacheViewScreen.js
@@ -1,10 +1,10 @@
-import {useEffect} from "react";
-import {StyleSheet, Text, View} from "react-native";
+import { useEffect } from "react";
+import { StyleSheet, Text, View } from "react-native";
import Screen from "../../layout/Screen";
-import {Button, ButtonTray} from "../../UI/Button";
+import { Button, ButtonTray } from "../../UI/Button";
import Card from "../../UI/Card";
-import {getSession} from "../../../hooks/SessionStore";
-import {GAME_MODE} from "../../../utils/gameConstants";
+import { getSession } from "../../../hooks/SessionStore";
+import { GAME_MODE } from "../../../utils/gameConstants";
const GlobalCacheViewScreen = ({ navigation, route }) => {
// Initialisations ---------------------
@@ -67,7 +67,8 @@ const GlobalCacheViewScreen = ({ navigation, route }) => {
{!initIsFound ? (
- Claim this cache from the Global Map while within 30m and facing it.
+ Claim this cache from the Global Map while within 30m and facing
+ it.
) : null}
@@ -91,7 +92,7 @@ const styles = StyleSheet.create({
title: {
fontSize: 22,
fontWeight: "700",
- color: "#111827",
+ color: "#cdd6f4",
},
statusBadge: {
alignSelf: "flex-start",
@@ -100,15 +101,15 @@ const styles = StyleSheet.create({
borderRadius: 12,
},
badgeFound: {
- backgroundColor: "#d1fae5",
+ backgroundColor: "#1e3a2f",
},
badgeOpen: {
- backgroundColor: "#fef3c7",
+ backgroundColor: "#3d3117",
},
statusText: {
fontSize: 13,
fontWeight: "600",
- color: "#374151",
+ color: "#cdd6f4",
},
detailRow: {
gap: 2,
@@ -116,17 +117,17 @@ const styles = StyleSheet.create({
label: {
fontSize: 12,
fontWeight: "600",
- color: "#6b7280",
+ color: "#a6adc8",
textTransform: "uppercase",
letterSpacing: 0.5,
},
value: {
fontSize: 15,
- color: "#111827",
+ color: "#cdd6f4",
},
claimHint: {
marginTop: 6,
- color: "#2563eb",
+ color: "#89b4fa",
fontSize: 13,
fontWeight: "600",
},
diff --git a/src/components/screens/global/GlobalEventsScreen.js b/src/components/screens/global/GlobalEventsScreen.js
index e069645..6ae1e3d 100644
--- a/src/components/screens/global/GlobalEventsScreen.js
+++ b/src/components/screens/global/GlobalEventsScreen.js
@@ -1,21 +1,17 @@
-import {useCallback, useEffect, useRef, useState} from "react";
-import {ActivityIndicator, StyleSheet, Text, View} from "react-native";
+import { useCallback, useEffect, useRef, useState } from "react";
+import { ActivityIndicator, StyleSheet, Text, View } from "react-native";
import Screen from "../../layout/Screen";
-import {Button, ButtonTray} from "../../UI/Button";
+import { Button, ButtonTray } from "../../UI/Button";
import EventList from "../../../entity/event/EventList";
import useGlobalHook from "../../../hooks/useGlobalHook";
-import {getSession, setGlobalSession} from "../../../hooks/SessionStore";
-import {GAME_MODE} from "../../../utils/gameConstants";
+import { getSession, setGlobalSession } from "../../../hooks/SessionStore";
+import { GAME_MODE } from "../../../utils/gameConstants";
const GlobalEventsScreen = ({ navigation }) => {
// Initialisations ---------------------
- const {
- getPublicEvents,
- getPlayersByEvent,
- joinEvent,
- isGlobalApiReady,
- } = useGlobalHook();
+ const { getPublicEvents, getPlayersByEvent, joinEvent, isGlobalApiReady } =
+ useGlobalHook();
const session = getSession();
const globalApiRef = useRef({
getPublicEvents,
@@ -45,7 +41,9 @@ const GlobalEventsScreen = ({ navigation }) => {
if (!globalApiRef.current.isGlobalApiReady()) {
setEvents([]);
- setError("Global API URL is not configured yet. Add it in src/components/API/api.json.");
+ setError(
+ "Global API URL is not configured yet. Add it in src/components/API/api.json.",
+ );
setIsLoading(false);
return;
}
@@ -68,7 +66,9 @@ const GlobalEventsScreen = ({ navigation }) => {
setJoining(event.EventID);
if (!globalApiRef.current.isGlobalApiReady()) {
- setError("Global API URL is not configured yet. Add it in src/components/API/api.json.");
+ setError(
+ "Global API URL is not configured yet. Add it in src/components/API/api.json.",
+ );
setJoining(null);
return;
}
@@ -82,7 +82,10 @@ const GlobalEventsScreen = ({ navigation }) => {
};
// Check if already a player
- const players = await globalApiRef.current.getPlayersByEvent(event.EventID, {forceRefresh: true});
+ const players = await globalApiRef.current.getPlayersByEvent(
+ event.EventID,
+ { forceRefresh: true },
+ );
const existing = (players || []).find(
(p) => String(p.PlayerUserID) === String(globalUserId),
);
@@ -110,7 +113,10 @@ const GlobalEventsScreen = ({ navigation }) => {
}
// If create fails due duplicate race/server behavior, recover by re-reading players.
- const refreshedPlayers = await globalApiRef.current.getPlayersByEvent(event.EventID, {forceRefresh: true});
+ const refreshedPlayers = await globalApiRef.current.getPlayersByEvent(
+ event.EventID,
+ { forceRefresh: true },
+ );
const recovered = (refreshedPlayers || []).find(
(p) => String(p.PlayerUserID) === String(globalUserId),
);
@@ -131,7 +137,10 @@ const GlobalEventsScreen = ({ navigation }) => {
-
{error ? {error} : null}
@@ -174,21 +183,21 @@ const styles = StyleSheet.create({
gap: 10,
},
loadingText: {
- color: "#6b7280",
+ color: "#a6adc8",
fontSize: 14,
},
empty: {
textAlign: "center",
- color: "#9ca3af",
+ color: "#a6adc8",
marginTop: 30,
fontSize: 15,
},
hint: {
fontSize: 13,
- color: "#6b7280",
+ color: "#a6adc8",
},
error: {
- color: "#dc2626",
+ color: "#f38ba8",
fontSize: 14,
},
overlay: {
diff --git a/src/components/screens/global/GlobalLeaderboardScreen.js b/src/components/screens/global/GlobalLeaderboardScreen.js
index 4270eab..0bf147f 100644
--- a/src/components/screens/global/GlobalLeaderboardScreen.js
+++ b/src/components/screens/global/GlobalLeaderboardScreen.js
@@ -1,12 +1,18 @@
-import {useCallback, useEffect, useRef, useState} from "react";
-import {ActivityIndicator, ScrollView, StyleSheet, Text, View,} from "react-native";
+import { useCallback, useEffect, useRef, useState } from "react";
+import {
+ ActivityIndicator,
+ ScrollView,
+ StyleSheet,
+ Text,
+ View,
+} from "react-native";
import Screen from "../../layout/Screen";
-import {Button, ButtonTray} from "../../UI/Button";
+import { Button, ButtonTray } from "../../UI/Button";
import Card from "../../UI/Card";
import FindList from "../../../entity/find/FindList";
import useGlobalHook from "../../../hooks/useGlobalHook";
-import {getSession} from "../../../hooks/SessionStore";
-import {GAME_MODE} from "../../../utils/gameConstants";
+import { getSession } from "../../../hooks/SessionStore";
+import { GAME_MODE } from "../../../utils/gameConstants";
const GlobalLeaderboardScreen = ({ navigation, route }) => {
// Initialisations ---------------------
@@ -35,75 +41,78 @@ const GlobalLeaderboardScreen = ({ navigation, route }) => {
// Handlers ----------------------------
- const loadData = useCallback(async (options = {}) => {
- if (!eventId) return;
+ const loadData = useCallback(
+ async (options = {}) => {
+ if (!eventId) return;
- setIsLoading(true);
+ setIsLoading(true);
- const [finds, caches, players] = await Promise.all([
- globalApiRef.current.getFindsByEvent(eventId, options),
- globalApiRef.current.getCachesByEvent(eventId, options),
- globalApiRef.current.getPlayersByEvent(eventId, options),
- ]);
+ const [finds, caches, players] = await Promise.all([
+ globalApiRef.current.getFindsByEvent(eventId, options),
+ globalApiRef.current.getCachesByEvent(eventId, options),
+ globalApiRef.current.getPlayersByEvent(eventId, options),
+ ]);
- // Build cache points lookup
- const cacheMap = {};
- (caches || []).forEach((c) => {
- cacheMap[String(c.CacheID)] = c;
- });
+ // Build cache points lookup
+ const cacheMap = {};
+ (caches || []).forEach((c) => {
+ cacheMap[String(c.CacheID)] = c;
+ });
- // Augment finds with cache info for FindList
- const augmented = (finds || []).map((f) => ({
- ...f,
- FindCache: f.FindCache || cacheMap[String(f.FindCacheID)] || null,
- }));
+ // Augment finds with cache info for FindList
+ const augmented = (finds || []).map((f) => ({
+ ...f,
+ FindCache: f.FindCache || cacheMap[String(f.FindCacheID)] || null,
+ }));
- // Sort recent first
- const sorted = [...augmented].sort(
- (a, b) => new Date(b.FindDatetime) - new Date(a.FindDatetime),
- );
- setRecentFinds(sorted.slice(0, 50));
+ // Sort recent first
+ const sorted = [...augmented].sort(
+ (a, b) => new Date(b.FindDatetime) - new Date(a.FindDatetime),
+ );
+ setRecentFinds(sorted.slice(0, 50));
- // Start ranking map with all players so zero-point players are visible.
- const pointsMap = {};
- (players || []).forEach((p) => {
- const pid = p.PlayerID;
- pointsMap[String(pid)] = {
- playerId: pid,
- points: Number(p.PlayerPoints || 0),
- finds: 0,
- name: p.PlayerUser?.UserUsername || `Player #${p.PlayerUserID}`,
- };
- });
-
- // Aggregate points and finds from recorded discoveries.
- augmented.forEach((f) => {
- const pid = f.FindPlayerID;
- const key = String(pid);
- const pts = Number(f.FindCache?.CachePoints || 0);
-
- if (!pointsMap[key]) {
- pointsMap[key] = {
+ // Start ranking map with all players so zero-point players are visible.
+ const pointsMap = {};
+ (players || []).forEach((p) => {
+ const pid = p.PlayerID;
+ pointsMap[String(pid)] = {
playerId: pid,
- points: 0,
+ points: Number(p.PlayerPoints || 0),
finds: 0,
- name: `Player #${f.FindPlayerID}`,
+ name: p.PlayerUser?.UserUsername || `Player #${p.PlayerUserID}`,
};
- }
+ });
- pointsMap[key].points += pts;
- pointsMap[key].finds += 1;
- });
+ // Aggregate points and finds from recorded discoveries.
+ augmented.forEach((f) => {
+ const pid = f.FindPlayerID;
+ const key = String(pid);
+ const pts = Number(f.FindCache?.CachePoints || 0);
- const ranked = Object.values(pointsMap).sort((a, b) => {
- if (b.points !== a.points) return b.points - a.points;
- if (b.finds !== a.finds) return b.finds - a.finds;
- return String(a.name || "").localeCompare(String(b.name || ""));
- });
+ if (!pointsMap[key]) {
+ pointsMap[key] = {
+ playerId: pid,
+ points: 0,
+ finds: 0,
+ name: `Player #${f.FindPlayerID}`,
+ };
+ }
- setRankings(ranked);
- setIsLoading(false);
- }, [eventId]);
+ pointsMap[key].points += pts;
+ pointsMap[key].finds += 1;
+ });
+
+ const ranked = Object.values(pointsMap).sort((a, b) => {
+ if (b.points !== a.points) return b.points - a.points;
+ if (b.finds !== a.finds) return b.finds - a.finds;
+ return String(a.name || "").localeCompare(String(b.name || ""));
+ });
+
+ setRankings(ranked);
+ setIsLoading(false);
+ },
+ [eventId],
+ );
useEffect(() => {
if (session.isBusiness || session.currentGameMode !== GAME_MODE.GLOBAL) {
@@ -126,12 +135,21 @@ const GlobalLeaderboardScreen = ({ navigation, route }) => {
]);
useEffect(() => {
- if (!eventId || session.currentGameMode !== GAME_MODE.GLOBAL || !session.currentGlobalPlayerId) {
+ if (
+ !eventId ||
+ session.currentGameMode !== GAME_MODE.GLOBAL ||
+ !session.currentGlobalPlayerId
+ ) {
return;
}
loadData();
- }, [eventId, loadData, session.currentGameMode, session.currentGlobalPlayerId]);
+ }, [
+ eventId,
+ loadData,
+ session.currentGameMode,
+ session.currentGlobalPlayerId,
+ ]);
// View --------------------------------
@@ -199,7 +217,10 @@ const GlobalLeaderboardScreen = ({ navigation, route }) => {
)}
- loadData({forceRefresh: true})} />
+ loadData({ forceRefresh: true })}
+ />
@@ -222,13 +243,13 @@ const tabStyles = StyleSheet.create({
paddingVertical: 8,
fontSize: 14,
fontWeight: "600",
- color: "#6b7280",
+ color: "#a6adc8",
borderBottomWidth: 2,
borderBottomColor: "transparent",
},
activeTab: {
- color: "#111827",
- borderBottomColor: "#111827",
+ color: "#cdd6f4",
+ borderBottomColor: "#89b4fa",
},
});
@@ -244,7 +265,7 @@ const styles = StyleSheet.create({
tabs: {
flexDirection: "row",
borderBottomWidth: 1,
- borderBottomColor: "#e5e7eb",
+ borderBottomColor: "#45475a",
},
rankList: {
gap: 6,
@@ -254,7 +275,7 @@ const styles = StyleSheet.create({
marginBottom: 0,
},
myCard: {
- borderColor: "#2563eb",
+ borderColor: "#89b4fa",
borderWidth: 2,
},
rankRow: {
@@ -265,14 +286,14 @@ const styles = StyleSheet.create({
rankPos: {
fontSize: 16,
fontWeight: "700",
- color: "#6b7280",
+ color: "#a6adc8",
width: 32,
},
rankName: {
flex: 1,
fontSize: 15,
fontWeight: "600",
- color: "#111827",
+ color: "#cdd6f4",
},
rankRight: {
alignItems: "flex-end",
@@ -280,15 +301,15 @@ const styles = StyleSheet.create({
rankPoints: {
fontSize: 16,
fontWeight: "700",
- color: "#16a34a",
+ color: "#a6e3a1",
},
rankFinds: {
fontSize: 12,
- color: "#9ca3af",
+ color: "#a6adc8",
},
empty: {
textAlign: "center",
- color: "#9ca3af",
+ color: "#a6adc8",
marginTop: 30,
fontSize: 15,
},
diff --git a/src/components/screens/global/GlobalMapScreen.js b/src/components/screens/global/GlobalMapScreen.js
index eada159..5f6e4d1 100644
--- a/src/components/screens/global/GlobalMapScreen.js
+++ b/src/components/screens/global/GlobalMapScreen.js
@@ -1,16 +1,16 @@
-import {useCallback, useEffect, useMemo, useRef, useState} from "react";
-import {ActivityIndicator, StyleSheet, Text, View} from "react-native";
-import MapView, {Circle, Marker, Polygon} from "react-native-maps";
+import { useCallback, useEffect, useMemo, useRef, useState } from "react";
+import { ActivityIndicator, StyleSheet, Text, View } from "react-native";
+import MapView, { Circle, Marker, Polygon } from "react-native-maps";
import * as Location from "expo-location";
import Screen from "../../layout/Screen";
-import {Button, ButtonTray} from "../../UI/Button";
+import { Button, ButtonTray } from "../../UI/Button";
import ClaimTimerView from "../../gameplay/ClaimTimerView";
import CacheList from "../../../entity/cache/CacheList";
import useGlobalHook from "../../../hooks/useGlobalHook";
import usePlayerGame from "../../../hooks/usePlayerGame";
-import {getSession} from "../../../hooks/SessionStore";
-import {getFovCone} from "../../../utils/geoMath";
-import {GAME_MODE} from "../../../utils/gameConstants";
+import { getSession } from "../../../hooks/SessionStore";
+import { getFovCone } from "../../../utils/geoMath";
+import { GAME_MODE } from "../../../utils/gameConstants";
const DEFAULT_REGION = {
latitude: 51.5074,
@@ -77,23 +77,29 @@ const GlobalMapScreen = ({ navigation, route }) => {
// Handlers ----------------------------
- const loadData = useCallback(async (options = {}) => {
- if (!eventId) return;
+ const loadData = useCallback(
+ async (options = {}) => {
+ if (!eventId) return;
- setIsLoading(true);
- setError("");
+ setIsLoading(true);
+ setError("");
- const [cacheData, findsData] = await Promise.all([
- globalApiRef.current.getCachesByEvent(eventId, options),
- session.currentGlobalPlayerId
- ? globalApiRef.current.getFindsByPlayer(session.currentGlobalPlayerId, options)
- : Promise.resolve([]),
- ]);
+ const [cacheData, findsData] = await Promise.all([
+ globalApiRef.current.getCachesByEvent(eventId, options),
+ session.currentGlobalPlayerId
+ ? globalApiRef.current.getFindsByPlayer(
+ session.currentGlobalPlayerId,
+ options,
+ )
+ : Promise.resolve([]),
+ ]);
- setCaches(cacheData || []);
- setFoundCacheIds((findsData || []).map((f) => f.FindCacheID));
- setIsLoading(false);
- }, [eventId, session.currentGlobalPlayerId]);
+ setCaches(cacheData || []);
+ setFoundCacheIds((findsData || []).map((f) => f.FindCacheID));
+ setIsLoading(false);
+ },
+ [eventId, session.currentGlobalPlayerId],
+ );
const handleClaim = useCallback(
async (cacheId) => {
@@ -119,7 +125,7 @@ const GlobalMapScreen = ({ navigation, route }) => {
if (result) {
setClaimedPopupVisible(true);
setTimeout(() => setClaimedPopupVisible(false), 3000);
- await loadData({forceRefresh: true});
+ await loadData({ forceRefresh: true });
}
},
[foundCacheIds, loadData, session.currentGlobalPlayerId, setIsClaiming],
@@ -131,7 +137,9 @@ const GlobalMapScreen = ({ navigation, route }) => {
};
const handleOpenSelectedCache = () => {
- const selected = (caches || []).find((cache) => cache.CacheID === selectedCacheId);
+ const selected = (caches || []).find(
+ (cache) => cache.CacheID === selectedCacheId,
+ );
if (!selected) return;
navigation.navigate("GlobalCacheViewScreen", {
cache: selected,
@@ -166,12 +174,21 @@ const GlobalMapScreen = ({ navigation, route }) => {
]);
useEffect(() => {
- if (!eventId || session.currentGameMode !== GAME_MODE.GLOBAL || !session.currentGlobalPlayerId) {
+ if (
+ !eventId ||
+ session.currentGameMode !== GAME_MODE.GLOBAL ||
+ !session.currentGlobalPlayerId
+ ) {
return;
}
loadData();
- }, [eventId, loadData, session.currentGameMode, session.currentGlobalPlayerId]);
+ }, [
+ eventId,
+ loadData,
+ session.currentGameMode,
+ session.currentGlobalPlayerId,
+ ]);
useEffect(() => {
const routeSelected = route?.params?.selectedCacheId;
@@ -180,7 +197,10 @@ const GlobalMapScreen = ({ navigation, route }) => {
}, [route?.params?.selectedCacheId]);
useEffect(() => {
- if (selectedCacheId && claimableCaches.some((cache) => cache.id === selectedCacheId)) {
+ if (
+ selectedCacheId &&
+ claimableCaches.some((cache) => cache.id === selectedCacheId)
+ ) {
return;
}
setSelectedCacheId(claimableCaches[0]?.id || null);
@@ -291,7 +311,9 @@ const GlobalMapScreen = ({ navigation, route }) => {
}}
title={cache.CacheName}
description={`${cache.CachePoints ?? 0} pts${found ? " ยท Found" : ""}`}
- pinColor={found ? "#22c55e" : selected ? "#f59e0b" : "#ef4444"}
+ pinColor={
+ found ? "#22c55e" : selected ? "#f59e0b" : "#ef4444"
+ }
onPress={() => setSelectedCacheId(cache.CacheID)}
onCalloutPress={() =>
navigation.navigate("GlobalCacheViewScreen", {
@@ -337,9 +359,16 @@ const GlobalMapScreen = ({ navigation, route }) => {
/>
-
+
- loadData({forceRefresh: true})} />
+ loadData({ forceRefresh: true })}
+ />
@@ -362,13 +391,13 @@ const tabStyles = StyleSheet.create({
paddingVertical: 8,
fontSize: 14,
fontWeight: "600",
- color: "#6b7280",
+ color: "#a6adc8",
borderBottomWidth: 2,
borderBottomColor: "transparent",
},
activeTab: {
- color: "#111827",
- borderBottomColor: "#111827",
+ color: "#cdd6f4",
+ borderBottomColor: "#89b4fa",
},
});
@@ -384,13 +413,13 @@ const styles = StyleSheet.create({
tabs: {
flexDirection: "row",
borderBottomWidth: 1,
- borderBottomColor: "#e5e7eb",
+ borderBottomColor: "#45475a",
},
map: {
flex: 1,
},
error: {
- color: "#dc2626",
+ color: "#f38ba8",
fontSize: 14,
},
});
diff --git a/src/components/screens/global/GlobalProfileScreen.js b/src/components/screens/global/GlobalProfileScreen.js
index 27f7c1b..9be2030 100644
--- a/src/components/screens/global/GlobalProfileScreen.js
+++ b/src/components/screens/global/GlobalProfileScreen.js
@@ -242,7 +242,7 @@ const styles = StyleSheet.create({
justifyContent: "center",
},
error: {
- color: "#dc2626",
+ color: "#f38ba8",
fontSize: 14,
},
avatarWrap: {
@@ -257,7 +257,7 @@ const styles = StyleSheet.create({
},
label: {
fontSize: 13,
- color: "#9ca3af",
+ color: "#a6adc8",
fontWeight: "600",
},
input: {