diff --git a/next.config.ts b/next.config.ts index 19fb2fa..241eff8 100644 --- a/next.config.ts +++ b/next.config.ts @@ -5,6 +5,32 @@ const withNextIntl = createNextIntlPlugin(); const nextConfig: NextConfig = { output: 'standalone', + async redirects() { + return [ + // Fix malformed URLs with /contact appended to product slugs + { + source: '/:locale(en|sr)/products/:slug*/contact', + destination: '/:locale/products/:slug*', + permanent: true, + }, + { + source: '/products/:slug*/contact', + destination: '/products/:slug*', + permanent: true, + }, + // Redirect old/removed product "manoon" to products listing + { + source: '/:locale(en|sr)/products/manoon', + destination: '/:locale/products', + permanent: true, + }, + { + source: '/products/manoon', + destination: '/products', + permanent: true, + }, + ]; + }, async rewrites() { const rybbitHost = process.env.NEXT_PUBLIC_RYBBIT_HOST || "https://rybbit.nodecrew.me"; return [ diff --git a/src/app/[locale]/not-found.tsx b/src/app/[locale]/not-found.tsx new file mode 100644 index 0000000..305e0d7 --- /dev/null +++ b/src/app/[locale]/not-found.tsx @@ -0,0 +1,68 @@ +"use client"; + +import { useTranslations, useLocale } from "next-intl"; +import Header from "@/components/layout/Header"; +import Footer from "@/components/layout/Footer"; +import Link from "next/link"; +import { Home, Search, Package } from "lucide-react"; + +export default function NotFoundPage() { + const t = useTranslations("NotFound"); + const locale = useLocale(); + const basePath = `/${locale}`; + + return ( + <> + + + + + {/* 404 Code */} + + 404 + + + + {t("title")} + + + {t("description")} + + + {/* Quick Links */} + + + + {t("browseProducts")} + + + + {t("goHome")} + + + + {/* Search Suggestion */} + + + + + {t("lookingFor")} + + + + {t("searchSuggestion")} + + + + + + + > + ); +} diff --git a/src/i18n/messages/en.json b/src/i18n/messages/en.json index 9554bfb..775607b 100644 --- a/src/i18n/messages/en.json +++ b/src/i18n/messages/en.json @@ -464,5 +464,13 @@ "description": "Pay via bank transfer", "comingSoon": "Coming soon" } + }, + "NotFound": { + "title": "Page Not Found", + "description": "The page you're looking for doesn't exist or has been moved.", + "browseProducts": "Browse Products", + "goHome": "Go Home", + "lookingFor": "Can't find what you're looking for?", + "searchSuggestion": "Try browsing our product collection or contact us for assistance." } } diff --git a/src/i18n/messages/sr.json b/src/i18n/messages/sr.json index 50af126..ae813bd 100644 --- a/src/i18n/messages/sr.json +++ b/src/i18n/messages/sr.json @@ -463,5 +463,13 @@ "description": "Platite putem bankovnog transfera", "comingSoon": "Uskoro dostupno" } + }, + "NotFound": { + "title": "Stranica Nije Pronađena", + "description": "Stranica koju tražite ne postoji ili je premeštena.", + "browseProducts": "Pregledaj Proizvode", + "goHome": "Početna Strana", + "lookingFor": "Ne možete da pronađete ono što tražite?", + "searchSuggestion": "Pokušajte da pregledate našu kolekciju proizvoda ili nas kontaktirajte za pomoć." } }
+ {t("description")} +
+ {t("searchSuggestion")} +