import Link from "next/link"; import type { ReactNode } from "react"; import { Container } from "@/components/ui"; import { Logomark } from "@/components/logomark"; import { footerNav } from "@/lib/site-config"; import type { SocialLinks } from "@/lib/social-links"; import { getDictionary } from "@/i18n/get-dictionary"; import { getLocale } from "@/i18n/locale"; import type { Dictionary } from "@/i18n/dictionary-type"; // Erstes vollstaendiges Geschaeftsjahr — Startpunkt der im Footer // angezeigten Copyright-Spanne "2023–". Das Endjahr wird // bewusst NICHT gespeichert, sondern bei jedem Render live aus // new Date().getFullYear() berechnet, damit es nie per Hand nachgepflegt // werden muss. const FOUNDING_YEAR = 2023; const SOCIAL_ICON_PROPS = { width: 16, height: 16, viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: 1.5 } as const; function TikTokIcon() { return ( ); } function YouTubeIcon() { return ( ); } function InstagramIcon() { return ( ); } /** * Ein Icon+Name-Link wird nur gerendert, wenn im Admin-Bereich (Inhalte -> * Social Media) tatsaechlich eine URL hinterlegt ist — nie ein toter/ * Platzhalter-Link (siehe getSocialLinks()/content-registry.ts). */ function SocialLink({ href, name, icon, t, }: { href: string; /** Plattformname (Eigenname, z.B. "TikTok") — unlokalisiert, dient als sichtbarer Linktext. */ name: string; icon: ReactNode; t: Dictionary; }) { return ( {icon} {name} ); } /** * Server Component (bewusst NICHT Teil von site-chrome.tsx/"use client"): * der Footer ist bis auf die Uebersetzungen rein statisches Markup, das auf * jeder Seite gerendert wird. Statt useI18n() (Client-Hook) wird die * Uebersetzung wie bei anderen Server Components direkt per * getDictionary(await getLocale()) aufgeloest — dadurch verlaesst dieser * Block das Client-JS-Bundle vollstaendig (siehe Kommentar in * i18n/i18n-provider.tsx zur RSC-Serialisierungsgrenze). */ export async function Footer({ companyInfo, socialLinks, }: { companyInfo: { name: string; email: string; address: { street: string; zip: string; city: string } }; socialLinks: SocialLinks; }) { const t = getDictionary(await getLocale()); const hasAnySocialLink = socialLinks.tiktok || socialLinks.youtube || socialLinks.instagram; const wabenhainLabels: Record<(typeof footerNav.wabenhain)[number]["key"], string> = { aboutUs: t.footer.aboutUs, origin: t.nav.origin, harvests: t.nav.harvests, contact: t.nav.contact, }; const einkaufenLabels: Record<(typeof footerNav.einkaufen)[number]["key"], string> = { shop: t.nav.shop, businessCustomers: t.footer.businessCustomers, trackOrder: t.footer.trackOrder, }; const rechtlichesLabels: Record<(typeof footerNav.rechtliches)[number]["key"], string> = { impressum: t.legalTitles.impressum, datenschutz: t.legalTitles.datenschutz, agb: t.legalTitles.agb, widerruf: t.legalTitles.widerruf, versandZahlung: t.legalTitles.versandZahlung, cookieRichtlinie: t.legalTitles.cookieRichtlinie, }; return ( ); } function FooterColumn({ title, links, labels, }: { title: string; links: readonly { href: string; key: string }[]; labels: Record; }) { return (

{title}

    {links.map((link) => (
  • {labels[link.key]}
  • ))}
); }