mirror of
https://github.com/complexcaresolutions/frontend.blogwoman.de.git
synced 2026-03-17 15:04:01 +00:00
- Fix getNavigation() to use contracts API (no broken type filter) - Single nav fetch in layout, pass mainMenu/footerMenu to components - Header, Navigation, MobileMenu use CMS mainMenu schema - Footer uses CMS footerMenu schema with linkType field - Add pnpm-workspace.yaml for onlyBuiltDependencies allowlist - Update payload-contracts to latest (navigation fix a0eea96) Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
245 lines
7 KiB
TypeScript
245 lines
7 KiB
TypeScript
/**
|
|
* Payload CMS API functions — powered by @c2s/payload-contracts
|
|
*
|
|
* Uses the shared API client for transport (tenant isolation, fetch caching).
|
|
* Returns data typed with local interfaces for component compatibility.
|
|
*
|
|
* Navigation uses contracts types directly (schema matches).
|
|
* Other types use 'as unknown as' bridge since local types differ
|
|
* from CMS types (meta vs seo, id string vs number, etc.).
|
|
*/
|
|
import { cms } from "./cms"
|
|
import type { Navigation } from "@c2s/payload-contracts/types"
|
|
import type {
|
|
Page,
|
|
Post,
|
|
Favorite,
|
|
Series,
|
|
Testimonial,
|
|
FAQ,
|
|
SeoSettings,
|
|
PaginatedResponse,
|
|
SiteSettings,
|
|
} from "./types"
|
|
|
|
export type { Navigation }
|
|
|
|
const TENANT_ID = process.env.NEXT_PUBLIC_TENANT_ID || "9"
|
|
|
|
// Pages
|
|
export async function getPage(slug: string, locale = "de"): Promise<Page | null> {
|
|
const result = await cms.pages.getPage(slug, {
|
|
locale: locale as "de" | "en",
|
|
depth: 2,
|
|
})
|
|
return result as unknown as Page | null
|
|
}
|
|
|
|
export async function getPages(options: {
|
|
limit?: number
|
|
page?: number
|
|
locale?: string
|
|
} = {}): Promise<PaginatedResponse<Page>> {
|
|
const result = await cms.pages.getPages({
|
|
limit: options.limit || 100,
|
|
page: options.page || 1,
|
|
locale: (options.locale || "de") as "de" | "en",
|
|
depth: 1,
|
|
})
|
|
return result as unknown as PaginatedResponse<Page>
|
|
}
|
|
|
|
// Posts
|
|
export async function getPost(slug: string, locale = "de"): Promise<Post | null> {
|
|
const result = await cms.posts.getPost(slug, {
|
|
locale: locale as "de" | "en",
|
|
depth: 2,
|
|
})
|
|
return result as unknown as Post | null
|
|
}
|
|
|
|
export async function getPosts(options: {
|
|
type?: string
|
|
category?: string
|
|
series?: string
|
|
limit?: number
|
|
page?: number
|
|
locale?: string
|
|
featured?: boolean
|
|
} = {}): Promise<PaginatedResponse<Post>> {
|
|
try {
|
|
const where: Record<string, unknown> = {}
|
|
if (options.featured) where["isFeatured][equals"] = "true"
|
|
|
|
const result = await cms.posts.getPosts({
|
|
type: options.type,
|
|
category: options.category,
|
|
series: options.series,
|
|
limit: options.limit || 10,
|
|
page: options.page || 1,
|
|
locale: (options.locale || "de") as "de" | "en",
|
|
where,
|
|
})
|
|
return result as unknown as PaginatedResponse<Post>
|
|
} catch {
|
|
return { docs: [], totalDocs: 0, limit: 10, totalPages: 0, page: 1, pagingCounter: 1, hasPrevPage: false, hasNextPage: false, prevPage: null, nextPage: null }
|
|
}
|
|
}
|
|
|
|
// Navigation — single document per tenant with mainMenu + footerMenu
|
|
// Uses contracts Navigation type directly (no bridge needed)
|
|
export async function getNavigation(): Promise<Navigation | null> {
|
|
try {
|
|
return await cms.navigation.getNavigation({ depth: 2 })
|
|
} catch {
|
|
return null
|
|
}
|
|
}
|
|
|
|
// Site Settings
|
|
export async function getSiteSettings(): Promise<SiteSettings | null> {
|
|
try {
|
|
const result = await cms.settings.getSiteSettings({ depth: 2 })
|
|
return result as unknown as SiteSettings | null
|
|
} catch {
|
|
return null
|
|
}
|
|
}
|
|
|
|
// SEO Settings (Global)
|
|
export async function getSeoSettings(): Promise<SeoSettings | null> {
|
|
try {
|
|
const result = await cms.settings.getSeoSettings()
|
|
return result as unknown as SeoSettings | null
|
|
} catch {
|
|
return null
|
|
}
|
|
}
|
|
|
|
// Testimonials
|
|
export async function getTestimonials(options: {
|
|
limit?: number
|
|
locale?: string
|
|
} = {}): Promise<PaginatedResponse<Testimonial>> {
|
|
const result = await cms.client.getCollection("testimonials", {
|
|
limit: options.limit || 10,
|
|
locale: (options.locale || "de") as "de" | "en",
|
|
depth: 1,
|
|
})
|
|
return result as unknown as PaginatedResponse<Testimonial>
|
|
}
|
|
|
|
// FAQs
|
|
export async function getFAQs(options: {
|
|
category?: string
|
|
limit?: number
|
|
locale?: string
|
|
} = {}): Promise<PaginatedResponse<FAQ>> {
|
|
const result = await cms.client.getCollection("faqs", {
|
|
limit: options.limit || 50,
|
|
locale: (options.locale || "de") as "de" | "en",
|
|
sort: "order",
|
|
depth: 1,
|
|
where: options.category ? { "category][equals": options.category } : undefined,
|
|
})
|
|
return result as unknown as PaginatedResponse<FAQ>
|
|
}
|
|
|
|
// BlogWoman: Favorites
|
|
export async function getFavorites(options: {
|
|
category?: string
|
|
badge?: string
|
|
limit?: number
|
|
page?: number
|
|
locale?: string
|
|
} = {}): Promise<PaginatedResponse<Favorite>> {
|
|
try {
|
|
const where: Record<string, unknown> = { "isActive][equals": "true" }
|
|
if (options.category) where["category][equals"] = options.category
|
|
if (options.badge) where["badge][equals"] = options.badge
|
|
|
|
const result = await cms.client.getCollection("favorites", {
|
|
limit: options.limit || 12,
|
|
page: options.page || 1,
|
|
locale: (options.locale || "de") as "de" | "en",
|
|
depth: 1,
|
|
where,
|
|
})
|
|
return result as unknown as PaginatedResponse<Favorite>
|
|
} catch {
|
|
return { docs: [], totalDocs: 0, limit: 12, totalPages: 0, page: 1, pagingCounter: 1, hasPrevPage: false, hasNextPage: false, prevPage: null, nextPage: null }
|
|
}
|
|
}
|
|
|
|
export async function getFavorite(slug: string, locale = "de"): Promise<Favorite | null> {
|
|
const data = await cms.client.getCollection("favorites", {
|
|
locale: locale as "de" | "en",
|
|
depth: 1,
|
|
where: { "slug][equals": slug, "isActive][equals": "true" },
|
|
limit: 1,
|
|
})
|
|
return (data.docs[0] as unknown as Favorite) ?? null
|
|
}
|
|
|
|
// BlogWoman: Series
|
|
export async function getSeries(options: {
|
|
limit?: number
|
|
locale?: string
|
|
} = {}): Promise<PaginatedResponse<Series>> {
|
|
try {
|
|
const result = await cms.client.getCollection("series", {
|
|
limit: options.limit || 20,
|
|
locale: (options.locale || "de") as "de" | "en",
|
|
depth: 2,
|
|
where: { "isActive][equals": "true" },
|
|
})
|
|
return result as unknown as PaginatedResponse<Series>
|
|
} catch {
|
|
return { docs: [], totalDocs: 0, limit: 20, totalPages: 0, page: 1, pagingCounter: 1, hasPrevPage: false, hasNextPage: false, prevPage: null, nextPage: null }
|
|
}
|
|
}
|
|
|
|
export async function getSeriesBySlug(slug: string, locale = "de"): Promise<Series | null> {
|
|
const data = await cms.client.getCollection("series", {
|
|
locale: locale as "de" | "en",
|
|
depth: 2,
|
|
where: { "slug][equals": slug, "isActive][equals": "true" },
|
|
limit: 1,
|
|
})
|
|
return (data.docs[0] as unknown as Series) ?? null
|
|
}
|
|
|
|
// 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(TENANT_ID),
|
|
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 },
|
|
],
|
|
})
|
|
}
|