diff --git a/backend/package.json b/backend/package.json index a0fa40d..f731fb9 100644 --- a/backend/package.json +++ b/backend/package.json @@ -1,6 +1,6 @@ { "name": "rosterchirp-backend", - "version": "0.12.47", + "version": "0.12.48", "description": "RosterChirp backend server", "main": "src/index.js", "scripts": { diff --git a/backend/src/routes/usergroups.js b/backend/src/routes/usergroups.js index 63d0cdf..cd49d19 100644 --- a/backend/src/routes/usergroups.js +++ b/backend/src/routes/usergroups.js @@ -211,7 +211,16 @@ router.get('/:id', authMiddleware, teamManagerMiddleware, async (req, res) => { FROM user_group_members ugm JOIN users u ON u.id=ugm.user_id WHERE ugm.user_group_id=$1 ORDER BY u.name ASC `, [req.params.id]); - res.json({ group, members }); + const aliasMembers = await query(req.schema, ` + SELECT ga.id, ga.first_name, ga.last_name, + ga.first_name || ' ' || ga.last_name AS name, + ga.guardian_id, ga.avatar, ga.date_of_birth + FROM alias_group_members agm + JOIN guardian_aliases ga ON ga.id = agm.alias_id + WHERE agm.user_group_id=$1 + ORDER BY ga.first_name, ga.last_name ASC + `, [req.params.id]); + res.json({ group, members, aliasMembers }); } catch (e) { res.status(500).json({ error: e.message }); } }); diff --git a/build.sh b/build.sh index c756507..d4f919d 100644 --- a/build.sh +++ b/build.sh @@ -13,7 +13,7 @@ # ───────────────────────────────────────────────────────────── set -euo pipefail -VERSION="${1:-0.12.47}" +VERSION="${1:-0.12.48}" ACTION="${2:-}" REGISTRY="${REGISTRY:-}" IMAGE_NAME="rosterchirp" diff --git a/frontend/package.json b/frontend/package.json index bc2f70c..37e25c7 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -1,6 +1,6 @@ { "name": "rosterchirp-frontend", - "version": "0.12.47", + "version": "0.12.48", "private": true, "scripts": { "dev": "vite", diff --git a/frontend/src/pages/GroupManagerPage.jsx b/frontend/src/pages/GroupManagerPage.jsx index 5e14088..24ba31f 100644 --- a/frontend/src/pages/GroupManagerPage.jsx +++ b/frontend/src/pages/GroupManagerPage.jsx @@ -67,6 +67,7 @@ function AllGroupsTab({ allUsers, onRefresh, isMobile = false, onIF, onIB }) { const [savedMembers, setSavedMembers] = useState(new Set()); const [members, setMembers] = useState(new Set()); const [fullMembers, setFullMembers] = useState([]); // full member objects including deleted + const [aliasMembers, setAliasMembers] = useState([]); // child aliases in this group const [editName, setEditName] = useState(''); const [noDm, setNoDm] = useState(false); const [saving, setSaving] = useState(false); @@ -81,16 +82,17 @@ function AllGroupsTab({ allUsers, onRefresh, isMobile = false, onIF, onIB }) { const selectGroup = async (g) => { setShowDelete(false); setAccordionOpen(false); - const { members: mems } = await api.getUserGroup(g.id); + const { members: mems, aliasMembers: aliases } = await api.getUserGroup(g.id); const ids = new Set(mems.map(m => m.id)); setSelected(g); setEditName(g.name); setMembers(ids); setSavedMembers(ids); setFullMembers(mems); + setAliasMembers(aliases || []); // No DM → checkbox enabled+checked; has DM → checkbox disabled+unchecked setNoDm(!g.dm_group_id); }; const clearSelection = () => { setSelected(null); setEditName(''); setMembers(new Set()); setSavedMembers(new Set()); - setShowDelete(false); setFullMembers([]); setNoDm(false); + setShowDelete(false); setFullMembers([]); setAliasMembers([]); setNoDm(false); }; const handleSave = async () => { @@ -102,9 +104,9 @@ function AllGroupsTab({ allUsers, onRefresh, isMobile = false, onIF, onIB }) { const createDm = !selected.dm_group_id && !noDm; const { group: updated } = await api.updateUserGroup(selected.id, { name: editName.trim(), memberIds: [...members], createDm }); toast('Group updated', 'success'); - const { members: fresh } = await api.getUserGroup(selected.id); + const { members: fresh, aliasMembers: freshAliases } = await api.getUserGroup(selected.id); const freshIds = new Set(fresh.map(m => m.id)); - setSavedMembers(freshIds); setMembers(freshIds); setFullMembers(fresh); + setSavedMembers(freshIds); setMembers(freshIds); setFullMembers(fresh); setAliasMembers(freshAliases || []); // Reflect new dm_group_id if a DM was just created setSelected(prev => ({ ...prev, name: editName.trim(), dm_group_id: updated?.dm_group_id ?? prev.dm_group_id })); if (createDm) setNoDm(false); @@ -220,6 +222,19 @@ function AllGroupsTab({ allUsers, onRefresh, isMobile = false, onIF, onIB }) {

{members.size} selected

+ {aliasMembers.length > 0 && ( +
+ +
+ {aliasMembers.map((a, i) => ( +
+ {a.name} + {a.date_of_birth && {a.date_of_birth.slice(0,10)}} +
+ ))} +
+
+ )} {deletedMembers.length > 0 && (