feat: username reset, system-message UX, meetings polish, sidebar identity

- auth: forgot-password now has Email/Username tabs; new public
  /api/auth-helpers/reset-by-username resolves a username and hands off to the
  existing reset flow (real email or admin-notify fallback)
- messages: conversations expose isSystem; System notices are read-only (no
  composer, no call button) and styled distinctly (shield icon + badge)
- meetings: compact, larger control bar; self tile shows real initials and an
  avatar (not black) when the camera is off; delete-room UI with confirm
- sidebar: username-only accounts show @username instead of a synthetic email

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
Khalid Abdi
2026-06-20 22:39:48 +03:00
parent 90e6ec4cc0
commit b74d5d2d05
12 changed files with 343 additions and 97 deletions
+15
View File
@@ -0,0 +1,15 @@
import { apiFetch } from "@/lib/api-client";
// Start a password reset by username (for staff who sign in with a username
// rather than an email). The backend resolves the username to its account and
// hands off to Better Auth's reset flow. Always resolves; never reveals whether
// the username exists.
export async function requestResetByUsername(
username: string,
redirectTo: string,
): Promise<void> {
await apiFetch("/api/auth-helpers/reset-by-username", {
method: "POST",
body: JSON.stringify({ username, redirectTo }),
});
}
+15 -1
View File
@@ -61,12 +61,17 @@
},
"forgotPassword": {
"title": "Reset your password",
"subtitle": "We'll email you a link to reset your password",
"subtitle": "We'll send a link to reset your password",
"modeEmail": "Email",
"modeUsername": "Username",
"emailLabel": "Email",
"emailPlaceholder": "you@clinic.org",
"usernameLabel": "Username",
"usernamePlaceholder": "your username",
"submit": "Send reset link",
"submitting": "Sending…",
"sent": "If an account exists for {{email}}, a reset link is on its way. Check your inbox.",
"sentUsername": "If that username exists, a reset link is on its way. If you don't have an inbox, your clinic admin has been notified to set a new password for you.",
"error": "Could not send the reset email.",
"failedToastTitle": "Couldn't send reset link",
"sentToastTitle": "Reset link sent",
@@ -732,9 +737,16 @@
"cancel": "Cancel",
"createFailedTitle": "Couldn't create room",
"createFailedBody": "Please try again.",
"deleteRoom": "Delete room",
"deleting": "Deleting…",
"deleteRoomConfirmTitle": "Delete this room?",
"deleteRoomConfirmBody": "“{{name}}” will be removed for everyone. Anyone currently in the call will be disconnected.",
"deleteFailedTitle": "Couldn't delete room",
"deleteFailedBody": "Please try again.",
"emptyTitle": "No room selected",
"emptyDescription": "Pick a room to join the call, or create a new one.",
"you": "You",
"guest": "Guest",
"inCall": "{{count}} in call",
"connecting": "Connecting…",
"roomFull": "Room is full (max {{max}}).",
@@ -834,6 +846,8 @@
"startCall": "Start a call with {{name}}",
"system": {
"label": "System message",
"tag": "System",
"readOnly": "This is an automated system notice — you can't reply here.",
"passwordResetTitle": "Password reset requested",
"passwordResetBody": "{{name}} forgot their password. Tap to open their settings and set a new one."
}
+1
View File
@@ -48,6 +48,7 @@ export type ConversationSummary = {
id: string;
name: string;
isGroup: boolean;
isSystem: boolean;
participants: Participant[];
lastMessage: ConversationMessage | null;
unread: boolean;