fix(profile): stop falling back to email when display_name is empty
The owner attribution helper used to fall back from display_name to
the part of the email before "@" when no display name was set. That
defeats the point of letting users pick a name: anyone who hadn't
explicitly chosen one had their email prefix surfaced publicly.
New fallback chain, applied uniformly:
- display_name (the user's chosen name) — if set, use it
- username (also chosen by the user as a URL slug) — if set, use it
- null — render nothing; the client hides the attribution line
Wire type ActivityPublic.owner_display is now `string | null`.
ActivityRow renders the "Lagt til av X" line only when display is
non-null.
Same idea applied to the user's own surfaces (nav + greeting):
- Nav button shows "Profil" (a label, not a name) when display_name
is empty, instead of falling back to the email.
- Home greeting drops "Velkommen, <name>." entirely when the user
has no display name, leaving just "Her er aktivitetene dine ...".
The feedback list (moderator view) and admin user table keep showing
the email — moderators and admins legitimately need it to identify
users for triage and role management.
This commit is contained in:
parent
d68859d68b
commit
43c24ec16b
6 changed files with 35 additions and 11 deletions
|
|
@ -66,16 +66,29 @@ function heartsFor(activityId: string, viewerId: string | null): { count: number
|
|||
return { count, hearted };
|
||||
}
|
||||
|
||||
function ownerAttribution(ownerId: string): { display: string; username: string | null } {
|
||||
/**
|
||||
* Build the public-facing attribution for an owner. Prefer the user's chosen
|
||||
* `display_name`; fall back to their `username` slug if set (also user-chosen);
|
||||
* otherwise return null so the client hides attribution entirely. We
|
||||
* deliberately do NOT fall back to the email or any prefix of it — that's a
|
||||
* contact identifier the user didn't elect to surface.
|
||||
*
|
||||
* `username` (the link target) is returned independently and is only non-null
|
||||
* when the owner has opted into a public list — drives whether the
|
||||
* attribution renders as a link to /<username>/list.
|
||||
*/
|
||||
function ownerAttribution(ownerId: string): { display: string | null; username: string | null } {
|
||||
const row = getDb()
|
||||
.prepare('SELECT display_name, email, username, public_list_enabled FROM users WHERE id = ?')
|
||||
.prepare('SELECT display_name, username, public_list_enabled FROM users WHERE id = ?')
|
||||
.get(ownerId) as
|
||||
| { display_name: string | null; email: string; username: string | null; public_list_enabled: number | null }
|
||||
| { display_name: string | null; username: string | null; public_list_enabled: number | null }
|
||||
| null;
|
||||
if (!row) return { display: 'ukjent', username: null };
|
||||
if (!row) return { display: null, username: null };
|
||||
const display = (row.display_name && row.display_name.trim())
|
||||
? row.display_name
|
||||
: (row.email.indexOf('@') > 0 ? row.email.slice(0, row.email.indexOf('@')) : row.email);
|
||||
: (row.username && row.username.trim())
|
||||
? row.username
|
||||
: null;
|
||||
const username = row.public_list_enabled === 1 ? row.username : null;
|
||||
return { display, username };
|
||||
}
|
||||
|
|
|
|||
|
|
@ -57,7 +57,9 @@ usersRoutes.get('/:username/list', (c) => {
|
|||
id: r.id,
|
||||
visibility: 'public',
|
||||
owner_id: r.owner_id,
|
||||
owner_display: user.display_name?.trim() || username,
|
||||
// Prefer the display name; fall back to the username slug (which is
|
||||
// what the URL already shows). Never falls through to email/id.
|
||||
owner_display: (user.display_name && user.display_name.trim()) || username,
|
||||
// The list itself is at /<username>/list, so we already know the slug.
|
||||
// Surfacing it on each row keeps ActivityRow's rendering uniform.
|
||||
owner_username: username,
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue