+
Block (not implemented)
+
{JSON.stringify(props, null, 2).slice(0, 200)}
+
+ )
+ }
+ return null
+}
+
+// porwoll.de blocks — replace placeholders with real components
+export const BlockRenderer = createBlockRenderer({
+ "hero-block": Placeholder as any,
+ "text-block": Placeholder as any,
+ "image-text-block": Placeholder as any,
+ "card-grid-block": Placeholder as any,
+ "cta-block": Placeholder as any,
+ "divider-block": Placeholder as any,
+ "testimonials-block": Placeholder as any,
+ "faq-block": Placeholder as any,
+ "contact-form-block": Placeholder as any,
+ "image-slider-block": Placeholder as any,
+ "services-block": Placeholder as any,
+ "team-block": Placeholder as any,
+ "locations-block": Placeholder as any,
+ "stats-block": Placeholder as any,
+ "quote-block": Placeholder as any,
+})
diff --git a/src/lib/api.ts b/src/lib/api.ts
new file mode 100644
index 0000000..76a4926
--- /dev/null
+++ b/src/lib/api.ts
@@ -0,0 +1,130 @@
+/**
+ * Payload CMS API functions for porwoll.de
+ *
+ * Uses @c2s/payload-contracts client for transport.
+ * All queries are automatically scoped to tenant "porwoll" (ID: 1).
+ */
+import { cms } from "./cms"
+
+// Re-export CMS types for convenience
+export type { Page, Post, Media, Navigation, SiteSetting, Testimonial, Faq } from "@c2s/payload-contracts/types"
+export type { PaginatedResponse } from "@c2s/payload-contracts/types"
+
+// Pages
+export async function getPage(slug: string, locale = "de") {
+ return cms.pages.getPage(slug, { locale: locale as "de" | "en", depth: 2 })
+}
+
+export async function getPages(options: { limit?: number; page?: number; locale?: string } = {}) {
+ return cms.pages.getPages({
+ limit: options.limit || 100,
+ page: options.page || 1,
+ locale: (options.locale || "de") as "de" | "en",
+ depth: 1,
+ })
+}
+
+// Posts
+export async function getPost(slug: string, locale = "de") {
+ return cms.posts.getPost(slug, { locale: locale as "de" | "en", depth: 2 })
+}
+
+export async function getPosts(options: {
+ type?: string
+ category?: string
+ limit?: number
+ page?: number
+ locale?: string
+} = {}) {
+ try {
+ return await cms.posts.getPosts({
+ type: options.type,
+ category: options.category,
+ limit: options.limit || 10,
+ page: options.page || 1,
+ locale: (options.locale || "de") as "de" | "en",
+ })
+ } catch {
+ return { docs: [], totalDocs: 0, limit: 10, totalPages: 0, page: 1, pagingCounter: 1, hasPrevPage: false, hasNextPage: false, prevPage: null, nextPage: null }
+ }
+}
+
+// Navigation
+export async function getNavigation(type: "header" | "footer" | "mobile") {
+ try {
+ return await cms.navigation.getNavigation(type, { depth: 2 })
+ } catch {
+ return null
+ }
+}
+
+// Site Settings
+export async function getSiteSettings() {
+ try {
+ return await cms.settings.getSiteSettings({ depth: 2 })
+ } catch {
+ return null
+ }
+}
+
+// SEO Settings (Global)
+export async function getSeoSettings() {
+ try {
+ return await cms.settings.getSeoSettings()
+ } catch {
+ return null
+ }
+}
+
+// Testimonials
+export async function getTestimonials(options: { limit?: number; locale?: string } = {}) {
+ return cms.client.getCollection("testimonials", {
+ limit: options.limit || 10,
+ locale: (options.locale || "de") as "de" | "en",
+ depth: 1,
+ })
+}
+
+// Bookings (porwoll-specific: photography bookings)
+export async function getBookings(options: { limit?: number; locale?: string } = {}) {
+ return cms.client.getCollection("bookings", {
+ limit: options.limit || 20,
+ locale: (options.locale || "de") as "de" | "en",
+ depth: 1,
+ })
+}
+
+// Newsletter Subscription
+export async function subscribeNewsletter(
+ email: string,
+ firstName?: string,
+ source = "website"
+): Promise<{ success: boolean; message?: string }> {
+ return cms.post("/api/newsletter/subscribe", {
+ email,
+ firstName,
+ tenantId: Number(process.env.NEXT_PUBLIC_TENANT_ID || "1"),
+ source,
+ })
+}
+
+// Contact Form Submission
+export async function submitContactForm(data: {
+ name: string
+ email: string
+ phone?: string
+ subject: string
+ message: string
+ formId?: number
+}): Promise<{ success: boolean; message?: string }> {
+ return cms.post("/api/form-submissions", {
+ form: data.formId || 1,
+ submissionData: [
+ { field: "name", value: data.name },
+ { field: "email", value: data.email },
+ { field: "phone", value: data.phone || "" },
+ { field: "subject", value: data.subject },
+ { field: "message", value: data.message },
+ ],
+ })
+}
diff --git a/src/lib/cms.ts b/src/lib/cms.ts
new file mode 100644
index 0000000..9914853
--- /dev/null
+++ b/src/lib/cms.ts
@@ -0,0 +1,15 @@
+/**
+ * Shared Payload CMS client for porwoll.de
+ *
+ * Configured for tenant "porwoll" (ID: 1).
+ * Tenant isolation is handled automatically.
+ */
+import { createPayloadClient } from "@c2s/payload-contracts/api-client"
+
+export const cms = createPayloadClient({
+ baseUrl: process.env.NEXT_PUBLIC_PAYLOAD_URL || "https://cms.c2sgmbh.de",
+ tenantId: process.env.NEXT_PUBLIC_TENANT_ID || "1",
+ defaultLocale: "de",
+ defaultDepth: 2,
+ defaultRevalidate: 60,
+})
diff --git a/tsconfig.json b/tsconfig.json
new file mode 100644
index 0000000..cf9c65d
--- /dev/null
+++ b/tsconfig.json
@@ -0,0 +1,34 @@
+{
+ "compilerOptions": {
+ "target": "ES2017",
+ "lib": ["dom", "dom.iterable", "esnext"],
+ "allowJs": true,
+ "skipLibCheck": true,
+ "strict": true,
+ "noEmit": true,
+ "esModuleInterop": true,
+ "module": "esnext",
+ "moduleResolution": "bundler",
+ "resolveJsonModule": true,
+ "isolatedModules": true,
+ "jsx": "react-jsx",
+ "incremental": true,
+ "plugins": [
+ {
+ "name": "next"
+ }
+ ],
+ "paths": {
+ "@/*": ["./src/*"]
+ }
+ },
+ "include": [
+ "next-env.d.ts",
+ "**/*.ts",
+ "**/*.tsx",
+ ".next/types/**/*.ts",
+ ".next/dev/types/**/*.ts",
+ "**/*.mts"
+ ],
+ "exclude": ["node_modules"]
+}