mirror of
https://github.com/mudabbir-ahmad/MAD-Treasure-Hunt.git
synced 2026-10-07 19:00:20 +00:00
Refactor business settings: update department-related UI elements, enhance game reset functionality, and improve data handling for business accounts.
This commit is contained in:
1 parent
e0065e885f
commit
dd5dd83737
6 files changed
+130
-74
No files matched your search
@@ -60,7 +60,7 @@ const DepartmentSettingsScreen = ({route, navigation}) => {
|
|||||||
text: 'Reset',
|
text: 'Reset',
|
||||||
style: 'destructive',
|
style: 'destructive',
|
||||||
onPress: async () => {
|
onPress: async () => {
|
||||||
await resetGame(Gid);
|
await resetGame(Gid, SGid);
|
||||||
Alert.alert('Done', 'Department progress has been reset.');
|
Alert.alert('Done', 'Department progress has been reset.');
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ const GameSettingsScreen = ({navigation}) => {
|
|||||||
// Initialisation ------------
|
// Initialisation ------------
|
||||||
|
|
||||||
const session = getSession();
|
const session = getSession();
|
||||||
const {getLobby, updateGroup, getSubgroups, createSubgroup, updateSubgroup, deleteSubgroup, resetGame, getAdminWaitlist, approveAdmin, rejectAdmin, getUser, disbandTeams} = useGameHook();
|
const {getLobby, updateGroup, getSubgroups, createSubgroup, deleteSubgroup, resetGame, getAdminWaitlist, approveAdmin, rejectAdmin, getUser, disbandTeams} = useGameHook();
|
||||||
const isBusiness = Boolean(session.isBusiness);
|
const isBusiness = Boolean(session.isBusiness);
|
||||||
|
|
||||||
// State ----------------------
|
// State ----------------------
|
||||||
@@ -209,24 +209,24 @@ const GameSettingsScreen = ({navigation}) => {
|
|||||||
return (
|
return (
|
||||||
<Screen>
|
<Screen>
|
||||||
<ScrollView contentContainerStyle={styles.formContainer} showsVerticalScrollIndicator={false}>
|
<ScrollView contentContainerStyle={styles.formContainer} showsVerticalScrollIndicator={false}>
|
||||||
<Text style={styles.sectionTitle}>Business Settings</Text>
|
<Text style={styles.sectionTitle}>Game Configuration :</Text>
|
||||||
|
|
||||||
<Text style={styles.label}>Business Name</Text>
|
<Text style={styles.label}>Organisation Name:</Text>
|
||||||
<TextInput
|
<TextInput
|
||||||
style={styles.input}
|
style={styles.input}
|
||||||
value={businessName}
|
value={businessName}
|
||||||
onChangeText={setBusinessName}
|
onChangeText={setBusinessName}
|
||||||
placeholder="Enter business name"
|
placeholder="Enter organisation name"
|
||||||
placeholderTextColor="#9ca3af"
|
placeholderTextColor="#9ca3af"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<View style={styles.codeSection}>
|
<View style={styles.codeSection}>
|
||||||
<Text style={styles.codeLabel}>Admin Join Code</Text>
|
<Text style={styles.codeLabel}>Admin join code:</Text>
|
||||||
<Text style={styles.codeValue}>{adminJoinCode || '—'}</Text>
|
<Text style={styles.codeValue}>{adminJoinCode || '—'}</Text>
|
||||||
</View>
|
</View>
|
||||||
|
|
||||||
<View style={styles.codeSection}>
|
<View style={styles.codeSection}>
|
||||||
<Text style={styles.codeLabel}>Organisation Join Code</Text>
|
<Text style={styles.codeLabel}>Org join code:</Text>
|
||||||
<Text style={styles.codeValue}>{orgJoinCode || '—'}</Text>
|
<Text style={styles.codeValue}>{orgJoinCode || '—'}</Text>
|
||||||
</View>
|
</View>
|
||||||
|
|
||||||
@@ -243,27 +243,36 @@ const GameSettingsScreen = ({navigation}) => {
|
|||||||
|
|
||||||
{/* Departments List */}
|
{/* Departments List */}
|
||||||
<View style={styles.deptSection}>
|
<View style={styles.deptSection}>
|
||||||
<Text style={styles.sectionTitle}>Departments</Text>
|
<Text style={styles.sectionTitle}>Departments:</Text>
|
||||||
{departments.map((sg) => (
|
{departments.map((sg, index) => (
|
||||||
<Card key={sg.SGid}>
|
<Card key={sg.SGid}>
|
||||||
<View style={styles.deptRow}>
|
<Text style={styles.deptIndexLabel}>Department {index + 1}:</Text>
|
||||||
<View style={styles.deptInfo}>
|
<View style={styles.deptCardRow}>
|
||||||
|
<View style={styles.deptCardInfo}>
|
||||||
|
<Text style={styles.deptInfoLabel}>Department Name</Text>
|
||||||
<Text style={styles.deptName}>{sg.SubGroupName}</Text>
|
<Text style={styles.deptName}>{sg.SubGroupName}</Text>
|
||||||
<Text style={styles.deptCode}>Join Code: {sg.JoinCode || '—'}</Text>
|
|
||||||
</View>
|
</View>
|
||||||
<View style={styles.deptActions}>
|
<View style={styles.deptCardActions}>
|
||||||
<Button
|
<Button
|
||||||
label="Delete"
|
label="Open Department Game Settings"
|
||||||
|
onClick={() => handleEnterDepartment(sg)}
|
||||||
|
styleButton={styles.deptOpenButton}
|
||||||
|
styleLabel={styles.deptBtnLabel}
|
||||||
|
/>
|
||||||
|
</View>
|
||||||
|
</View>
|
||||||
|
<View style={styles.deptCardRow}>
|
||||||
|
<View style={styles.deptCardInfo}>
|
||||||
|
<Text style={styles.deptInfoLabel}>Department Join code</Text>
|
||||||
|
<Text style={styles.deptCode}>{sg.JoinCode || '—'}</Text>
|
||||||
|
</View>
|
||||||
|
<View style={styles.deptCardActions}>
|
||||||
|
<Button
|
||||||
|
label="Delete Department"
|
||||||
onClick={() => handleDeleteDepartment(sg)}
|
onClick={() => handleDeleteDepartment(sg)}
|
||||||
styleButton={styles.deptDeleteButton}
|
styleButton={styles.deptDeleteButton}
|
||||||
styleLabel={styles.deptBtnLabel}
|
styleLabel={styles.deptBtnLabel}
|
||||||
/>
|
/>
|
||||||
<Button
|
|
||||||
label="→"
|
|
||||||
onClick={() => handleEnterDepartment(sg)}
|
|
||||||
styleButton={styles.deptArrowButton}
|
|
||||||
styleLabel={styles.deptArrowLabel}
|
|
||||||
/>
|
|
||||||
</View>
|
</View>
|
||||||
</View>
|
</View>
|
||||||
</Card>
|
</Card>
|
||||||
@@ -475,15 +484,16 @@ const styles = StyleSheet.create({
|
|||||||
saveLabel: {color: '#ffffff', fontWeight: '600'},
|
saveLabel: {color: '#ffffff', fontWeight: '600'},
|
||||||
// Department / subgroup styles
|
// Department / subgroup styles
|
||||||
deptSection: {marginTop: 30},
|
deptSection: {marginTop: 30},
|
||||||
deptRow: {flexDirection: 'row', justifyContent: 'space-between', alignItems: 'center'},
|
deptIndexLabel: {fontSize: 14, fontWeight: '700', color: '#374151', marginBottom: 8},
|
||||||
deptInfo: {flex: 1},
|
deptCardRow: {flexDirection: 'row', justifyContent: 'space-between', alignItems: 'center', marginBottom: 8},
|
||||||
|
deptCardInfo: {flex: 1, paddingRight: 10},
|
||||||
|
deptCardActions: {flexDirection: 'row', gap: 6, flex: 0},
|
||||||
|
deptInfoLabel: {fontSize: 12, fontWeight: '600', color: '#6b7280', marginBottom: 2},
|
||||||
deptName: {fontSize: 15, fontWeight: '700', color: '#1f2937'},
|
deptName: {fontSize: 15, fontWeight: '700', color: '#1f2937'},
|
||||||
deptCode: {fontSize: 13, fontWeight: '600', color: '#2563eb', marginTop: 2, letterSpacing: 1},
|
deptCode: {fontSize: 13, fontWeight: '600', color: '#2563eb', marginTop: 2, letterSpacing: 1},
|
||||||
deptActions: {flexDirection: 'row', gap: 6},
|
|
||||||
deptDeleteButton: {backgroundColor: '#dc2626', borderColor: '#dc2626', minHeight: 36, flex: 0, paddingHorizontal: 10},
|
deptDeleteButton: {backgroundColor: '#dc2626', borderColor: '#dc2626', minHeight: 36, flex: 0, paddingHorizontal: 10},
|
||||||
|
deptOpenButton: {backgroundColor: '#2563eb', borderColor: '#2563eb', minHeight: 36, flex: 0, paddingHorizontal: 10},
|
||||||
deptBtnLabel: {color: '#ffffff', fontWeight: '600', fontSize: 13},
|
deptBtnLabel: {color: '#ffffff', fontWeight: '600', fontSize: 13},
|
||||||
deptArrowButton: {backgroundColor: '#2563eb', borderColor: '#2563eb', minHeight: 36, flex: 0, paddingHorizontal: 14},
|
|
||||||
deptArrowLabel: {color: '#ffffff', fontWeight: '700', fontSize: 18},
|
|
||||||
createDeptRow: {flexDirection: 'row', gap: 10, marginTop: 12, alignItems: 'center'},
|
createDeptRow: {flexDirection: 'row', gap: 10, marginTop: 12, alignItems: 'center'},
|
||||||
createDeptButton: {backgroundColor: '#16a34a', borderColor: '#16a34a', flex: 0, paddingHorizontal: 16},
|
createDeptButton: {backgroundColor: '#16a34a', borderColor: '#16a34a', flex: 0, paddingHorizontal: 16},
|
||||||
createDeptLabel: {color: '#ffffff', fontWeight: '600'},
|
createDeptLabel: {color: '#ffffff', fontWeight: '600'},
|
||||||
|
|||||||
@@ -6,12 +6,14 @@ import {Button} from '../UI/Button';
|
|||||||
import useGameHook from '../../hooks/useGameHook';
|
import useGameHook from '../../hooks/useGameHook';
|
||||||
import {getSession} from '../../hooks/SessionStore';
|
import {getSession} from '../../hooks/SessionStore';
|
||||||
|
|
||||||
const LeaderboardScreen = () => {
|
const LeaderboardScreen = ({navigation, route}) => {
|
||||||
// Initialisation ------------
|
// Initialisation ------------
|
||||||
|
|
||||||
const session = getSession();
|
const session = getSession();
|
||||||
const isAdmin = session.isAcceptedAdmin;
|
const isAdmin = session.isAcceptedAdmin;
|
||||||
const {getLobby, getTeams, getTeamMembers, getGroupMembers, getCaches, getUser, deleteTeam, resetPlayerProgress, resetTeamProgress} = useGameHook();
|
const isBusiness = Boolean(session.isBusiness);
|
||||||
|
const selectedDepartment = route?.params?.department || null;
|
||||||
|
const {getLobby, getTeams, getTeamMembers, getGroupMembers, getCaches, getUser, deleteTeam, resetPlayerProgress, resetTeamProgress, getSubgroups} = useGameHook();
|
||||||
|
|
||||||
// State ----------------------
|
// State ----------------------
|
||||||
|
|
||||||
@@ -23,6 +25,7 @@ const LeaderboardScreen = () => {
|
|||||||
const [myTeamRanking, setMyTeamRanking] = useState([]);
|
const [myTeamRanking, setMyTeamRanking] = useState([]);
|
||||||
const [expandedTeam, setExpandedTeam] = useState(null);
|
const [expandedTeam, setExpandedTeam] = useState(null);
|
||||||
const [totalCacheCount, setTotalCacheCount] = useState(0);
|
const [totalCacheCount, setTotalCacheCount] = useState(0);
|
||||||
|
const [departmentList, setDepartmentList] = useState([]);
|
||||||
|
|
||||||
// Handlers -------------------
|
// Handlers -------------------
|
||||||
|
|
||||||
@@ -33,7 +36,18 @@ const LeaderboardScreen = () => {
|
|||||||
const isTeams = Boolean(group?.TeamsEnabled);
|
const isTeams = Boolean(group?.TeamsEnabled);
|
||||||
setTeamsEnabled(isTeams);
|
setTeamsEnabled(isTeams);
|
||||||
|
|
||||||
const caches = await getCaches(session.currentGid, null);
|
if (isBusiness && isAdmin && !selectedDepartment) {
|
||||||
|
const sgs = await getSubgroups(session.currentGid);
|
||||||
|
setDepartmentList((sgs || []).filter((sg) => !sg.IsAdminGroup));
|
||||||
|
setLoading(false);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const leaderboardSGid = (isBusiness && isAdmin && selectedDepartment?.SGid)
|
||||||
|
? selectedDepartment.SGid
|
||||||
|
: null;
|
||||||
|
|
||||||
|
const caches = await getCaches(session.currentGid, leaderboardSGid);
|
||||||
const total = (caches || []).length;
|
const total = (caches || []).length;
|
||||||
setTotalCacheCount(total);
|
setTotalCacheCount(total);
|
||||||
|
|
||||||
@@ -42,7 +56,11 @@ const LeaderboardScreen = () => {
|
|||||||
const teams = await getTeams(session.currentGid);
|
const teams = await getTeams(session.currentGid);
|
||||||
const teamData = [];
|
const teamData = [];
|
||||||
|
|
||||||
for (const team of (teams || [])) {
|
const scopedTeams = leaderboardSGid
|
||||||
|
? (teams || []).filter((team) => !team.SGid || team.SGid === leaderboardSGid)
|
||||||
|
: (teams || []);
|
||||||
|
|
||||||
|
for (const team of scopedTeams) {
|
||||||
const members = await getTeamMembers(team.Tid);
|
const members = await getTeamMembers(team.Tid);
|
||||||
const memberData = [];
|
const memberData = [];
|
||||||
for (const m of (members || [])) {
|
for (const m of (members || [])) {
|
||||||
@@ -81,8 +99,11 @@ const LeaderboardScreen = () => {
|
|||||||
} else {
|
} else {
|
||||||
// Build player rankings (no teams)
|
// Build player rankings (no teams)
|
||||||
const allMembers = await getGroupMembers(session.currentGid);
|
const allMembers = await getGroupMembers(session.currentGid);
|
||||||
|
const scopedMembers = leaderboardSGid
|
||||||
|
? (allMembers || []).filter((mem) => mem.SGid === leaderboardSGid)
|
||||||
|
: (allMembers || []);
|
||||||
const playerData = [];
|
const playerData = [];
|
||||||
for (const m of (allMembers || []).filter((mem) => !mem.IsAcceptedAdmin)) {
|
for (const m of scopedMembers.filter((mem) => !mem.IsAcceptedAdmin)) {
|
||||||
const user = await getUser(m.Uid);
|
const user = await getUser(m.Uid);
|
||||||
const count = (caches || []).filter((c) =>
|
const count = (caches || []).filter((c) =>
|
||||||
(c.Claims || []).some((cl) => cl.Uid === m.Uid)
|
(c.Claims || []).some((cl) => cl.Uid === m.Uid)
|
||||||
@@ -98,7 +119,7 @@ const LeaderboardScreen = () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
setLoading(false);
|
setLoading(false);
|
||||||
}, [session.currentGid, session.currentTid]);
|
}, [session.currentGid, session.currentTid, isBusiness, isAdmin, selectedDepartment, selectedDepartment?.SGid]);
|
||||||
|
|
||||||
useEffect(() => { loadData(); }, [loadData]);
|
useEffect(() => { loadData(); }, [loadData]);
|
||||||
|
|
||||||
@@ -166,6 +187,32 @@ const LeaderboardScreen = () => {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (isBusiness && isAdmin && !selectedDepartment) {
|
||||||
|
return (
|
||||||
|
<Screen style={styles.container}>
|
||||||
|
<Text style={styles.departmentTitle}>Departments</Text>
|
||||||
|
<ScrollView style={styles.listSection}>
|
||||||
|
{departmentList.map((department) => (
|
||||||
|
<Pressable
|
||||||
|
key={department.SGid}
|
||||||
|
onPress={() => navigation.navigate('LeaderboardScreen', {department})}
|
||||||
|
>
|
||||||
|
<Card>
|
||||||
|
<View style={styles.rankRow}>
|
||||||
|
<Text style={styles.rankName}>{department.SubGroupName}</Text>
|
||||||
|
<Text style={styles.openLabel}>Open</Text>
|
||||||
|
</View>
|
||||||
|
</Card>
|
||||||
|
</Pressable>
|
||||||
|
))}
|
||||||
|
{departmentList.length === 0 && (
|
||||||
|
<Text style={styles.emptyText}>No departments yet.</Text>
|
||||||
|
)}
|
||||||
|
</ScrollView>
|
||||||
|
</Screen>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
// Helper: render an expandable team card (admin version with delete + reset)
|
// Helper: render an expandable team card (admin version with delete + reset)
|
||||||
const renderAdminTeamCard = (team, index) => (
|
const renderAdminTeamCard = (team, index) => (
|
||||||
<Card key={team.tid}>
|
<Card key={team.tid}>
|
||||||
@@ -269,7 +316,10 @@ const LeaderboardScreen = () => {
|
|||||||
// Teams enabled: show team list (no tabs for admin)
|
// Teams enabled: show team list (no tabs for admin)
|
||||||
if (teamsEnabled) {
|
if (teamsEnabled) {
|
||||||
return (
|
return (
|
||||||
<Screen style={styles.container}>
|
<Screen style={styles.container} showBack={Boolean(selectedDepartment)}>
|
||||||
|
{selectedDepartment && (
|
||||||
|
<Text style={styles.departmentTitle}>{selectedDepartment.SubGroupName}</Text>
|
||||||
|
)}
|
||||||
<ScrollView style={styles.listSection}>
|
<ScrollView style={styles.listSection}>
|
||||||
{teamRankings.map((team, index) => renderAdminTeamCard(team, index))}
|
{teamRankings.map((team, index) => renderAdminTeamCard(team, index))}
|
||||||
{teamRankings.length === 0 && (
|
{teamRankings.length === 0 && (
|
||||||
@@ -282,7 +332,10 @@ const LeaderboardScreen = () => {
|
|||||||
|
|
||||||
// Teams disabled: show player list with reset buttons
|
// Teams disabled: show player list with reset buttons
|
||||||
return (
|
return (
|
||||||
<Screen style={styles.container}>
|
<Screen style={styles.container} showBack={Boolean(selectedDepartment)}>
|
||||||
|
{selectedDepartment && (
|
||||||
|
<Text style={styles.departmentTitle}>{selectedDepartment.SubGroupName}</Text>
|
||||||
|
)}
|
||||||
<ScrollView style={styles.listSection}>
|
<ScrollView style={styles.listSection}>
|
||||||
{playerRankings.map((player, index) => renderAdminPlayerCard(player, index))}
|
{playerRankings.map((player, index) => renderAdminPlayerCard(player, index))}
|
||||||
{playerRankings.length === 0 && (
|
{playerRankings.length === 0 && (
|
||||||
@@ -361,6 +414,8 @@ const styles = StyleSheet.create({
|
|||||||
center: {justifyContent: 'center', alignItems: 'center'},
|
center: {justifyContent: 'center', alignItems: 'center'},
|
||||||
container: {padding: 0},
|
container: {padding: 0},
|
||||||
body: {color: '#4b5563', fontSize: 15},
|
body: {color: '#4b5563', fontSize: 15},
|
||||||
|
departmentTitle: {fontSize: 20, fontWeight: '700', color: '#1f2937', paddingHorizontal: 15, paddingTop: 15, marginBottom: 6},
|
||||||
|
openLabel: {fontSize: 13, fontWeight: '700', color: '#2563eb'},
|
||||||
tabRow: {
|
tabRow: {
|
||||||
flexDirection: 'row',
|
flexDirection: 'row',
|
||||||
borderBottomWidth: 1,
|
borderBottomWidth: 1,
|
||||||
|
|||||||
@@ -42,7 +42,7 @@ const MapScreen = ({navigation}) => {
|
|||||||
const [subgroups, setSubgroups] = useState([]);
|
const [subgroups, setSubgroups] = useState([]);
|
||||||
|
|
||||||
// Business join flow state
|
// Business join flow state
|
||||||
const [joinStep, setJoinStep] = useState(null); // null | 'orgCode' | 'deptCode'
|
const [joinStep, setJoinStep] = useState(null); // null | 'deptCode'
|
||||||
const [orgCode, setOrgCode] = useState('');
|
const [orgCode, setOrgCode] = useState('');
|
||||||
const [deptCode, setDeptCode] = useState('');
|
const [deptCode, setDeptCode] = useState('');
|
||||||
const [matchedGroup, setMatchedGroup] = useState(null);
|
const [matchedGroup, setMatchedGroup] = useState(null);
|
||||||
@@ -365,7 +365,7 @@ const MapScreen = ({navigation}) => {
|
|||||||
<ButtonTray>
|
<ButtonTray>
|
||||||
<Button
|
<Button
|
||||||
label="Back"
|
label="Back"
|
||||||
onClick={() => { setJoinStep('orgCode'); setDeptCode(''); setJoinError(''); }}
|
onClick={() => { setJoinStep(null); setDeptCode(''); setJoinError(''); }}
|
||||||
styleButton={styles.backButton}
|
styleButton={styles.backButton}
|
||||||
styleLabel={styles.backLabel}
|
styleLabel={styles.backLabel}
|
||||||
/>
|
/>
|
||||||
@@ -375,48 +375,28 @@ const MapScreen = ({navigation}) => {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Step 1: Enter org code (or choose create / join)
|
// Default: Join company or Create company choice
|
||||||
if (joinStep === 'orgCode') {
|
|
||||||
return (
|
return (
|
||||||
<Screen style={styles.center}>
|
<Screen style={styles.center}>
|
||||||
<Text style={styles.bizTitle}>Join a Company</Text>
|
<Text style={styles.bizTitle}>Welcome</Text>
|
||||||
<Text style={styles.bizSubtitle}>Enter the organisation code provided by your company</Text>
|
<Text style={styles.bizSubtitle}>Set up your organisation or join an existing one</Text>
|
||||||
<View style={styles.inputRow}>
|
<View style={styles.inputRow}>
|
||||||
<TextInput
|
<TextInput
|
||||||
style={styles.codeInput}
|
style={styles.codeInput}
|
||||||
placeholder="Organisation Code"
|
placeholder="Company Code"
|
||||||
placeholderTextColor="#9ca3af"
|
placeholderTextColor="#9ca3af"
|
||||||
value={orgCode}
|
value={orgCode}
|
||||||
onChangeText={(text) => setOrgCode(text.toUpperCase())}
|
onChangeText={(text) => setOrgCode(text.toUpperCase())}
|
||||||
autoCapitalize="characters"
|
autoCapitalize="characters"
|
||||||
/>
|
/>
|
||||||
<Button
|
<Button
|
||||||
label="Next"
|
label="Join Company"
|
||||||
onClick={handleVerifyOrgCode}
|
onClick={handleVerifyOrgCode}
|
||||||
styleButton={styles.joinButton}
|
styleButton={styles.joinButton}
|
||||||
styleLabel={styles.joinLabel}
|
styleLabel={styles.joinLabel}
|
||||||
/>
|
/>
|
||||||
</View>
|
</View>
|
||||||
{joinError ? <Text style={styles.joinError}>{joinError}</Text> : null}
|
{joinError ? <Text style={styles.joinError}>{joinError}</Text> : null}
|
||||||
<View style={styles.fullRow}>
|
|
||||||
<ButtonTray>
|
|
||||||
<Button
|
|
||||||
label="Back"
|
|
||||||
onClick={() => { setJoinStep(null); setOrgCode(''); setJoinError(''); }}
|
|
||||||
styleButton={styles.backButton}
|
|
||||||
styleLabel={styles.backLabel}
|
|
||||||
/>
|
|
||||||
</ButtonTray>
|
|
||||||
</View>
|
|
||||||
</Screen>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Default: Create company or Join company choice
|
|
||||||
return (
|
|
||||||
<Screen style={styles.center}>
|
|
||||||
<Text style={styles.bizTitle}>Welcome</Text>
|
|
||||||
<Text style={styles.bizSubtitle}>Set up your organisation or join an existing one</Text>
|
|
||||||
<View style={styles.fullRow}>
|
<View style={styles.fullRow}>
|
||||||
<ButtonTray>
|
<ButtonTray>
|
||||||
<Button
|
<Button
|
||||||
@@ -427,16 +407,6 @@ const MapScreen = ({navigation}) => {
|
|||||||
/>
|
/>
|
||||||
</ButtonTray>
|
</ButtonTray>
|
||||||
</View>
|
</View>
|
||||||
<View style={styles.fullRow}>
|
|
||||||
<ButtonTray>
|
|
||||||
<Button
|
|
||||||
label="Join Company"
|
|
||||||
onClick={() => setJoinStep('orgCode')}
|
|
||||||
styleButton={styles.joinButton}
|
|
||||||
styleLabel={styles.joinLabel}
|
|
||||||
/>
|
|
||||||
</ButtonTray>
|
|
||||||
</View>
|
|
||||||
</Screen>
|
</Screen>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,7 +10,8 @@ const PlayersScreen = () => {
|
|||||||
// Initialisation ------------
|
// Initialisation ------------
|
||||||
|
|
||||||
const session = getSession();
|
const session = getSession();
|
||||||
const {getTeams, getTeamMembers, getGroupMembers, removeMember, resetPlayerProgress, getUser, getAdminWaitlist, approveAdmin, rejectAdmin} = useGameHook();
|
const {getTeams, getTeamMembers, getGroupMembers, removeMember, resetPlayerProgress, getUser, getAdminWaitlist, approveAdmin, rejectAdmin, getSubgroups} = useGameHook();
|
||||||
|
const isBusiness = Boolean(session.isBusiness);
|
||||||
|
|
||||||
// State ----------------------
|
// State ----------------------
|
||||||
|
|
||||||
@@ -22,6 +23,15 @@ const PlayersScreen = () => {
|
|||||||
const loadData = useCallback(async () => {
|
const loadData = useCallback(async () => {
|
||||||
if (!session.currentGid) { setLoading(false); return; }
|
if (!session.currentGid) { setLoading(false); return; }
|
||||||
|
|
||||||
|
// Load subgroup names for department display (business accounts)
|
||||||
|
let subgroupNameMap = {};
|
||||||
|
if (isBusiness) {
|
||||||
|
const sgs = await getSubgroups(session.currentGid);
|
||||||
|
for (const sg of (sgs || [])) {
|
||||||
|
if (!sg.IsAdminGroup) subgroupNameMap[sg.SGid] = sg.SubGroupName;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Get ALL members (including admins)
|
// Get ALL members (including admins)
|
||||||
const allMembers = await getGroupMembers(session.currentGid);
|
const allMembers = await getGroupMembers(session.currentGid);
|
||||||
|
|
||||||
@@ -73,6 +83,7 @@ const PlayersScreen = () => {
|
|||||||
team: teamInfoByUid[m.Uid] || null,
|
team: teamInfoByUid[m.Uid] || null,
|
||||||
adminTag,
|
adminTag,
|
||||||
waitlistId,
|
waitlistId,
|
||||||
|
departmentName: subgroupNameMap[m.SGid] || null,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -89,6 +100,7 @@ const PlayersScreen = () => {
|
|||||||
team: null,
|
team: null,
|
||||||
adminTag: '[Admin Awaiting Response]',
|
adminTag: '[Admin Awaiting Response]',
|
||||||
waitlistId: w.id,
|
waitlistId: w.id,
|
||||||
|
departmentName: null,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -167,6 +179,12 @@ const PlayersScreen = () => {
|
|||||||
{' '}{player.adminTag}
|
{' '}{player.adminTag}
|
||||||
</Text>
|
</Text>
|
||||||
)}
|
)}
|
||||||
|
{/* Show department name in brackets for non-admin players (org accounts) */}
|
||||||
|
{!player.adminTag && player.departmentName && (
|
||||||
|
<Text style={styles.departmentName}>
|
||||||
|
{' '}({player.departmentName})
|
||||||
|
</Text>
|
||||||
|
)}
|
||||||
</Text>
|
</Text>
|
||||||
<View style={styles.playerMeta}>
|
<View style={styles.playerMeta}>
|
||||||
{player.team?.isLeader && (
|
{player.team?.isLeader && (
|
||||||
@@ -255,6 +273,7 @@ const styles = StyleSheet.create({
|
|||||||
resetButton: {backgroundColor: '#f59e0b', borderColor: '#f59e0b', minHeight: 36, flex: 1, paddingHorizontal: 10},
|
resetButton: {backgroundColor: '#f59e0b', borderColor: '#f59e0b', minHeight: 36, flex: 1, paddingHorizontal: 10},
|
||||||
removeButton: {backgroundColor: '#dc2626', borderColor: '#dc2626', minHeight: 36, flex: 1, paddingHorizontal: 10},
|
removeButton: {backgroundColor: '#dc2626', borderColor: '#dc2626', minHeight: 36, flex: 1, paddingHorizontal: 10},
|
||||||
actionLabel: {color: '#ffffff', fontWeight: '600', fontSize: 13},
|
actionLabel: {color: '#ffffff', fontWeight: '600', fontSize: 13},
|
||||||
|
departmentName: {fontSize: 14, color: '#6b7280', fontStyle: 'italic'},
|
||||||
// Waitlisted admin card tint — light red so they read as pending, not regular players
|
// Waitlisted admin card tint — light red so they read as pending, not regular players
|
||||||
waitlistCard: {backgroundColor: '#FFD1DC', borderColor: '#fca5a5'},
|
waitlistCard: {backgroundColor: '#FFD1DC', borderColor: '#fca5a5'},
|
||||||
// Approve / deny buttons for waitlisted admins
|
// Approve / deny buttons for waitlisted admins
|
||||||
|
|||||||
@@ -175,9 +175,11 @@ const useGameHook = () => {
|
|||||||
return response.isSuccess;
|
return response.isSuccess;
|
||||||
};
|
};
|
||||||
|
|
||||||
// Game reset — remove all caches for a game
|
// Game reset — remove all caches for a game (optionally scoped to a subgroup)
|
||||||
const resetGame = async (gid) => {
|
const resetGame = async (gid, sgid = null) => {
|
||||||
const response = await API.post(`${cachesEndpoint}/reset?Gid=${gid}`, {});
|
let url = `${cachesEndpoint}/reset?Gid=${gid}`;
|
||||||
|
if (sgid !== null) url += `&SGid=${sgid}`;
|
||||||
|
const response = await API.post(url, {});
|
||||||
return response.isSuccess;
|
return response.isSuccess;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
Reference in new issue
Block a user