/** * Admin > People > Teams */ const { html } = window; const { useState, useEffect, useCallback } = hooks; export default function TeamsSection() { const [teams, setTeams] = useState([]); const [loading, setLoading] = useState(true); const [detail, setDetail] = useState(null); // team object or null const [members, setMembers] = useState([]); const [allUsers, setAllUsers] = useState([]); const [showCreate, setShowCreate] = useState(false); const [showAddMember, setShowAddMember] = useState(false); const loadTeams = useCallback(async () => { try { const resp = await sw.api.admin.teams.list(); // Paginated response: { data: [...], total, page } const list = Array.isArray(resp) ? resp : (resp && resp.data ? resp.data : []); setTeams(list); } catch (e) { sw.toast(e.message, 'error'); } finally { setLoading(false); } }, []); useEffect(() => { loadTeams(); }, []); async function openDetail(team) { setDetail(team); try { const [m, u] = await Promise.all([ sw.api.admin.teams.members(team.id), sw.api.admin.users.list(), ]); setMembers(m || []); const uList = u || []; setAllUsers(uList); } catch (e) { sw.toast(e.message, 'error'); } } async function createTeam(e) { e.preventDefault(); const form = e.target; try { await sw.api.admin.teams.create({ name: form.name.value.trim(), description: form.desc.value.trim() }); sw.toast('Team created', 'success'); setShowCreate(false); loadTeams(); } catch (e) { sw.toast(e.message, 'error'); } } async function deleteTeam(id) { const ok = await sw.confirm('Delete this team? All members will be removed.', true); if (!ok) return; try { await sw.api.admin.teams.del(id); sw.toast('Team deleted', 'success'); setDetail(null); loadTeams(); } catch (e) { sw.toast(e.message, 'error'); } } async function addMember(e) { e.preventDefault(); const form = e.target; try { await sw.api.admin.teams.addMember(detail.id, form.userId.value, form.role.value); sw.toast('Member added', 'success'); setShowAddMember(false); const m = await sw.api.admin.teams.members(detail.id); setMembers(m || []); } catch (e) { sw.toast(e.message, 'error'); } } async function removeMember(mid) { try { await sw.api.admin.teams.removeMember(detail.id, mid); sw.toast('Member removed', 'success'); setMembers(prev => prev.filter(m => m.id !== mid)); } catch (e) { sw.toast(e.message, 'error'); } } async function updateMemberRole(mid, role) { try { await sw.api.admin.teams.updateMember(detail.id, mid, role); sw.toast('Role updated', 'success'); setMembers(prev => prev.map(m => m.id === mid ? { ...m, role } : m)); } catch (e) { sw.toast(e.message, 'error'); } } if (loading) return html`
Loading\u2026
`; // Detail view if (detail) return html`

${detail.name}

${detail.description && html`

${detail.description}

`}
Members (${members.length})
${members.map(m => html`
${m.username || m.user_id}
`)}
${showAddMember ? html`
` : html`` }
`; // List view return html`
${showCreate && html`
`}
${teams.length === 0 && html`
No teams
`} ${teams.map(t => html`
openDetail(t)}> ${t.name} ${t.member_count ?? '?'} members ${t.is_active ? 'active' : 'inactive'}
`)}
`; }