Public Access
88 lines
3.4 KiB
React
88 lines
3.4 KiB
React
import {useEffect, useRef, useState} from 'react';
|
|
import {useSearchParams} from 'react-router-dom';
|
|
import {useTranslation} from 'react-i18next';
|
|
import {toast} from 'sonner';
|
|
|
|
import {Skeleton} from '@/components/ui/skeleton';
|
|
import AccountInfoCard from '../components/AccountInfoCard.jsx';
|
|
import AppearanceCard from '../components/AppearanceCard.jsx';
|
|
import BuildVersionCard from '../components/BuildVersionCard.jsx';
|
|
import ChangePasswordCard from '../components/ChangePasswordCard.jsx';
|
|
import DeleteAccountCard from '../components/DeleteAccountCard.jsx';
|
|
import FollowsCard from '../components/FollowsCard.jsx';
|
|
import PreferencesCard from '../components/PreferencesCard.jsx';
|
|
import ProfileCard from '../components/ProfileCard.jsx';
|
|
import SteamAccountCard from '../components/SteamAccountCard.jsx';
|
|
import {useCurrentUserContext} from '../context/CurrentUserContext.jsx';
|
|
import useSettingsLoad from '../hooks/useSettingsLoad.js';
|
|
|
|
// The `steam` query parameter Auth adds when "Sign in through Steam" sends the user back.
|
|
const STEAM_LINK_TOASTS = {
|
|
linked: {show: toast.success, key: 'SETTINGS.STEAM_LINK.LINKED'},
|
|
'in-use': {show: toast.error, key: 'SETTINGS.STEAM_LINK.IN_USE'},
|
|
cancelled: {show: toast.info, key: 'SETTINGS.STEAM_LINK.CANCELLED'},
|
|
failed: {show: toast.error, key: 'SETTINGS.STEAM_LINK.FAILED'},
|
|
};
|
|
|
|
export default function SettingsPage() {
|
|
const {t} = useTranslation();
|
|
const {user: profile, updateUser: updateProfile} = useCurrentUserContext();
|
|
const [searchParams, setSearchParams] = useSearchParams();
|
|
// Read once: removing the parameter below must not load the profile again.
|
|
const [steamOutcome] = useState(() => searchParams.get('steam'));
|
|
const {isLoading, loadError, displayName} = useSettingsLoad(steamOutcome);
|
|
|
|
// A language change gives a new `t` and runs the effect again; the toast shows once.
|
|
const steamToastShown = useRef(false);
|
|
useEffect(() => {
|
|
const outcome = STEAM_LINK_TOASTS[steamOutcome];
|
|
if (!outcome || steamToastShown.current) return;
|
|
steamToastShown.current = true;
|
|
outcome.show(t(outcome.key));
|
|
setSearchParams((params) => {
|
|
params.delete('steam');
|
|
return params;
|
|
}, {replace: true});
|
|
}, [steamOutcome, setSearchParams, t]);
|
|
|
|
if (isLoading) {
|
|
return (
|
|
<div className="w-full max-w-2xl mx-auto p-4 md:p-8 space-y-6">
|
|
<Skeleton className="h-9 w-48"/>
|
|
<Skeleton className="h-56 rounded-xl"/>
|
|
<Skeleton className="h-40 rounded-xl"/>
|
|
<Skeleton className="h-44 rounded-xl"/>
|
|
</div>
|
|
);
|
|
}
|
|
|
|
if (loadError) {
|
|
return <div className="py-24 text-center text-destructive">{t(loadError)}</div>;
|
|
}
|
|
|
|
return (
|
|
<div className="w-full max-w-2xl mx-auto p-4 md:p-8 space-y-6">
|
|
<h1 className="text-3xl font-bold tracking-tight">{t('SETTINGS.TITLE')}</h1>
|
|
|
|
<AccountInfoCard/>
|
|
|
|
<PreferencesCard/>
|
|
|
|
<AppearanceCard/>
|
|
|
|
<SteamAccountCard steamId={profile?.steamId} verified={!!profile?.steamIdVerified}
|
|
onUnlinked={() => updateProfile((p) => ({...p, steamId: null, steamIdVerified: false}))}/>
|
|
|
|
<ProfileCard displayName={displayName}/>
|
|
|
|
<FollowsCard/>
|
|
|
|
<BuildVersionCard/>
|
|
|
|
<ChangePasswordCard/>
|
|
|
|
<DeleteAccountCard email={profile?.email}/>
|
|
</div>
|
|
);
|
|
}
|