feat(library): sort by rating and priority

This commit is contained in:
lobo committed 2026-09-24 13:17:12 +02:00
1 parent bad11807e0
commit 03259d0515
4 files changed
+27 -12

No files matched your search

+3 -1
View File
@@ -123,7 +123,9 @@
"LAST_SYNCED": "Zuletzt synchronisiert {{when}}", "LAST_SYNCED": "Zuletzt synchronisiert {{when}}",
"FILTER_ALL": "Alle", "FILTER_ALL": "Alle",
"SEARCH_PLACEHOLDER": "Spiel suchen …", "SEARCH_PLACEHOLDER": "Spiel suchen …",
"NO_MATCH": "Keine Spiele für diesen Filter." "NO_MATCH": "Keine Spiele für diesen Filter.",
"SORT_RATING": "Beste Bewertung",
"SORT_PRIORITY": "Höchste Priorität"
}, },
"GAME_DETAIL": { "GAME_DETAIL": {
"BACK": "Zurück", "BACK": "Zurück",
+3 -1
View File
@@ -123,7 +123,9 @@
"LAST_SYNCED": "Last synced {{when}}", "LAST_SYNCED": "Last synced {{when}}",
"FILTER_ALL": "All", "FILTER_ALL": "All",
"SEARCH_PLACEHOLDER": "Search games …", "SEARCH_PLACEHOLDER": "Search games …",
"NO_MATCH": "No games match this filter." "NO_MATCH": "No games match this filter.",
"SORT_RATING": "Best rated",
"SORT_PRIORITY": "Highest priority"
}, },
"GAME_DETAIL": { "GAME_DETAIL": {
"BACK": "Back", "BACK": "Back",
+2
View File
@@ -26,6 +26,8 @@ const SORT_OPTIONS = [
{value: 'playtimeMinutes,asc', labelKey: 'LIBRARY.SORT_PLAYTIME_ASC'}, {value: 'playtimeMinutes,asc', labelKey: 'LIBRARY.SORT_PLAYTIME_ASC'},
{value: 'lastSeenAt,desc', labelKey: 'LIBRARY.SORT_LAST_SEEN'}, {value: 'lastSeenAt,desc', labelKey: 'LIBRARY.SORT_LAST_SEEN'},
{value: 'firstSeenAt,desc', labelKey: 'LIBRARY.SORT_FIRST_SEEN'}, {value: 'firstSeenAt,desc', labelKey: 'LIBRARY.SORT_FIRST_SEEN'},
{value: 'rating,desc', labelKey: 'LIBRARY.SORT_RATING'},
{value: 'priority,desc', labelKey: 'LIBRARY.SORT_PRIORITY'},
]; ];
export default function GameLibrary() { export default function GameLibrary() {
+19 -10
View File
@@ -39,17 +39,17 @@ function renderLibrary(initialEntry = '/library') {
const typeInto = (value) => fireEvent.change(screen.getByRole('searchbox'), {target: {value}}); const typeInto = (value) => fireEvent.change(screen.getByRole('searchbox'), {target: {value}});
beforeEach(() => {
localStorage.setItem('tbp_jwt', 'token');
globalThis.fetch = vi.fn(async () => ({ok: true, status: 200, json: async () => page}));
});
afterEach(() => {
cleanup();
localStorage.clear();
});
describe('GameLibrary search', () => { describe('GameLibrary search', () => {
beforeEach(() => {
localStorage.setItem('tbp_jwt', 'token');
globalThis.fetch = vi.fn(async () => ({ok: true, status: 200, json: async () => page}));
});
afterEach(() => {
cleanup();
localStorage.clear();
});
it('writes the trimmed search to the URL after the delay and resets the page', async () => { it('writes the trimmed search to the URL after the delay and resets the page', async () => {
const lib = renderLibrary('/library?page=3'); const lib = renderLibrary('/library?page=3');
@@ -93,3 +93,12 @@ describe('GameLibrary search', () => {
await waitFor(() => expect(screen.getByRole('searchbox').value).toBe('')); await waitFor(() => expect(screen.getByRole('searchbox').value).toBe(''));
}); });
}); });
describe('GameLibrary sort', () => {
it.each(['rating,desc', 'priority,desc'])('sends the sort %s from the URL', async (sort) => {
renderLibrary(`/library?sort=${encodeURIComponent(sort)}`);
await waitFor(() => expect(fetch).toHaveBeenCalled());
expect(new URL(fetch.mock.calls[0][0], 'http://x').searchParams.get('sort')).toBe(sort);
});
});