Spaces:
Runtime error
Runtime error
File size: 3,260 Bytes
09c1faf | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 | import type {
Book,
BookDetail,
CreatePlanPayload,
GoogleAuthResponse,
Plan,
PlanDayDetail,
PlanSummary,
} from "./types";
import {
getDemoBook,
getDemoBooks,
getDemoPlan,
getDemoPlanDay,
getDemoPlans,
registerDemoPlan,
} from "./demo-data";
const API_BASE_URL = process.env.NEXT_PUBLIC_API_BASE_URL ?? "http://127.0.0.1:8000";
export const DEMO_MODE = process.env.NODE_ENV === "production" && !process.env.NEXT_PUBLIC_API_BASE_URL;
async function demoRequest<T>(path: string, init?: RequestInit): Promise<T> {
const [pathname] = path.split("?");
if (pathname === "/auth/google") {
return {
user_id: "demo-user",
email: "demo@pluckai.local",
display_name: "Demo User",
} as T;
}
if (pathname === "/books") {
return getDemoBooks() as T;
}
if (pathname.startsWith("/books/")) {
const slug = decodeURIComponent(pathname.slice("/books/".length));
return getDemoBook(slug) as T;
}
if (pathname.startsWith("/users/") && pathname.endsWith("/plans")) {
const email = decodeURIComponent(pathname.slice("/users/".length, -"/plans".length));
return getDemoPlans(email) as T;
}
if (pathname === "/plans" && init?.method?.toUpperCase() === "POST") {
const body = typeof init.body === "string" ? init.body : "{}";
return registerDemoPlan(JSON.parse(body) as CreatePlanPayload) as T;
}
if (pathname.startsWith("/plans/") && pathname.includes("/days/")) {
const segments = pathname.split("/");
const planId = decodeURIComponent(segments[2] ?? "");
const dayValue = Number(segments[4] ?? "1");
return getDemoPlanDay(planId, dayValue) as T;
}
if (pathname.startsWith("/plans/")) {
const planId = decodeURIComponent(pathname.slice("/plans/".length));
return getDemoPlan(planId) as T;
}
throw new Error(`No demo response available for ${pathname}`);
}
async function request<T>(path: string, init?: RequestInit): Promise<T> {
if (DEMO_MODE) {
return demoRequest<T>(path, init);
}
const response = await fetch(`${API_BASE_URL}${path}`, {
...init,
headers: {
"Content-Type": "application/json",
...(init?.headers || {}),
},
cache: "no-store",
});
if (!response.ok) {
let message = response.statusText;
try {
const payload = await response.json();
message = payload.detail || payload.error || JSON.stringify(payload);
} catch {
// ignore body parse errors
}
throw new Error(message);
}
return (await response.json()) as T;
}
export const api = {
verifyGoogleToken: (idToken: string) =>
request<GoogleAuthResponse>("/auth/google", {
method: "POST",
body: JSON.stringify({ id_token: idToken }),
}),
listBooks: () => request<Book[]>("/books"),
getBook: (slug: string) => request<BookDetail>(`/books/${slug}`),
listPlans: (email: string) => request<PlanSummary[]>(`/users/${encodeURIComponent(email)}/plans`),
createPlan: (payload: CreatePlanPayload) =>
request<Plan>("/plans", { method: "POST", body: JSON.stringify(payload) }),
getPlan: (planId: string) => request<Plan>(`/plans/${planId}`),
getPlanDay: (planId: string, dayNumber: number) =>
request<PlanDayDetail>(`/plans/${planId}/days/${dayNumber}`),
};
|