Enhance navigation and data handling: update BottomNavbar to pass selected department, refactor GameSettingsScreen and PlayersScreen for improved subgroup management, and adjust API calls to support department-specific data.

This commit is contained in:
bobbert committed 2026-04-09 13:10:59 +01:00
1 parent 43c8bb2bff
commit 4a0468d155
7 files changed
+147 -59

No files matched your search

+15 -3
View File
@@ -3,17 +3,29 @@ import {useSafeAreaInsets} from 'react-native-safe-area-context';
import {clearGameSession, getSession} from '../../hooks/SessionStore'; import {clearGameSession, getSession} from '../../hooks/SessionStore';
import API, {API_BASE_URL} from '../API/API'; import API, {API_BASE_URL} from '../API/API';
const BottomNavbar = ({navigation, routeName}) => { const BottomNavbar = ({navigation, routeName, routeParams}) => {
// Initialisation ------------ // Initialisation ------------
const insets = useSafeAreaInsets(); const insets = useSafeAreaInsets();
const session = getSession(); const session = getSession();
const selectedDepartment = routeName === 'DepartmentSettingsScreen' && routeParams?.SGid
? {SGid: routeParams.SGid, SubGroupName: routeParams.SubGroupName || routeParams.selectedDepartmentName || 'Department'}
: null;
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')},
{label: 'Players', route: 'PlayersScreen', onPress: () => navigation.navigate('PlayersScreen')}, {
{label: 'Leaderboard', route: 'LeaderboardScreen', onPress: () => navigation.navigate('LeaderboardScreen')}, label: 'Players',
route: 'PlayersScreen',
onPress: () => navigation.navigate('PlayersScreen', selectedDepartment ? {department: selectedDepartment} : undefined),
},
{
label: 'Leaderboard',
route: 'LeaderboardScreen',
onPress: () => navigation.navigate('LeaderboardScreen', selectedDepartment ? {department: selectedDepartment} : undefined),
},
]; ];
// Only show the Leave tab when the player is actually in a game // Only show the Leave tab when the player is actually in a game
+1 -1
View File
@@ -35,7 +35,7 @@ const Screen = ({ children, style, showBack = false }) => {
<View style={[styles.screen, isAuthScreen && {paddingTop: insets.top, paddingBottom: insets.bottom}]}> <View style={[styles.screen, isAuthScreen && {paddingTop: insets.top, paddingBottom: insets.bottom}]}>
{!isAuthScreen && <TopNavbar title={pageTitle} showBack={showBack} navigation={navigation} />} {!isAuthScreen && <TopNavbar title={pageTitle} showBack={showBack} navigation={navigation} />}
<View style={[styles.content, style]}>{children}</View> <View style={[styles.content, style]}>{children}</View>
{!isAuthScreen && <BottomNavbar navigation={navigation} routeName={routeName} />} {!isAuthScreen && <BottomNavbar navigation={navigation} routeName={routeName} routeParams={route.params} />}
<StatusBar style="light" /> <StatusBar style="light" />
</View> </View>
); );
+33 -22
View File
@@ -1,5 +1,6 @@
import React, {useEffect, useState} from 'react'; import React, {useCallback, useState} from 'react';
import {ActivityIndicator, Alert, ScrollView, StyleSheet, Switch, Text, TextInput, View} from 'react-native'; import {ActivityIndicator, Alert, ScrollView, StyleSheet, Switch, Text, TextInput, View} from 'react-native';
import {useFocusEffect} from '@react-navigation/native';
import Screen from '../layout/Screen'; 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';
@@ -11,7 +12,6 @@ const GameSettingsScreen = ({navigation}) => {
const session = getSession(); const session = getSession();
const {getLobby, updateGroup, getSubgroups, createSubgroup, 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);
// State ---------------------- // State ----------------------
@@ -27,15 +27,16 @@ const GameSettingsScreen = ({navigation}) => {
const [memberJoinCode, setMemberJoinCode] = useState(''); const [memberJoinCode, setMemberJoinCode] = useState('');
const [waitlist, setWaitlist] = useState([]); const [waitlist, setWaitlist] = useState([]);
const [waitlistNames, setWaitlistNames] = useState({}); const [waitlistNames, setWaitlistNames] = useState({});
const [isBusinessGroup, setIsBusinessGroup] = useState(Boolean(session.isBusiness));
// Business subgroup management // Business subgroup management
const [subgroupList, setSubgroupList] = useState([]); const [subgroupList, setSubgroupList] = useState([]);
const [newDeptName, setNewDeptName] = useState(''); const [newDeptName, setNewDeptName] = useState('');
// Handlers ------------------- // Handlers -------------------
const loadWaitlist = async () => { const loadWaitlist = useCallback(async (gid) => {
if (!session.currentGid) return; if (!gid) return;
const rows = await getAdminWaitlist(session.currentGid); const rows = await getAdminWaitlist(gid);
setWaitlist(rows || []); setWaitlist(rows || []);
const names = {}; const names = {};
for (const entry of (rows || [])) { for (const entry of (rows || [])) {
@@ -43,27 +44,28 @@ const GameSettingsScreen = ({navigation}) => {
if (u) names[entry.Uid] = u.username; if (u) names[entry.Uid] = u.username;
} }
setWaitlistNames(names); setWaitlistNames(names);
}; }, [getAdminWaitlist, getUser]);
const loadSubgroups = async () => { const loadSubgroups = useCallback(async (gid) => {
if (!session.currentGid) return; if (!gid) return;
const sgs = await getSubgroups(session.currentGid); const sgs = await getSubgroups(gid);
setSubgroupList(sgs || []); setSubgroupList(sgs || []);
// Set the default member join code from first non-admin subgroup // Set the default member join code from first non-admin subgroup
const memberSg = (sgs || []).find((sg) => !sg.IsAdminGroup); const memberSg = (sgs || []).find((sg) => !sg.IsAdminGroup);
if (memberSg) setMemberJoinCode(memberSg.JoinCode || ''); if (memberSg) setMemberJoinCode(memberSg.JoinCode || '');
}; }, [getSubgroups]);
useEffect(() => { const loadSettings = useCallback(async () => {
const load = async () => { const activeSession = getSession();
if (!session.currentGid) { if (!activeSession.currentGid) {
setLoading(false); setLoading(false);
return; return;
} }
const group = await getLobby(session.currentGid); const group = await getLobby(activeSession.currentGid);
if (group) { if (group) {
setGroupName(group.GroupName || ''); setGroupName(group.GroupName || '');
setBusinessName(group.BusinessOrSchoolName || ''); setBusinessName(group.BusinessOrSchoolName || '');
setIsBusinessGroup(Boolean(group.BusinessOrSchoolName || group.OrgJoinCode));
const serverTeams = Boolean(group.TeamsEnabled); const serverTeams = Boolean(group.TeamsEnabled);
setTeamsEnabled(serverTeams); setTeamsEnabled(serverTeams);
setServerTeamsEnabled(serverTeams); setServerTeamsEnabled(serverTeams);
@@ -72,12 +74,17 @@ const GameSettingsScreen = ({navigation}) => {
setAdminJoinCode(group.AdminJoinCode || ''); setAdminJoinCode(group.AdminJoinCode || '');
setOrgJoinCode(group.OrgJoinCode || ''); setOrgJoinCode(group.OrgJoinCode || '');
} }
await loadSubgroups(); await loadSubgroups(activeSession.currentGid);
await loadWaitlist(); await loadWaitlist(activeSession.currentGid);
setLoading(false); setLoading(false);
}; }, [getLobby, loadSubgroups, loadWaitlist]);
load();
}, []); useFocusEffect(
useCallback(() => {
setLoading(true);
loadSettings();
}, [loadSettings]),
);
// --- Individual save --- // --- Individual save ---
const saveSettings = async () => { const saveSettings = async () => {
@@ -100,7 +107,7 @@ const GameSettingsScreen = ({navigation}) => {
const handleSave = async () => { const handleSave = async () => {
if (!session.currentGid) return; if (!session.currentGid) return;
// Business save — only save business name // Business save — only save business name
if (isBusiness) { if (isBusinessGroup) {
setSaving(true); setSaving(true);
await updateGroup(session.currentGid, { await updateGroup(session.currentGid, {
BusinessOrSchoolName: businessName.trim(), BusinessOrSchoolName: businessName.trim(),
@@ -180,7 +187,11 @@ const GameSettingsScreen = ({navigation}) => {
// Business — navigate to department settings // Business — navigate to department settings
const handleEnterDepartment = (sg) => { const handleEnterDepartment = (sg) => {
navigation.navigate('DepartmentSettingsScreen', {SGid: sg.SGid, Gid: session.currentGid}); navigation.navigate('DepartmentSettingsScreen', {
SGid: sg.SGid,
Gid: session.currentGid,
SubGroupName: sg.SubGroupName,
});
}; };
// View ----------------------- // View -----------------------
@@ -205,7 +216,7 @@ const GameSettingsScreen = ({navigation}) => {
const departments = subgroupList.filter((sg) => !sg.IsAdminGroup); const departments = subgroupList.filter((sg) => !sg.IsAdminGroup);
// ===== Business Admin View ===== // ===== Business Admin View =====
if (isBusiness) { if (isBusinessGroup) {
return ( return (
<Screen> <Screen>
<ScrollView contentContainerStyle={styles.formContainer} showsVerticalScrollIndicator={false}> <ScrollView contentContainerStyle={styles.formContainer} showsVerticalScrollIndicator={false}>
+17 -19
View File
@@ -13,7 +13,7 @@ const LeaderboardScreen = ({navigation, route}) => {
const isAdmin = session.isAcceptedAdmin; const isAdmin = session.isAcceptedAdmin;
const isBusiness = Boolean(session.isBusiness); const isBusiness = Boolean(session.isBusiness);
const selectedDepartment = route?.params?.department || null; const selectedDepartment = route?.params?.department || null;
const {getLobby, getTeams, getTeamMembers, getGroupMembers, getCaches, getUser, deleteTeam, resetPlayerProgress, resetTeamProgress, getSubgroups} = useGameHook(); const {getLobby, getSubgroup, getTeams, getTeamMembers, getGroupMembers, getCaches, getUser, deleteTeam, resetPlayerProgress, resetTeamProgress, getSubgroups} = useGameHook();
// State ---------------------- // State ----------------------
@@ -33,7 +33,16 @@ const LeaderboardScreen = ({navigation, route}) => {
if (!session.currentGid) { setLoading(false); return; } if (!session.currentGid) { setLoading(false); return; }
const group = await getLobby(session.currentGid); const group = await getLobby(session.currentGid);
const isTeams = Boolean(group?.TeamsEnabled);
const effectiveSGid = isBusiness
? ((isAdmin && selectedDepartment?.SGid) ? selectedDepartment.SGid : (isAdmin ? null : session.currentSGid))
: null;
let isTeams = Boolean(group?.TeamsEnabled);
if (effectiveSGid !== null && effectiveSGid !== undefined) {
const subgroup = await getSubgroup(effectiveSGid);
if (subgroup) isTeams = Boolean(subgroup.TeamsEnabled);
}
setTeamsEnabled(isTeams); setTeamsEnabled(isTeams);
if (isBusiness && isAdmin && !selectedDepartment) { if (isBusiness && isAdmin && !selectedDepartment) {
@@ -43,24 +52,16 @@ const LeaderboardScreen = ({navigation, route}) => {
return; return;
} }
const leaderboardSGid = (isBusiness && isAdmin && selectedDepartment?.SGid) const caches = await getCaches(session.currentGid, effectiveSGid ?? null);
? selectedDepartment.SGid
: null;
const caches = await getCaches(session.currentGid, leaderboardSGid);
const total = (caches || []).length; const total = (caches || []).length;
setTotalCacheCount(total); setTotalCacheCount(total);
if (isTeams) { if (isTeams) {
// Build team rankings // Build team rankings
const teams = await getTeams(session.currentGid); const teams = await getTeams(session.currentGid, effectiveSGid ?? null);
const teamData = []; const teamData = [];
const scopedTeams = leaderboardSGid for (const team of (teams || [])) {
? (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 || [])) {
@@ -98,12 +99,9 @@ const LeaderboardScreen = ({navigation, route}) => {
} }
} else { } else {
// Build player rankings (no teams) // Build player rankings (no teams)
const allMembers = await getGroupMembers(session.currentGid); const scopedMembers = await getGroupMembers(session.currentGid, effectiveSGid ?? null);
const scopedMembers = leaderboardSGid
? (allMembers || []).filter((mem) => mem.SGid === leaderboardSGid)
: (allMembers || []);
const playerData = []; const playerData = [];
for (const m of scopedMembers.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)
@@ -119,7 +117,7 @@ const LeaderboardScreen = ({navigation, route}) => {
} }
setLoading(false); setLoading(false);
}, [session.currentGid, session.currentTid, isBusiness, isAdmin, selectedDepartment, selectedDepartment?.SGid]); }, [session.currentGid, session.currentTid, session.currentSGid, isBusiness, isAdmin, selectedDepartment, selectedDepartment?.SGid]);
useEffect(() => { loadData(); }, [loadData]); useEffect(() => { loadData(); }, [loadData]);
+48 -6
View File
@@ -1,28 +1,43 @@
import React, {useCallback, useEffect, useState} from 'react'; import React, {useCallback, useEffect, useState} from 'react';
import {ActivityIndicator, Alert, ScrollView, StyleSheet, Text, View} from 'react-native'; import {ActivityIndicator, Alert, Pressable, ScrollView, StyleSheet, Text, View} from 'react-native';
import Screen from '../layout/Screen'; import Screen from '../layout/Screen';
import Card from '../UI/Card'; import Card from '../UI/Card';
import {Button} from '../UI/Button'; 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 PlayersScreen = () => { const PlayersScreen = ({navigation, route}) => {
// Initialisation ------------ // Initialisation ------------
const session = getSession(); const session = getSession();
const {getTeams, getTeamMembers, getGroupMembers, removeMember, resetPlayerProgress, getUser, getAdminWaitlist, approveAdmin, rejectAdmin, getSubgroups} = useGameHook(); const {getTeams, getTeamMembers, getGroupMembers, removeMember, resetPlayerProgress, getUser, getAdminWaitlist, approveAdmin, rejectAdmin, getSubgroups} = useGameHook();
const isBusiness = Boolean(session.isBusiness); const isBusiness = Boolean(session.isBusiness);
const isAdmin = Boolean(session.isAcceptedAdmin);
const selectedDepartment = route?.params?.department || null;
// State ---------------------- // State ----------------------
const [loading, setLoading] = useState(true); const [loading, setLoading] = useState(true);
const [players, setPlayers] = useState([]); const [players, setPlayers] = useState([]);
const [departmentList, setDepartmentList] = useState([]);
// Handlers ------------------- // Handlers -------------------
const loadData = useCallback(async () => { const loadData = useCallback(async () => {
if (!session.currentGid) { setLoading(false); return; } if (!session.currentGid) { setLoading(false); return; }
const effectiveSGid = isBusiness
? ((isAdmin && selectedDepartment?.SGid) ? selectedDepartment.SGid : (isAdmin ? null : session.currentSGid))
: null;
if (isBusiness && isAdmin && !selectedDepartment) {
const sgs = await getSubgroups(session.currentGid);
setDepartmentList((sgs || []).filter((sg) => !sg.IsAdminGroup));
setPlayers([]);
setLoading(false);
return;
}
// Load subgroup names for department display (business accounts) // Load subgroup names for department display (business accounts)
let subgroupNameMap = {}; let subgroupNameMap = {};
if (isBusiness) { if (isBusiness) {
@@ -33,10 +48,10 @@ const PlayersScreen = () => {
} }
// Get ALL members (including admins) // Get ALL members (including admins)
const allMembers = await getGroupMembers(session.currentGid); const allMembers = await getGroupMembers(session.currentGid, effectiveSGid ?? null);
// Get admin waitlist entries // Get admin waitlist entries
const waitlist = await getAdminWaitlist(session.currentGid); const waitlist = effectiveSGid ? [] : await getAdminWaitlist(session.currentGid);
// Deduplicate allMembers by Uid — a user may have two rows if they were a // Deduplicate allMembers by Uid — a user may have two rows if they were a
// regular member before being approved as an admin. Prefer the admin row. // regular member before being approved as an admin. Prefer the admin row.
@@ -46,7 +61,7 @@ const PlayersScreen = () => {
.filter((m) => { if (seenUids.has(m.Uid)) return false; seenUids.add(m.Uid); return true; }); .filter((m) => { if (seenUids.has(m.Uid)) return false; seenUids.add(m.Uid); return true; });
// Build team lookup: { Uid -> { teamCode, teamName, isLeader } } // Build team lookup: { Uid -> { teamCode, teamName, isLeader } }
const allTeams = await getTeams(session.currentGid); const allTeams = await getTeams(session.currentGid, effectiveSGid ?? null);
const teamInfoByUid = {}; const teamInfoByUid = {};
for (const team of (allTeams || [])) { for (const team of (allTeams || [])) {
const tms = await getTeamMembers(team.Tid); const tms = await getTeamMembers(team.Tid);
@@ -107,7 +122,7 @@ const PlayersScreen = () => {
setPlayers(playerList); setPlayers(playerList);
setLoading(false); setLoading(false);
}, [session.currentGid]); }, [session.currentGid, session.currentUid, session.currentSGid, isBusiness, isAdmin, selectedDepartment, selectedDepartment?.SGid]);
useEffect(() => { loadData(); }, [loadData]); useEffect(() => { loadData(); }, [loadData]);
@@ -164,8 +179,34 @@ const PlayersScreen = () => {
); );
} }
if (isBusiness && isAdmin && !selectedDepartment) {
return ( return (
<Screen style={styles.container}> <Screen style={styles.container}>
<Text style={styles.sectionTitle}>Departments</Text>
<ScrollView style={styles.listSection}>
{departmentList.map((department) => (
<Pressable
key={department.SGid}
onPress={() => navigation.navigate('PlayersScreen', {department})}
>
<Card>
<View style={styles.playerRow}>
<Text style={styles.playerName}>{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>
);
}
return (
<Screen style={styles.container} showBack={Boolean(selectedDepartment)}>
<Text style={styles.sectionTitle}>Players</Text> <Text style={styles.sectionTitle}>Players</Text>
<ScrollView style={styles.listSection}> <ScrollView style={styles.listSection}>
{players.map((player) => ( {players.map((player) => (
@@ -255,6 +296,7 @@ const styles = StyleSheet.create({
paddingHorizontal: 15, paddingHorizontal: 15,
paddingTop: 15, paddingTop: 15,
}, },
openLabel: {fontSize: 13, fontWeight: '700', color: '#2563eb'},
listSection: {flex: 1, paddingHorizontal: 15}, listSection: {flex: 1, paddingHorizontal: 15},
emptyText: {color: '#9ca3af', textAlign: 'center', marginTop: 30, fontSize: 14}, emptyText: {color: '#9ca3af', textAlign: 'center', marginTop: 30, fontSize: 14},
playerRow: { playerRow: {
+16 -3
View File
@@ -11,7 +11,8 @@ const TeamScreen = () => {
const session = getSession(); const session = getSession();
const isAdmin = session.isAcceptedAdmin; const isAdmin = session.isAcceptedAdmin;
const {getLobby, getTeam, createTeam, joinTeamByCode, getTeamMembers, leaveTeam, getUser, updateUser, updateTeam, getAdminWaitlist} = useGameHook(); const isBusiness = Boolean(session.isBusiness);
const {getLobby, getSubgroup, getTeam, createTeam, joinTeamByCode, getTeamMembers, leaveTeam, getUser, updateUser, updateTeam, getAdminWaitlist} = useGameHook();
// State ---------------------- // State ----------------------
@@ -46,11 +47,19 @@ const TeamScreen = () => {
if (!session.currentGid) { setLoading(false); return; } if (!session.currentGid) { setLoading(false); return; }
const group = await getLobby(session.currentGid); const group = await getLobby(session.currentGid);
if (group && !group.TeamsEnabled) { let teamsAreEnabled = Boolean(group?.TeamsEnabled);
if (isBusiness && session.currentSGid) {
const subgroup = await getSubgroup(session.currentSGid);
if (subgroup) teamsAreEnabled = Boolean(subgroup.TeamsEnabled);
}
if (!teamsAreEnabled) {
setTeamsDisabled(true); setTeamsDisabled(true);
setLoading(false); setLoading(false);
return; return;
} }
setTeamsDisabled(false);
if (!activeTid) { if (!activeTid) {
const waitlist = await getAdminWaitlist(session.currentGid, session.currentUid); const waitlist = await getAdminWaitlist(session.currentGid, session.currentUid);
@@ -70,7 +79,11 @@ const TeamScreen = () => {
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
const code = teamCode.trim().toUpperCase(); const code = teamCode.trim().toUpperCase();
const result = await joinTeamByCode({JoinCode: code, Uid: session.currentUid}); const result = await joinTeamByCode({
JoinCode: code,
Uid: session.currentUid,
ExpectedSGid: session.currentSGid,
});
if (!result) return; if (!result) return;
// If the server indicates this code matched the admin join code // If the server indicates this code matched the admin join code
+17 -5
View File
@@ -89,8 +89,10 @@ const useGameHook = () => {
return response.isSuccess ? response.result : null; return response.isSuccess ? response.result : null;
}; };
const getGroupMembers = async (gid) => { const getGroupMembers = async (gid, sgid = null) => {
const response = await API.get(`${subgroupMembersEndpoint}?Gid=${gid}`); let url = `${subgroupMembersEndpoint}?Gid=${gid}`;
if (sgid !== null && sgid !== undefined) url += `&SGid=${sgid}`;
const response = await API.get(url);
return response.isSuccess ? response.result : []; return response.isSuccess ? response.result : [];
}; };
@@ -100,8 +102,10 @@ const useGameHook = () => {
}; };
// Teams // Teams
const getTeams = async (gid) => { const getTeams = async (gid, sgid = null) => {
const response = await API.get(`${teamsEndpoint}?Gid=${gid}`); let url = `${teamsEndpoint}?Gid=${gid}`;
if (sgid !== null && sgid !== undefined) url += `&SGid=${sgid}`;
const response = await API.get(url);
return response.isSuccess ? response.result : []; return response.isSuccess ? response.result : [];
}; };
@@ -131,7 +135,15 @@ const useGameHook = () => {
}; };
const joinTeamByCode = async (payload) => { const joinTeamByCode = async (payload) => {
const response = await API.post(teamMembersEndpoint, payload); const data = {
Uid: payload.Uid,
};
if (payload.JoinCode !== undefined) data.JoinCode = payload.JoinCode;
if (payload.Tid !== undefined) data.Tid = payload.Tid;
if (payload.ExpectedSGid !== undefined && payload.ExpectedSGid !== null) {
data.ExpectedSGid = payload.ExpectedSGid;
}
const response = await API.post(teamMembersEndpoint, data);
return response.isSuccess ? response.result : null; return response.isSuccess ? response.result : null;
}; };