mirror of
https://github.com/mudabbir-ahmad/MAD-Treasure-Hunt.git
synced 2026-10-07 19:00:20 +00:00
fixed issues with merge + Global logic
This commit is contained in:
1 parent
b9b11463cc
commit
20a2edbbda
18 files changed
+386
-346
No files matched your search
@@ -12,7 +12,6 @@ import GameSettingsScreen from "./src/components/screens/GameSettingsScreen";
|
|||||||
import DepartmentSettingsScreen from "./src/components/screens/DepartmentSettingsScreen";
|
import DepartmentSettingsScreen from "./src/components/screens/DepartmentSettingsScreen";
|
||||||
import PlayersScreen from "./src/components/screens/PlayersScreen";
|
import PlayersScreen from "./src/components/screens/PlayersScreen";
|
||||||
import ExpandedMapScreen from "./src/components/screens/ExpandedMapScreen";
|
import ExpandedMapScreen from "./src/components/screens/ExpandedMapScreen";
|
||||||
import GameSelectionScreen from "./src/components/screens/GameSelectionScreen";
|
|
||||||
import GlobalEventsScreen from "./src/components/screens/global/GlobalEventsScreen";
|
import GlobalEventsScreen from "./src/components/screens/global/GlobalEventsScreen";
|
||||||
import GlobalMapScreen from "./src/components/screens/global/GlobalMapScreen";
|
import GlobalMapScreen from "./src/components/screens/global/GlobalMapScreen";
|
||||||
import GlobalCacheViewScreen from "./src/components/screens/global/GlobalCacheViewScreen";
|
import GlobalCacheViewScreen from "./src/components/screens/global/GlobalCacheViewScreen";
|
||||||
@@ -26,7 +25,7 @@ const AdminStackNav = createNativeStackNavigator();
|
|||||||
|
|
||||||
const screenOptions = {
|
const screenOptions = {
|
||||||
headerShown: false,
|
headerShown: false,
|
||||||
contentStyle: { backgroundColor: "#ffffff" },
|
contentStyle: { backgroundColor: "#1e1e2e" },
|
||||||
};
|
};
|
||||||
|
|
||||||
const AuthStack = () => (
|
const AuthStack = () => (
|
||||||
@@ -40,10 +39,6 @@ const AuthStack = () => (
|
|||||||
|
|
||||||
const GameStack = () => (
|
const GameStack = () => (
|
||||||
<GameStackNav.Navigator screenOptions={screenOptions}>
|
<GameStackNav.Navigator screenOptions={screenOptions}>
|
||||||
<GameStackNav.Screen
|
|
||||||
name="GameSelectionScreen"
|
|
||||||
component={GameSelectionScreen}
|
|
||||||
/>
|
|
||||||
<GameStackNav.Screen name="MapScreen" component={MapScreen} />
|
<GameStackNav.Screen name="MapScreen" component={MapScreen} />
|
||||||
<GameStackNav.Screen name="TeamScreen" component={TeamScreen} />
|
<GameStackNav.Screen name="TeamScreen" component={TeamScreen} />
|
||||||
<GameStackNav.Screen
|
<GameStackNav.Screen
|
||||||
@@ -73,14 +68,14 @@ const GameStack = () => (
|
|||||||
|
|
||||||
const AdminStack = () => (
|
const AdminStack = () => (
|
||||||
<AdminStackNav.Navigator screenOptions={screenOptions}>
|
<AdminStackNav.Navigator screenOptions={screenOptions}>
|
||||||
<AdminStackNav.Screen
|
|
||||||
name="GameSelectionScreen"
|
|
||||||
component={GameSelectionScreen}
|
|
||||||
/>
|
|
||||||
<AdminStackNav.Screen
|
<AdminStackNav.Screen
|
||||||
name="GameSettingsScreen"
|
name="GameSettingsScreen"
|
||||||
component={GameSettingsScreen}
|
component={GameSettingsScreen}
|
||||||
/>
|
/>
|
||||||
|
<AdminStackNav.Screen
|
||||||
|
name="DepartmentSettingsScreen"
|
||||||
|
component={DepartmentSettingsScreen}
|
||||||
|
/>
|
||||||
<AdminStackNav.Screen name="MapScreen" component={MapScreen} />
|
<AdminStackNav.Screen name="MapScreen" component={MapScreen} />
|
||||||
<AdminStackNav.Screen
|
<AdminStackNav.Screen
|
||||||
name="LeaderboardScreen"
|
name="LeaderboardScreen"
|
||||||
@@ -106,15 +101,6 @@ const AdminStack = () => (
|
|||||||
component={GlobalLeaderboardScreen}
|
component={GlobalLeaderboardScreen}
|
||||||
/>
|
/>
|
||||||
</AdminStackNav.Navigator>
|
</AdminStackNav.Navigator>
|
||||||
<AdminStackNav.Navigator screenOptions={screenOptions}>
|
|
||||||
<AdminStackNav.Screen name="GameSettingsScreen" component={GameSettingsScreen}/>
|
|
||||||
<AdminStackNav.Screen name="DepartmentSettingsScreen" component={DepartmentSettingsScreen}/>
|
|
||||||
<AdminStackNav.Screen name="MapScreen" component={MapScreen}/>
|
|
||||||
<AdminStackNav.Screen name="LeaderboardScreen" component={LeaderboardScreen}/>
|
|
||||||
<AdminStackNav.Screen name="PlayersScreen" component={PlayersScreen}/>
|
|
||||||
<AdminStackNav.Screen name="ExpandedMapScreen" component={ExpandedMapScreen}/>
|
|
||||||
<AdminStackNav.Screen name="TeamScreen" component={TeamScreen}/>
|
|
||||||
</AdminStackNav.Navigator>
|
|
||||||
);
|
);
|
||||||
|
|
||||||
export const App = () => {
|
export const App = () => {
|
||||||
|
|||||||
Binary file not shown.
|
After Width: | Height: | Size: 34 KiB |
@@ -36,6 +36,7 @@ const styles = StyleSheet.create({
|
|||||||
flex: 1,
|
flex: 1,
|
||||||
flexDirection: "row",
|
flexDirection: "row",
|
||||||
gap: 5,
|
gap: 5,
|
||||||
|
marginHorizontal: 4,
|
||||||
},
|
},
|
||||||
label: {
|
label: {
|
||||||
fontSize: 16,
|
fontSize: 16,
|
||||||
|
|||||||
@@ -0,0 +1,75 @@
|
|||||||
|
import {StyleSheet, TextInput, View} from 'react-native';
|
||||||
|
import {Button} from './Button';
|
||||||
|
|
||||||
|
const CodeJoinRow = ({
|
||||||
|
value,
|
||||||
|
onChange,
|
||||||
|
placeholder,
|
||||||
|
buttonLabel = 'Join',
|
||||||
|
onSubmit,
|
||||||
|
disabled = false,
|
||||||
|
style,
|
||||||
|
}) => {
|
||||||
|
// Initialisation -------------
|
||||||
|
// State ----------------------
|
||||||
|
// Handlers -------------------
|
||||||
|
// View -----------------------
|
||||||
|
|
||||||
|
return (
|
||||||
|
<View style={[styles.inputRow, style]}>
|
||||||
|
<TextInput
|
||||||
|
style={[styles.codeInput, disabled && styles.inputDisabled]}
|
||||||
|
placeholder={placeholder}
|
||||||
|
placeholderTextColor="#9ca3af"
|
||||||
|
value={value}
|
||||||
|
onChangeText={(text) => onChange(text.toUpperCase())}
|
||||||
|
autoCapitalize="characters"
|
||||||
|
editable={!disabled}
|
||||||
|
/>
|
||||||
|
<Button
|
||||||
|
label={buttonLabel}
|
||||||
|
onClick={onSubmit}
|
||||||
|
styleButton={styles.joinButton}
|
||||||
|
styleLabel={styles.joinLabel}
|
||||||
|
disabled={disabled}
|
||||||
|
/>
|
||||||
|
</View>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
const styles = StyleSheet.create({
|
||||||
|
inputRow: {
|
||||||
|
flexDirection: 'row',
|
||||||
|
gap: 10,
|
||||||
|
marginBottom: 15,
|
||||||
|
width: '100%',
|
||||||
|
paddingHorizontal: 20,
|
||||||
|
},
|
||||||
|
codeInput: {
|
||||||
|
flex: 1,
|
||||||
|
borderWidth: 1,
|
||||||
|
borderColor: '#45475a',
|
||||||
|
borderRadius: 8,
|
||||||
|
paddingHorizontal: 12,
|
||||||
|
paddingVertical: 10,
|
||||||
|
fontSize: 16,
|
||||||
|
color: '#cdd6f4',
|
||||||
|
backgroundColor: '#313244',
|
||||||
|
},
|
||||||
|
inputDisabled: {
|
||||||
|
opacity: 0.5,
|
||||||
|
},
|
||||||
|
joinButton: {
|
||||||
|
backgroundColor: '#bd93f9',
|
||||||
|
borderColor: '#bd93f9',
|
||||||
|
flex: 0,
|
||||||
|
paddingHorizontal: 20,
|
||||||
|
},
|
||||||
|
joinLabel: {
|
||||||
|
color: '#1e1e2e',
|
||||||
|
fontWeight: '600',
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
export default CodeJoinRow;
|
||||||
|
|
||||||
@@ -1,84 +1,63 @@
|
|||||||
import { Alert, Pressable, StyleSheet, Text, View } from "react-native";
|
import {Alert, Image, Pressable, StyleSheet, Text, View} from 'react-native';
|
||||||
import { useSafeAreaInsets } from "react-native-safe-area-context";
|
import {useSafeAreaInsets} from 'react-native-safe-area-context';
|
||||||
import { clearGameSession, getSession } from "../../hooks/SessionStore";
|
import {clearGameSession, clearGlobalSession, getSession, setSessionMode} from '../../hooks/SessionStore';
|
||||||
import API, { API_BASE_URL } from "../API/API";
|
import API, {API_BASE_URL} from '../API/API';
|
||||||
|
import {GAME_MODE} from '../../utils/gameConstants';
|
||||||
|
|
||||||
|
const iconMap = {
|
||||||
|
Settings: require('../../../assets/icons/settings-icon.png'),
|
||||||
|
Events: require('../../../assets/icons/events-icon.png'),
|
||||||
|
Map: require('../../../assets/icons/Map-icon.png'),
|
||||||
|
Leaderboard: require('../../../assets/icons/Leaderboard-icon.png'),
|
||||||
|
Team: require('../../../assets/icons/Teams-icon.png'),
|
||||||
|
Players: require('../../../assets/icons/Teams-icon.png'),
|
||||||
|
};
|
||||||
|
|
||||||
const BottomNavbar = ({ navigation, routeName }) => {
|
|
||||||
// Initialisation ------------
|
|
||||||
const BottomNavbar = ({navigation, routeName, routeParams}) => {
|
const BottomNavbar = ({navigation, routeName, routeParams}) => {
|
||||||
// Initialisation ------------
|
// Initialisation ------------
|
||||||
|
|
||||||
const insets = useSafeAreaInsets();
|
const insets = useSafeAreaInsets();
|
||||||
const session = getSession();
|
const session = getSession();
|
||||||
|
const inGame = Boolean(session.currentGid);
|
||||||
|
const isGlobalMode = !session.isBusiness && session.currentGameMode === GAME_MODE.GLOBAL;
|
||||||
|
|
||||||
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"),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: "Global",
|
|
||||||
route: "GlobalEventsScreen",
|
|
||||||
onPress: () => navigation.navigate("GlobalEventsScreen"),
|
|
||||||
},
|
|
||||||
];
|
|
||||||
|
|
||||||
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"),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: "Global",
|
|
||||||
route: "GlobalEventsScreen",
|
|
||||||
onPress: () => navigation.navigate("GlobalEventsScreen"),
|
|
||||||
},
|
|
||||||
|
|
||||||
{ label: "Leave", route: "__leave__", onPress: () => handleLeaveGame() },
|
|
||||||
];
|
|
||||||
|
|
||||||
const tabs = session.isAcceptedAdmin ? adminTabs : playerTabs;
|
|
||||||
const selectedDepartment = routeName === 'DepartmentSettingsScreen' && routeParams?.SGid
|
const selectedDepartment = routeName === 'DepartmentSettingsScreen' && routeParams?.SGid
|
||||||
? {SGid: routeParams.SGid, SubGroupName: routeParams.SubGroupName || routeParams.selectedDepartmentName || 'Department'}
|
? {
|
||||||
|
SGid: routeParams.SGid,
|
||||||
|
SubGroupName: routeParams.SubGroupName || routeParams.selectedDepartmentName || 'Department',
|
||||||
|
}
|
||||||
: null;
|
: null;
|
||||||
|
|
||||||
|
// State ----------------------
|
||||||
|
// Handlers -------------------
|
||||||
|
|
||||||
|
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 currentSession = getSession();
|
||||||
|
const endpoint = `${API_BASE_URL}/subgroup-members?Uid=${currentSession.currentUid}&Gid=${currentSession.currentGid}`;
|
||||||
|
const response = await API.get(endpoint);
|
||||||
|
if (response.isSuccess && response.result.length > 0) {
|
||||||
|
await API.delete(`${API_BASE_URL}/subgroup-members/${response.result[0].id}`);
|
||||||
|
}
|
||||||
|
clearGameSession();
|
||||||
|
const rootNav = navigation.getParent() || navigation;
|
||||||
|
rootNav.reset({index: 0, routes: [{name: 'Game'}]});
|
||||||
|
},
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleExitGlobal = () => {
|
||||||
|
clearGlobalSession();
|
||||||
|
setSessionMode(session.currentGid ? GAME_MODE.REGULAR : null);
|
||||||
|
navigation.navigate('MapScreen');
|
||||||
|
};
|
||||||
|
|
||||||
const adminTabs = [
|
const adminTabs = [
|
||||||
{label: 'Settings', route: 'GameSettingsScreen', onPress: () => navigation.navigate('GameSettingsScreen')},
|
{label: 'Settings', route: 'GameSettingsScreen', onPress: () => navigation.navigate('GameSettingsScreen')},
|
||||||
{
|
{
|
||||||
@@ -101,149 +80,51 @@ const BottomNavbar = ({navigation, routeName, routeParams}) => {
|
|||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
// Only show the Leave tab when the player is actually in a game
|
|
||||||
const inGame = Boolean(session.currentGid);
|
|
||||||
|
|
||||||
const playerTabs = [
|
const playerTabs = [
|
||||||
{label: 'Team', route: 'TeamScreen', onPress: () => navigation.navigate('TeamScreen')},
|
{label: 'Team', route: 'TeamScreen', onPress: () => navigation.navigate('TeamScreen')},
|
||||||
{label: 'Map', route: 'MapScreen', onPress: () => navigation.navigate('MapScreen')},
|
{label: 'Map', route: 'MapScreen', onPress: () => navigation.navigate('MapScreen')},
|
||||||
{label: 'Leaderboard', route: 'LeaderboardScreen', onPress: () => navigation.navigate('LeaderboardScreen')},
|
{label: 'Leaderboard', route: 'LeaderboardScreen', onPress: () => navigation.navigate('LeaderboardScreen')},
|
||||||
...(inGame ? [{label: 'Leave', route: '__leave__', onPress: () => handleLeaveGame()}] : []),
|
...(inGame ? [{label: 'Leave', route: '__leave__', onPress: handleLeaveGame}] : []),
|
||||||
];
|
];
|
||||||
|
|
||||||
const tabs = session.isAcceptedAdmin ? adminTabs : playerTabs;
|
|
||||||
const pendingTabs = [
|
const pendingTabs = [
|
||||||
{label: 'Pending', route: 'TeamScreen', onPress: () => navigation.navigate('TeamScreen')},
|
{label: 'Pending', route: 'TeamScreen', onPress: () => navigation.navigate('TeamScreen')},
|
||||||
...(inGame ? [{label: 'Leave', route: '__leave__', onPress: () => handleLeaveGame()}] : []),
|
...(inGame ? [{label: 'Leave', route: '__leave__', onPress: handleLeaveGame}] : []),
|
||||||
];
|
];
|
||||||
const visibleTabs = (session.isPendingAdmin && !session.isAcceptedAdmin) ? pendingTabs : tabs;
|
|
||||||
|
|
||||||
// State ----------------------
|
const globalTabs = [
|
||||||
// Handlers -------------------
|
{label: 'Events', route: 'GlobalEventsScreen', onPress: () => navigation.navigate('GlobalEventsScreen')},
|
||||||
|
{label: 'Map', route: 'GlobalMapScreen', onPress: () => navigation.navigate('GlobalMapScreen')},
|
||||||
|
{label: 'Leaderboard', route: 'GlobalLeaderboardScreen', onPress: () => navigation.navigate('GlobalLeaderboardScreen')},
|
||||||
|
{label: 'Exit', route: '__exit_global__', onPress: handleExitGlobal},
|
||||||
|
];
|
||||||
|
|
||||||
const handleLeaveGame = () => {
|
let visibleTabs = session.isAcceptedAdmin ? adminTabs : playerTabs;
|
||||||
Alert.alert("Leave Game", "Are you sure you want to leave this game?", [
|
if (session.isPendingAdmin && !session.isAcceptedAdmin) {
|
||||||
{ text: "Cancel", style: "cancel" },
|
visibleTabs = pendingTabs;
|
||||||
{
|
|
||||||
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();
|
if (isGlobalMode) {
|
||||||
navigation.reset({ index: 0, routes: [{ name: "Game" }] });
|
visibleTabs = globalTabs;
|
||||||
},
|
|
||||||
},
|
|
||||||
]);
|
|
||||||
};
|
|
||||||
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-members?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-members/${res.result[0].id}`);
|
|
||||||
}
|
}
|
||||||
clearGameSession();
|
|
||||||
navigation.reset({index: 0, routes: [{name: 'Game'}]});
|
|
||||||
},
|
|
||||||
},
|
|
||||||
]);
|
|
||||||
};
|
|
||||||
|
|
||||||
// View -----------------------
|
// View -----------------------
|
||||||
|
|
||||||
return (
|
|
||||||
<View style={[styles.container, { paddingBottom: insets.bottom }]}>
|
|
||||||
{tabs.map((tab) => {
|
|
||||||
const isActive = routeName === tab.route;
|
|
||||||
const isLeave = tab.route === "__leave__";
|
|
||||||
return (
|
|
||||||
<Pressable
|
|
||||||
key={tab.label}
|
|
||||||
onPress={tab.onPress}
|
|
||||||
style={[
|
|
||||||
styles.tab,
|
|
||||||
isActive && styles.tabActive,
|
|
||||||
isLeave && styles.tabLeave,
|
|
||||||
]}
|
|
||||||
>
|
|
||||||
<Text
|
|
||||||
style={[
|
|
||||||
styles.tabText,
|
|
||||||
isActive && styles.tabTextActive,
|
|
||||||
isLeave && styles.tabTextLeave,
|
|
||||||
]}
|
|
||||||
>
|
|
||||||
{tab.label}
|
|
||||||
</Text>
|
|
||||||
</Pressable>
|
|
||||||
);
|
|
||||||
})}
|
|
||||||
</View>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
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",
|
|
||||||
},
|
|
||||||
return (
|
return (
|
||||||
<View style={[styles.container, {paddingBottom: insets.bottom}]}>
|
<View style={[styles.container, {paddingBottom: insets.bottom}]}>
|
||||||
{visibleTabs.map((tab) => {
|
{visibleTabs.map((tab) => {
|
||||||
const isActive = routeName === tab.route;
|
const isActive = routeName === tab.route;
|
||||||
const isLeave = tab.route === '__leave__';
|
const isLeave = tab.route === '__leave__';
|
||||||
|
const isExitGlobal = tab.route === '__exit_global__';
|
||||||
|
const iconSource = iconMap[tab.label];
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Pressable
|
<Pressable
|
||||||
key={tab.label}
|
key={tab.label}
|
||||||
onPress={tab.onPress}
|
onPress={tab.onPress}
|
||||||
style={[styles.tab, isActive && styles.tabActive, isLeave && styles.tabLeave]}
|
style={[styles.tab, isActive && styles.tabActive, (isLeave || isExitGlobal) && styles.tabLeave]}
|
||||||
>
|
>
|
||||||
<Text style={[styles.tabText, isActive && styles.tabTextActive, isLeave && styles.tabTextLeave]}>
|
{iconSource ? <Image source={iconSource} style={styles.icon} resizeMode="contain" /> : null}
|
||||||
|
<Text style={[styles.tabText, isActive && styles.tabTextActive, (isLeave || isExitGlobal) && styles.tabTextLeave]}>
|
||||||
{tab.label}
|
{tab.label}
|
||||||
</Text>
|
</Text>
|
||||||
</Pressable>
|
</Pressable>
|
||||||
@@ -269,14 +150,20 @@ const styles = StyleSheet.create({
|
|||||||
flex: 1,
|
flex: 1,
|
||||||
alignItems: 'center',
|
alignItems: 'center',
|
||||||
justifyContent: 'center',
|
justifyContent: 'center',
|
||||||
paddingVertical: 12,
|
paddingVertical: 8,
|
||||||
marginHorizontal: 4,
|
marginHorizontal: 4,
|
||||||
|
gap: 4,
|
||||||
},
|
},
|
||||||
tabActive: {
|
tabActive: {
|
||||||
backgroundColor: '#45475a',
|
backgroundColor: '#45475a',
|
||||||
},
|
},
|
||||||
tabLeave: {
|
tabLeave: {
|
||||||
backgroundColor: 'rgba(243, 139, 168, 0.15)',
|
backgroundColor: 'rgba(217, 40, 0, 0.15)',
|
||||||
|
},
|
||||||
|
icon: {
|
||||||
|
width: 16,
|
||||||
|
height: 16,
|
||||||
|
opacity: 0.95,
|
||||||
},
|
},
|
||||||
tabText: {
|
tabText: {
|
||||||
color: '#bac2de',
|
color: '#bac2de',
|
||||||
@@ -288,7 +175,7 @@ const styles = StyleSheet.create({
|
|||||||
color: '#cdd6f4',
|
color: '#cdd6f4',
|
||||||
},
|
},
|
||||||
tabTextLeave: {
|
tabTextLeave: {
|
||||||
color: '#D92800',
|
color: '#ffffff',
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
import { StatusBar } from "expo-status-bar";
|
import {StatusBar} from 'expo-status-bar';
|
||||||
import { StyleSheet, View } from "react-native";
|
import {StyleSheet, View} from 'react-native';
|
||||||
import { useNavigation, useRoute } from "@react-navigation/native";
|
import {useNavigation, useRoute} from '@react-navigation/native';
|
||||||
import { useSafeAreaInsets } from "react-native-safe-area-context";
|
import {useSafeAreaInsets} from 'react-native-safe-area-context';
|
||||||
import TopNavbar from "./TopNavbar";
|
import TopNavbar from './TopNavbar';
|
||||||
import BottomNavbar from "./BottomNavbar";
|
import BottomNavbar from './BottomNavbar';
|
||||||
|
|
||||||
const Screen = ({children, style, showBack = false}) => {
|
const Screen = ({children, style, showBack = false}) => {
|
||||||
// Initialisation -------------
|
// Initialisation -------------
|
||||||
@@ -13,26 +13,25 @@ const Screen = ({ children, style, showBack = false }) => {
|
|||||||
const insets = useSafeAreaInsets();
|
const insets = useSafeAreaInsets();
|
||||||
|
|
||||||
const titleMap = {
|
const titleMap = {
|
||||||
LeaderboardScreen: "Leaderboard",
|
LeaderboardScreen: 'Leaderboard',
|
||||||
TeamScreen: "Current Team",
|
TeamScreen: 'Current Team',
|
||||||
MapScreen: "Map",
|
MapScreen: 'Map',
|
||||||
GameSettingsScreen: "Game Settings",
|
GameSettingsScreen: 'Game Settings',
|
||||||
GameSelectionScreen: "Games",
|
GameSelectionScreen: 'Games',
|
||||||
DepartmentSettingsScreen: "Department Settings",
|
DepartmentSettingsScreen: 'Department Settings',
|
||||||
PlayersScreen: "Players",
|
PlayersScreen: 'Players',
|
||||||
ExpandedMapScreen: "Map View",
|
ExpandedMapScreen: 'Map View',
|
||||||
GlobalEventsScreen: "Global Events",
|
GlobalEventsScreen: 'Global Events',
|
||||||
GlobalMapScreen: "Global Map",
|
GlobalMapScreen: 'Global Map',
|
||||||
GlobalCacheViewScreen: "Cache Details",
|
GlobalCacheViewScreen: 'Cache Details',
|
||||||
GlobalLeaderboardScreen: "Global Leaderboard",
|
GlobalLeaderboardScreen: 'Global Leaderboard',
|
||||||
};
|
};
|
||||||
|
|
||||||
// State ----------------------
|
// State ----------------------
|
||||||
|
|
||||||
const routeName = route.name;
|
const routeName = route.name;
|
||||||
const isAuthScreen =
|
const isAuthScreen = routeName === 'LoginScreen' || routeName === 'RegisterScreen';
|
||||||
routeName === "LoginScreen" || routeName === "RegisterScreen";
|
const pageTitle = titleMap[routeName] || 'Treasure Hunt';
|
||||||
const pageTitle = titleMap[routeName] || "Treasure Hunt";
|
|
||||||
|
|
||||||
// Handlers -------------------
|
// Handlers -------------------
|
||||||
// View -----------------------
|
// View -----------------------
|
||||||
@@ -56,9 +55,12 @@ const Screen = ({ children, style, showBack = false }) => {
|
|||||||
)}
|
)}
|
||||||
<View style={[styles.content, style]}>{children}</View>
|
<View style={[styles.content, style]}>{children}</View>
|
||||||
{!isAuthScreen && (
|
{!isAuthScreen && (
|
||||||
<BottomNavbar navigation={navigation} routeName={routeName} />
|
<BottomNavbar
|
||||||
|
navigation={navigation}
|
||||||
|
routeName={routeName}
|
||||||
|
routeParams={route.params}
|
||||||
|
/>
|
||||||
)}
|
)}
|
||||||
{!isAuthScreen && <BottomNavbar navigation={navigation} routeName={routeName} routeParams={route.params} />}
|
|
||||||
<StatusBar style="light" />
|
<StatusBar style="light" />
|
||||||
</View>
|
</View>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -16,7 +16,8 @@ const TopNavbar = ({title, showBack, navigation}) => {
|
|||||||
|
|
||||||
const handleLogout = () => {
|
const handleLogout = () => {
|
||||||
clearSession();
|
clearSession();
|
||||||
navigation.reset({
|
const rootNav = navigation.getParent() || navigation;
|
||||||
|
rootNav.reset({
|
||||||
index: 0,
|
index: 0,
|
||||||
routes: [{name: 'Auth', params: {screen: 'LoginScreen'}}],
|
routes: [{name: 'Auth', params: {screen: 'LoginScreen'}}],
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -34,10 +34,6 @@ const GameSelectionScreen = ({ navigation }) => {
|
|||||||
navigation.navigate("TeamScreen");
|
navigation.navigate("TeamScreen");
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleExplore = () => {
|
|
||||||
navigation.navigate("GlobalEventsScreen");
|
|
||||||
};
|
|
||||||
|
|
||||||
// View --------------------------------
|
// View --------------------------------
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@@ -77,16 +73,8 @@ const GameSelectionScreen = ({ navigation }) => {
|
|||||||
<View style={styles.sectionBlock}>
|
<View style={styles.sectionBlock}>
|
||||||
<Text style={styles.blockTitle}>Global Mode</Text>
|
<Text style={styles.blockTitle}>Global Mode</Text>
|
||||||
<Text style={styles.supportText}>
|
<Text style={styles.supportText}>
|
||||||
Explore all visible caches and live activity from the map.
|
Individual users can enter GLOBAL in the game join field to switch to Global mode.
|
||||||
</Text>
|
</Text>
|
||||||
<ButtonTray>
|
|
||||||
<Button
|
|
||||||
label="Explore"
|
|
||||||
onClick={handleExplore}
|
|
||||||
styleButton={styles.neutralButton}
|
|
||||||
styleLabel={styles.neutralButtonLabel}
|
|
||||||
/>
|
|
||||||
</ButtonTray>
|
|
||||||
</View>
|
</View>
|
||||||
</ScrollView>
|
</ScrollView>
|
||||||
</Screen>
|
</Screen>
|
||||||
@@ -170,15 +158,6 @@ const styles = StyleSheet.create({
|
|||||||
fontWeight: "600",
|
fontWeight: "600",
|
||||||
fontSize: 14,
|
fontSize: 14,
|
||||||
},
|
},
|
||||||
neutralButton: {
|
|
||||||
backgroundColor: "#374151",
|
|
||||||
borderColor: "#374151",
|
|
||||||
maxWidth: 180,
|
|
||||||
},
|
|
||||||
neutralButtonLabel: {
|
|
||||||
color: "#ffffff",
|
|
||||||
fontWeight: "600",
|
|
||||||
},
|
|
||||||
});
|
});
|
||||||
|
|
||||||
export default GameSelectionScreen;
|
export default GameSelectionScreen;
|
||||||
@@ -15,11 +15,12 @@ const LoginScreen = ({ navigation }) => {
|
|||||||
if (!user) {
|
if (!user) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
const rootNav = navigation.getParent() || navigation;
|
||||||
if (user.IsAcceptedAdmin) {
|
if (user.IsAcceptedAdmin) {
|
||||||
navigation.reset({ index: 0, routes: [{ name: 'Admin' }] });
|
rootNav.reset({ index: 0, routes: [{ name: 'Admin' }] });
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
navigation.reset({ index: 0, routes: [{ name: 'Game' }] });
|
rootNav.reset({ index: 0, routes: [{ name: 'Game' }] });
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@@ -58,7 +59,7 @@ const LoginScreen = ({ navigation }) => {
|
|||||||
/>
|
/>
|
||||||
</ButtonTray>
|
</ButtonTray>
|
||||||
|
|
||||||
<Pressable onPress={() => navigation.navigate('Auth', { screen: 'RegisterScreen' })}>
|
<Pressable onPress={() => navigation.navigate('RegisterScreen')}>
|
||||||
<Text style={styles.linkText}>Create new account</Text>
|
<Text style={styles.linkText}>Create new account</Text>
|
||||||
</Pressable>
|
</Pressable>
|
||||||
</View>
|
</View>
|
||||||
|
|||||||
@@ -5,14 +5,25 @@ import * as Location from 'expo-location';
|
|||||||
import {useFocusEffect} from '@react-navigation/native';
|
import {useFocusEffect} from '@react-navigation/native';
|
||||||
import Screen from '../layout/Screen';
|
import Screen from '../layout/Screen';
|
||||||
import {Button, ButtonTray} from '../UI/Button';
|
import {Button, ButtonTray} from '../UI/Button';
|
||||||
|
import CodeJoinRow from '../UI/CodeJoinRow';
|
||||||
import PendingApprovalView from '../UI/PendingApprovalView';
|
import PendingApprovalView from '../UI/PendingApprovalView';
|
||||||
import CacheCardItem from '../gameplay/CacheCardItem';
|
import CacheCardItem from '../gameplay/CacheCardItem';
|
||||||
import ClaimTimerView from '../gameplay/ClaimTimerView';
|
import ClaimTimerView from '../gameplay/ClaimTimerView';
|
||||||
import PlayerMapView from '../gameplay/PlayerMapView';
|
import PlayerMapView from '../gameplay/PlayerMapView';
|
||||||
|
import Card from '../UI/Card';
|
||||||
import useGameHook from '../../hooks/useGameHook';
|
import useGameHook from '../../hooks/useGameHook';
|
||||||
import usePlayerGame from '../../hooks/usePlayerGame';
|
import usePlayerGame from '../../hooks/usePlayerGame';
|
||||||
import {getSession, setPendingAdmin, setSelectedCache, setSessionGroup, setSessionTeam, setSessionUser} from '../../hooks/SessionStore';
|
import {
|
||||||
|
getSession,
|
||||||
|
setPendingAdmin,
|
||||||
|
setSelectedCache,
|
||||||
|
setSessionGroup,
|
||||||
|
setSessionMode,
|
||||||
|
setSessionTeam,
|
||||||
|
setSessionUser
|
||||||
|
} from '../../hooks/SessionStore';
|
||||||
import {getFovCone} from '../../utils/geoMath';
|
import {getFovCone} from '../../utils/geoMath';
|
||||||
|
import {GAME_MODE} from '../../utils/gameConstants';
|
||||||
|
|
||||||
const DEFAULT_REGION = {latitude: 51.5074, longitude: -0.1278, latitudeDelta: 0.05, longitudeDelta: 0.05};
|
const DEFAULT_REGION = {latitude: 51.5074, longitude: -0.1278, latitudeDelta: 0.05, longitudeDelta: 0.05};
|
||||||
|
|
||||||
@@ -20,11 +31,17 @@ const DEFAULT_REGION = {latitude: 51.5074, longitude: -0.1278, latitudeDelta: 0.
|
|||||||
const MapScreen = ({navigation, route}) => {
|
const MapScreen = ({navigation, route}) => {
|
||||||
const session = getSession();
|
const session = getSession();
|
||||||
const isBusiness = Boolean(session.isBusiness);
|
const isBusiness = Boolean(session.isBusiness);
|
||||||
const {getCaches, claimCache, upsertCache, deleteCache, joinPrivateGame, joinTeamByCode, createPrivateGame, getLobby, getUser, getSubgroups, getGroupByOrgCode} = useGameHook();
|
const {getCaches, claimCache, upsertCache, deleteCache, joinPrivateGame, joinTeamByCode, createPrivateGame, getGroups, getLobby, getUser, getSubgroups, getGroupByOrgCode} = useGameHook();
|
||||||
|
|
||||||
// Stable ref to prevent infinite re-render loops
|
// Stable ref to prevent infinite re-render loops
|
||||||
const getCachesRef = useRef(getCaches);
|
const getCachesRef = useRef(getCaches);
|
||||||
getCachesRef.current = getCaches;
|
getCachesRef.current = getCaches;
|
||||||
|
const getLobbyRef = useRef(getLobby);
|
||||||
|
getLobbyRef.current = getLobby;
|
||||||
|
const getSubgroupsRef = useRef(getSubgroups);
|
||||||
|
getSubgroupsRef.current = getSubgroups;
|
||||||
|
const getGroupsRef = useRef(getGroups);
|
||||||
|
getGroupsRef.current = getGroups;
|
||||||
const lastAppliedRouteDepartmentRef = useRef(null);
|
const lastAppliedRouteDepartmentRef = useRef(null);
|
||||||
|
|
||||||
const [inGame, setInGame] = useState(Boolean(session.currentGid));
|
const [inGame, setInGame] = useState(Boolean(session.currentGid));
|
||||||
@@ -39,6 +56,8 @@ const MapScreen = ({navigation, route}) => {
|
|||||||
const [selectedCacheId, setSelectedCacheIdState] = useState(session.selectedCacheId);
|
const [selectedCacheId, setSelectedCacheIdState] = useState(session.selectedCacheId);
|
||||||
const [claimedPopupVisible, setClaimedPopupVisible] = useState(false);
|
const [claimedPopupVisible, setClaimedPopupVisible] = useState(false);
|
||||||
const [subgroups, setSubgroups] = useState([]);
|
const [subgroups, setSubgroups] = useState([]);
|
||||||
|
const [availableGames, setAvailableGames] = useState([]);
|
||||||
|
const [gamesLoading, setGamesLoading] = useState(false);
|
||||||
|
|
||||||
// Business join flow state
|
// Business join flow state
|
||||||
const [joinStep, setJoinStep] = useState(null);
|
const [joinStep, setJoinStep] = useState(null);
|
||||||
@@ -87,9 +106,26 @@ const MapScreen = ({navigation, route}) => {
|
|||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!session.currentGid) return;
|
if (!session.currentGid) return;
|
||||||
getLobby(session.currentGid).then(setGroupInfo);
|
getLobbyRef.current(session.currentGid).then(setGroupInfo);
|
||||||
getSubgroups(session.currentGid).then(setSubgroups);
|
getSubgroupsRef.current(session.currentGid).then(setSubgroups);
|
||||||
}, [inGame]);
|
}, [inGame, session.currentGid]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const loadAvailableGames = async () => {
|
||||||
|
if (inGame || session.isBusiness) {
|
||||||
|
setAvailableGames([]);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
setGamesLoading(true);
|
||||||
|
const groups = await getGroupsRef.current();
|
||||||
|
const individualGames = (groups || []).filter((group) => !group.BusinessOrSchoolName);
|
||||||
|
setAvailableGames(individualGames);
|
||||||
|
setGamesLoading(false);
|
||||||
|
};
|
||||||
|
|
||||||
|
loadAvailableGames();
|
||||||
|
}, [inGame, session.isBusiness]);
|
||||||
|
|
||||||
// Default member subgroup SGid for cache creation (first non-admin subgroup)
|
// Default member subgroup SGid for cache creation (first non-admin subgroup)
|
||||||
const departments = useMemo(
|
const departments = useMemo(
|
||||||
@@ -153,7 +189,7 @@ const MapScreen = ({navigation, route}) => {
|
|||||||
const firstId = activeCachesForPlayer[0].id;
|
const firstId = activeCachesForPlayer[0].id;
|
||||||
setSelectedCacheIdState(firstId);
|
setSelectedCacheIdState(firstId);
|
||||||
setSelectedCache(firstId);
|
setSelectedCache(firstId);
|
||||||
}, [activeCachesForPlayer, isPlayer]);
|
}, [activeCachesForPlayer, isPlayer, selectedCacheId]);
|
||||||
|
|
||||||
// Location tracking
|
// Location tracking
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@@ -198,9 +234,12 @@ const MapScreen = ({navigation, route}) => {
|
|||||||
|
|
||||||
const handleJoinGame = async () => {
|
const handleJoinGame = async () => {
|
||||||
if (!gameCode.trim()) return;
|
if (!gameCode.trim()) return;
|
||||||
const result = await joinPrivateGame({JoinCode: gameCode.trim().toUpperCase(), Uid: session.currentUid});
|
const code = gameCode.trim().toUpperCase();
|
||||||
|
|
||||||
|
const result = await joinPrivateGame({JoinCode: code, Uid: session.currentUid});
|
||||||
if (!result) return;
|
if (!result) return;
|
||||||
setSessionGroup(result.Gid, result.SGid);
|
setSessionGroup(result.Gid, result.SGid);
|
||||||
|
setSessionMode(GAME_MODE.REGULAR);
|
||||||
setPendingAdmin(false);
|
setPendingAdmin(false);
|
||||||
|
|
||||||
const freshUser = await getUser(session.currentUid);
|
const freshUser = await getUser(session.currentUid);
|
||||||
@@ -214,6 +253,11 @@ const MapScreen = ({navigation, route}) => {
|
|||||||
navigation.navigate('TeamScreen');
|
navigation.navigate('TeamScreen');
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const handleEnterGlobal = () => {
|
||||||
|
setSessionMode(GAME_MODE.GLOBAL);
|
||||||
|
navigation.navigate('GlobalEventsScreen');
|
||||||
|
};
|
||||||
|
|
||||||
const handleCreateGame = async () => {
|
const handleCreateGame = async () => {
|
||||||
const result = await createPrivateGame({
|
const result = await createPrivateGame({
|
||||||
GroupName: 'My Game',
|
GroupName: 'My Game',
|
||||||
@@ -222,6 +266,7 @@ const MapScreen = ({navigation, route}) => {
|
|||||||
MaxMemberSubgroups: 1,
|
MaxMemberSubgroups: 1,
|
||||||
});
|
});
|
||||||
if (!result) return;
|
if (!result) return;
|
||||||
|
setSessionMode(GAME_MODE.REGULAR);
|
||||||
setPendingAdmin(false);
|
setPendingAdmin(false);
|
||||||
const freshUser = await getUser(session.currentUid);
|
const freshUser = await getUser(session.currentUid);
|
||||||
if (freshUser) {
|
if (freshUser) {
|
||||||
@@ -243,6 +288,7 @@ const MapScreen = ({navigation, route}) => {
|
|||||||
isBusiness: true,
|
isBusiness: true,
|
||||||
});
|
});
|
||||||
if (!result) return;
|
if (!result) return;
|
||||||
|
setSessionMode(GAME_MODE.REGULAR);
|
||||||
setPendingAdmin(false);
|
setPendingAdmin(false);
|
||||||
const freshUser = await getUser(session.currentUid);
|
const freshUser = await getUser(session.currentUid);
|
||||||
if (freshUser) {
|
if (freshUser) {
|
||||||
@@ -305,6 +351,7 @@ const MapScreen = ({navigation, route}) => {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
setSessionGroup(result.Gid, result.SGid);
|
setSessionGroup(result.Gid, result.SGid);
|
||||||
|
setSessionMode(GAME_MODE.REGULAR);
|
||||||
setPendingAdmin(false);
|
setPendingAdmin(false);
|
||||||
const freshUser = await getUser(session.currentUid);
|
const freshUser = await getUser(session.currentUid);
|
||||||
if (freshUser) {
|
if (freshUser) {
|
||||||
@@ -332,7 +379,7 @@ const MapScreen = ({navigation, route}) => {
|
|||||||
setTimeout(() => setClaimedPopupVisible(false), 3000);
|
setTimeout(() => setClaimedPopupVisible(false), 3000);
|
||||||
}
|
}
|
||||||
await loadCaches();
|
await loadCaches();
|
||||||
}, [session.currentGid, session.currentUid, session.currentTid, effectiveSGid, loadCaches]);
|
}, [session.currentGid, session.currentUid, session.currentTid, effectiveSGid, claimCache, setIsClaiming, loadCaches]);
|
||||||
|
|
||||||
const handleCreateCachePress = () => {
|
const handleCreateCachePress = () => {
|
||||||
const fallback = userLocation || {latitude: mapRegion.latitude, longitude: mapRegion.longitude};
|
const fallback = userLocation || {latitude: mapRegion.latitude, longitude: mapRegion.longitude};
|
||||||
@@ -421,22 +468,12 @@ const MapScreen = ({navigation, route}) => {
|
|||||||
<Screen style={styles.center}>
|
<Screen style={styles.center}>
|
||||||
<Text style={styles.bizTitle}>Join {matchedGroup.BusinessOrSchoolName || 'Company'}</Text>
|
<Text style={styles.bizTitle}>Join {matchedGroup.BusinessOrSchoolName || 'Company'}</Text>
|
||||||
<Text style={styles.bizSubtitle}>Enter your department code to join</Text>
|
<Text style={styles.bizSubtitle}>Enter your department code to join</Text>
|
||||||
<View style={styles.inputRow}>
|
<CodeJoinRow
|
||||||
<TextInput
|
|
||||||
style={styles.codeInput}
|
|
||||||
placeholder="Department Code"
|
|
||||||
placeholderTextColor="#9ca3af"
|
|
||||||
value={deptCode}
|
value={deptCode}
|
||||||
onChangeText={(text) => setDeptCode(text.toUpperCase())}
|
onChange={setDeptCode}
|
||||||
autoCapitalize="characters"
|
placeholder="Department Code"
|
||||||
|
onSubmit={handleJoinDepartment}
|
||||||
/>
|
/>
|
||||||
<Button
|
|
||||||
label="Join"
|
|
||||||
onClick={handleJoinDepartment}
|
|
||||||
styleButton={styles.joinButton}
|
|
||||||
styleLabel={styles.joinLabel}
|
|
||||||
/>
|
|
||||||
</View>
|
|
||||||
{joinError ? <Text style={styles.joinError}>{joinError}</Text> : null}
|
{joinError ? <Text style={styles.joinError}>{joinError}</Text> : null}
|
||||||
<View style={styles.fullRow}>
|
<View style={styles.fullRow}>
|
||||||
<ButtonTray>
|
<ButtonTray>
|
||||||
@@ -457,22 +494,13 @@ const MapScreen = ({navigation, route}) => {
|
|||||||
<Screen style={styles.center}>
|
<Screen style={styles.center}>
|
||||||
<Text style={styles.bizTitle}>Welcome</Text>
|
<Text style={styles.bizTitle}>Welcome</Text>
|
||||||
<Text style={styles.bizSubtitle}>Set up your organisation or join an existing one</Text>
|
<Text style={styles.bizSubtitle}>Set up your organisation or join an existing one</Text>
|
||||||
<View style={styles.inputRow}>
|
<CodeJoinRow
|
||||||
<TextInput
|
|
||||||
style={styles.codeInput}
|
|
||||||
placeholder="Company Code"
|
|
||||||
placeholderTextColor="#9ca3af"
|
|
||||||
value={orgCode}
|
value={orgCode}
|
||||||
onChangeText={(text) => setOrgCode(text.toUpperCase())}
|
onChange={setOrgCode}
|
||||||
autoCapitalize="characters"
|
placeholder="Company Code"
|
||||||
|
buttonLabel="Join Company"
|
||||||
|
onSubmit={handleVerifyOrgCode}
|
||||||
/>
|
/>
|
||||||
<Button
|
|
||||||
label="Join Company"
|
|
||||||
onClick={handleVerifyOrgCode}
|
|
||||||
styleButton={styles.joinButton}
|
|
||||||
styleLabel={styles.joinLabel}
|
|
||||||
/>
|
|
||||||
</View>
|
|
||||||
{joinError ? <Text style={styles.joinError}>{joinError}</Text> : null}
|
{joinError ? <Text style={styles.joinError}>{joinError}</Text> : null}
|
||||||
<View style={styles.fullRow}>
|
<View style={styles.fullRow}>
|
||||||
<ButtonTray>
|
<ButtonTray>
|
||||||
@@ -492,23 +520,23 @@ const MapScreen = ({navigation, route}) => {
|
|||||||
if (!inGame) {
|
if (!inGame) {
|
||||||
return (
|
return (
|
||||||
<Screen style={styles.center}>
|
<Screen style={styles.center}>
|
||||||
<View style={styles.inputRow}>
|
<View style={[styles.fullRow, styles.globalButtonRow]}>
|
||||||
<TextInput
|
<ButtonTray>
|
||||||
style={styles.codeInput}
|
|
||||||
placeholder="Enter Game Code"
|
|
||||||
placeholderTextColor="#9ca3af"
|
|
||||||
value={gameCode}
|
|
||||||
onChangeText={(text) => setGameCode(text.toUpperCase())}
|
|
||||||
autoCapitalize="characters"
|
|
||||||
/>
|
|
||||||
<Button
|
<Button
|
||||||
label="Join"
|
label="Join Global Game"
|
||||||
onClick={handleJoinGame}
|
onClick={handleEnterGlobal}
|
||||||
styleButton={styles.joinButton}
|
styleButton={styles.globalJoinButton}
|
||||||
styleLabel={styles.joinLabel}
|
styleLabel={styles.globalJoinLabel}
|
||||||
/>
|
/>
|
||||||
|
</ButtonTray>
|
||||||
</View>
|
</View>
|
||||||
<View style={styles.fullRow}>
|
<CodeJoinRow
|
||||||
|
value={gameCode}
|
||||||
|
onChange={setGameCode}
|
||||||
|
placeholder="Enter Game Code"
|
||||||
|
onSubmit={handleJoinGame}
|
||||||
|
/>
|
||||||
|
<View style={[styles.fullRow, styles.createGameRow]}>
|
||||||
<ButtonTray>
|
<ButtonTray>
|
||||||
<Button
|
<Button
|
||||||
label="Create a Game"
|
label="Create a Game"
|
||||||
@@ -518,6 +546,23 @@ const MapScreen = ({navigation, route}) => {
|
|||||||
/>
|
/>
|
||||||
</ButtonTray>
|
</ButtonTray>
|
||||||
</View>
|
</View>
|
||||||
|
<View style={[styles.fullRow, styles.availableGamesRow]}>
|
||||||
|
<Text style={styles.availableGamesTitle}>Available Individual Games</Text>
|
||||||
|
{gamesLoading ? (
|
||||||
|
<Text style={styles.availableGamesBody}>Loading games...</Text>
|
||||||
|
) : availableGames.length === 0 ? (
|
||||||
|
<Text style={styles.availableGamesBody}>No individual games available right now.</Text>
|
||||||
|
) : (
|
||||||
|
<ScrollView style={styles.availableGamesList} contentContainerStyle={styles.availableGamesContent}>
|
||||||
|
{availableGames.map((group) => (
|
||||||
|
<Card key={group.Gid} style={styles.availableGameCard}>
|
||||||
|
<Text style={styles.availableGameName}>{group.GroupName || `Game ${group.Gid}`}</Text>
|
||||||
|
<Text style={styles.availableGameMeta}>Game ID: {group.Gid}</Text>
|
||||||
|
</Card>
|
||||||
|
))}
|
||||||
|
</ScrollView>
|
||||||
|
)}
|
||||||
|
</View>
|
||||||
</Screen>
|
</Screen>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -794,20 +839,19 @@ const styles = StyleSheet.create({
|
|||||||
mapContainer: {height: 200},
|
mapContainer: {height: 200},
|
||||||
error: {color: '#D92800', fontSize: 15},
|
error: {color: '#D92800', fontSize: 15},
|
||||||
loadingText: {color: '#6c7086', fontSize: 14, marginTop: 10},
|
loadingText: {color: '#6c7086', fontSize: 14, marginTop: 10},
|
||||||
inputRow: {flexDirection: 'row', gap: 10, marginBottom: 15, width: '100%', paddingHorizontal: 20},
|
|
||||||
fullRow: {width: '100%', paddingHorizontal: 20},
|
fullRow: {width: '100%', paddingHorizontal: 20},
|
||||||
codeInput: {
|
globalButtonRow: {marginBottom: 12},
|
||||||
flex: 1,
|
createGameRow: {marginBottom: 12},
|
||||||
borderWidth: 1,
|
availableGamesRow: {paddingTop: 4},
|
||||||
borderColor: '#45475a',
|
globalJoinButton: {backgroundColor: '#bd93f9', borderColor: '#bd93f9'},
|
||||||
borderRadius: 8,
|
globalJoinLabel: {color: '#1e1e2e', fontWeight: '600'},
|
||||||
paddingHorizontal: 12,
|
availableGamesTitle: {color: '#cdd6f4', fontSize: 16, fontWeight: '700', marginBottom: 8},
|
||||||
paddingVertical: 10,
|
availableGamesBody: {color: '#bac2de', fontSize: 14, marginBottom: 6},
|
||||||
fontSize: 16,
|
availableGamesList: {maxHeight: 220},
|
||||||
color: '#cdd6f4',
|
availableGamesContent: {paddingBottom: 10},
|
||||||
backgroundColor: '#313244',
|
availableGameCard: {marginBottom: 8},
|
||||||
}, joinButton: {backgroundColor: '#bd93f9', borderColor: '#bd93f9', flex: 0, paddingHorizontal: 20},
|
availableGameName: {color: '#cdd6f4', fontSize: 15, fontWeight: '700', marginBottom: 3},
|
||||||
joinLabel: {color: '#1e1e2e', fontWeight: '600'},
|
availableGameMeta: {color: '#bac2de', fontSize: 12},
|
||||||
createButton: {backgroundColor: '#a6e3a1', borderColor: '#a6e3a1'},
|
createButton: {backgroundColor: '#a6e3a1', borderColor: '#a6e3a1'},
|
||||||
createLabel: {color: '#1e1e2e', fontWeight: '600'},
|
createLabel: {color: '#1e1e2e', fontWeight: '600'},
|
||||||
bizTitle: {fontSize: 22, fontWeight: '700', color: '#cdd6f4', marginBottom: 6, textAlign: 'center'},
|
bizTitle: {fontSize: 22, fontWeight: '700', color: '#cdd6f4', marginBottom: 6, textAlign: 'center'},
|
||||||
|
|||||||
@@ -19,11 +19,12 @@ const RegisterScreen = ({navigation}) => {
|
|||||||
const user = await register();
|
const user = await register();
|
||||||
setSubmitting(false);
|
setSubmitting(false);
|
||||||
if (!user) return;
|
if (!user) return;
|
||||||
|
const rootNav = navigation.getParent() || navigation;
|
||||||
if (user.IsAcceptedAdmin) {
|
if (user.IsAcceptedAdmin) {
|
||||||
navigation.reset({index: 0, routes: [{name: 'Admin'}]});
|
rootNav.reset({index: 0, routes: [{name: 'Admin'}]});
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
navigation.reset({index: 0, routes: [{name: 'Game'}]});
|
rootNav.reset({index: 0, routes: [{name: 'Game'}]});
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@@ -100,7 +101,7 @@ const RegisterScreen = ({navigation}) => {
|
|||||||
/>
|
/>
|
||||||
</ButtonTray>
|
</ButtonTray>
|
||||||
|
|
||||||
<Pressable onPress={() => navigation.navigate('Auth', {screen: 'LoginScreen'})}>
|
<Pressable onPress={() => navigation.navigate('LoginScreen')}>
|
||||||
<Text style={styles.linkText}>Back to Login</Text>
|
<Text style={styles.linkText}>Back to Login</Text>
|
||||||
</Pressable>
|
</Pressable>
|
||||||
</View>
|
</View>
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import { Button, ButtonTray } from "../../UI/Button";
|
|||||||
import Card from "../../UI/Card";
|
import Card from "../../UI/Card";
|
||||||
import useGlobalHook from "../../../hooks/useGlobalHook";
|
import useGlobalHook from "../../../hooks/useGlobalHook";
|
||||||
import {getSession} from "../../../hooks/SessionStore";
|
import {getSession} from "../../../hooks/SessionStore";
|
||||||
|
import {GAME_MODE} from "../../../utils/gameConstants";
|
||||||
|
|
||||||
const GlobalCacheViewScreen = ({ navigation, route }) => {
|
const GlobalCacheViewScreen = ({ navigation, route }) => {
|
||||||
// Initialisations ---------------------
|
// Initialisations ---------------------
|
||||||
@@ -60,6 +61,12 @@ const GlobalCacheViewScreen = ({ navigation, route }) => {
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (session.isBusiness || session.currentGameMode !== GAME_MODE.GLOBAL) {
|
||||||
|
navigation.replace("MapScreen");
|
||||||
|
}
|
||||||
|
}, [navigation, session.currentGameMode, session.isBusiness]);
|
||||||
|
|
||||||
// View --------------------------------
|
// View --------------------------------
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|||||||
@@ -1,16 +1,27 @@
|
|||||||
import { useCallback, useEffect, useState } from "react";
|
import {useCallback, useEffect, useRef, useState} from "react";
|
||||||
import {ActivityIndicator, StyleSheet, Text, View} from "react-native";
|
import {ActivityIndicator, StyleSheet, Text, View} from "react-native";
|
||||||
import Screen from "../../layout/Screen";
|
import Screen from "../../layout/Screen";
|
||||||
import {Button, ButtonTray} from "../../UI/Button";
|
import {Button, ButtonTray} from "../../UI/Button";
|
||||||
import EventList from "../../../entity/event/EventList";
|
import EventList from "../../../entity/event/EventList";
|
||||||
import useGlobalHook from "../../../hooks/useGlobalHook";
|
import useGlobalHook from "../../../hooks/useGlobalHook";
|
||||||
import {getSession, setGlobalSession} from "../../../hooks/SessionStore";
|
import {getSession, setGlobalSession} from "../../../hooks/SessionStore";
|
||||||
|
import {GAME_MODE} from "../../../utils/gameConstants";
|
||||||
|
|
||||||
const GlobalEventsScreen = ({ navigation }) => {
|
const GlobalEventsScreen = ({ navigation }) => {
|
||||||
// Initialisations ---------------------
|
// Initialisations ---------------------
|
||||||
|
|
||||||
const { getPublicEvents, getPlayersByEvent, joinEvent } = useGlobalHook();
|
const { getPublicEvents, getPlayersByEvent, joinEvent } = useGlobalHook();
|
||||||
const session = getSession();
|
const session = getSession();
|
||||||
|
const globalApiRef = useRef({
|
||||||
|
getPublicEvents,
|
||||||
|
getPlayersByEvent,
|
||||||
|
joinEvent,
|
||||||
|
});
|
||||||
|
globalApiRef.current = {
|
||||||
|
getPublicEvents,
|
||||||
|
getPlayersByEvent,
|
||||||
|
joinEvent,
|
||||||
|
};
|
||||||
|
|
||||||
// State -------------------------------
|
// State -------------------------------
|
||||||
|
|
||||||
@@ -24,21 +35,25 @@ const GlobalEventsScreen = ({ navigation }) => {
|
|||||||
const loadEvents = useCallback(async () => {
|
const loadEvents = useCallback(async () => {
|
||||||
setIsLoading(true);
|
setIsLoading(true);
|
||||||
setError("");
|
setError("");
|
||||||
const data = await getPublicEvents();
|
const data = await globalApiRef.current.getPublicEvents();
|
||||||
setEvents(data);
|
setEvents(data);
|
||||||
setIsLoading(false);
|
setIsLoading(false);
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
if (session.isBusiness || session.currentGameMode !== GAME_MODE.GLOBAL) {
|
||||||
|
navigation.replace("MapScreen");
|
||||||
|
return;
|
||||||
|
}
|
||||||
loadEvents();
|
loadEvents();
|
||||||
}, [loadEvents]);
|
}, [loadEvents, navigation, session.currentGameMode, session.isBusiness]);
|
||||||
|
|
||||||
const handleSelect = async (event) => {
|
const handleSelect = async (event) => {
|
||||||
setError("");
|
setError("");
|
||||||
setJoining(event.EventID);
|
setJoining(event.EventID);
|
||||||
|
|
||||||
// Check if already a player
|
// Check if already a player
|
||||||
const players = await getPlayersByEvent(event.EventID);
|
const players = await globalApiRef.current.getPlayersByEvent(event.EventID);
|
||||||
const existing = (players || []).find(
|
const existing = (players || []).find(
|
||||||
(p) => p.PlayerUserID === session.currentUid,
|
(p) => p.PlayerUserID === session.currentUid,
|
||||||
);
|
);
|
||||||
@@ -48,7 +63,7 @@ const GlobalEventsScreen = ({ navigation }) => {
|
|||||||
navigation.navigate("GlobalMapScreen", { eventId: event.EventID });
|
navigation.navigate("GlobalMapScreen", { eventId: event.EventID });
|
||||||
} else {
|
} else {
|
||||||
// Join the event
|
// Join the event
|
||||||
const player = await joinEvent({
|
const player = await globalApiRef.current.joinEvent({
|
||||||
PlayerUserID: session.currentUid,
|
PlayerUserID: session.currentUid,
|
||||||
PlayerEventID: event.EventID,
|
PlayerEventID: event.EventID,
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1,22 +1,17 @@
|
|||||||
import {useCallback, useEffect, useState} from "react";
|
import {useCallback, useEffect, useState} from "react";
|
||||||
import {
|
import {ActivityIndicator, ScrollView, StyleSheet, Text, View,} from "react-native";
|
||||||
ActivityIndicator,
|
|
||||||
ScrollView,
|
|
||||||
StyleSheet,
|
|
||||||
Text,
|
|
||||||
View,
|
|
||||||
} from "react-native";
|
|
||||||
import Screen from "../../layout/Screen";
|
import Screen from "../../layout/Screen";
|
||||||
import {Button, ButtonTray} from "../../UI/Button";
|
import {Button, ButtonTray} from "../../UI/Button";
|
||||||
import Card from "../../UI/Card";
|
import Card from "../../UI/Card";
|
||||||
import FindList from "../../../entity/find/FindList";
|
import FindList from "../../../entity/find/FindList";
|
||||||
import useGlobalHook from "../../../hooks/useGlobalHook";
|
import useGlobalHook from "../../../hooks/useGlobalHook";
|
||||||
import {getSession} from "../../../hooks/SessionStore";
|
import {getSession} from "../../../hooks/SessionStore";
|
||||||
|
import {GAME_MODE} from "../../../utils/gameConstants";
|
||||||
|
|
||||||
const GlobalLeaderboardScreen = ({ navigation, route }) => {
|
const GlobalLeaderboardScreen = ({ navigation, route }) => {
|
||||||
// Initialisations ---------------------
|
// Initialisations ---------------------
|
||||||
|
|
||||||
const { eventId } = route.params;
|
const eventId = route?.params?.eventId ?? getSession().currentGlobalEventId;
|
||||||
const { getFindsByEvent, getCachesByEvent, getPlayersByEvent } =
|
const { getFindsByEvent, getCachesByEvent, getPlayersByEvent } =
|
||||||
useGlobalHook();
|
useGlobalHook();
|
||||||
const session = getSession();
|
const session = getSession();
|
||||||
@@ -79,11 +74,19 @@ const GlobalLeaderboardScreen = ({ navigation, route }) => {
|
|||||||
const ranked = Object.values(pointsMap).sort((a, b) => b.points - a.points);
|
const ranked = Object.values(pointsMap).sort((a, b) => b.points - a.points);
|
||||||
setRankings(ranked);
|
setRankings(ranked);
|
||||||
setIsLoading(false);
|
setIsLoading(false);
|
||||||
}, [eventId]);
|
}, [eventId, getFindsByEvent, getCachesByEvent, getPlayersByEvent]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
if (session.isBusiness || session.currentGameMode !== GAME_MODE.GLOBAL) {
|
||||||
|
navigation.replace("MapScreen");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!eventId) {
|
||||||
|
navigation.replace("GlobalEventsScreen");
|
||||||
|
return;
|
||||||
|
}
|
||||||
loadData();
|
loadData();
|
||||||
}, [loadData]);
|
}, [eventId, loadData, navigation, session.currentGameMode, session.isBusiness]);
|
||||||
|
|
||||||
// View --------------------------------
|
// View --------------------------------
|
||||||
|
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ import { Button, ButtonTray } from "../../UI/Button";
|
|||||||
import CacheList from "../../../entity/cache/CacheList";
|
import CacheList from "../../../entity/cache/CacheList";
|
||||||
import useGlobalHook from "../../../hooks/useGlobalHook";
|
import useGlobalHook from "../../../hooks/useGlobalHook";
|
||||||
import {getSession} from "../../../hooks/SessionStore";
|
import {getSession} from "../../../hooks/SessionStore";
|
||||||
|
import {GAME_MODE} from "../../../utils/gameConstants";
|
||||||
|
|
||||||
const DEFAULT_REGION = {
|
const DEFAULT_REGION = {
|
||||||
latitude: 51.5074,
|
latitude: 51.5074,
|
||||||
@@ -18,7 +19,7 @@ const DEFAULT_REGION = {
|
|||||||
const GlobalMapScreen = ({ navigation, route }) => {
|
const GlobalMapScreen = ({ navigation, route }) => {
|
||||||
// Initialisations ---------------------
|
// Initialisations ---------------------
|
||||||
|
|
||||||
const { eventId } = route.params;
|
const eventId = route?.params?.eventId ?? getSession().currentGlobalEventId;
|
||||||
const { getCachesByEvent, getFindsByPlayer } = useGlobalHook();
|
const { getCachesByEvent, getFindsByPlayer } = useGlobalHook();
|
||||||
const session = getSession();
|
const session = getSession();
|
||||||
|
|
||||||
@@ -47,11 +48,19 @@ const GlobalMapScreen = ({ navigation, route }) => {
|
|||||||
setCaches(cacheData);
|
setCaches(cacheData);
|
||||||
setFoundCacheIds((findsData || []).map((f) => f.FindCacheID));
|
setFoundCacheIds((findsData || []).map((f) => f.FindCacheID));
|
||||||
setIsLoading(false);
|
setIsLoading(false);
|
||||||
}, [eventId]);
|
}, [eventId, getCachesByEvent, getFindsByPlayer, session.currentGlobalPlayerId]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
if (session.isBusiness || session.currentGameMode !== GAME_MODE.GLOBAL) {
|
||||||
|
navigation.replace("MapScreen");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!eventId) {
|
||||||
|
navigation.replace("GlobalEventsScreen");
|
||||||
|
return;
|
||||||
|
}
|
||||||
loadData();
|
loadData();
|
||||||
}, [loadData]);
|
}, [eventId, loadData, navigation, session.currentGameMode, session.isBusiness]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
let sub;
|
let sub;
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
// --- Session Store (with AsyncStorage persistence) ---
|
|
||||||
|
|
||||||
import AsyncStorage from "@react-native-async-storage/async-storage";
|
import AsyncStorage from "@react-native-async-storage/async-storage";
|
||||||
|
import {GAME_MODE} from '../utils/gameConstants';
|
||||||
|
|
||||||
const STORAGE_KEY = "@mad_session";
|
const STORAGE_KEY = "@mad_session";
|
||||||
|
|
||||||
@@ -13,6 +12,7 @@ const session = {
|
|||||||
isAcceptedAdmin: false,
|
isAcceptedAdmin: false,
|
||||||
isPendingAdmin: false,
|
isPendingAdmin: false,
|
||||||
teamsEnabled: false,
|
teamsEnabled: false,
|
||||||
|
currentGameMode: null,
|
||||||
// Global gameplay
|
// Global gameplay
|
||||||
currentGlobalEventId: null,
|
currentGlobalEventId: null,
|
||||||
currentGlobalPlayerId: null,
|
currentGlobalPlayerId: null,
|
||||||
@@ -31,11 +31,16 @@ const setSessionUser = (user) => {
|
|||||||
session.isPendingAdmin = Boolean(
|
session.isPendingAdmin = Boolean(
|
||||||
user?.isBusiness && user?.Gid && !user?.SGid && !user?.IsAcceptedAdmin,
|
user?.isBusiness && user?.Gid && !user?.SGid && !user?.IsAcceptedAdmin,
|
||||||
);
|
);
|
||||||
|
// New login/register starts in regular flow; global flow requires entering GLOBAL code.
|
||||||
|
session.currentGlobalEventId = null;
|
||||||
|
session.currentGlobalPlayerId = null;
|
||||||
|
session.currentGameMode = user?.Gid ? GAME_MODE.REGULAR : null;
|
||||||
persistSession();
|
persistSession();
|
||||||
};
|
};
|
||||||
|
|
||||||
const setSessionGroup = (gid, sgid = null) => {
|
const setSessionGroup = (gid, sgid = null) => {
|
||||||
session.currentGid = gid ?? null;
|
session.currentGid = gid ?? null;
|
||||||
|
session.currentGameMode = gid ? GAME_MODE.REGULAR : session.currentGameMode;
|
||||||
if (sgid !== undefined) {
|
if (sgid !== undefined) {
|
||||||
session.currentSGid = sgid ?? null;
|
session.currentSGid = sgid ?? null;
|
||||||
}
|
}
|
||||||
@@ -67,12 +72,19 @@ const getSession = () => ({ ...session });
|
|||||||
const setGlobalSession = (eventId, playerId) => {
|
const setGlobalSession = (eventId, playerId) => {
|
||||||
session.currentGlobalEventId = eventId ?? null;
|
session.currentGlobalEventId = eventId ?? null;
|
||||||
session.currentGlobalPlayerId = playerId ?? null;
|
session.currentGlobalPlayerId = playerId ?? null;
|
||||||
|
session.currentGameMode = eventId ? GAME_MODE.GLOBAL : session.currentGameMode;
|
||||||
|
persistSession();
|
||||||
|
};
|
||||||
|
|
||||||
|
const setSessionMode = (mode) => {
|
||||||
|
session.currentGameMode = mode ?? null;
|
||||||
persistSession();
|
persistSession();
|
||||||
};
|
};
|
||||||
|
|
||||||
const clearGlobalSession = () => {
|
const clearGlobalSession = () => {
|
||||||
session.currentGlobalEventId = null;
|
session.currentGlobalEventId = null;
|
||||||
session.currentGlobalPlayerId = null;
|
session.currentGlobalPlayerId = null;
|
||||||
|
if (!session.currentGid) session.currentGameMode = null;
|
||||||
persistSession();
|
persistSession();
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -83,6 +95,7 @@ const clearSession = () => {
|
|||||||
session.currentTid = null;
|
session.currentTid = null;
|
||||||
session.isBusiness = null;
|
session.isBusiness = null;
|
||||||
session.isAcceptedAdmin = false;
|
session.isAcceptedAdmin = false;
|
||||||
|
session.currentGameMode = null;
|
||||||
session.currentGlobalEventId = null;
|
session.currentGlobalEventId = null;
|
||||||
session.currentGlobalPlayerId = null;
|
session.currentGlobalPlayerId = null;
|
||||||
session.isPendingAdmin = false;
|
session.isPendingAdmin = false;
|
||||||
@@ -98,6 +111,7 @@ const clearGameSession = () => {
|
|||||||
session.isPendingAdmin = false;
|
session.isPendingAdmin = false;
|
||||||
session.teamsEnabled = false;
|
session.teamsEnabled = false;
|
||||||
session.selectedCacheId = null;
|
session.selectedCacheId = null;
|
||||||
|
if (!session.currentGlobalEventId) session.currentGameMode = null;
|
||||||
persistSession();
|
persistSession();
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -125,11 +139,13 @@ export {
|
|||||||
setSessionGroup,
|
setSessionGroup,
|
||||||
setSessionTeam,
|
setSessionTeam,
|
||||||
setSessionTeamsEnabled,
|
setSessionTeamsEnabled,
|
||||||
|
setPendingAdmin,
|
||||||
|
setSelectedCache,
|
||||||
getSession,
|
getSession,
|
||||||
clearSession,
|
clearSession,
|
||||||
clearGameSession,
|
clearGameSession,
|
||||||
loadSession,
|
loadSession,
|
||||||
setGlobalSession,
|
setGlobalSession,
|
||||||
clearGlobalSession,
|
clearGlobalSession,
|
||||||
|
setSessionMode,
|
||||||
};
|
};
|
||||||
export { setSessionUser, setSessionGroup, setSessionTeam, setSessionTeamsEnabled, setPendingAdmin, setSelectedCache, getSession, clearSession, clearGameSession, loadSession };
|
|
||||||
@@ -31,6 +31,11 @@ const useGameHook = () => {
|
|||||||
return response.isSuccess ? response.result : null;
|
return response.isSuccess ? response.result : null;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const getGroups = async () => {
|
||||||
|
const response = await API.get(groupsEndpoint);
|
||||||
|
return response.isSuccess ? response.result : [];
|
||||||
|
};
|
||||||
|
|
||||||
const getLobby = async (gid) => {
|
const getLobby = async (gid) => {
|
||||||
const response = await API.get(`${groupsEndpoint}/${gid}`);
|
const response = await API.get(`${groupsEndpoint}/${gid}`);
|
||||||
return response.isSuccess ? response.result : null;
|
return response.isSuccess ? response.result : null;
|
||||||
@@ -250,6 +255,7 @@ const useGameHook = () => {
|
|||||||
getUser,
|
getUser,
|
||||||
updateUser,
|
updateUser,
|
||||||
createPrivateGame,
|
createPrivateGame,
|
||||||
|
getGroups,
|
||||||
getLobby,
|
getLobby,
|
||||||
updateGroup,
|
updateGroup,
|
||||||
getGroupByOrgCode,
|
getGroupByOrgCode,
|
||||||
|
|||||||
@@ -0,0 +1,7 @@
|
|||||||
|
export const GLOBAL_GAME_CODE = 'GLOBAL';
|
||||||
|
|
||||||
|
export const GAME_MODE = {
|
||||||
|
REGULAR: 'regular',
|
||||||
|
GLOBAL: 'global',
|
||||||
|
};
|
||||||
|
|
||||||
Reference in new issue
Block a user