mirror of
https://github.com/mudabbir-ahmad/MAD-Treasure-Hunt.git
synced 2026-10-08 03:00:20 +00:00
Refactor session management to use AsyncStorage for persistence; update game settings and leaderboard screens for improved functionality
This commit is contained in:
1 parent
2646c7b9bc
commit
5183039b7b
26 files changed
+636
-849
No files matched your search
@@ -1,5 +1,5 @@
|
||||
import React, {useCallback, useEffect, useState} from 'react';
|
||||
import {ActivityIndicator, Pressable, ScrollView, StyleSheet, Text, View} from 'react-native';
|
||||
import {ActivityIndicator, ScrollView, StyleSheet, Text, View} from 'react-native';
|
||||
import Screen from '../layout/Screen';
|
||||
import Card from '../UI/Card';
|
||||
import {Button} from '../UI/Button';
|
||||
@@ -10,93 +10,59 @@ const PlayersScreen = () => {
|
||||
// Initialisation ------------
|
||||
|
||||
const session = getSession();
|
||||
const {getLobby, getTeams, getTeamMembers, getGroupMembers, removeMember, getUser, getCaches} = useGameHook();
|
||||
const {getTeams, getTeamMembers, getGroupMembers, removeMember, getUser} = useGameHook();
|
||||
|
||||
// State ----------------------
|
||||
|
||||
const [loading, setLoading] = useState(true);
|
||||
const [groupInfo, setGroupInfo] = useState(null);
|
||||
const [teams, setTeams] = useState([]);
|
||||
const [players, setPlayers] = useState([]);
|
||||
const [selectedTeam, setSelectedTeam] = useState(null);
|
||||
const [teamMembers, setTeamMembers] = useState([]);
|
||||
const [memberNames, setMemberNames] = useState({});
|
||||
const [memberCacheCounts, setMemberCacheCounts] = useState({});
|
||||
const [detailLoading, setDetailLoading] = useState(false);
|
||||
|
||||
// Handlers -------------------
|
||||
|
||||
const loadData = useCallback(async () => {
|
||||
if (!session.currentGid) {
|
||||
setLoading(false);
|
||||
return;
|
||||
}
|
||||
const group = await getLobby(session.currentGid);
|
||||
setGroupInfo(group);
|
||||
if (!session.currentGid) { setLoading(false); return; }
|
||||
|
||||
if (group && group.TeamsEnabled) {
|
||||
const teamRows = await getTeams(session.currentGid);
|
||||
setTeams(teamRows || []);
|
||||
} else {
|
||||
const allMembers = await getGroupMembers(session.currentGid);
|
||||
const nonAdminMembers = (allMembers || []).filter((m) => !m.IsAcceptedAdmin);
|
||||
const playerList = [];
|
||||
for (const m of nonAdminMembers) {
|
||||
const user = await getUser(m.Uid);
|
||||
if (user) playerList.push({...user, membershipId: m.id});
|
||||
// Get all non-admin players
|
||||
const allMembers = await getGroupMembers(session.currentGid);
|
||||
const nonAdminMembers = (allMembers || []).filter((m) => !m.IsAcceptedAdmin);
|
||||
|
||||
// Build team lookup: { Uid -> { teamCode, teamName, isLeader } }
|
||||
const allTeams = await getTeams(session.currentGid);
|
||||
const teamInfoByUid = {};
|
||||
for (const team of (allTeams || [])) {
|
||||
const tms = await getTeamMembers(team.Tid);
|
||||
for (const tm of (tms || [])) {
|
||||
teamInfoByUid[tm.Uid] = {
|
||||
teamCode: team.JoinCode,
|
||||
teamName: team.TeamName,
|
||||
isLeader: Boolean(tm.IsLeader),
|
||||
};
|
||||
}
|
||||
setPlayers(playerList);
|
||||
}
|
||||
|
||||
// Build player list
|
||||
const playerList = [];
|
||||
for (const m of nonAdminMembers) {
|
||||
const user = await getUser(m.Uid);
|
||||
if (user) {
|
||||
playerList.push({
|
||||
...user,
|
||||
membershipId: m.id,
|
||||
team: teamInfoByUid[m.Uid] || null,
|
||||
});
|
||||
}
|
||||
}
|
||||
setPlayers(playerList);
|
||||
setLoading(false);
|
||||
}, [session.currentGid]);
|
||||
|
||||
useEffect(() => { loadData(); }, [loadData]);
|
||||
|
||||
const handleSelectTeam = async (team) => {
|
||||
setSelectedTeam(team);
|
||||
setDetailLoading(true);
|
||||
|
||||
const ms = await getTeamMembers(team.Tid);
|
||||
setTeamMembers(ms || []);
|
||||
|
||||
const names = {};
|
||||
for (const m of (ms || [])) {
|
||||
const user = await getUser(m.Uid);
|
||||
if (user) names[m.Uid] = user.username;
|
||||
}
|
||||
setMemberNames(names);
|
||||
|
||||
const caches = await getCaches(session.currentGid, null);
|
||||
const counts = {};
|
||||
for (const m of (ms || [])) {
|
||||
counts[m.Uid] = (caches || []).filter((c) => c.ClaimedByUid === m.Uid).length;
|
||||
}
|
||||
setMemberCacheCounts(counts);
|
||||
setDetailLoading(false);
|
||||
};
|
||||
|
||||
const handleBackToTeams = () => {
|
||||
setSelectedTeam(null);
|
||||
setTeamMembers([]);
|
||||
setMemberNames({});
|
||||
setMemberCacheCounts({});
|
||||
};
|
||||
|
||||
const handleRemovePlayer = async (membershipId) => {
|
||||
await removeMember(membershipId);
|
||||
await loadData();
|
||||
};
|
||||
|
||||
const handleRemoveTeamMember = async (member) => {
|
||||
// Find this user's subgroup membership to remove them from the game
|
||||
const allMembers = await getGroupMembers(session.currentGid);
|
||||
const membership = (allMembers || []).find((m) => m.Uid === member.Uid && !m.IsAcceptedAdmin);
|
||||
if (membership) {
|
||||
await removeMember(membership.id);
|
||||
await handleSelectTeam(selectedTeam);
|
||||
}
|
||||
};
|
||||
|
||||
// View -----------------------
|
||||
|
||||
if (loading) {
|
||||
@@ -115,101 +81,24 @@ const PlayersScreen = () => {
|
||||
);
|
||||
}
|
||||
|
||||
// Teams enabled — show team detail view
|
||||
if (groupInfo?.TeamsEnabled && selectedTeam) {
|
||||
return (
|
||||
<Screen style={styles.container}>
|
||||
<View style={styles.teamDetailHeader}>
|
||||
<Text style={styles.teamDetailName}>{selectedTeam.TeamName || 'Unnamed Team'}</Text>
|
||||
<Text style={styles.teamDetailCode}>Code: {selectedTeam.JoinCode}</Text>
|
||||
</View>
|
||||
|
||||
{detailLoading ? (
|
||||
<View style={styles.center}>
|
||||
<ActivityIndicator size="large"/>
|
||||
</View>
|
||||
) : (
|
||||
<ScrollView style={styles.listSection}>
|
||||
<Text style={styles.sectionTitle}>Team Members</Text>
|
||||
{teamMembers.map((m) => (
|
||||
<Card key={m.id}>
|
||||
<View style={styles.memberRow}>
|
||||
<Text style={styles.memberName}>
|
||||
{memberNames[m.Uid] || `Player ${m.Uid}`}
|
||||
</Text>
|
||||
<Text style={styles.memberCaches}>
|
||||
{memberCacheCounts[m.Uid] || 0} cache(s) claimed
|
||||
</Text>
|
||||
</View>
|
||||
<View style={styles.removeWrap}>
|
||||
<Button
|
||||
label="Remove"
|
||||
onClick={() => handleRemoveTeamMember(m)}
|
||||
styleButton={styles.removeButton}
|
||||
styleLabel={styles.removeLabel}
|
||||
/>
|
||||
</View>
|
||||
</Card>
|
||||
))}
|
||||
{teamMembers.length === 0 && (
|
||||
<Text style={styles.emptyText}>No members in this team.</Text>
|
||||
)}
|
||||
</ScrollView>
|
||||
)}
|
||||
|
||||
<View style={styles.backWrap}>
|
||||
<Button
|
||||
label="Back to Teams"
|
||||
onClick={handleBackToTeams}
|
||||
styleButton={styles.backButton}
|
||||
styleLabel={styles.backLabel}
|
||||
/>
|
||||
</View>
|
||||
</Screen>
|
||||
);
|
||||
}
|
||||
|
||||
// Teams enabled — show team cards
|
||||
if (groupInfo?.TeamsEnabled) {
|
||||
return (
|
||||
<Screen style={styles.container}>
|
||||
<Text style={styles.sectionTitle}>Teams</Text>
|
||||
<ScrollView style={styles.listSection}>
|
||||
{teams.map((team) => (
|
||||
<Pressable key={team.Tid} onPress={() => handleSelectTeam(team)}>
|
||||
<Card>
|
||||
<View style={styles.teamCardRow}>
|
||||
<Text style={styles.teamName}>
|
||||
{team.TeamName || 'Unnamed Team'}
|
||||
</Text>
|
||||
<Text style={styles.teamCode}>
|
||||
Code: {team.JoinCode}
|
||||
</Text>
|
||||
</View>
|
||||
</Card>
|
||||
</Pressable>
|
||||
))}
|
||||
{teams.length === 0 && (
|
||||
<Text style={styles.emptyText}>No teams have been created yet.</Text>
|
||||
)}
|
||||
</ScrollView>
|
||||
</Screen>
|
||||
);
|
||||
}
|
||||
|
||||
// Teams disabled — show player list
|
||||
return (
|
||||
<Screen style={styles.container}>
|
||||
<Text style={styles.sectionTitle}>Players</Text>
|
||||
<ScrollView style={styles.listSection}>
|
||||
{players.map((player) => (
|
||||
<Card key={player.Uid}>
|
||||
<View style={styles.memberRow}>
|
||||
<Text style={styles.playerName}>{player.username}</Text>
|
||||
</View>
|
||||
<View style={styles.removeWrap}>
|
||||
<View style={styles.playerRow}>
|
||||
<Text style={styles.playerName} numberOfLines={1}>{player.username}</Text>
|
||||
<View style={styles.playerMeta}>
|
||||
{player.team?.isLeader && (
|
||||
<Text style={styles.leaderBadge}>(Team Leader)</Text>
|
||||
)}
|
||||
{player.team && (
|
||||
<Text style={styles.teamCodeBadge}>{player.team.teamCode}</Text>
|
||||
)}
|
||||
</View>
|
||||
<Button
|
||||
label="Remove"
|
||||
label="Kick"
|
||||
onClick={() => handleRemovePlayer(player.membershipId)}
|
||||
styleButton={styles.removeButton}
|
||||
styleLabel={styles.removeLabel}
|
||||
@@ -239,38 +128,17 @@ const styles = StyleSheet.create({
|
||||
},
|
||||
listSection: {flex: 1, paddingHorizontal: 15},
|
||||
emptyText: {color: '#9ca3af', textAlign: 'center', marginTop: 30, fontSize: 14},
|
||||
// Team cards
|
||||
teamCardRow: {
|
||||
playerRow: {
|
||||
flexDirection: 'row',
|
||||
justifyContent: 'space-between',
|
||||
alignItems: 'center',
|
||||
gap: 8,
|
||||
},
|
||||
teamName: {fontSize: 16, fontWeight: '600', color: '#1f2937'},
|
||||
teamCode: {fontSize: 14, fontWeight: '700', color: '#2563eb', letterSpacing: 1},
|
||||
// Team detail
|
||||
teamDetailHeader: {
|
||||
backgroundColor: '#374151',
|
||||
paddingVertical: 14,
|
||||
paddingHorizontal: 16,
|
||||
},
|
||||
teamDetailName: {fontSize: 18, fontWeight: '700', color: '#ffffff', marginBottom: 4},
|
||||
teamDetailCode: {fontSize: 14, fontWeight: '600', color: '#93c5fd', letterSpacing: 1},
|
||||
memberRow: {
|
||||
flexDirection: 'row',
|
||||
justifyContent: 'space-between',
|
||||
alignItems: 'center',
|
||||
},
|
||||
memberName: {fontSize: 16, fontWeight: '600', color: '#1f2937'},
|
||||
memberCaches: {fontSize: 13, fontWeight: '600', color: '#16a34a'},
|
||||
// Remove button
|
||||
removeWrap: {marginTop: 8},
|
||||
removeButton: {backgroundColor: '#dc2626', borderColor: '#dc2626', minHeight: 36},
|
||||
playerName: {fontSize: 15, fontWeight: '600', color: '#1f2937', flex: 1},
|
||||
playerMeta: {flexDirection: 'row', alignItems: 'center', gap: 6},
|
||||
leaderBadge: {fontSize: 11, color: '#2563eb', fontWeight: '700'},
|
||||
teamCodeBadge: {fontSize: 12, fontWeight: '700', color: '#16a34a', letterSpacing: 1},
|
||||
removeButton: {backgroundColor: '#dc2626', borderColor: '#dc2626', minHeight: 36, flex: 0, paddingHorizontal: 12},
|
||||
removeLabel: {color: '#ffffff', fontWeight: '600', fontSize: 13},
|
||||
backWrap: {padding: 15},
|
||||
backButton: {backgroundColor: '#6b7280', borderColor: '#6b7280'},
|
||||
backLabel: {color: '#ffffff', fontWeight: '600'},
|
||||
// Player list
|
||||
playerName: {fontSize: 16, fontWeight: '600', color: '#1f2937'},
|
||||
});
|
||||
|
||||
export default PlayersScreen;
|
||||
|
||||
Reference in new issue
Block a user