fix(webui): derive the account avatar initial by code point

(displayName).charAt(0) returns the first UTF-16 unit, so a non-BMP first character
(emoji, rare CJK) rendered as a lone surrogate (�). Spread to iterate by code point.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
Sergey Kozyrenko
2026-06-14 12:36:47 +07:00
co-authored by Claude Fable 5
parent 86c7616efa
commit bc80aac985
2 changed files with 13 additions and 1 deletions
@@ -32,6 +32,18 @@ describe('SettingsAccount gating', () => {
expect(screen.getAllByRole('button', { name: 'Change' })).toHaveLength(3);
});
it.each([
['😀 Team', '😀'],
['中文 用户', '中'],
['한국 사용자', '한'],
['𠀋 Lin', '𠀋'],
])('uses the first whole code point of %s as the avatar initial', (name, expected) => {
authState.value = { user: { mail: 'e@x.com', name, type: 'local' } };
render(<SettingsAccount />);
expect(screen.getByText(expected)).toBeInTheDocument();
});
it('hides password and email editing for an OAuth account but keeps the name editable', () => {
authState.value = { user: githubUser };
render(<SettingsAccount />);
@@ -31,7 +31,7 @@ function SettingsAccount() {
const stopEditing = () => setEditing(null);
const displayName = user.name?.trim() || user.mail;
const initial = (displayName || '?').charAt(0).toUpperCase();
const initial = ([...(displayName || '?')][0] ?? '?').toUpperCase();
const createdAt = user.created_at ? new Date(user.created_at) : null;
const memberSince =
createdAt && !Number.isNaN(createdAt.getTime()) ? format(createdAt, 'MMMM yyyy', { locale: enUS }) : null;