Public Access
feat(stats): add stats page and pile trend
Show the stat groups on /stats, the pile trend on the dashboard card, one switch per group in the settings, and the shared groups on the public profile.
This commit is contained in:
1 parent
83bbc2730d
commit
9d1c7bb40d
31 files changed
+978
-11
No files matched your search
@@ -16,12 +16,14 @@ import {Skeleton} from '@/components/ui/skeleton';
|
||||
import {Switch} from '@/components/ui/switch';
|
||||
import FormField from '../components/FormField.jsx';
|
||||
import SteamAccountCard from '../components/SteamAccountCard.jsx';
|
||||
import ProfileStatsSettings from '../components/stats/ProfileStatsSettings.jsx';
|
||||
import {settingsSchema} from '../utils/validation.js';
|
||||
import {usePreferences} from '../context/PreferencesContext.jsx';
|
||||
import useSessionExpired from '../hooks/useSessionExpired.js';
|
||||
import useSaveAppearance from '../hooks/useSaveAppearance.js';
|
||||
import {ACCENTS, CORNERS} from '../utils/appearance.js';
|
||||
import {coverUrl} from '../utils/games.js';
|
||||
import {saveProfileStats} from '../utils/stats.js';
|
||||
import {cn} from '@/lib/utils';
|
||||
import {apiFetch, refreshSession} from '../utils/api.js';
|
||||
import {hasSession, markSession} from '../utils/auth.js';
|
||||
@@ -59,6 +61,7 @@ export default function SettingsPage() {
|
||||
const [profile, setProfile] = useState(null);
|
||||
const [isLoading, setIsLoading] = useState(true);
|
||||
const [loadError, setLoadError] = useState(null);
|
||||
const [savingProfileStats, setSavingProfileStats] = useState(false);
|
||||
const [searchParams, setSearchParams] = useSearchParams();
|
||||
// Read once: removing the parameter below must not load the profile again.
|
||||
const [steamOutcome] = useState(() => searchParams.get('steam'));
|
||||
@@ -197,6 +200,31 @@ export default function SettingsPage() {
|
||||
}
|
||||
};
|
||||
|
||||
// Shown at once; the switches wait for the answer, so the saves reach Auth one after the other.
|
||||
const handleProfileStatsChange = async (groups) => {
|
||||
const previous = profile?.settings?.profileStats ?? [];
|
||||
const showProfileStats = (next) => setProfile((p) => ({...p, settings: {...p.settings, profileStats: next}}));
|
||||
showProfileStats(groups);
|
||||
setSavingProfileStats(true);
|
||||
try {
|
||||
const response = await saveProfileStats(groups);
|
||||
if (response.status === 401) {
|
||||
expireSession();
|
||||
return;
|
||||
}
|
||||
if (!response.ok) {
|
||||
showProfileStats(previous);
|
||||
toast.error(t('SETTINGS.ERROR_SAVE'));
|
||||
}
|
||||
} catch (err) {
|
||||
console.error('Profile stats save error:', err);
|
||||
showProfileStats(previous);
|
||||
toast.error(t('INFO.ERROR.NETWORK_FAILURE'));
|
||||
} finally {
|
||||
setSavingProfileStats(false);
|
||||
}
|
||||
};
|
||||
|
||||
const copyProfileLink = async (link) => {
|
||||
try {
|
||||
await navigator.clipboard.writeText(link);
|
||||
@@ -429,6 +457,9 @@ export default function SettingsPage() {
|
||||
</Button>
|
||||
</div>
|
||||
)}
|
||||
<ProfileStatsSettings selected={profile?.settings?.profileStats ?? []}
|
||||
disabled={!publicProfile} saving={savingProfileStats}
|
||||
onChange={handleProfileStatsChange}/>
|
||||
</div>
|
||||
</CardContent>
|
||||
</Card>
|
||||
|
||||
Reference in new issue
Block a user