diff --git a/app/api/pages/[slug]/pdf/route.tsx b/app/api/pages/[slug]/pdf/route.tsx index ff304d06..944628dd 100644 --- a/app/api/pages/[slug]/pdf/route.tsx +++ b/app/api/pages/[slug]/pdf/route.tsx @@ -11,8 +11,38 @@ export async function GET(req: NextRequest, { params }: { params: Promise<{ slug try { const { slug } = await params; - // Hardcoded bypass for AGBs to use the original uploaded PDF. + // Handle AGBs specifically - either fetch from collection or use fallback file if (slug === 'agbs') { + const payload = await getPayload({ config: configPromise }); + const currentAgbs = await payload.find({ + collection: 'agbs-collection', + where: { + isCurrent: { equals: true }, + }, + limit: 1, + }); + + if (currentAgbs.totalDocs > 0) { + const agb = currentAgbs.docs[0]; + const media = agb.file as any; + if (media && media.url) { + // If it's a remote URL or absolute path, we might need to fetch it + // For now assume it's a local file in public/media + const filePath = path.join(process.cwd(), 'public', media.url); + if (fs.existsSync(filePath)) { + const fileBuffer = fs.readFileSync(filePath); + return new NextResponse(fileBuffer, { + status: 200, + headers: { + 'Content-Type': 'application/pdf', + 'Content-Disposition': `attachment; filename="${media.filename}"`, + }, + }); + } + } + } + + // Fallback for hardcoded legacy AGB const filePath = path.join(process.cwd(), 'public', 'AVB-KLZ-4-2026.pdf'); if (fs.existsSync(filePath)) { const fileBuffer = fs.readFileSync(filePath); diff --git a/components/AgbHistoryBlock.tsx b/components/AgbHistoryBlock.tsx new file mode 100644 index 00000000..f11e82a6 --- /dev/null +++ b/components/AgbHistoryBlock.tsx @@ -0,0 +1,76 @@ +import React from 'react'; +import { getPayload } from 'payload'; +import configPromise from '@payload-config'; +import { Container, Card, Heading } from '@/components/ui'; + +export const AgbHistoryBlock: React.FC<{ title: string }> = async ({ title }) => { + const payload = await getPayload({ config: configPromise }); + + const agbs = await payload.find({ + collection: 'agbs-collection', + sort: '-versionDate', + limit: 100, + }); + + if (agbs.totalDocs === 0) { + return null; + } + + return ( +
+ + {title || 'Vorherige Versionen'} + +
+ {agbs.docs.map((agb: any) => { + const date = new Date(agb.versionDate).toLocaleDateString('de-DE', { + year: 'numeric', + month: 'long', + day: 'numeric', + }); + + const fileUrl = typeof agb.file === 'object' ? agb.file.url : ''; + const filename = typeof agb.file === 'object' ? agb.file.filename : 'agb.pdf'; + + return ( +
+
+

+ {agb.title} +

+

Gültig ab {date}

+
+ {fileUrl && ( + + + + + + + + )} +
+ ); + })} +
+
+ ); +}; diff --git a/components/PayloadRichText.tsx b/components/PayloadRichText.tsx index 83b44670..3497b2aa 100644 --- a/components/PayloadRichText.tsx +++ b/components/PayloadRichText.tsx @@ -38,6 +38,7 @@ import GallerySection from '@/components/home/GallerySection'; import VideoSection from '@/components/home/VideoSection'; import CTA from '@/components/home/CTA'; import { PDFDownloadBlock } from '@/components/PDFDownloadBlock'; +import { AgbHistoryBlock } from '@/components/AgbHistoryBlock'; /** * Splits a text string on \n and intersperses
elements. @@ -436,6 +437,8 @@ const jsxConverters: JSXConverters = { 'block-pdfDownload': ({ node }: any) => ( ), + agbHistory: ({ node }: any) => , + 'block-agbHistory': ({ node }: any) => , // ─── New Page Blocks ─────────────────────────────────────────── heroSection: ({ node }: any) => { const f = node.fields; diff --git a/payload.config.ts b/payload.config.ts index f0acfcc8..be4f545e 100644 --- a/payload.config.ts +++ b/payload.config.ts @@ -21,6 +21,7 @@ import { Posts } from './src/payload/collections/Posts'; import { FormSubmissions } from './src/payload/collections/FormSubmissions'; import { Products } from './src/payload/collections/Products'; import { Pages } from './src/payload/collections/Pages'; +import { Agbs } from './src/payload/collections/Agbs'; import { seedDatabase } from './src/payload/seed'; const filename = fileURLToPath(import.meta.url); @@ -56,7 +57,7 @@ export default buildConfig({ defaultLocale: 'de', fallback: true, }, - collections: [Users, Media, Posts, FormSubmissions, Products, Pages], + collections: [Users, Media, Posts, FormSubmissions, Products, Pages, Agbs], editor: lexicalEditor({ features: ({ defaultFeatures }) => [ ...defaultFeatures, diff --git a/src/payload/blocks/AgbHistory.ts b/src/payload/blocks/AgbHistory.ts new file mode 100644 index 00000000..b1eb9577 --- /dev/null +++ b/src/payload/blocks/AgbHistory.ts @@ -0,0 +1,18 @@ +import { Block } from 'payload'; + +export const AgbHistory: Block = { + slug: 'agbHistory', + labels: { + singular: 'AGB Historie', + plural: 'AGB Historien', + }, + fields: [ + { + name: 'title', + type: 'text', + label: 'Titel', + localized: true, + defaultValue: 'Vorherige Versionen', + }, + ], +}; diff --git a/src/payload/blocks/allBlocks.ts b/src/payload/blocks/allBlocks.ts index ffcbc51e..f34ff28e 100644 --- a/src/payload/blocks/allBlocks.ts +++ b/src/payload/blocks/allBlocks.ts @@ -17,6 +17,7 @@ import { TeamProfile } from './TeamProfile'; import { TechnicalGrid } from './TechnicalGrid'; import { VisualLinkPreview } from './VisualLinkPreview'; import { PDFDownload } from './PDFDownload'; +import { AgbHistory } from './AgbHistory'; import { homeBlocksArray } from './HomeBlocks'; export const payloadBlocks = [ @@ -40,4 +41,5 @@ export const payloadBlocks = [ TechnicalGrid, VisualLinkPreview, PDFDownload, + AgbHistory, ]; diff --git a/src/payload/collections/Agbs.ts b/src/payload/collections/Agbs.ts new file mode 100644 index 00000000..78d14a2a --- /dev/null +++ b/src/payload/collections/Agbs.ts @@ -0,0 +1,49 @@ +import { CollectionConfig } from 'payload'; + +export const Agbs: CollectionConfig = { + slug: 'agbs-collection', + admin: { + useAsTitle: 'title', + defaultColumns: ['title', 'versionDate', 'updatedAt'], + group: 'Rechtliches', + }, + access: { + read: () => true, + }, + fields: [ + { + name: 'title', + type: 'text', + required: true, + localized: true, + label: 'Titel (z.B. AGB April 2026)', + }, + { + name: 'versionDate', + type: 'date', + required: true, + label: 'Gültig ab', + admin: { + date: { + pickerAppearance: 'dayOnly', + }, + }, + }, + { + name: 'file', + type: 'upload', + relationTo: 'media', + required: true, + label: 'PDF Datei', + }, + { + name: 'isCurrent', + type: 'checkbox', + label: 'Aktuelle Version', + defaultValue: false, + admin: { + position: 'sidebar', + }, + }, + ], +};