Files
minstrel/web/src/lib/api/me.ts
T
bvandeusen 6b7e4f1dee feat(web): send timezone on login + bootstrap + weekly
Web client posts Intl.DateTimeFormat().resolvedOptions().timeZone to
PUT /api/me/timezone after every successful login, register, and
bootstrap when the locally-stored tz_last_sent_at is >7 days old.
Cadence tracked in localStorage keeps the server stateless on the
"is this stale?" check.

Failures swallowed: the server's UTC default + last-known value keep
the scheduler functioning until the next successful attempt. SSR-
safe via the typeof window guard.

For #392 Half B. Companion Flutter change in next commit.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-13 12:14:21 -04:00

65 lines
2.1 KiB
TypeScript

import { createQuery } from '@tanstack/svelte-query';
import { api } from './client';
import { qk } from './queries';
export type SystemPlaylistsStatus = {
in_flight: boolean;
last_run_at: string | null;
last_error: string | null;
};
export async function getSystemPlaylistsStatus(): Promise<SystemPlaylistsStatus> {
return api.get<SystemPlaylistsStatus>('/api/me/system-playlists-status');
}
// Refresh aggressively while a build is in_flight so the building → built
// transition appears live on the home page. Stale-time is short; manual
// invalidations on the server's POST endpoints are out of scope.
export function createSystemPlaylistsStatusQuery() {
return createQuery({
queryKey: qk.systemPlaylistsStatus(),
queryFn: getSystemPlaylistsStatus,
staleTime: 10_000
});
}
// Self-service profile / password / API-token endpoints (U3) ---------------
export type MyProfile = {
id: string;
username: string;
display_name: string | null;
email: string | null;
is_admin: boolean;
};
export type APITokenResponse = { api_token: string };
export async function changePassword(currentPassword: string, newPassword: string): Promise<void> {
await api.put('/api/me/password', {
current_password: currentPassword,
new_password: newPassword,
});
}
export async function updateProfile(input: { display_name?: string; email?: string }): Promise<MyProfile> {
return api.put<MyProfile>('/api/me/profile', input);
}
export async function getAPIToken(): Promise<APITokenResponse> {
return api.get<APITokenResponse>('/api/me/api-token');
}
export async function regenerateAPIToken(): Promise<APITokenResponse> {
return api.post<APITokenResponse>('/api/me/api-token', {});
}
// Submits the browser's current IANA timezone for the authenticated
// user. Called from the auth store on login + bootstrap + once weekly
// (cadence tracked client-side in localStorage). Failures are
// non-fatal — the server's UTC fallback keeps the scheduler working
// until the next attempt.
export async function putMyTimezone(timezone: string): Promise<void> {
await api.put<void>('/api/me/timezone', { timezone });
}