feat: add user display profiles and fix web context menu UX
Some checks failed
CI / test (push) Failing after 17s

backend:

- add required user name and optional bio fields

- extend auth/register and user schemas/services with name/bio

- add alembic migration 0006 with safe backfill name=username

- compute per-user chat display_title for private chats

- keep Saved Messages delete-for-all protections

web:

- registration now includes name

- add profile edit modal (name/username/bio/avatar url)

- show private chat names via display_title

- fix context menus to open near cursor with viewport clamping

- stabilize +/close floating button to remove visual jump
This commit is contained in:
2026-03-08 00:57:02 +03:00
parent 321f918dca
commit 456595a576
20 changed files with 249 additions and 39 deletions

View File

@@ -9,6 +9,7 @@ export function AuthPanel() {
const loading = useAuthStore((s) => s.loading);
const [mode, setMode] = useState<Mode>("login");
const [email, setEmail] = useState("");
const [name, setName] = useState("");
const [username, setUsername] = useState("");
const [password, setPassword] = useState("");
const [error, setError] = useState<string | null>(null);
@@ -20,7 +21,7 @@ export function AuthPanel() {
setSuccess(null);
try {
if (mode === "register") {
await registerRequest(email, username, password);
await registerRequest(email, name, username, password);
setSuccess("Registered. Check email verification, then login.");
setMode("login");
return;
@@ -44,7 +45,10 @@ export function AuthPanel() {
<form className="space-y-3" onSubmit={onSubmit}>
<input className="w-full rounded bg-slate-800 px-3 py-2" placeholder="Email" value={email} onChange={(e) => setEmail(e.target.value)} />
{mode === "register" && (
<input className="w-full rounded bg-slate-800 px-3 py-2" placeholder="Username" value={username} onChange={(e) => setUsername(e.target.value)} />
<>
<input className="w-full rounded bg-slate-800 px-3 py-2" placeholder="Name" value={name} onChange={(e) => setName(e.target.value)} />
<input className="w-full rounded bg-slate-800 px-3 py-2" placeholder="Username" value={username} onChange={(e) => setUsername(e.target.value)} />
</>
)}
<input className="w-full rounded bg-slate-800 px-3 py-2" placeholder="Password" type="password" value={password} onChange={(e) => setPassword(e.target.value)} />
<button className="w-full rounded bg-accent px-3 py-2 font-semibold text-black disabled:opacity-50" disabled={loading} type="submit">