Public Access
feat(profile): set a display name and greet with it on the dashboard
Settings: new Profil card with display name and Steam ID. Registration: optional display name. The dashboard falls back to the email prefix when no display name is set.
This commit is contained in:
1 parent
6773040d59
commit
7b676f0a1e
7 files changed
+90
-13
No files matched your search
@@ -20,6 +20,7 @@ import {usePreferences} from '../context/PreferencesContext.jsx';
|
||||
|
||||
const BACKEND_ERROR_KEY = {
|
||||
STEAM_ID_ALREADY_IN_USE: 'REGISTRATION.ERROR_STEAM_ID_IN_USE',
|
||||
DISPLAY_NAME_ALREADY_IN_USE: 'SETTINGS.ERROR_DISPLAY_NAME_IN_USE',
|
||||
};
|
||||
|
||||
const SUPPORTED_LANGUAGES = ['en', 'de'];
|
||||
@@ -49,7 +50,7 @@ export default function SettingsPage() {
|
||||
formState: {errors, isSubmitting},
|
||||
} = useForm({
|
||||
resolver: zodResolver(settingsSchema),
|
||||
defaultValues: {useDarkTheme: true, language: 'en', steamId: ''},
|
||||
defaultValues: {useDarkTheme: true, language: 'en', steamId: '', displayName: ''},
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
@@ -86,6 +87,7 @@ export default function SettingsPage() {
|
||||
useDarkTheme: !!data.settings?.useDarkTheme,
|
||||
language: data.settings?.language || 'en',
|
||||
steamId: data.steamId ?? '',
|
||||
displayName: data.displayName ?? '',
|
||||
});
|
||||
} catch (err) {
|
||||
console.error('Settings load error:', err);
|
||||
@@ -146,6 +148,7 @@ export default function SettingsPage() {
|
||||
useDarkTheme: next,
|
||||
language: i18n.language,
|
||||
steamId: profile?.steamId ?? null,
|
||||
displayName: profile?.displayName ?? null,
|
||||
});
|
||||
};
|
||||
|
||||
@@ -155,17 +158,19 @@ export default function SettingsPage() {
|
||||
useDarkTheme: isDarkMode,
|
||||
language: next,
|
||||
steamId: profile?.steamId ?? null,
|
||||
displayName: profile?.displayName ?? null,
|
||||
});
|
||||
};
|
||||
|
||||
const onSubmitSteamId = async (values) => {
|
||||
const onSubmitProfile = async (values) => {
|
||||
const result = await persistSettings({
|
||||
useDarkTheme: isDarkMode,
|
||||
language: i18n.language,
|
||||
steamId: values.steamId,
|
||||
displayName: values.displayName,
|
||||
});
|
||||
if (result.ok) {
|
||||
setProfile((p) => (p ? {...p, steamId: values.steamId} : p));
|
||||
setProfile((p) => (p ? {...p, steamId: values.steamId, displayName: values.displayName} : p));
|
||||
}
|
||||
};
|
||||
|
||||
@@ -240,10 +245,21 @@ export default function SettingsPage() {
|
||||
|
||||
<Card>
|
||||
<CardHeader>
|
||||
<CardTitle className="flex items-center gap-2"><Gamepad2 className="size-4 text-primary"/>{t('SETTINGS.STEAM')}</CardTitle>
|
||||
<CardTitle className="flex items-center gap-2"><Gamepad2 className="size-4 text-primary"/>{t('SETTINGS.PROFILE')}</CardTitle>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<form onSubmit={handleSubmit(onSubmitSteamId)} className="space-y-4" noValidate>
|
||||
<form onSubmit={handleSubmit(onSubmitProfile)} className="space-y-4" noValidate>
|
||||
<FormField id="displayName" label={t('SETTINGS.DISPLAY_NAME')} error={errors.displayName} t={t}>
|
||||
<Input
|
||||
id="displayName"
|
||||
type="text"
|
||||
maxLength={24}
|
||||
placeholder={t('SETTINGS.DISPLAY_NAME_PLACEHOLDER')}
|
||||
aria-invalid={!!errors.displayName}
|
||||
{...register('displayName')}
|
||||
/>
|
||||
<p className="text-xs text-muted-foreground">{t('SETTINGS.DISPLAY_NAME_HINT')}</p>
|
||||
</FormField>
|
||||
<FormField id="steamId" label={t('SETTINGS.STEAM_ID')} error={errors.steamId} t={t}>
|
||||
<Input
|
||||
id="steamId"
|
||||
@@ -256,7 +272,7 @@ export default function SettingsPage() {
|
||||
</FormField>
|
||||
<Button type="submit" disabled={isSubmitting}>
|
||||
{isSubmitting ? <Loader2 className="animate-spin"/> : <Save/>}
|
||||
{t('SETTINGS.SAVE_STEAM_ID')}
|
||||
{t('SETTINGS.SAVE_PROFILE')}
|
||||
</Button>
|
||||
</form>
|
||||
</CardContent>
|
||||
|
||||
Reference in new issue
Block a user