Public Access
feat(profile): let users design their public profile
This commit is contained in:
1 parent
a5458b3f86
commit
b55fcfec92
20 files changed
+674
-138
No files matched your search
@@ -9,7 +9,7 @@ export const DEFAULT_APPEARANCE = {
|
||||
accent: 'violet', corners: 'default', wideLayout: false, backgroundAppid: null, bannerAppid: null, showBanner: true,
|
||||
};
|
||||
|
||||
const appid = (value) => (Number.isInteger(value) && value > 0 ? value : null);
|
||||
export const appid = (value) => (Number.isInteger(value) && value > 0 ? value : null);
|
||||
|
||||
const STORAGE_KEY = 'tbp_appearance';
|
||||
const REQUEST_TIMEOUT_MS = 10000;
|
||||
|
||||
@@ -0,0 +1,37 @@
|
||||
import {apiFetch} from './api.js';
|
||||
import {ACCENTS, CORNERS, DEFAULT_APPEARANCE, appid} from './appearance.js';
|
||||
|
||||
// Auth accepts only these names (ProfileStyleRequest); Core sends no data for a section that is not listed.
|
||||
export const PROFILE_SECTIONS = ['SUMMARY', 'STATUS', 'PLAYING', 'FINISHED', 'STATS'];
|
||||
|
||||
export const DEFAULT_PROFILE_STYLE = {
|
||||
accent: DEFAULT_APPEARANCE.accent, corners: DEFAULT_APPEARANCE.corners, bannerAppid: null, backgroundAppid: null,
|
||||
sections: PROFILE_SECTIONS,
|
||||
};
|
||||
|
||||
export const normalizeProfileStyle = (value) => ({
|
||||
accent: ACCENTS.includes(value?.accent) ? value.accent : DEFAULT_PROFILE_STYLE.accent,
|
||||
corners: CORNERS.includes(value?.corners) ? value.corners : DEFAULT_PROFILE_STYLE.corners,
|
||||
bannerAppid: appid(value?.bannerAppid),
|
||||
backgroundAppid: appid(value?.backgroundAppid),
|
||||
sections: Array.isArray(value?.sections)
|
||||
? value.sections.filter((s, i) => PROFILE_SECTIONS.includes(s) && value.sections.indexOf(s) === i)
|
||||
: PROFILE_SECTIONS,
|
||||
});
|
||||
|
||||
/**
|
||||
* The stored style from GET /api/users/me; null when there is no answer to use.
|
||||
*/
|
||||
export const loadProfileStyle = async () => {
|
||||
const response = await apiFetch(`${import.meta.env.VITE_API_URL}/api/users/me?v=1`);
|
||||
if (!response.ok) return null;
|
||||
const data = await response.json();
|
||||
return normalizeProfileStyle(data.settings?.profileStyle);
|
||||
};
|
||||
|
||||
export const saveProfileStyle = (style) =>
|
||||
apiFetch(`${import.meta.env.VITE_API_URL}/api/users/settings/profile-style`, {
|
||||
method: 'PUT',
|
||||
headers: {'Content-Type': 'application/json'},
|
||||
body: JSON.stringify(style),
|
||||
});
|
||||
@@ -0,0 +1,18 @@
|
||||
import {describe, expect, it} from 'vitest';
|
||||
import {DEFAULT_PROFILE_STYLE, normalizeProfileStyle} from './profileStyle.js';
|
||||
|
||||
describe('normalizeProfileStyle', () => {
|
||||
it('is the default without a style, e.g. from an older Auth', () => {
|
||||
expect(normalizeProfileStyle(undefined)).toEqual(DEFAULT_PROFILE_STYLE);
|
||||
});
|
||||
|
||||
it('keeps the order, drops unknown and repeated sections and bad values', () => {
|
||||
expect(normalizeProfileStyle({accent: 'hotpink', corners: 'round', bannerAppid: -5, backgroundAppid: 620,
|
||||
sections: ['STATS', 'NOTES', 'PLAYING', 'STATS']}))
|
||||
.toEqual({accent: 'violet', corners: 'round', bannerAppid: null, backgroundAppid: 620, sections: ['STATS', 'PLAYING']});
|
||||
});
|
||||
|
||||
it('keeps an empty list: every section hidden', () => {
|
||||
expect(normalizeProfileStyle({sections: []}).sections).toEqual([]);
|
||||
});
|
||||
});
|
||||
Reference in new issue
Block a user