diff --git a/.env.example b/.env.example index 57c966e..2495e25 100644 --- a/.env.example +++ b/.env.example @@ -7,7 +7,7 @@ TZ=UTC # Copy this file to .env and customize # Image version to run (set by build.sh, or use 'latest') -JAMA_VERSION=0.6.7 +JAMA_VERSION=0.6.8 # Default admin credentials (used on FIRST RUN only) ADMIN_NAME=Admin User diff --git a/backend/package.json b/backend/package.json index b9b2d20..414eb0a 100644 --- a/backend/package.json +++ b/backend/package.json @@ -1,6 +1,6 @@ { "name": "jama-backend", - "version": "0.6.7", + "version": "0.6.8", "description": "TeamChat backend server", "main": "src/index.js", "scripts": { diff --git a/backend/src/data/help.md b/backend/src/data/help.md index ddf7b0c..48c1ed8 100644 --- a/backend/src/data/help.md +++ b/backend/src/data/help.md @@ -6,10 +6,11 @@ Welcome to **JAMA** — your private, self-hosted team messaging app. ## Navigating JAMA -### PRIVACY ASSURED -The only people that can read your direct messages (person 2 person or group) are the members of the message group. No one else, including admins, know which message groups exist or which you are part of, unless an they are a member of a given group that you are. -Every user can, at minimum, read all public messages. +### 🛡️ Your Privacy Assured +The only people that can read your direct messages (person 2 person or group) are the members of the message group. No one else, including admins, know which message groups exist or which you are part of, unless an they are a member. + +Every user, at minimum, can read all public messages. --- @@ -65,7 +66,7 @@ To create a group conversation: 3. Enter a **Message Name** 4. Click **Create** -> If a group with the exact same members already exists, you will be redirected to it automatically to help avoid duplication. +> If a message group with the exact same members already exists, you will be redirected to it automatically. This helps to avoid duplication. --- @@ -97,8 +98,8 @@ Other members still see the original group name, unless they change to customise Admins can access **Settings** from the user menu to configure: -- Branding a new app name and logo -- Set new user password +- Branding: a new app name and logo +- User Manager: Set new user password - Notification preferences --- diff --git a/build.sh b/build.sh index 6adb43d..0f9077d 100644 --- a/build.sh +++ b/build.sh @@ -13,7 +13,7 @@ # ───────────────────────────────────────────────────────────── set -euo pipefail -VERSION="${1:-0.6.7}" +VERSION="${1:-0.6.8}" ACTION="${2:-}" REGISTRY="${REGISTRY:-}" IMAGE_NAME="jama" diff --git a/frontend/package.json b/frontend/package.json index c688b3f..d73f567 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -1,6 +1,6 @@ { "name": "jama-frontend", - "version": "0.6.7", + "version": "0.6.8", "private": true, "scripts": { "dev": "vite", diff --git a/frontend/src/components/ProfileModal.jsx b/frontend/src/components/ProfileModal.jsx index 62ff9cd..2448f67 100644 --- a/frontend/src/components/ProfileModal.jsx +++ b/frontend/src/components/ProfileModal.jsx @@ -9,6 +9,7 @@ export default function ProfileModal({ onClose }) { const toast = useToast(); const [displayName, setDisplayName] = useState(user?.display_name || ''); + const [savedDisplayName, setSavedDisplayName] = useState(user?.display_name || ''); const [displayNameWarning, setDisplayNameWarning] = useState(''); const [aboutMe, setAboutMe] = useState(user?.about_me || ''); const [currentPw, setCurrentPw] = useState(''); @@ -24,6 +25,7 @@ export default function ProfileModal({ onClose }) { try { const { user: updated } = await api.updateProfile({ displayName, aboutMe, hideAdminTag }); updateUser(updated); + setSavedDisplayName(displayName); toast('Profile updated', 'success'); } catch (e) { toast(e.message, 'error'); @@ -100,24 +102,37 @@ export default function ProfileModal({ onClose }) {
- { - const val = e.target.value; - setDisplayName(val); - setDisplayNameWarning(''); - if (val && val !== user?.display_name) { - try { - const { taken } = await api.checkDisplayName(val); - if (taken) setDisplayNameWarning('Display name is already in use'); - } catch {} - } - }} - placeholder={user?.name} - style={{ borderColor: displayNameWarning ? '#e53935' : undefined }} - /> +
+ { + const val = e.target.value; + setDisplayName(val); + setDisplayNameWarning(''); + if (val && val !== user?.display_name) { + try { + const { taken } = await api.checkDisplayName(val); + if (taken) setDisplayNameWarning('Display name is already in use'); + } catch {} + } + }} + placeholder={user?.name} + style={{ borderColor: displayNameWarning ? '#e53935' : undefined }} + /> + {displayName !== savedDisplayName ? null : savedDisplayName ? ( + + ) : null} +
{displayNameWarning && {displayNameWarning}} + {savedDisplayName && Username: {user?.name}}
diff --git a/frontend/src/index.css b/frontend/src/index.css index 5640088..816bd32 100644 --- a/frontend/src/index.css +++ b/frontend/src/index.css @@ -214,7 +214,7 @@ a { color: inherit; text-decoration: none; } --border: #2e2e45; --text-primary: #e2e2f0; --text-secondary: #9898b8; - --text-tertiary: #6060808; + --text-tertiary: #606080; --bubble-out: #4d8fd4; --bubble-in: #252535; } diff --git a/frontend/src/pages/Chat.jsx b/frontend/src/pages/Chat.jsx index 1b66843..4770d2a 100644 --- a/frontend/src/pages/Chat.jsx +++ b/frontend/src/pages/Chat.jsx @@ -121,11 +121,18 @@ export default function Chat() { // Update group preview text setGroups(prev => { const updateGroup = (g) => g.id === msg.group_id - ? { ...g, last_message: msg.content || (msg.image_url ? '📷 Image' : ''), last_message_at: msg.created_at } + ? { ...g, last_message: msg.content || (msg.image_url ? '📷 Image' : ''), last_message_at: msg.created_at, last_message_user_id: msg.user_id } : g; + const updatedPrivate = prev.privateGroups.map(updateGroup) + .sort((a, b) => { + if (!a.last_message_at && !b.last_message_at) return 0; + if (!a.last_message_at) return 1; + if (!b.last_message_at) return -1; + return new Date(b.last_message_at) - new Date(a.last_message_at); + }); return { publicGroups: prev.publicGroups.map(updateGroup), - privateGroups: prev.privateGroups.map(updateGroup), + privateGroups: updatedPrivate, }; }); // Don't badge own messages