Public Access
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.
53 lines
2.2 KiB
JavaScript
53 lines
2.2 KiB
JavaScript
import {apiFetch} from './api.js';
|
|
|
|
// The groups a user can show on the public profile; the overview numbers are always there.
|
|
export const PROFILE_STAT_GROUPS = ['PILE', 'TREND', 'TOP_GAMES', 'TASTE', 'HABITS', 'FINISHED'];
|
|
|
|
/**
|
|
* PUT /api/users/settings/profile-stats on Auth. The caller handles the response status.
|
|
*/
|
|
export const saveProfileStats = (groups) =>
|
|
apiFetch(`${import.meta.env.VITE_API_URL}/api/users/settings/profile-stats`, {
|
|
method: 'PUT',
|
|
headers: {'Content-Type': 'application/json'},
|
|
body: JSON.stringify({groups}),
|
|
});
|
|
|
|
/**
|
|
* @param groups comma separated stat groups of Core (StatGroup); empty for all
|
|
*/
|
|
export const statsUrl = (groups) => {
|
|
const query = groups ? `?groups=${groups}` : '';
|
|
return `${import.meta.env.VITE_CORE_API_URL}/api/library/stats${query}`;
|
|
};
|
|
|
|
/**
|
|
* The i18n key of an IGDB genre name, e.g. "Role-playing (RPG)" -> "ROLE_PLAYING_RPG". Callers fall back to the
|
|
* name, so a genre IGDB adds later still shows.
|
|
*/
|
|
export const genreKey = (name) => name.toUpperCase().replace(/[^A-Z0-9]+/g, '_').replace(/^_|_$/g, '');
|
|
|
|
export const formatDecimal = (value, locale, digits = 1) =>
|
|
value.toLocaleString(locale, {minimumFractionDigits: 0, maximumFractionDigits: digits});
|
|
|
|
export const formatPercent = (share, locale) =>
|
|
share.toLocaleString(locale, {style: 'percent', maximumFractionDigits: 0});
|
|
|
|
const DAY_MS = 24 * 60 * 60 * 1000;
|
|
const dayNumber = (day) => Math.round(Date.parse(`${day}T00:00:00Z`) / DAY_MS);
|
|
|
|
/**
|
|
* Points of an SVG polyline for the pile per day, oldest left. x follows the date, so days without a snapshot
|
|
* keep their width. The y axis starts at 0, so a small change looks small. One day gives a flat line over the
|
|
* whole width.
|
|
*/
|
|
export const trendPoints = (days, width, height) => {
|
|
if (days.length === 0) return '';
|
|
const max = Math.max(1, ...days.map((d) => d.backlogGames));
|
|
const y = (d) => height - (d.backlogGames / max) * height;
|
|
if (days.length === 1) return `0,${y(days[0])} ${width},${y(days[0])}`;
|
|
const first = dayNumber(days[0].day);
|
|
const span = dayNumber(days[days.length - 1].day) - first;
|
|
return days.map((d) => `${((dayNumber(d.day) - first) / span) * width},${y(d)}`).join(' ');
|
|
};
|