diff --git a/app/[locale]/events/[slug]/page.tsx b/app/[locale]/events/[slug]/page.tsx index b4903bf..27eb265 100644 --- a/app/[locale]/events/[slug]/page.tsx +++ b/app/[locale]/events/[slug]/page.tsx @@ -2,7 +2,7 @@ import { ArrowLeft, Calendar, Clock, ExternalLink, MapPin } from "lucide-react"; import type { Metadata } from "next"; import Image from "next/image"; import { notFound } from "next/navigation"; -import { getTranslations } from "next-intl/server"; +import { getTranslations, setRequestLocale } from "next-intl/server"; import ReactMarkdown from "react-markdown"; import remarkGfm from "remark-gfm"; @@ -105,7 +105,9 @@ export default async function EventPage({ }: { params: Promise<{ slug: string; locale: string }>; }) { - const { slug } = await params; + const { slug, locale } = await params; + setRequestLocale(locale); + const t = await getTranslations("eventDetail"); const event = getEventBySlug(slug); @@ -123,16 +125,29 @@ export default async function EventPage({
{event.imageUrl ? ( <> - +
) : ( <> -
diff --git a/app/[locale]/events/page.tsx b/app/[locale]/events/page.tsx index dede39e..951aac9 100644 --- a/app/[locale]/events/page.tsx +++ b/app/[locale]/events/page.tsx @@ -1,7 +1,7 @@ import { ArrowLeft } from "lucide-react"; import type { Metadata } from "next"; import Image from "next/image"; -import { getTranslations } from "next-intl/server"; +import { getTranslations, setRequestLocale } from "next-intl/server"; import { EventCard } from "@/components/event-card"; import { ICalFeedButton } from "@/components/ical-feed-button"; @@ -34,7 +34,10 @@ export async function generateMetadata({ }; } -export default async function EventsPage() { +export default async function EventsPage({ params }: { params: Promise<{ locale: string }> }) { + const { locale } = await params; + setRequestLocale(locale); + const t = await getTranslations("eventsPage"); const { upcomingEvents, pastEvents } = getEventsByDate(); @@ -44,9 +47,14 @@ export default async function EventsPage() { {/* Header */}
-
diff --git a/app/[locale]/layout.tsx b/app/[locale]/layout.tsx index 24ed0da..4aeb4ad 100644 --- a/app/[locale]/layout.tsx +++ b/app/[locale]/layout.tsx @@ -4,7 +4,7 @@ import type { Metadata } from "next"; import { JetBrains_Mono, Rubik } from "next/font/google"; import { notFound } from "next/navigation"; import { NextIntlClientProvider } from "next-intl"; -import { getMessages, getTranslations } from "next-intl/server"; +import { getMessages, getTranslations, setRequestLocale } from "next-intl/server"; import type React from "react"; import Footer from "@/components/footer"; @@ -117,6 +117,12 @@ export function generateStaticParams() { return routing.locales.map((locale) => ({ locale })); } +// The static pages under this tree split events into upcoming/past with today's +// date, so without revalidation that split freezes at build time — and deploys only +// happen on merges, which can be weeks apart. Hourly ISR lets an event flip to past +// (and its JSON-LD offer expire, see buildOffers) without waiting for the next deploy. +export const revalidate = 3600; + export default async function LocaleLayout({ children, params, @@ -130,6 +136,10 @@ export default async function LocaleLayout({ notFound(); } + // Opts this route tree into static rendering; without it next-intl renders + // every locale route dynamically. + setRequestLocale(locale); + const messages = await getMessages(); return ( diff --git a/app/[locale]/page.tsx b/app/[locale]/page.tsx index 9fe10f4..71b8fe6 100644 --- a/app/[locale]/page.tsx +++ b/app/[locale]/page.tsx @@ -1,7 +1,7 @@ import { ArrowRight, Calendar } from "lucide-react"; import type { Metadata } from "next"; import Image from "next/image"; -import { getTranslations } from "next-intl/server"; +import { getTranslations, setRequestLocale } from "next-intl/server"; import FeaturedEvents from "@/components/featured-events"; import { ICalFeedButton } from "@/components/ical-feed-button"; @@ -32,7 +32,10 @@ export async function generateMetadata({ }; } -export default async function Home() { +export default async function Home({ params }: { params: Promise<{ locale: string }> }) { + const { locale } = await params; + setRequestLocale(locale); + const t = await getTranslations(); return ( @@ -41,9 +44,14 @@ export default async function Home() { {/* Hero Section */}
-
@@ -54,8 +62,8 @@ export default async function Home() { {t("hero.subtitle")}

- @@ -63,8 +71,9 @@ export default async function Home() { variant="outline" size="lg" className="border-purple-500 text-purple-400 hover:bg-purple-950 hover:text-purple-300" + asChild > - + {t("hero.joinCommunity")} @@ -111,8 +120,8 @@ export default async function Home() {
- @@ -127,9 +136,12 @@ export default async function Home() { {/* Join Community Section */}
-

diff --git a/components/footer.tsx b/components/footer.tsx index 452d48d..834b943 100644 --- a/components/footer.tsx +++ b/components/footer.tsx @@ -61,7 +61,7 @@ export default async function Footer() {

-
+

{t("copyright", { year: getCurrentYear() })}

diff --git a/components/navbar.tsx b/components/navbar.tsx index fdae8c4..edb0e4f 100644 --- a/components/navbar.tsx +++ b/components/navbar.tsx @@ -46,7 +46,7 @@ export default function Navbar() {
-
@@ -63,7 +69,10 @@ export default function Navbar() { {isMenuOpen && (
-
- diff --git a/components/ui/accordion.tsx b/components/ui/accordion.tsx deleted file mode 100644 index cb52cf9..0000000 --- a/components/ui/accordion.tsx +++ /dev/null @@ -1,54 +0,0 @@ -"use client"; - -import * as AccordionPrimitive from "@radix-ui/react-accordion"; -import { ChevronDown } from "lucide-react"; -import * as React from "react"; - -import { cn } from "@/lib/utils"; - -const Accordion = AccordionPrimitive.Root; - -const AccordionItem = React.forwardRef< - React.ElementRef, - React.ComponentPropsWithoutRef ->(({ className, ...props }, ref) => ( - -)); -AccordionItem.displayName = "AccordionItem"; - -const AccordionTrigger = React.forwardRef< - React.ElementRef, - React.ComponentPropsWithoutRef ->(({ className, children, ...props }, ref) => ( - - svg]:rotate-180", - className - )} - {...props} - > - {children} - - - -)); -AccordionTrigger.displayName = AccordionPrimitive.Trigger.displayName; - -const AccordionContent = React.forwardRef< - React.ElementRef, - React.ComponentPropsWithoutRef ->(({ className, children, ...props }, ref) => ( - -
{children}
-
-)); - -AccordionContent.displayName = AccordionPrimitive.Content.displayName; - -export { Accordion, AccordionContent, AccordionItem, AccordionTrigger }; diff --git a/components/ui/alert-dialog.tsx b/components/ui/alert-dialog.tsx deleted file mode 100644 index 8484df4..0000000 --- a/components/ui/alert-dialog.tsx +++ /dev/null @@ -1,117 +0,0 @@ -"use client"; - -import * as AlertDialogPrimitive from "@radix-ui/react-alert-dialog"; -import * as React from "react"; - -import { buttonVariants } from "@/components/ui/button"; -import { cn } from "@/lib/utils"; - -const AlertDialog = AlertDialogPrimitive.Root; - -const AlertDialogTrigger = AlertDialogPrimitive.Trigger; - -const AlertDialogPortal = AlertDialogPrimitive.Portal; - -const AlertDialogOverlay = React.forwardRef< - React.ElementRef, - React.ComponentPropsWithoutRef ->(({ className, ...props }, ref) => ( - -)); -AlertDialogOverlay.displayName = AlertDialogPrimitive.Overlay.displayName; - -const AlertDialogContent = React.forwardRef< - React.ElementRef, - React.ComponentPropsWithoutRef ->(({ className, ...props }, ref) => ( - - - - -)); -AlertDialogContent.displayName = AlertDialogPrimitive.Content.displayName; - -const AlertDialogHeader = ({ className, ...props }: React.HTMLAttributes) => ( -
-); -AlertDialogHeader.displayName = "AlertDialogHeader"; - -const AlertDialogFooter = ({ className, ...props }: React.HTMLAttributes) => ( -
-); -AlertDialogFooter.displayName = "AlertDialogFooter"; - -const AlertDialogTitle = React.forwardRef< - React.ElementRef, - React.ComponentPropsWithoutRef ->(({ className, ...props }, ref) => ( - -)); -AlertDialogTitle.displayName = AlertDialogPrimitive.Title.displayName; - -const AlertDialogDescription = React.forwardRef< - React.ElementRef, - React.ComponentPropsWithoutRef ->(({ className, ...props }, ref) => ( - -)); -AlertDialogDescription.displayName = AlertDialogPrimitive.Description.displayName; - -const AlertDialogAction = React.forwardRef< - React.ElementRef, - React.ComponentPropsWithoutRef ->(({ className, ...props }, ref) => ( - -)); -AlertDialogAction.displayName = AlertDialogPrimitive.Action.displayName; - -const AlertDialogCancel = React.forwardRef< - React.ElementRef, - React.ComponentPropsWithoutRef ->(({ className, ...props }, ref) => ( - -)); -AlertDialogCancel.displayName = AlertDialogPrimitive.Cancel.displayName; - -export { - AlertDialog, - AlertDialogAction, - AlertDialogCancel, - AlertDialogContent, - AlertDialogDescription, - AlertDialogFooter, - AlertDialogHeader, - AlertDialogOverlay, - AlertDialogPortal, - AlertDialogTitle, - AlertDialogTrigger, -}; diff --git a/components/ui/alert.tsx b/components/ui/alert.tsx deleted file mode 100644 index 4269389..0000000 --- a/components/ui/alert.tsx +++ /dev/null @@ -1,49 +0,0 @@ -import { cva, type VariantProps } from "class-variance-authority"; -import * as React from "react"; - -import { cn } from "@/lib/utils"; - -const alertVariants = cva( - "relative w-full rounded-lg border p-4 [&>svg~*]:pl-7 [&>svg+div]:translate-y-[-3px] [&>svg]:absolute [&>svg]:left-4 [&>svg]:top-4 [&>svg]:text-foreground", - { - variants: { - variant: { - default: "bg-background text-foreground", - destructive: - "border-destructive/50 text-destructive dark:border-destructive [&>svg]:text-destructive", - }, - }, - defaultVariants: { - variant: "default", - }, - } -); - -const Alert = React.forwardRef< - HTMLDivElement, - React.HTMLAttributes & VariantProps ->(({ className, variant, ...props }, ref) => ( -
-)); -Alert.displayName = "Alert"; - -const AlertTitle = React.forwardRef>( - ({ className, ...props }, ref) => ( -
- ) -); -AlertTitle.displayName = "AlertTitle"; - -const AlertDescription = React.forwardRef< - HTMLParagraphElement, - React.HTMLAttributes ->(({ className, ...props }, ref) => ( -
-)); -AlertDescription.displayName = "AlertDescription"; - -export { Alert, AlertDescription, AlertTitle }; diff --git a/components/ui/aspect-ratio.tsx b/components/ui/aspect-ratio.tsx deleted file mode 100644 index 359bc94..0000000 --- a/components/ui/aspect-ratio.tsx +++ /dev/null @@ -1,7 +0,0 @@ -"use client"; - -import * as AspectRatioPrimitive from "@radix-ui/react-aspect-ratio"; - -const AspectRatio = AspectRatioPrimitive.Root; - -export { AspectRatio }; diff --git a/components/ui/avatar.tsx b/components/ui/avatar.tsx deleted file mode 100644 index 9d4278f..0000000 --- a/components/ui/avatar.tsx +++ /dev/null @@ -1,47 +0,0 @@ -"use client"; - -import * as AvatarPrimitive from "@radix-ui/react-avatar"; -import * as React from "react"; - -import { cn } from "@/lib/utils"; - -const Avatar = React.forwardRef< - React.ElementRef, - React.ComponentPropsWithoutRef ->(({ className, ...props }, ref) => ( - -)); -Avatar.displayName = AvatarPrimitive.Root.displayName; - -const AvatarImage = React.forwardRef< - React.ElementRef, - React.ComponentPropsWithoutRef ->(({ className, ...props }, ref) => ( - -)); -AvatarImage.displayName = AvatarPrimitive.Image.displayName; - -const AvatarFallback = React.forwardRef< - React.ElementRef, - React.ComponentPropsWithoutRef ->(({ className, ...props }, ref) => ( - -)); -AvatarFallback.displayName = AvatarPrimitive.Fallback.displayName; - -export { Avatar, AvatarFallback, AvatarImage }; diff --git a/components/ui/badge.tsx b/components/ui/badge.tsx deleted file mode 100644 index 1fc1de2..0000000 --- a/components/ui/badge.tsx +++ /dev/null @@ -1,32 +0,0 @@ -import { cva, type VariantProps } from "class-variance-authority"; -import * as React from "react"; - -import { cn } from "@/lib/utils"; - -const badgeVariants = cva( - "inline-flex items-center rounded-full border px-2.5 py-0.5 text-xs font-semibold transition-colors focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2", - { - variants: { - variant: { - default: "border-transparent bg-primary text-primary-foreground hover:bg-primary/80", - secondary: - "border-transparent bg-secondary text-secondary-foreground hover:bg-secondary/80", - destructive: - "border-transparent bg-destructive text-destructive-foreground hover:bg-destructive/80", - outline: "text-foreground", - }, - }, - defaultVariants: { - variant: "default", - }, - } -); - -export interface BadgeProps - extends React.HTMLAttributes, VariantProps {} - -function Badge({ className, variant, ...props }: BadgeProps) { - return
; -} - -export { Badge, badgeVariants }; diff --git a/components/ui/breadcrumb.tsx b/components/ui/breadcrumb.tsx deleted file mode 100644 index 6ca668f..0000000 --- a/components/ui/breadcrumb.tsx +++ /dev/null @@ -1,101 +0,0 @@ -import { Slot } from "@radix-ui/react-slot"; -import { ChevronRight, MoreHorizontal } from "lucide-react"; -import * as React from "react"; - -import { cn } from "@/lib/utils"; - -const Breadcrumb = React.forwardRef< - HTMLElement, - React.ComponentPropsWithoutRef<"nav"> & { - separator?: React.ReactNode; - } ->(({ ...props }, ref) =>