const PAYLOAD_URL = process.env.PAYLOAD_URL || "https://payload.mk360.de"; const TENANT_SLUG = "einfach-produktiv"; export type BlogPost = { id: number; title: string; slug: string; category: string; readTime: number; excerpt: string; thumbnail: string | null; }; type PayloadPost = { id: number; title: string; slug: string; category: { name: string } | number | null; readTime: number; excerpt: string; thumbnail: { url: string } | number | null; }; export async function getBlogPosts(limit = 3): Promise { const params = new URLSearchParams({ "where[tenant.slug][equals]": TENANT_SLUG, sort: "-publishedAt", depth: "2", limit: String(limit), }); const res = await fetch(`${PAYLOAD_URL}/api/posts?${params}`, { next: { revalidate: 60 }, }); if (!res.ok) { console.error(`getBlogPosts: Payload returned ${res.status} ${res.statusText}`); return []; } const data: { docs?: PayloadPost[] } = await res.json(); const docs = Array.isArray(data.docs) ? data.docs : []; return docs.map((post) => ({ id: post.id, title: post.title, slug: post.slug, category: typeof post.category === "object" && post.category ? post.category.name : "", readTime: post.readTime, excerpt: post.excerpt, thumbnail: typeof post.thumbnail === "object" && post.thumbnail ? post.thumbnail.url : null, })); } export type PostDetail = BlogPost & { content: unknown; publishedAt: string; }; type PayloadPostDetail = PayloadPost & { content: unknown; publishedAt: string }; export async function getPostBySlug(slug: string): Promise { const params = new URLSearchParams({ "where[tenant.slug][equals]": TENANT_SLUG, "where[slug][equals]": slug, depth: "2", limit: "1", }); const res = await fetch(`${PAYLOAD_URL}/api/posts?${params}`, { next: { revalidate: 60 }, }); if (!res.ok) { console.error(`getPostBySlug: Payload returned ${res.status} ${res.statusText}`); return null; } const data: { docs?: PayloadPostDetail[] } = await res.json(); const doc = data.docs?.[0]; if (!doc) return null; return { id: doc.id, title: doc.title, slug: doc.slug, category: typeof doc.category === "object" && doc.category ? doc.category.name : "", readTime: doc.readTime, excerpt: doc.excerpt, thumbnail: typeof doc.thumbnail === "object" && doc.thumbnail ? doc.thumbnail.url : null, content: doc.content, publishedAt: doc.publishedAt, }; } // Frontend-facing shape — `id` is Payload's `slug` field, not its numeric // row id. Cart items are stored in localStorage keyed by this string (see // lib/cart.ts), so slugs were chosen in the Products collection to match // the ids the old hardcoded catalog used ("todo-karten" etc.) — switching // to numeric ids here would silently orphan every existing shopper's cart. export type Product = { id: string; name: string; description: string; price: number; image: string; href: string | null; }; type PayloadProduct = { id: number; name: string; slug: string; description: string | null; price: number; image: { url: string } | number | null; detailHref: string | null; }; export async function getProducts(): Promise { const params = new URLSearchParams({ "where[tenant.slug][equals]": TENANT_SLUG, sort: "sortOrder", depth: "2", limit: "100", }); const res = await fetch(`${PAYLOAD_URL}/api/products?${params}`, { next: { revalidate: 60 }, }); if (!res.ok) { console.error(`getProducts: Payload returned ${res.status} ${res.statusText}`); return []; } const data: { docs?: PayloadProduct[] } = await res.json(); const docs = Array.isArray(data.docs) ? data.docs : []; return docs.map((product) => ({ id: product.slug, name: product.name, description: product.description ?? "", price: product.price, image: typeof product.image === "object" && product.image ? product.image.url : "", href: product.detailHref || null, })); } export async function getProductBySlug(slug: string): Promise { const products = await getProducts(); return products.find((p) => p.id === slug) ?? null; } export type LegalPageType = "impressum" | "datenschutz" | "agb" | "widerruf"; export type LegalPage = { type: LegalPageType; title: string; content: unknown; attachment: { url: string; title: string } | null; }; type PayloadLegalPage = { type: LegalPageType; title: string; content: unknown; attachment: { url: string; title: string } | number | null; }; export async function getLegalPage(type: LegalPageType): Promise { const params = new URLSearchParams({ "where[tenant.slug][equals]": TENANT_SLUG, "where[type][equals]": type, depth: "1", limit: "1", }); const res = await fetch(`${PAYLOAD_URL}/api/legal-pages?${params}`, { next: { revalidate: 60 }, }); if (!res.ok) { console.error(`getLegalPage: Payload returned ${res.status} ${res.statusText}`); return null; } const data: { docs?: PayloadLegalPage[] } = await res.json(); const doc = data.docs?.[0]; if (!doc) return null; return { type: doc.type, title: doc.title, content: doc.content, attachment: typeof doc.attachment === "object" && doc.attachment ? { url: doc.attachment.url, title: doc.attachment.title } : null, }; }