feat(web): add /settings page with ListenBrainz section

Adds api.put helper, ListenBrainz API module with query/mutation
helpers, a /settings route with token + enable/disable UI, and 5
tests. Adds Settings to the Shell nav.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-04-28 15:45:42 -04:00
parent 46b23424c2
commit 13e12d97ae
5 changed files with 250 additions and 1 deletions
+2
View File
@@ -45,6 +45,8 @@ export const api = {
get: <T>(path: string): Promise<T> => apiFetch(path) as Promise<T>,
post: <T>(path: string, body: unknown): Promise<T> =>
apiFetch(path, { method: 'POST', body: JSON.stringify(body) }) as Promise<T>,
put: <T>(path: string, body: unknown): Promise<T> =>
apiFetch(path, { method: 'PUT', body: JSON.stringify(body) }) as Promise<T>,
del: (path: string): Promise<null> =>
apiFetch(path, { method: 'DELETE' }) as Promise<null>
};
+44
View File
@@ -0,0 +1,44 @@
import { createQuery, createMutation } from '@tanstack/svelte-query';
import type { QueryClient } from '@tanstack/svelte-query';
import { api } from './client';
export type LBStatus = {
enabled: boolean;
token_set: boolean;
last_scrobbled_at: string | null;
};
export function getListenBrainzStatus(): Promise<LBStatus> {
return api.get<LBStatus>('/api/me/listenbrainz');
}
export function setListenBrainzToken(token: string): Promise<LBStatus> {
return api.put<LBStatus>('/api/me/listenbrainz', { token });
}
export function setListenBrainzEnabled(enabled: boolean): Promise<LBStatus> {
return api.put<LBStatus>('/api/me/listenbrainz', { enabled });
}
export const LB_QUERY_KEY = ['settings', 'listenbrainz'] as const;
export function createLBStatusQuery() {
return createQuery({
queryKey: LB_QUERY_KEY,
queryFn: getListenBrainzStatus
});
}
export function createTokenMutation(queryClient: QueryClient) {
return createMutation<LBStatus, Error, string>({
mutationFn: (token: string) => setListenBrainzToken(token),
onSuccess: () => queryClient.invalidateQueries({ queryKey: LB_QUERY_KEY })
});
}
export function createEnabledMutation(queryClient: QueryClient) {
return createMutation<LBStatus, Error, boolean>({
mutationFn: (enabled: boolean) => setListenBrainzEnabled(enabled),
onSuccess: () => queryClient.invalidateQueries({ queryKey: LB_QUERY_KEY })
});
}