diff --git a/backend/package.json b/backend/package.json index 22c3a5a..142bdd0 100644 --- a/backend/package.json +++ b/backend/package.json @@ -1,6 +1,6 @@ { "name": "rosterchirp-backend", - "version": "0.12.14", + "version": "0.12.15", "description": "RosterChirp backend server", "main": "src/index.js", "scripts": { diff --git a/backend/src/routes/usergroups.js b/backend/src/routes/usergroups.js index 001a8e0..de49512 100644 --- a/backend/src/routes/usergroups.js +++ b/backend/src/routes/usergroups.js @@ -156,8 +156,8 @@ router.patch('/multigroup/:id', authMiddleware, teamManagerMiddleware, async (re `, [mg.id, uid]); if (!stillIn) { await exec(req.schema, 'DELETE FROM group_members WHERE group_id=$1 AND user_id=$2', [mg.dm_group_id, uid]); - io.in(R(schema,'user',uid)).socketsLeave(R(schema,'group',mg.dm_group_id)); - io.to(R(schema,'user',uid)).emit('group:deleted', { groupId: mg.dm_group_id }); + io.in(R(req.schema,'user',uid)).socketsLeave(R(req.schema,'group',mg.dm_group_id)); + io.to(R(req.schema,'user',uid)).emit('group:deleted', { groupId: mg.dm_group_id }); } } await postSysMsg(req.schema, mg.dm_group_id, req.user.id, `A group has been removed from this conversation.`); @@ -175,7 +175,7 @@ router.delete('/multigroup/:id', authMiddleware, teamManagerMiddleware, async (r if (mg.dm_group_id) { const members = (await query(req.schema, 'SELECT user_id FROM group_members WHERE group_id=$1', [mg.dm_group_id])).map(r => r.user_id); await exec(req.schema, 'DELETE FROM groups WHERE id=$1', [mg.dm_group_id]); - for (const uid of members) io.to(R(schema,'user',uid)).emit('group:deleted', { groupId: mg.dm_group_id }); + for (const uid of members) io.to(R(req.schema,'user',uid)).emit('group:deleted', { groupId: mg.dm_group_id }); } await exec(req.schema, 'DELETE FROM multi_group_dms WHERE id=$1', [mg.id]); res.json({ success: true }); @@ -268,8 +268,8 @@ router.patch('/:id', authMiddleware, teamManagerMiddleware, async (req, res) => if (!newIds.has(uid)) { await exec(req.schema, 'DELETE FROM user_group_members WHERE user_group_id=$1 AND user_id=$2', [ug.id, uid]); await exec(req.schema, 'DELETE FROM group_members WHERE group_id=$1 AND user_id=$2', [ug.dm_group_id, uid]); - io.in(R(schema,'user',uid)).socketsLeave(R(schema,'group',ug.dm_group_id)); - io.to(R(schema,'user',uid)).emit('group:deleted', { groupId: ug.dm_group_id }); + io.in(R(req.schema,'user',uid)).socketsLeave(R(req.schema,'group',ug.dm_group_id)); + io.to(R(req.schema,'user',uid)).emit('group:deleted', { groupId: ug.dm_group_id }); removedUids.push(uid); } } @@ -303,8 +303,8 @@ router.patch('/:id', authMiddleware, teamManagerMiddleware, async (req, res) => `, [mg.id, uid]); if (!stillIn) { await exec(req.schema, 'DELETE FROM group_members WHERE group_id=$1 AND user_id=$2', [mg.dm_group_id, uid]); - io.in(R(schema,'user',uid)).socketsLeave(R(schema,'group',mg.dm_group_id)); - io.to(R(schema,'user',uid)).emit('group:deleted', { groupId: mg.dm_group_id }); + io.in(R(req.schema,'user',uid)).socketsLeave(R(req.schema,'group',mg.dm_group_id)); + io.to(R(req.schema,'user',uid)).emit('group:deleted', { groupId: mg.dm_group_id }); } } if (addedUids.length === 1) { @@ -335,7 +335,7 @@ router.delete('/:id', authMiddleware, teamManagerMiddleware, async (req, res) => if (ug.dm_group_id) { const members = (await query(req.schema, 'SELECT user_id FROM group_members WHERE group_id=$1', [ug.dm_group_id])).map(r => r.user_id); await exec(req.schema, 'DELETE FROM groups WHERE id=$1', [ug.dm_group_id]); - for (const uid of members) { io.in(R(schema,'user',uid)).socketsLeave(R(schema,'group',ug.dm_group_id)); io.to(R(schema,'user',uid)).emit('group:deleted', { groupId: ug.dm_group_id }); } + for (const uid of members) { io.in(R(req.schema,'user',uid)).socketsLeave(R(req.schema,'group',ug.dm_group_id)); io.to(R(req.schema,'user',uid)).emit('group:deleted', { groupId: ug.dm_group_id }); } } await exec(req.schema, 'DELETE FROM user_groups WHERE id=$1', [ug.id]); res.json({ success: true }); diff --git a/build.sh b/build.sh index 52c5b02..0309ee2 100644 --- a/build.sh +++ b/build.sh @@ -13,7 +13,7 @@ # ───────────────────────────────────────────────────────────── set -euo pipefail -VERSION="${1:-0.12.14}" +VERSION="${1:-0.12.15}" ACTION="${2:-}" REGISTRY="${REGISTRY:-}" IMAGE_NAME="rosterchirp" diff --git a/frontend/package.json b/frontend/package.json index 5befef1..6bb948a 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -1,6 +1,6 @@ { "name": "rosterchirp-frontend", - "version": "0.12.14", + "version": "0.12.15", "private": true, "scripts": { "dev": "vite", diff --git a/frontend/src/components/ProfileModal.jsx b/frontend/src/components/ProfileModal.jsx index cf76e7e..34cb13f 100644 --- a/frontend/src/components/ProfileModal.jsx +++ b/frontend/src/components/ProfileModal.jsx @@ -19,6 +19,9 @@ export default function ProfileModal({ onClose }) { const [tab, setTab] = useState('profile'); // 'profile' | 'password' | 'notifications' const [pushTesting, setPushTesting] = useState(false); const [pushResult, setPushResult] = useState(null); + const [notifPermission, setNotifPermission] = useState( + typeof Notification !== 'undefined' ? Notification.permission : 'unsupported' + ); const [hideAdminTag, setHideAdminTag] = useState(!!user?.hide_admin_tag); const [allowDm, setAllowDm] = useState(user?.allow_dm !== 0); @@ -172,58 +175,77 @@ export default function ProfileModal({ onClose }) { {tab === 'notifications' && (
Tap Send Test Notification to trigger a push to this device. The notification will arrive shortly if everything is configured correctly.
-If it doesn't arrive, check:
- • Notification permission granted (browser prompt)
- • Android Settings → Apps → RosterChirp → Notifications → Enabled
- • App is backgrounded when the test fires
-
Tap Send Test Notification to trigger a push to this device. The notification will arrive shortly if everything is configured correctly.
+If it doesn't arrive, check:
+ • Android Settings → Apps → RosterChirp → Notifications → Enabled
+ • App is backgrounded when the test fires
+