Public Access
fix(settings): keep the language and save settings one after the other
This commit is contained in:
1 parent
14dd59f9e0
commit
f605917874
25 files changed
+423
-98
No files matched your search
+15
-38
@@ -31,6 +31,7 @@ import {coverUrl} from '../utils/games.js';
|
||||
import {apiFetch, refreshSession} from '../utils/api.js';
|
||||
import {hasSession, markSession} from '../utils/auth.js';
|
||||
import {FAVORITE_PLATFORMS, saveFavoritePlatform} from '../utils/platforms.js';
|
||||
import {LANGUAGES, saveSettings} from '../utils/settings.js';
|
||||
|
||||
const BACKEND_ERROR_KEY = {
|
||||
DISPLAY_NAME_ALREADY_IN_USE: 'SETTINGS.ERROR_DISPLAY_NAME_IN_USE',
|
||||
@@ -44,7 +45,6 @@ const STEAM_LINK_TOASTS = {
|
||||
failed: {show: toast.error, key: 'SETTINGS.STEAM_LINK.FAILED'},
|
||||
};
|
||||
|
||||
const SUPPORTED_LANGUAGES = ['en', 'de'];
|
||||
// Radix Select has no empty value.
|
||||
const NO_FAVORITE = 'NONE';
|
||||
|
||||
@@ -81,7 +81,7 @@ export default function SettingsPage() {
|
||||
formState: {errors, isSubmitting},
|
||||
} = useForm({
|
||||
resolver: zodResolver(settingsSchema),
|
||||
defaultValues: {useDarkTheme: true, language: 'en', displayName: ''},
|
||||
defaultValues: {displayName: ''},
|
||||
});
|
||||
|
||||
// A language change gives a new `t` and runs the effect again; the toast shows once.
|
||||
@@ -123,42 +123,32 @@ export default function SettingsPage() {
|
||||
}
|
||||
|
||||
if (!response.ok) {
|
||||
setLoadError(t('INFO.ERROR.LOAD_PROFILE'));
|
||||
setLoadError('INFO.ERROR.LOAD_PROFILE');
|
||||
return;
|
||||
}
|
||||
|
||||
const data = await response.json();
|
||||
setProfile(data);
|
||||
reset({
|
||||
useDarkTheme: !!data.settings?.useDarkTheme,
|
||||
language: data.settings?.language || 'en',
|
||||
displayName: data.displayName ?? '',
|
||||
});
|
||||
reset({displayName: data.displayName ?? ''});
|
||||
} catch (err) {
|
||||
console.error('Settings load error:', err);
|
||||
setLoadError(t('INFO.ERROR.NETWORK_FAILURE'));
|
||||
setLoadError('INFO.ERROR.NETWORK_FAILURE');
|
||||
} finally {
|
||||
setIsLoading(false);
|
||||
}
|
||||
};
|
||||
|
||||
load();
|
||||
}, [navigate, expireSession, reset, t, steamOutcome]);
|
||||
}, [navigate, expireSession, reset, steamOutcome]);
|
||||
|
||||
const persistSettings = async (payload) => {
|
||||
const persistSettings = async (send) => {
|
||||
if (!hasSession()) {
|
||||
navigate('/login');
|
||||
return {ok: false};
|
||||
}
|
||||
|
||||
try {
|
||||
const response = await apiFetch(`${import.meta.env.VITE_API_URL}/api/users/settings`, {
|
||||
method: 'PUT',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: JSON.stringify(payload),
|
||||
});
|
||||
const response = await send();
|
||||
|
||||
if (response.status === 401) {
|
||||
expireSession();
|
||||
@@ -181,23 +171,14 @@ export default function SettingsPage() {
|
||||
}
|
||||
};
|
||||
|
||||
// The backend replaces all settings, so every save sends the saved values of the fields it does not change.
|
||||
const savedSettings = () => ({
|
||||
useDarkTheme: isDarkMode,
|
||||
language: i18n.language,
|
||||
displayName: profile?.displayName ?? null,
|
||||
publicProfile: !!profile?.settings?.publicProfile,
|
||||
});
|
||||
|
||||
const handleDarkThemeToggle = async () => {
|
||||
const next = !isDarkMode;
|
||||
setDarkMode(next); // apply on the fly
|
||||
await persistSettings({...savedSettings(), useDarkTheme: next});
|
||||
await persistSettings(() => saveSettings({useDarkTheme: next}));
|
||||
};
|
||||
|
||||
const handleLanguageChange = async (next) => {
|
||||
setLanguage(next); // apply on the fly
|
||||
await persistSettings({...savedSettings(), language: next});
|
||||
await persistSettings(() => setLanguage(next));
|
||||
};
|
||||
|
||||
const handleFavoritePlatformChange = async (value) => {
|
||||
@@ -210,7 +191,7 @@ export default function SettingsPage() {
|
||||
|
||||
const handlePublicProfileToggle = async () => {
|
||||
const next = !profile?.settings?.publicProfile;
|
||||
const result = await persistSettings({...savedSettings(), publicProfile: next});
|
||||
const result = await persistSettings(() => saveSettings({publicProfile: next}));
|
||||
if (result.ok) {
|
||||
setProfile((p) => ({...p, settings: {...p.settings, publicProfile: next}}));
|
||||
}
|
||||
@@ -237,12 +218,8 @@ export default function SettingsPage() {
|
||||
|
||||
const onSubmitProfile = async (values) => {
|
||||
// Without a name the profile has no link, so removing the name also makes it private.
|
||||
const publicProfile = savedSettings().publicProfile && !!values.displayName;
|
||||
const result = await persistSettings({
|
||||
...savedSettings(),
|
||||
displayName: values.displayName,
|
||||
publicProfile,
|
||||
});
|
||||
const publicProfile = !!profile?.settings?.publicProfile && !!values.displayName;
|
||||
const result = await persistSettings(() => saveSettings({displayName: values.displayName, publicProfile}));
|
||||
if (result.ok) {
|
||||
setProfile((p) => (p ? {
|
||||
...p, displayName: values.displayName, settings: {...p.settings, publicProfile},
|
||||
@@ -262,7 +239,7 @@ export default function SettingsPage() {
|
||||
}
|
||||
|
||||
if (loadError) {
|
||||
return <div className="py-24 text-center text-destructive">{loadError}</div>;
|
||||
return <div className="py-24 text-center text-destructive">{t(loadError)}</div>;
|
||||
}
|
||||
|
||||
const publicProfile = !!profile?.settings?.publicProfile;
|
||||
@@ -313,7 +290,7 @@ export default function SettingsPage() {
|
||||
<SelectValue/>
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
{SUPPORTED_LANGUAGES.map((lang) => (
|
||||
{LANGUAGES.map((lang) => (
|
||||
<SelectItem key={lang} value={lang}>
|
||||
{t(`SETTINGS.LANGUAGE_OPTIONS.${lang.toUpperCase()}`)}
|
||||
</SelectItem>
|
||||
|
||||
Reference in new issue
Block a user