mirror of
https://github.com/mudabbir-ahmad/MAD-Treasure-Hunt.git
synced 2026-10-08 03:00:20 +00:00
Add pending admin state handling and update navigation logic for admin approval
This commit is contained in:
1 parent
41b0b723ca
commit
f69ead8e45
7 files changed
+148
-11
No files matched your search
@@ -15,7 +15,14 @@ const BottomNavbar = ({navigation, routeName, routeParams}) => {
|
|||||||
|
|
||||||
const adminTabs = [
|
const adminTabs = [
|
||||||
{label: 'Settings', route: 'GameSettingsScreen', onPress: () => navigation.navigate('GameSettingsScreen')},
|
{label: 'Settings', route: 'GameSettingsScreen', onPress: () => navigation.navigate('GameSettingsScreen')},
|
||||||
{label: 'Map', route: 'MapScreen', onPress: () => navigation.navigate('MapScreen')},
|
{
|
||||||
|
label: 'Map',
|
||||||
|
route: 'MapScreen',
|
||||||
|
onPress: () => navigation.navigate('MapScreen', {
|
||||||
|
selectedDepartmentSGid: null,
|
||||||
|
selectedDepartmentName: null,
|
||||||
|
}),
|
||||||
|
},
|
||||||
{
|
{
|
||||||
label: 'Players',
|
label: 'Players',
|
||||||
route: 'PlayersScreen',
|
route: 'PlayersScreen',
|
||||||
@@ -39,6 +46,11 @@ const BottomNavbar = ({navigation, routeName, routeParams}) => {
|
|||||||
];
|
];
|
||||||
|
|
||||||
const tabs = session.isAcceptedAdmin ? adminTabs : playerTabs;
|
const tabs = session.isAcceptedAdmin ? adminTabs : playerTabs;
|
||||||
|
const pendingTabs = [
|
||||||
|
{label: 'Pending', route: 'TeamScreen', onPress: () => navigation.navigate('TeamScreen')},
|
||||||
|
...(inGame ? [{label: 'Leave', route: '__leave__', onPress: () => handleLeaveGame()}] : []),
|
||||||
|
];
|
||||||
|
const visibleTabs = (session.isPendingAdmin && !session.isAcceptedAdmin) ? pendingTabs : tabs;
|
||||||
|
|
||||||
// State ----------------------
|
// State ----------------------
|
||||||
// Handlers -------------------
|
// Handlers -------------------
|
||||||
@@ -67,7 +79,7 @@ const BottomNavbar = ({navigation, routeName, routeParams}) => {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<View style={[styles.container, {paddingBottom: insets.bottom}]}>
|
<View style={[styles.container, {paddingBottom: insets.bottom}]}>
|
||||||
{tabs.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__';
|
||||||
return (
|
return (
|
||||||
|
|||||||
@@ -184,6 +184,14 @@ const LeaderboardScreen = ({navigation, route}) => {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (session.isPendingAdmin && !session.isAcceptedAdmin) {
|
||||||
|
return (
|
||||||
|
<Screen style={styles.center}>
|
||||||
|
<Text style={styles.body}>Waiting for admin approval. You will get access once approved.</Text>
|
||||||
|
</Screen>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
if (isBusiness && isAdmin && !selectedDepartment) {
|
if (isBusiness && isAdmin && !selectedDepartment) {
|
||||||
return (
|
return (
|
||||||
<Screen style={styles.container}>
|
<Screen style={styles.container}>
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ import ClaimTimerView from '../gameplay/ClaimTimerView';
|
|||||||
import PlayerMapView from '../gameplay/PlayerMapView';
|
import PlayerMapView from '../gameplay/PlayerMapView';
|
||||||
import useGameHook from '../../hooks/useGameHook';
|
import useGameHook from '../../hooks/useGameHook';
|
||||||
import usePlayerGame from '../../hooks/usePlayerGame';
|
import usePlayerGame from '../../hooks/usePlayerGame';
|
||||||
import {getSession, setSelectedCache, setSessionGroup, setSessionTeam, setSessionUser} from '../../hooks/SessionStore';
|
import {getSession, setPendingAdmin, setSelectedCache, setSessionGroup, setSessionTeam, setSessionUser} from '../../hooks/SessionStore';
|
||||||
import {getFovCone} from '../../utils/geoMath';
|
import {getFovCone} from '../../utils/geoMath';
|
||||||
|
|
||||||
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};
|
||||||
@@ -19,7 +19,7 @@ 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, createPrivateGame, getLobby, getUser, getSubgroups, getGroupByOrgCode} = useGameHook();
|
const {getCaches, claimCache, upsertCache, deleteCache, joinPrivateGame, joinTeamByCode, createPrivateGame, 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);
|
||||||
@@ -104,8 +104,9 @@ const MapScreen = ({navigation, route}) => {
|
|||||||
return map;
|
return map;
|
||||||
}, [departments]);
|
}, [departments]);
|
||||||
const routeDepartmentSGid = route?.params?.selectedDepartmentSGid;
|
const routeDepartmentSGid = route?.params?.selectedDepartmentSGid;
|
||||||
|
const isDepartmentScopedMap = routeDepartmentSGid !== null && routeDepartmentSGid !== undefined;
|
||||||
const effectiveSGid = isBusiness
|
const effectiveSGid = isBusiness
|
||||||
? (isAdmin ? (selectedCacheSubgroupId ?? routeDepartmentSGid ?? defaultMemberSGid ?? null) : (session.currentSGid ?? null))
|
? (isAdmin ? (isDepartmentScopedMap ? routeDepartmentSGid : null) : (session.currentSGid ?? null))
|
||||||
: null;
|
: null;
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@@ -199,6 +200,7 @@ const MapScreen = ({navigation, route}) => {
|
|||||||
const result = await joinPrivateGame({JoinCode: gameCode.trim().toUpperCase(), Uid: session.currentUid});
|
const result = await joinPrivateGame({JoinCode: gameCode.trim().toUpperCase(), Uid: session.currentUid});
|
||||||
if (!result) return;
|
if (!result) return;
|
||||||
setSessionGroup(result.Gid, result.SGid);
|
setSessionGroup(result.Gid, result.SGid);
|
||||||
|
setPendingAdmin(false);
|
||||||
|
|
||||||
const freshUser = await getUser(session.currentUid);
|
const freshUser = await getUser(session.currentUid);
|
||||||
if (freshUser) {
|
if (freshUser) {
|
||||||
@@ -219,6 +221,7 @@ const MapScreen = ({navigation, route}) => {
|
|||||||
MaxMemberSubgroups: 1,
|
MaxMemberSubgroups: 1,
|
||||||
});
|
});
|
||||||
if (!result) return;
|
if (!result) return;
|
||||||
|
setPendingAdmin(false);
|
||||||
const freshUser = await getUser(session.currentUid);
|
const freshUser = await getUser(session.currentUid);
|
||||||
if (freshUser) {
|
if (freshUser) {
|
||||||
setSessionUser(freshUser);
|
setSessionUser(freshUser);
|
||||||
@@ -239,6 +242,7 @@ const MapScreen = ({navigation, route}) => {
|
|||||||
isBusiness: true,
|
isBusiness: true,
|
||||||
});
|
});
|
||||||
if (!result) return;
|
if (!result) return;
|
||||||
|
setPendingAdmin(false);
|
||||||
const freshUser = await getUser(session.currentUid);
|
const freshUser = await getUser(session.currentUid);
|
||||||
if (freshUser) {
|
if (freshUser) {
|
||||||
setSessionUser(freshUser);
|
setSessionUser(freshUser);
|
||||||
@@ -265,8 +269,33 @@ const MapScreen = ({navigation, route}) => {
|
|||||||
const handleJoinDepartment = async () => {
|
const handleJoinDepartment = async () => {
|
||||||
setJoinError('');
|
setJoinError('');
|
||||||
if (!deptCode.trim()) return;
|
if (!deptCode.trim()) return;
|
||||||
|
const enteredCode = deptCode.trim().toUpperCase();
|
||||||
|
const adminCode = String(matchedGroup?.AdminJoinCode || '').trim().toUpperCase();
|
||||||
|
|
||||||
|
// If the code matches the org admin code, submit an admin waitlist request
|
||||||
|
if (adminCode && enteredCode === adminCode) {
|
||||||
|
const waitlistResult = await joinTeamByCode({
|
||||||
|
JoinCode: enteredCode,
|
||||||
|
Uid: session.currentUid,
|
||||||
|
ExpectedGid: matchedGroup.Gid,
|
||||||
|
});
|
||||||
|
if (!waitlistResult || !waitlistResult.adminWaitlist) {
|
||||||
|
setJoinError('Could not submit admin request. Please try again.');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
setSessionGroup(matchedGroup.Gid, null);
|
||||||
|
setSessionTeam(null);
|
||||||
|
setPendingAdmin(true);
|
||||||
|
setInGame(true);
|
||||||
|
setIsAdmin(false);
|
||||||
|
setJoinStep(null);
|
||||||
|
setDeptCode('');
|
||||||
|
navigation.navigate('TeamScreen');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
const result = await joinPrivateGame({
|
const result = await joinPrivateGame({
|
||||||
JoinCode: deptCode.trim().toUpperCase(),
|
JoinCode: enteredCode,
|
||||||
Uid: session.currentUid,
|
Uid: session.currentUid,
|
||||||
ExpectedGid: matchedGroup.Gid,
|
ExpectedGid: matchedGroup.Gid,
|
||||||
});
|
});
|
||||||
@@ -275,6 +304,7 @@ const MapScreen = ({navigation, route}) => {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
setSessionGroup(result.Gid, result.SGid);
|
setSessionGroup(result.Gid, result.SGid);
|
||||||
|
setPendingAdmin(false);
|
||||||
const freshUser = await getUser(session.currentUid);
|
const freshUser = await getUser(session.currentUid);
|
||||||
if (freshUser) {
|
if (freshUser) {
|
||||||
setSessionUser(freshUser);
|
setSessionUser(freshUser);
|
||||||
@@ -684,6 +714,14 @@ const MapScreen = ({navigation, route}) => {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (session.isPendingAdmin && !session.isAcceptedAdmin) {
|
||||||
|
return (
|
||||||
|
<Screen style={styles.center}>
|
||||||
|
<Text style={styles.loadingText}>Waiting for admin approval. You will get access once approved.</Text>
|
||||||
|
</Screen>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
// Player — loading location
|
// Player — loading location
|
||||||
if (playerLoading) {
|
if (playerLoading) {
|
||||||
return (
|
return (
|
||||||
|
|||||||
@@ -178,6 +178,14 @@ const PlayersScreen = ({navigation, route}) => {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (session.isPendingAdmin && !session.isAcceptedAdmin) {
|
||||||
|
return (
|
||||||
|
<Screen style={styles.center}>
|
||||||
|
<Text style={styles.body}>Waiting for admin approval. You will get access once approved.</Text>
|
||||||
|
</Screen>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
if (isBusiness && isAdmin && !selectedDepartment) {
|
if (isBusiness && isAdmin && !selectedDepartment) {
|
||||||
return (
|
return (
|
||||||
<Screen style={styles.container}>
|
<Screen style={styles.container}>
|
||||||
|
|||||||
@@ -4,9 +4,9 @@ import Screen from '../layout/Screen';
|
|||||||
import Card from '../UI/Card';
|
import Card from '../UI/Card';
|
||||||
import {Button, ButtonTray} from '../UI/Button';
|
import {Button, ButtonTray} from '../UI/Button';
|
||||||
import useGameHook from '../../hooks/useGameHook';
|
import useGameHook from '../../hooks/useGameHook';
|
||||||
import {getSession, setSessionTeam} from '../../hooks/SessionStore';
|
import {getSession, setPendingAdmin, setSessionTeam, setSessionUser} from '../../hooks/SessionStore';
|
||||||
|
|
||||||
const TeamScreen = () => {
|
const TeamScreen = ({navigation}) => {
|
||||||
const session = getSession();
|
const session = getSession();
|
||||||
const isAdmin = session.isAcceptedAdmin;
|
const isAdmin = session.isAcceptedAdmin;
|
||||||
const isBusiness = Boolean(session.isBusiness);
|
const isBusiness = Boolean(session.isBusiness);
|
||||||
@@ -48,6 +48,24 @@ const TeamScreen = () => {
|
|||||||
if (subgroup) teamsAreEnabled = Boolean(subgroup.TeamsEnabled);
|
if (subgroup) teamsAreEnabled = Boolean(subgroup.TeamsEnabled);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (session.isPendingAdmin && !session.isAcceptedAdmin) {
|
||||||
|
const freshUser = await getUser(session.currentUid);
|
||||||
|
if (freshUser?.IsAcceptedAdmin) {
|
||||||
|
setPendingAdmin(false);
|
||||||
|
setSessionUser(freshUser);
|
||||||
|
setSessionTeam(freshUser.TGid ?? null);
|
||||||
|
navigation.reset({index: 0, routes: [{name: 'Admin'}]});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const waitlist = await getAdminWaitlist(session.currentGid, session.currentUid);
|
||||||
|
if (waitlist.length > 0) {
|
||||||
|
setOnAdminWaitlist(true);
|
||||||
|
setLoading(false);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
setPendingAdmin(false);
|
||||||
|
}
|
||||||
|
|
||||||
if (!teamsAreEnabled) {
|
if (!teamsAreEnabled) {
|
||||||
setTeamsDisabled(true);
|
setTeamsDisabled(true);
|
||||||
setLoading(false);
|
setLoading(false);
|
||||||
@@ -69,6 +87,44 @@ const TeamScreen = () => {
|
|||||||
load();
|
load();
|
||||||
}, [activeTid]);
|
}, [activeTid]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (!onAdminWaitlist && !session.isPendingAdmin) return;
|
||||||
|
|
||||||
|
let stopped = false;
|
||||||
|
const refreshWaitlistStatus = async () => {
|
||||||
|
const currentSession = getSession();
|
||||||
|
if (!currentSession.currentUid || !currentSession.currentGid) return;
|
||||||
|
|
||||||
|
const freshUser = await getUser(currentSession.currentUid);
|
||||||
|
if (stopped) return;
|
||||||
|
|
||||||
|
if (freshUser?.IsAcceptedAdmin) {
|
||||||
|
setPendingAdmin(false);
|
||||||
|
setSessionUser(freshUser);
|
||||||
|
setSessionTeam(freshUser.TGid ?? null);
|
||||||
|
navigation.reset({index: 0, routes: [{name: 'Admin'}]});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const waitlist = await getAdminWaitlist(currentSession.currentGid, currentSession.currentUid);
|
||||||
|
if (stopped) return;
|
||||||
|
|
||||||
|
const isStillWaiting = waitlist.length > 0;
|
||||||
|
setOnAdminWaitlist(isStillWaiting);
|
||||||
|
if (!isStillWaiting) {
|
||||||
|
setPendingAdmin(false);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
refreshWaitlistStatus();
|
||||||
|
const intervalId = setInterval(refreshWaitlistStatus, 5000);
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
stopped = true;
|
||||||
|
clearInterval(intervalId);
|
||||||
|
};
|
||||||
|
}, [onAdminWaitlist, session.isPendingAdmin]);
|
||||||
|
|
||||||
const handleJoinTeam = async () => {
|
const handleJoinTeam = async () => {
|
||||||
if (!teamCode.trim()) return;
|
if (!teamCode.trim()) return;
|
||||||
// Force uppercase just in case a lowercase code is pasted
|
// Force uppercase just in case a lowercase code is pasted
|
||||||
@@ -82,6 +138,7 @@ const TeamScreen = () => {
|
|||||||
|
|
||||||
// If the server indicates this code matched the admin join code
|
// If the server indicates this code matched the admin join code
|
||||||
if (result.adminWaitlist) {
|
if (result.adminWaitlist) {
|
||||||
|
setPendingAdmin(true);
|
||||||
setOnAdminWaitlist(true);
|
setOnAdminWaitlist(true);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ const session = {
|
|||||||
currentTid: null,
|
currentTid: null,
|
||||||
isBusiness: null,
|
isBusiness: null,
|
||||||
isAcceptedAdmin: false,
|
isAcceptedAdmin: false,
|
||||||
|
isPendingAdmin: false,
|
||||||
teamsEnabled: false,
|
teamsEnabled: false,
|
||||||
selectedCacheId: null,
|
selectedCacheId: null,
|
||||||
};
|
};
|
||||||
@@ -24,13 +25,16 @@ const setSessionUser = (user) => {
|
|||||||
session.currentTid = user?.TGid ?? null;
|
session.currentTid = user?.TGid ?? null;
|
||||||
session.isBusiness = user?.isBusiness ?? null;
|
session.isBusiness = user?.isBusiness ?? null;
|
||||||
session.isAcceptedAdmin = Boolean(user?.IsAcceptedAdmin);
|
session.isAcceptedAdmin = Boolean(user?.IsAcceptedAdmin);
|
||||||
|
session.isPendingAdmin = Boolean(
|
||||||
|
user?.isBusiness && user?.Gid && !user?.SGid && !user?.IsAcceptedAdmin,
|
||||||
|
);
|
||||||
persistSession();
|
persistSession();
|
||||||
};
|
};
|
||||||
|
|
||||||
const setSessionGroup = (gid, sgid = null) => {
|
const setSessionGroup = (gid, sgid = null) => {
|
||||||
session.currentGid = gid ?? null;
|
session.currentGid = gid ?? null;
|
||||||
if (sgid !== null && sgid !== undefined) {
|
if (sgid !== undefined) {
|
||||||
session.currentSGid = sgid;
|
session.currentSGid = sgid ?? null;
|
||||||
}
|
}
|
||||||
persistSession();
|
persistSession();
|
||||||
};
|
};
|
||||||
@@ -45,6 +49,11 @@ const setSessionTeamsEnabled = (val) => {
|
|||||||
persistSession();
|
persistSession();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const setPendingAdmin = (val) => {
|
||||||
|
session.isPendingAdmin = Boolean(val);
|
||||||
|
persistSession();
|
||||||
|
};
|
||||||
|
|
||||||
const setSelectedCache = (cacheId) => {
|
const setSelectedCache = (cacheId) => {
|
||||||
session.selectedCacheId = cacheId ?? null;
|
session.selectedCacheId = cacheId ?? null;
|
||||||
persistSession();
|
persistSession();
|
||||||
@@ -59,6 +68,7 @@ const clearSession = () => {
|
|||||||
session.currentTid = null;
|
session.currentTid = null;
|
||||||
session.isBusiness = null;
|
session.isBusiness = null;
|
||||||
session.isAcceptedAdmin = false;
|
session.isAcceptedAdmin = false;
|
||||||
|
session.isPendingAdmin = false;
|
||||||
AsyncStorage.removeItem(STORAGE_KEY).catch(() => {});
|
AsyncStorage.removeItem(STORAGE_KEY).catch(() => {});
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -68,6 +78,7 @@ const clearGameSession = () => {
|
|||||||
session.currentSGid = null;
|
session.currentSGid = null;
|
||||||
session.currentTid = null;
|
session.currentTid = null;
|
||||||
session.isAcceptedAdmin = false;
|
session.isAcceptedAdmin = false;
|
||||||
|
session.isPendingAdmin = false;
|
||||||
session.teamsEnabled = false;
|
session.teamsEnabled = false;
|
||||||
session.selectedCacheId = null;
|
session.selectedCacheId = null;
|
||||||
persistSession();
|
persistSession();
|
||||||
@@ -92,4 +103,4 @@ const loadSession = async () => {
|
|||||||
return { ...session };
|
return { ...session };
|
||||||
};
|
};
|
||||||
|
|
||||||
export { setSessionUser, setSessionGroup, setSessionTeam, setSessionTeamsEnabled, setSelectedCache, getSession, clearSession, clearGameSession, loadSession };
|
export { setSessionUser, setSessionGroup, setSessionTeam, setSessionTeamsEnabled, setPendingAdmin, setSelectedCache, getSession, clearSession, clearGameSession, loadSession };
|
||||||
@@ -140,6 +140,9 @@ const useGameHook = () => {
|
|||||||
};
|
};
|
||||||
if (payload.JoinCode !== undefined) data.JoinCode = payload.JoinCode;
|
if (payload.JoinCode !== undefined) data.JoinCode = payload.JoinCode;
|
||||||
if (payload.Tid !== undefined) data.Tid = payload.Tid;
|
if (payload.Tid !== undefined) data.Tid = payload.Tid;
|
||||||
|
if (payload.ExpectedGid !== undefined && payload.ExpectedGid !== null) {
|
||||||
|
data.ExpectedGid = payload.ExpectedGid;
|
||||||
|
}
|
||||||
if (payload.ExpectedSGid !== undefined && payload.ExpectedSGid !== null) {
|
if (payload.ExpectedSGid !== undefined && payload.ExpectedSGid !== null) {
|
||||||
data.ExpectedSGid = payload.ExpectedSGid;
|
data.ExpectedSGid = payload.ExpectedSGid;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in new issue
Block a user