Public Access
feat(ui): make stat numbers clickable to open games
StatDrill context holds one dialog for a page. StatCount wraps a number: total and status counts link to the library filter, other numbers open StatGamesDialog. DrillRow and DrillButton support drill-down in tag bars (genres, platforms, moods) and other stat displays. Dialog shows 40 games per page with bottom-sheet layout on phones, handles pagination and errors (403 not shared, 401 expired, 400 bad argument).
This commit is contained in:
1 parent
ed5df8c40d
commit
777ba87fd6
31 files changed
+1026
-261
No files matched your search
@@ -15,12 +15,13 @@ const library = {
|
||||
};
|
||||
|
||||
// `me` only for a test with a session: without one the page asks nothing about the viewer.
|
||||
function mockBackends({name = 'Lobo', profileStatus = 200, libraryStatus = 200, style, answer = library, me, equipped = {}, rewardsStatus = 200} = {}) {
|
||||
function mockBackends({name = 'Lobo', profileStatus = 200, libraryStatus = 200, style, answer = library, me, equipped = {}, rewardsStatus = 200, extra = {}} = {}) {
|
||||
fetchRoutes({
|
||||
[`GET /api/public/profiles/${encodeURIComponent(name)}`]:
|
||||
json(profileStatus, {displayName: 'Lobo', memberSince: '2026-03-02', ticket: 'the-ticket', style}),
|
||||
'GET /api/public/profiles/library': json(libraryStatus, answer),
|
||||
'GET /api/public/profiles/rewards': json(rewardsStatus, {equipped}),
|
||||
...extra,
|
||||
...(me && {
|
||||
'GET /api/users/me': json(200, me),
|
||||
'PUT /api/users/settings/profile-tiles': json(204, {}),
|
||||
@@ -260,4 +261,33 @@ describe('PublicProfilePage', () => {
|
||||
|
||||
await waitFor(() => expect(screen.getByText('PROFILE.ERROR_LOAD')).toBeTruthy());
|
||||
});
|
||||
|
||||
it('opensTheGamesBehindAStatusCountWithTheTicket', async () => {
|
||||
mockBackends({extra: {'GET /api/public/profiles/library/stats/games': json(200, {
|
||||
content: [{appid: 1, name: 'Backlogged', status: 'BACKLOG', playtimeMinutes: 0}], page: 0, size: 40, totalElements: 1, totalPages: 1})}});
|
||||
const {container} = renderPage();
|
||||
|
||||
fireEvent.click(await screen.findByRole('button', {name: 'BACKLOG.STATUS.BACKLOG: 142'}));
|
||||
|
||||
expect(await screen.findByText('Backlogged')).toBeTruthy();
|
||||
const call = fetch.mock.calls.find(([url]) => url.includes('/stats/games'));
|
||||
expect(call[0]).toContain('key=STATUS&arg=BACKLOG');
|
||||
expect(call[1].headers['X-Profile-Ticket']).toBe('the-ticket');
|
||||
expect(container.querySelector('a[href^="/library"]')).toBeNull();
|
||||
});
|
||||
|
||||
it('rendersNoButtonForAGroupTheOwnerDoesNotShare', async () => {
|
||||
library.stats = {pile: null, trend: null, topGames: null, taste: null, finished: null,
|
||||
habits: {moonTrips: 2.5, longestDay: null, underOneHourGames: 0, underOneHourShare: null}};
|
||||
try {
|
||||
mockBackends({style: {tiles: [{id: 'STATS_HABITS', size: 'M'}, {id: 'STATS_PILE', size: 'M'}]}});
|
||||
renderPage();
|
||||
|
||||
await screen.findByText('STATS.HABITS.TITLE');
|
||||
|
||||
expect(screen.queryByRole('button', {name: /STATS\.PILE/})).toBeNull();
|
||||
} finally {
|
||||
delete library.stats;
|
||||
}
|
||||
});
|
||||
});
|
||||
Reference in new issue
Block a user