diff --git a/.env.example b/.env.example index da6d418..270e4c8 100644 --- a/.env.example +++ b/.env.example @@ -10,7 +10,7 @@ PROJECT_NAME=jama # Image version to run (set by build.sh, or use 'latest') -JAMA_VERSION=0.9.23 +JAMA_VERSION=0.9.24 # App port — the host port Docker maps to the container PORT=3000 diff --git a/backend/package.json b/backend/package.json index 74a7973..954aaac 100644 --- a/backend/package.json +++ b/backend/package.json @@ -1,6 +1,6 @@ { "name": "jama-backend", - "version": "0.9.23", + "version": "0.9.24", "description": "TeamChat backend server", "main": "src/index.js", "scripts": { diff --git a/backend/src/routes/groups.js b/backend/src/routes/groups.js index f564051..60f47b7 100644 --- a/backend/src/routes/groups.js +++ b/backend/src/routes/groups.js @@ -307,7 +307,30 @@ router.delete('/:id/members/:userId', authMiddleware, (req, res) => { } const targetId = parseInt(req.params.userId); if (targetId === group.owner_id) return res.status(400).json({ error: 'Cannot remove the group owner' }); + + const removedUser = db.prepare('SELECT name, display_name FROM users WHERE id = ?').get(targetId); + const removedName = removedUser?.display_name || removedUser?.name || 'Unknown'; + db.prepare('DELETE FROM group_members WHERE group_id = ? AND user_id = ?').run(group.id, targetId); + + // Post system message so remaining members see the removal notice + const sysResult = db.prepare(` + INSERT INTO messages (group_id, user_id, content, type) + VALUES (?, ?, ?, 'system') + `).run(group.id, targetId, `${removedName} has been removed from the conversation.`); + const sysMsg = db.prepare(` + SELECT m.*, u.name as user_name, u.display_name as user_display_name, + u.avatar as user_avatar, u.role as user_role, u.status as user_status, + u.hide_admin_tag as user_hide_admin_tag, u.about_me as user_about_me + FROM messages m JOIN users u ON m.user_id = u.id WHERE m.id = ? + `).get(sysResult.lastInsertRowid); + sysMsg.reactions = []; + io.to(`group:${group.id}`).emit('message:new', sysMsg); + + // Remove the user from the socket room and update their sidebar + io.in(`user:${targetId}`).socketsLeave(`group:${group.id}`); + io.to(`user:${targetId}`).emit('group:deleted', { groupId: group.id }); + res.json({ success: true }); }); @@ -340,6 +363,10 @@ router.delete('/:id/leave', authMiddleware, (req, res) => { // Broadcast to remaining members in the group room io.to(`group:${group.id}`).emit('message:new', sysMsg); + // Always remove leaver from socket room and their sidebar + io.in(`user:${userId}`).socketsLeave(`group:${group.id}`); + io.to(`user:${userId}`).emit('group:deleted', { groupId: group.id }); + if (group.is_direct) { // Make remaining user owner so they can still manage the conversation const remaining = db.prepare('SELECT user_id FROM group_members WHERE group_id = ? LIMIT 1').get(group.id); @@ -347,8 +374,6 @@ router.delete('/:id/leave', authMiddleware, (req, res) => { db.prepare("UPDATE groups SET owner_id = ?, updated_at = datetime('now') WHERE id = ?") .run(remaining.user_id, group.id); } - // Tell the leaver's socket to leave the group room and remove from sidebar - io.to(`user:${userId}`).emit('group:deleted', { groupId: group.id }); } res.json({ success: true }); diff --git a/build.sh b/build.sh index 6172330..4a70062 100644 --- a/build.sh +++ b/build.sh @@ -13,7 +13,7 @@ # ───────────────────────────────────────────────────────────── set -euo pipefail -VERSION="${1:-0.9.23}" +VERSION="${1:-0.9.24}" ACTION="${2:-}" REGISTRY="${REGISTRY:-}" IMAGE_NAME="jama" diff --git a/frontend/package.json b/frontend/package.json index 8eb0a66..2ec5c96 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -1,6 +1,6 @@ { "name": "jama-frontend", - "version": "0.9.23", + "version": "0.9.24", "private": true, "scripts": { "dev": "vite",