From 8ebfb6a6f31d100b3fc9a2c5f12365c715873eb1 Mon Sep 17 00:00:00 2001 From: Unchained Date: Sat, 28 Mar 2026 22:34:08 +0200 Subject: [PATCH] fix: update not-found.tsx location and fix params error - Move not-found.tsx to app root for proper 404 handling - Fix params destructuring error in not-found component - Add app root level not-found.tsx for locale-aware 404 pages --- src/app/[locale]/not-found.tsx | 20 +-- src/app/not-found.tsx | 279 +++++++++++++++++++++++++++++++++ 2 files changed, 290 insertions(+), 9 deletions(-) create mode 100644 src/app/not-found.tsx diff --git a/src/app/[locale]/not-found.tsx b/src/app/[locale]/not-found.tsx index 51b55f5..5616de8 100644 --- a/src/app/[locale]/not-found.tsx +++ b/src/app/[locale]/not-found.tsx @@ -16,13 +16,16 @@ export const metadata: Metadata = { description: "Discover our bestselling natural oils for hair and skin care.", }; -interface NotFoundPageProps { - params: Promise<{ locale: string }>; -} - -export default async function NotFoundPage({ params }: NotFoundPageProps) { - const { locale } = await params; - const validLocale = isValidLocale(locale) ? locale : DEFAULT_LOCALE; +export default async function NotFoundPage() { + // Get locale from URL path + const headersList = await headers(); + const pathname = headersList.get("x-invoke-path") || headersList.get("x-matched-path") || "/"; + + // Extract locale from path (e.g., /en/products → en, /sr/products → sr) + const pathSegments = pathname.split("/").filter(Boolean); + const potentialLocale = pathSegments[0]; + const validLocale = isValidLocale(potentialLocale) ? potentialLocale : DEFAULT_LOCALE; + const t = await getTranslations({ locale: validLocale, namespace: "NotFound" }); const productReviewT = await getTranslations({ locale: validLocale, namespace: "ProductReviews" }); @@ -49,7 +52,6 @@ export default async function NotFoundPage({ params }: NotFoundPageProps) { }>; // Track 404 page view via OpenPanel (client-side will handle this) - const headersList = await headers(); const referer = headersList.get("referer") || ""; return ( @@ -189,7 +191,7 @@ export default async function NotFoundPage({ params }: NotFoundPageProps) {
{[...Array(5)].map((_, i) => ( diff --git a/src/app/not-found.tsx b/src/app/not-found.tsx new file mode 100644 index 0000000..5616de8 --- /dev/null +++ b/src/app/not-found.tsx @@ -0,0 +1,279 @@ +import { Metadata } from "next"; +import { getTranslations } from "next-intl/server"; +import { getProducts, getProductImage, getProductPrice } from "@/lib/saleor"; +import { getSaleorLocale, isValidLocale, DEFAULT_LOCALE } from "@/lib/i18n/locales"; +import type { Locale } from "@/lib/i18n/locales"; +import type { Product } from "@/types/saleor"; +import Link from "next/link"; +import Image from "next/image"; +import { Star, ArrowRight } from "lucide-react"; +import TrustBadges from "@/components/home/TrustBadges"; +import UrgencyMessages from "@/components/404/UrgencyMessages"; +import { headers } from "next/headers"; + +export const metadata: Metadata = { + title: "Page Not Found | ManoonOils", + description: "Discover our bestselling natural oils for hair and skin care.", +}; + +export default async function NotFoundPage() { + // Get locale from URL path + const headersList = await headers(); + const pathname = headersList.get("x-invoke-path") || headersList.get("x-matched-path") || "/"; + + // Extract locale from path (e.g., /en/products → en, /sr/products → sr) + const pathSegments = pathname.split("/").filter(Boolean); + const potentialLocale = pathSegments[0]; + const validLocale = isValidLocale(potentialLocale) ? potentialLocale : DEFAULT_LOCALE; + + const t = await getTranslations({ locale: validLocale, namespace: "NotFound" }); + const productReviewT = await getTranslations({ locale: validLocale, namespace: "ProductReviews" }); + + const saleorLocale = getSaleorLocale(validLocale as Locale); + + // Fetch products + let products: Product[] = []; + try { + products = await getProducts(saleorLocale); + } catch (error) { + console.error("Error fetching products for 404 page:", error); + } + + // Get first 4 products as bestsellers + const bestsellers = products.slice(0, 4); + + // Get product reviews for rotation + const productReviews = productReviewT.raw("reviews") as Array<{ + id: number; + name: string; + location: string; + text: string; + rating: number; + }>; + + // Track 404 page view via OpenPanel (client-side will handle this) + const referer = headersList.get("referer") || ""; + + return ( +
+ {/* Hero Section */} +
+
+
+

+ {t("title")} +

+

+ {t("subtitle")} +

+ + + {t("shopBestsellers")} + + +
+
+
+ + {/* Trust Badges */} + + + {/* Urgency Messages */} + + + {/* Bestsellers Section */} +
+
+
+ + Popular + +

+ {t("bestsellersTitle")} +

+
+ + {bestsellers.length > 0 ? ( +
+ {bestsellers.map((product, index) => { + const image = getProductImage(product); + const price = getProductPrice(product); + const isAvailable = product.variants?.[0]?.quantityAvailable > 0; + + return ( +
+ +
+ {image ? ( + {product.name} + ) : ( +
+ No Image +
+ )} + + {!isAvailable && ( +
+ + Out of Stock + +
+ )} + +
+ +
+
+ +
+

+ {product.name} +

+

+ {price || "Contact for price"} +

+
+ +
+ ); + })} +
+ ) : ( +
+

No products available at the moment.

+
+ )} +
+
+ + {/* Testimonials Section */} +
+
+
+ + Testimonials + +

+ {t("testimonialsTitle")} +

+
+ +
+ {productReviews.slice(0, 6).map((review, index) => ( +
+
+ {[...Array(5)].map((_, i) => ( + + ))} +
+

+ “{review.text}” +

+
+
+ {review.name.charAt(0)} +
+
+

{review.name}

+

{review.location}

+
+
+
+ ))} +
+
+
+ + {/* Final CTA Section */} +
+
+
+

+ {t("finalCTATitle")} +

+

+ {t("finalCTASubtitle")} +

+ + + {t("viewAllProducts")} + + +
+
+
+ + {/* OpenPanel Tracking Script */} +