mirror of
https://github.com/mudabbir-ahmad/MAD-Treasure-Hunt.git
synced 2026-10-07 19: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 = [
|
||||
{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',
|
||||
route: 'PlayersScreen',
|
||||
@@ -39,6 +46,11 @@ const BottomNavbar = ({navigation, routeName, routeParams}) => {
|
||||
];
|
||||
|
||||
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 ----------------------
|
||||
// Handlers -------------------
|
||||
@@ -67,7 +79,7 @@ const BottomNavbar = ({navigation, routeName, routeParams}) => {
|
||||
|
||||
return (
|
||||
<View style={[styles.container, {paddingBottom: insets.bottom}]}>
|
||||
{tabs.map((tab) => {
|
||||
{visibleTabs.map((tab) => {
|
||||
const isActive = routeName === tab.route;
|
||||
const isLeave = tab.route === '__leave__';
|
||||
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) {
|
||||
return (
|
||||
<Screen style={styles.container}>
|
||||
|
||||
@@ -10,7 +10,7 @@ import ClaimTimerView from '../gameplay/ClaimTimerView';
|
||||
import PlayerMapView from '../gameplay/PlayerMapView';
|
||||
import useGameHook from '../../hooks/useGameHook';
|
||||
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';
|
||||
|
||||
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 session = getSession();
|
||||
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
|
||||
const getCachesRef = useRef(getCaches);
|
||||
@@ -104,8 +104,9 @@ const MapScreen = ({navigation, route}) => {
|
||||
return map;
|
||||
}, [departments]);
|
||||
const routeDepartmentSGid = route?.params?.selectedDepartmentSGid;
|
||||
const isDepartmentScopedMap = routeDepartmentSGid !== null && routeDepartmentSGid !== undefined;
|
||||
const effectiveSGid = isBusiness
|
||||
? (isAdmin ? (selectedCacheSubgroupId ?? routeDepartmentSGid ?? defaultMemberSGid ?? null) : (session.currentSGid ?? null))
|
||||
? (isAdmin ? (isDepartmentScopedMap ? routeDepartmentSGid : null) : (session.currentSGid ?? null))
|
||||
: null;
|
||||
|
||||
useEffect(() => {
|
||||
@@ -199,6 +200,7 @@ const MapScreen = ({navigation, route}) => {
|
||||
const result = await joinPrivateGame({JoinCode: gameCode.trim().toUpperCase(), Uid: session.currentUid});
|
||||
if (!result) return;
|
||||
setSessionGroup(result.Gid, result.SGid);
|
||||
setPendingAdmin(false);
|
||||
|
||||
const freshUser = await getUser(session.currentUid);
|
||||
if (freshUser) {
|
||||
@@ -219,6 +221,7 @@ const MapScreen = ({navigation, route}) => {
|
||||
MaxMemberSubgroups: 1,
|
||||
});
|
||||
if (!result) return;
|
||||
setPendingAdmin(false);
|
||||
const freshUser = await getUser(session.currentUid);
|
||||
if (freshUser) {
|
||||
setSessionUser(freshUser);
|
||||
@@ -239,6 +242,7 @@ const MapScreen = ({navigation, route}) => {
|
||||
isBusiness: true,
|
||||
});
|
||||
if (!result) return;
|
||||
setPendingAdmin(false);
|
||||
const freshUser = await getUser(session.currentUid);
|
||||
if (freshUser) {
|
||||
setSessionUser(freshUser);
|
||||
@@ -265,8 +269,33 @@ const MapScreen = ({navigation, route}) => {
|
||||
const handleJoinDepartment = async () => {
|
||||
setJoinError('');
|
||||
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({
|
||||
JoinCode: deptCode.trim().toUpperCase(),
|
||||
JoinCode: enteredCode,
|
||||
Uid: session.currentUid,
|
||||
ExpectedGid: matchedGroup.Gid,
|
||||
});
|
||||
@@ -275,6 +304,7 @@ const MapScreen = ({navigation, route}) => {
|
||||
return;
|
||||
}
|
||||
setSessionGroup(result.Gid, result.SGid);
|
||||
setPendingAdmin(false);
|
||||
const freshUser = await getUser(session.currentUid);
|
||||
if (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
|
||||
if (playerLoading) {
|
||||
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) {
|
||||
return (
|
||||
<Screen style={styles.container}>
|
||||
|
||||
@@ -4,9 +4,9 @@ import Screen from '../layout/Screen';
|
||||
import Card from '../UI/Card';
|
||||
import {Button, ButtonTray} from '../UI/Button';
|
||||
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 isAdmin = session.isAcceptedAdmin;
|
||||
const isBusiness = Boolean(session.isBusiness);
|
||||
@@ -48,6 +48,24 @@ const TeamScreen = () => {
|
||||
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) {
|
||||
setTeamsDisabled(true);
|
||||
setLoading(false);
|
||||
@@ -69,6 +87,44 @@ const TeamScreen = () => {
|
||||
load();
|
||||
}, [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 () => {
|
||||
if (!teamCode.trim()) return;
|
||||
// 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 (result.adminWaitlist) {
|
||||
setPendingAdmin(true);
|
||||
setOnAdminWaitlist(true);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -11,6 +11,7 @@ const session = {
|
||||
currentTid: null,
|
||||
isBusiness: null,
|
||||
isAcceptedAdmin: false,
|
||||
isPendingAdmin: false,
|
||||
teamsEnabled: false,
|
||||
selectedCacheId: null,
|
||||
};
|
||||
@@ -24,13 +25,16 @@ const setSessionUser = (user) => {
|
||||
session.currentTid = user?.TGid ?? null;
|
||||
session.isBusiness = user?.isBusiness ?? null;
|
||||
session.isAcceptedAdmin = Boolean(user?.IsAcceptedAdmin);
|
||||
session.isPendingAdmin = Boolean(
|
||||
user?.isBusiness && user?.Gid && !user?.SGid && !user?.IsAcceptedAdmin,
|
||||
);
|
||||
persistSession();
|
||||
};
|
||||
|
||||
const setSessionGroup = (gid, sgid = null) => {
|
||||
session.currentGid = gid ?? null;
|
||||
if (sgid !== null && sgid !== undefined) {
|
||||
session.currentSGid = sgid;
|
||||
if (sgid !== undefined) {
|
||||
session.currentSGid = sgid ?? null;
|
||||
}
|
||||
persistSession();
|
||||
};
|
||||
@@ -45,6 +49,11 @@ const setSessionTeamsEnabled = (val) => {
|
||||
persistSession();
|
||||
};
|
||||
|
||||
const setPendingAdmin = (val) => {
|
||||
session.isPendingAdmin = Boolean(val);
|
||||
persistSession();
|
||||
};
|
||||
|
||||
const setSelectedCache = (cacheId) => {
|
||||
session.selectedCacheId = cacheId ?? null;
|
||||
persistSession();
|
||||
@@ -59,6 +68,7 @@ const clearSession = () => {
|
||||
session.currentTid = null;
|
||||
session.isBusiness = null;
|
||||
session.isAcceptedAdmin = false;
|
||||
session.isPendingAdmin = false;
|
||||
AsyncStorage.removeItem(STORAGE_KEY).catch(() => {});
|
||||
};
|
||||
|
||||
@@ -68,6 +78,7 @@ const clearGameSession = () => {
|
||||
session.currentSGid = null;
|
||||
session.currentTid = null;
|
||||
session.isAcceptedAdmin = false;
|
||||
session.isPendingAdmin = false;
|
||||
session.teamsEnabled = false;
|
||||
session.selectedCacheId = null;
|
||||
persistSession();
|
||||
@@ -92,4 +103,4 @@ const loadSession = async () => {
|
||||
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.Tid !== undefined) data.Tid = payload.Tid;
|
||||
if (payload.ExpectedGid !== undefined && payload.ExpectedGid !== null) {
|
||||
data.ExpectedGid = payload.ExpectedGid;
|
||||
}
|
||||
if (payload.ExpectedSGid !== undefined && payload.ExpectedSGid !== null) {
|
||||
data.ExpectedSGid = payload.ExpectedSGid;
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user