From 4d5eac38b79ad8c15f662dead289c13a6a074412 Mon Sep 17 00:00:00 2001 From: suddenlyoranges Date: Wed, 8 Apr 2026 21:03:03 +0100 Subject: [PATCH] added games screen games screen added to bottom navbar. Now user can go to games screen and select private or public game type --- App.js | 146 +++++++---- src/components/layout/BottomNavbar.js | 247 +++++++++++------- src/components/layout/Screen.js | 35 ++- src/components/screens/GameSelectionScreen.js | 184 +++++++++++++ src/template.js | 13 + 5 files changed, 463 insertions(+), 162 deletions(-) create mode 100644 src/components/screens/GameSelectionScreen.js create mode 100644 src/template.js diff --git a/App.js b/App.js index 222b6a0..1ba19b5 100644 --- a/App.js +++ b/App.js @@ -1,8 +1,8 @@ -import {useEffect, useState} from "react"; -import {ActivityIndicator, View} from "react-native"; -import {NavigationContainer} from "@react-navigation/native"; -import {createNativeStackNavigator} from "@react-navigation/native-stack"; -import {SafeAreaProvider} from "react-native-safe-area-context"; +import { useEffect, useState } from "react"; +import { ActivityIndicator, View } from "react-native"; +import { NavigationContainer } from "@react-navigation/native"; +import { createNativeStackNavigator } from "@react-navigation/native-stack"; +import { SafeAreaProvider } from "react-native-safe-area-context"; import LoginScreen from "./src/components/screens/LoginScreen"; import RegisterScreen from "./src/components/screens/RegisterScreen"; import TeamScreen from "./src/components/screens/TeamScreen"; @@ -11,7 +11,8 @@ import LeaderboardScreen from "./src/components/screens/LeaderboardScreen"; import GameSettingsScreen from "./src/components/screens/GameSettingsScreen"; import PlayersScreen from "./src/components/screens/PlayersScreen"; import ExpandedMapScreen from "./src/components/screens/ExpandedMapScreen"; -import {loadSession} from "./src/hooks/SessionStore"; +import GameSelectionScreen from "./src/components/screens/GameSelectionScreen"; +import { loadSession } from "./src/hooks/SessionStore"; const RootStack = createNativeStackNavigator(); const AuthStackNav = createNativeStackNavigator(); @@ -19,71 +20,106 @@ const GameStackNav = createNativeStackNavigator(); const AdminStackNav = createNativeStackNavigator(); const screenOptions = { - headerShown: false, - contentStyle: {backgroundColor: '#ffffff'}, + headerShown: false, + contentStyle: { backgroundColor: "#ffffff" }, }; const AuthStack = () => ( - - - - + + + + ); const GameStack = () => ( - - - - - - - + + + + + + + + ); const AdminStack = () => ( - - - - - - - - + + + + + + + + + ); export const App = () => { - // Load persisted session from AsyncStorage before choosing initial route - const [loading, setLoading] = useState(true); - const [initialRoute, setInitialRoute] = useState('Auth'); + // Load persisted session from AsyncStorage before choosing initial route + const [loading, setLoading] = useState(true); + const [initialRoute, setInitialRoute] = useState("Auth"); - useEffect(() => { - loadSession().then((session) => { - if (session.currentUid) { - setInitialRoute(session.isAcceptedAdmin ? 'Admin' : 'Game'); - } - setLoading(false); - }); - }, []); - - if (loading) { - return ( - - - - ); - } + useEffect(() => { + loadSession().then((session) => { + if (session.currentUid) { + setInitialRoute(session.isAcceptedAdmin ? "Admin" : "Game"); + } + setLoading(false); + }); + }, []); + if (loading) { return ( - - - - - - - - - + + + ); + } + + return ( + + + + + + + + + + ); }; export default App; diff --git a/src/components/layout/BottomNavbar.js b/src/components/layout/BottomNavbar.js index 528699a..0e68805 100644 --- a/src/components/layout/BottomNavbar.js +++ b/src/components/layout/BottomNavbar.js @@ -1,113 +1,164 @@ -import {Alert, Pressable, StyleSheet, Text, View} from 'react-native'; -import {useSafeAreaInsets} from 'react-native-safe-area-context'; -import {clearGameSession, getSession} from '../../hooks/SessionStore'; -import API, {API_BASE_URL} from '../API/API'; +import { Alert, Pressable, StyleSheet, Text, View } from "react-native"; +import { useSafeAreaInsets } from "react-native-safe-area-context"; +import { clearGameSession, getSession } from "../../hooks/SessionStore"; +import API, { API_BASE_URL } from "../API/API"; -const BottomNavbar = ({navigation, routeName}) => { -// Initialisation ------------ +const BottomNavbar = ({ navigation, routeName }) => { + // Initialisation ------------ - const insets = useSafeAreaInsets(); - const session = getSession(); + const insets = useSafeAreaInsets(); + const session = getSession(); - const adminTabs = [ - {label: 'Settings', route: 'GameSettingsScreen', onPress: () => navigation.navigate('GameSettingsScreen')}, - {label: 'Map', route: 'MapScreen', onPress: () => navigation.navigate('MapScreen')}, - {label: 'Players', route: 'PlayersScreen', onPress: () => navigation.navigate('PlayersScreen')}, - {label: 'Leaderboard', route: 'LeaderboardScreen', onPress: () => navigation.navigate('LeaderboardScreen')}, - ]; + const adminTabs = [ + { + label: "Settings", + route: "GameSettingsScreen", + onPress: () => navigation.navigate("GameSettingsScreen"), + }, + { + label: "Map", + route: "MapScreen", + onPress: () => navigation.navigate("MapScreen"), + }, + { + label: "Players", + route: "PlayersScreen", + onPress: () => navigation.navigate("PlayersScreen"), + }, + { + label: "Leaderboard", + route: "LeaderboardScreen", + onPress: () => navigation.navigate("LeaderboardScreen"), + }, + { + label: "Games", + route: "GameSelectionScreen", + onPress: () => navigation.navigate("GameSelectionScreen"), + }, + ]; - const playerTabs = [ - {label: 'Team', route: 'TeamScreen', onPress: () => navigation.navigate('TeamScreen')}, - {label: 'Map', route: 'MapScreen', onPress: () => navigation.navigate('MapScreen')}, - {label: 'Leaderboard', route: 'LeaderboardScreen', onPress: () => navigation.navigate('LeaderboardScreen')}, - {label: 'Leave', route: '__leave__', onPress: () => handleLeaveGame()}, - ]; + const playerTabs = [ + { + label: "Team", + route: "TeamScreen", + onPress: () => navigation.navigate("TeamScreen"), + }, + { + label: "Map", + route: "MapScreen", + onPress: () => navigation.navigate("MapScreen"), + }, + { + label: "Leaderboard", + route: "LeaderboardScreen", + onPress: () => navigation.navigate("LeaderboardScreen"), + }, + { + label: "Games", + route: "GameSelectionScreen", + onPress: () => navigation.navigate("GameSelectionScreen"), + }, - const tabs = session.isAcceptedAdmin ? adminTabs : playerTabs; + { label: "Leave", route: "__leave__", onPress: () => handleLeaveGame() }, + ]; -// State ---------------------- -// Handlers ------------------- + const tabs = session.isAcceptedAdmin ? adminTabs : playerTabs; - const handleLeaveGame = () => { - Alert.alert('Leave Game', 'Are you sure you want to leave this game?', [ - {text: 'Cancel', style: 'cancel'}, - { - text: 'Leave', - style: 'destructive', - onPress: async () => { - const s = getSession(); - const endpoint = `${API_BASE_URL}/subgroup-memberships?Uid=${s.currentUid}&Gid=${s.currentGid}`; - const res = await API.get(endpoint); - if (res.isSuccess && res.result.length > 0) { - await API.delete(`${API_BASE_URL}/subgroup-memberships/${res.result[0].id}`); - } - clearGameSession(); - navigation.reset({index: 0, routes: [{name: 'Game'}]}); - }, - }, - ]); - }; + // State ---------------------- + // Handlers ------------------- -// View ----------------------- + const handleLeaveGame = () => { + Alert.alert("Leave Game", "Are you sure you want to leave this game?", [ + { text: "Cancel", style: "cancel" }, + { + text: "Leave", + style: "destructive", + onPress: async () => { + const s = getSession(); + const endpoint = `${API_BASE_URL}/subgroup-memberships?Uid=${s.currentUid}&Gid=${s.currentGid}`; + const res = await API.get(endpoint); + if (res.isSuccess && res.result.length > 0) { + await API.delete( + `${API_BASE_URL}/subgroup-memberships/${res.result[0].id}`, + ); + } + clearGameSession(); + navigation.reset({ index: 0, routes: [{ name: "Game" }] }); + }, + }, + ]); + }; - return ( - - {tabs.map((tab) => { - const isActive = routeName === tab.route; - const isLeave = tab.route === '__leave__'; - return ( - - - {tab.label} - - - ); - })} - - ); + // View ----------------------- + + return ( + + {tabs.map((tab) => { + const isActive = routeName === tab.route; + const isLeave = tab.route === "__leave__"; + return ( + + + {tab.label} + + + ); + })} + + ); }; const styles = StyleSheet.create({ - container: { - minHeight: 64, - borderTopWidth: 1, - borderTopColor: '#555555', - backgroundColor: '#4a4a4a', - flexDirection: 'row', - alignItems: 'center', - justifyContent: 'space-around', - paddingHorizontal: 8, - }, - tab: { - flex: 1, - alignItems: 'center', - justifyContent: 'center', - paddingVertical: 12, - borderRadius: 8, - marginHorizontal: 4, - }, - tabActive: { - backgroundColor: '#5c5c5c', - }, - tabLeave: { - backgroundColor: 'rgba(220,38,38,0.15)', - }, - tabText: { - color: '#d1d5db', - fontSize: 12, - fontWeight: '600', - textAlign: 'center', - }, - tabTextActive: { - color: '#ffffff', - }, - tabTextLeave: { - color: '#fca5a5', - }, + container: { + minHeight: 64, + borderTopWidth: 1, + borderTopColor: "#555555", + backgroundColor: "#4a4a4a", + flexDirection: "row", + alignItems: "center", + justifyContent: "space-around", + paddingHorizontal: 8, + }, + tab: { + flex: 1, + alignItems: "center", + justifyContent: "center", + paddingVertical: 12, + borderRadius: 8, + marginHorizontal: 4, + }, + tabActive: { + backgroundColor: "#5c5c5c", + }, + tabLeave: { + backgroundColor: "rgba(220,38,38,0.15)", + }, + tabText: { + color: "#d1d5db", + fontSize: 12, + fontWeight: "600", + textAlign: "center", + }, + tabTextActive: { + color: "#ffffff", + }, + tabTextLeave: { + color: "#fca5a5", + }, }); export default BottomNavbar; diff --git a/src/components/layout/Screen.js b/src/components/layout/Screen.js index 95957bd..25ffb0a 100644 --- a/src/components/layout/Screen.js +++ b/src/components/layout/Screen.js @@ -1,7 +1,7 @@ -import {StatusBar} from "expo-status-bar"; -import {StyleSheet, View} from "react-native"; -import {useNavigation, useRoute} from "@react-navigation/native"; -import {useSafeAreaInsets} from "react-native-safe-area-context"; +import { StatusBar } from "expo-status-bar"; +import { StyleSheet, View } from "react-native"; +import { useNavigation, useRoute } from "@react-navigation/native"; +import { useSafeAreaInsets } from "react-native-safe-area-context"; import TopNavbar from "./TopNavbar"; import BottomNavbar from "./BottomNavbar"; @@ -17,6 +17,7 @@ const Screen = ({ children, style, showBack = false }) => { TeamScreen: "Current Team", MapScreen: "Map", GameSettingsScreen: "Game Settings", + GameSelectionScreen: "Games", PlayersScreen: "Players", ExpandedMapScreen: "Map View", }; @@ -24,17 +25,34 @@ const Screen = ({ children, style, showBack = false }) => { // State ---------------------- const routeName = route.name; - const isAuthScreen = routeName === "LoginScreen" || routeName === "RegisterScreen"; + const isAuthScreen = + routeName === "LoginScreen" || routeName === "RegisterScreen"; const pageTitle = titleMap[routeName] || "Treasure Hunt"; // Handlers ------------------- // View ----------------------- return ( - - {!isAuthScreen && } + + {!isAuthScreen && ( + + )} {children} - {!isAuthScreen && } + {!isAuthScreen && ( + + )} ); @@ -52,4 +70,3 @@ const styles = StyleSheet.create({ }); export default Screen; - diff --git a/src/components/screens/GameSelectionScreen.js b/src/components/screens/GameSelectionScreen.js new file mode 100644 index 0000000..5377e5c --- /dev/null +++ b/src/components/screens/GameSelectionScreen.js @@ -0,0 +1,184 @@ +import { ScrollView, StyleSheet, Text, View } from "react-native"; +import Screen from "../layout/Screen"; +import Card from "../UI/Card"; +import { Button, ButtonTray } from "../UI/Button"; +import { getSession } from "../../hooks/SessionStore"; + +const GameSelectionScreen = ({ navigation }) => { + // Initialisations --------------------- + + const session = getSession(); + const isAdmin = Boolean(session.isAcceptedAdmin); + + const privateGames = [ + { + id: "active-game", + name: "Private Game", + players: "4 players", + endsIn: "Ends in 2h 15m", + }, + ]; + + // State ------------------------------- + // Handlers ---------------------------- + + const handleCreateGame = () => { + if (isAdmin) { + navigation.navigate("GameSettingsScreen"); + return; + } + navigation.navigate("TeamScreen"); + }; + + const handleOpenGame = () => { + navigation.navigate("TeamScreen"); + }; + + const handleExplore = () => { + navigation.navigate("MapScreen"); + }; + + // View -------------------------------- + + return ( + + + + Your Games + +