/** * Server-side fetch from the FlatRender Admin API. * * All functions return hardcoded fallback data when: * - ADMIN_API_URL is not set, or * - The admin service is unreachable. * * This means the Next.js app works standalone with no admin service running. */ const BASE = process.env.ADMIN_API_URL?.replace(/\/$/, ""); export interface AdminCategory { id: string; name: string; slug: string; description?: string; iconUrl?: string; type: "video" | "image" | "both"; sortOrder: number; projectCount: number; } export interface AdminProject { id: string; title: string; slug: string; description?: string; type: "video" | "image"; status: string; categoryId?: string; categoryName?: string; coverImageUrl?: string; previewVideoUrl?: string; tags: string[]; metaJson?: string; sortOrder: number; mediaCount: number; createdAt: string; updatedAt: string; } export interface AdminProjectsResponse { total: number; page: number; pageSize: number; items: AdminProject[]; } // ── Fetch helpers ───────────────────────────────────────────────────────────── async function safeFetch(url: string): Promise { if (!BASE) return null; try { const res = await fetch(url, { next: { revalidate: 60 }, // cache for 60 s (ISR) headers: { Accept: "application/json" }, }); if (!res.ok) return null; return res.json() as Promise; } catch { return null; } } // ── Public API ──────────────────────────────────────────────────────────────── export async function fetchCategories( type?: "video" | "image" ): Promise { const qs = type ? `?type=${type}` : ""; return ( (await safeFetch(`${BASE}/api/public/categories${qs}`)) ?? [] ); } export async function fetchProjects(opts?: { type?: "video" | "image"; categorySlug?: string; search?: string; page?: number; pageSize?: number; }): Promise { const params = new URLSearchParams(); if (opts?.type) params.set("type", opts.type); if (opts?.categorySlug) params.set("categorySlug", opts.categorySlug); if (opts?.search) params.set("search", opts.search); if (opts?.page) params.set("page", String(opts.page)); if (opts?.pageSize) params.set("pageSize", String(opts.pageSize)); const qs = params.size ? `?${params}` : ""; return ( (await safeFetch( `${BASE}/api/public/projects${qs}` )) ?? { total: 0, page: 1, pageSize: 20, items: [] } ); } export async function fetchProject(slug: string): Promise { return safeFetch(`${BASE}/api/public/projects/${slug}`); } /** True when admin API is configured and reachable. */ export async function isAdminApiAvailable(): Promise { if (!BASE) return false; try { const res = await fetch(`${BASE}/api/public/categories`, { next: { revalidate: 30 }, }); return res.ok; } catch { return false; } }