feat: add users question

This commit is contained in:
2026-08-20 18:48:22 +03:30
parent aba556618b
commit 96c74601c8
6 changed files with 365 additions and 11 deletions
+27 -2
View File
@@ -1,7 +1,11 @@
// Thin fetch wrapper for the meditation API. The app is a static SPA, so every
// call runs in the browser and carries the bearer token from localStorage.
import { MEDITATION_BASE_URL, TOKEN_STORAGE_KEY } from "./config";
import {
APPRO_TOKEN_STORAGE_KEY,
MEDITATION_BASE_URL,
TOKEN_STORAGE_KEY,
} from "./config";
export class ApiError extends Error {
status: number;
@@ -29,6 +33,21 @@ export function clearToken() {
window.localStorage.removeItem(TOKEN_STORAGE_KEY);
}
export function getApproToken(): string | null {
if (typeof window === "undefined") return null;
return window.localStorage.getItem(APPRO_TOKEN_STORAGE_KEY);
}
export function setApproToken(token: string) {
if (typeof window === "undefined") return;
window.localStorage.setItem(APPRO_TOKEN_STORAGE_KEY, token);
}
export function clearApproToken() {
if (typeof window === "undefined") return;
window.localStorage.removeItem(APPRO_TOKEN_STORAGE_KEY);
}
type Query = Record<string, string | number | boolean | undefined | null>;
interface RequestOptions {
@@ -40,6 +59,8 @@ interface RequestOptions {
baseUrl?: string;
// Skip attaching the bearer token (used by the login calls).
auth?: boolean;
// Extra headers to merge into the request.
headers?: Record<string, string>;
}
function buildUrl(path: string, query?: Query, baseUrl = MEDITATION_BASE_URL) {
@@ -60,7 +81,7 @@ export async function apiFetch<T = unknown>(
path: string,
options: RequestOptions = {},
): Promise<T> {
const { method = "GET", body, query, baseUrl, auth = true } = options;
const { method = "GET", body, query, baseUrl, auth = true, headers: extraHeaders } = options;
const headers: Record<string, string> = { Accept: "application/json" };
@@ -69,6 +90,10 @@ export async function apiFetch<T = unknown>(
if (token) headers.Authorization = `Bearer ${token}`;
}
if (extraHeaders) {
Object.assign(headers, extraHeaders);
}
let payload: BodyInit | undefined;
if (body instanceof FormData) {
payload = body; // browser sets multipart Content-Type + boundary