diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..9ddb0ad --- /dev/null +++ b/Dockerfile @@ -0,0 +1,27 @@ +FROM node:22-alpine AS base +WORKDIR /app + +FROM base AS deps +COPY package.json package-lock.json* ./ +RUN npm ci + +FROM base AS builder +COPY --from=deps /app/node_modules ./node_modules +COPY . . +RUN npm run build + +FROM base AS runner +ENV NODE_ENV=production + +RUN addgroup --system --gid 1001 nodejs || true +RUN adduser --system --uid 1001 nextjs || true + +COPY --from=builder /app/public ./public +COPY --from=builder --chown=nextjs:nodejs /app/.next/standalone ./ +COPY --from=builder --chown=nextjs:nodejs /app/.next/static ./.next/static + +USER nextjs +EXPOSE 3000 +ENV PORT=3000 +ENV HOSTNAME="0.0.0.0" +CMD ["node", "server.js"] diff --git a/next.config.ts b/next.config.ts index 9df45bd..4629d1a 100644 --- a/next.config.ts +++ b/next.config.ts @@ -1,6 +1,10 @@ +import createNextIntlPlugin from "next-intl/plugin"; import type { NextConfig } from "next"; +const withNextIntl = createNextIntlPlugin(); + const nextConfig: NextConfig = { + output: 'standalone', images: { remotePatterns: [ { @@ -17,4 +21,4 @@ const nextConfig: NextConfig = { }, }; -export default nextConfig; +export default withNextIntl(nextConfig); diff --git a/src/app/about/page.tsx b/src/app/[locale]/about/page.tsx similarity index 100% rename from src/app/about/page.tsx rename to src/app/[locale]/about/page.tsx diff --git a/src/app/contact/page.tsx b/src/app/[locale]/contact/page.tsx similarity index 100% rename from src/app/contact/page.tsx rename to src/app/[locale]/contact/page.tsx diff --git a/src/app/[locale]/page.tsx b/src/app/[locale]/page.tsx new file mode 100644 index 0000000..450ab84 --- /dev/null +++ b/src/app/[locale]/page.tsx @@ -0,0 +1,67 @@ +import { getProducts } from "@/lib/woocommerce"; +import Header from "@/components/layout/Header"; +import Footer from "@/components/layout/Footer"; +import ProductCard from "@/components/product/ProductCard"; + +export const metadata = { + title: "ManoonOils - Premium Natural Oils for Hair & Skin", + description: "Discover our premium collection of natural oils for hair and skin care. Handmade with love.", +}; + +export default async function Homepage() { + const products = await getProducts(); + const publishedProducts = products.filter((p) => p.status === "publish").slice(0, 4); + + return ( +
+
+ + {/* Hero Section */} +
+
+

+ ManoonOils +

+

+ Premium Natural Oils for Hair & Skin +

+ + Shop Now + +
+
+ + {/* Products Section */} + {publishedProducts.length > 0 && ( +
+
+

Our Products

+
+ {publishedProducts.map((product, index) => ( + + ))} +
+
+
+ )} + + {/* About Teaser */} +
+
+

Natural & Pure

+

+ Our oils are crafted with love using only the finest natural ingredients. +

+ + Learn More + +
+
+ +
+ ); +} diff --git a/src/app/[locale]/products/[slug]/page.tsx b/src/app/[locale]/products/[slug]/page.tsx new file mode 100644 index 0000000..e0a6e58 --- /dev/null +++ b/src/app/[locale]/products/[slug]/page.tsx @@ -0,0 +1,77 @@ +import { getProducts } from "@/lib/woocommerce"; +import Header from "@/components/layout/Header"; +import Footer from "@/components/layout/Footer"; + +export async function generateStaticParams() { + try { + const products = await getProducts(); + return products.map((product) => ({ + slug: product.slug || product.id.toString(), + })); + } catch { + return []; + } +} + +export default async function ProductPage({ params }: { params: Promise<{ slug: string }> }) { + const { slug } = await params; + let product = null; + + try { + const products = await getProducts(); + product = products.find((p) => (p.slug || p.id.toString()) === slug); + } catch (e) { + // Fallback + } + + if (!product) { + return ( +
+
+
+

Product not found

+
+
+ ); + } + + const image = product.images?.[0]?.src || '/placeholder.jpg'; + const price = product.sale_price || product.price; + + return ( +
+
+ +
+
+
+
+ {product.name} +
+ +
+

{product.name}

+ +
{price} RSD
+ +
+ + +
+
+
+
+ +
+ ); +} diff --git a/src/app/products/page.tsx b/src/app/[locale]/products/page.tsx similarity index 100% rename from src/app/products/page.tsx rename to src/app/[locale]/products/page.tsx diff --git a/src/app/layout.tsx b/src/app/layout.tsx index 720b84b..1cd2e40 100644 --- a/src/app/layout.tsx +++ b/src/app/layout.tsx @@ -2,16 +2,25 @@ import "./globals.css"; import type { Metadata } from "next"; export const metadata: Metadata = { - title: "ManoonOils - Premium Natural Oils for Hair & Skin", + title: { + default: "ManoonOils - Premium Natural Oils for Hair & Skin", + template: "%s | ManoonOils", + }, description: "Discover our premium collection of natural oils for hair and skin care. Handmade with love.", robots: "index, follow", + openGraph: { + title: "ManoonOils - Premium Natural Oils for Hair & Skin", + description: "Discover our premium collection of natural oils for hair and skin care.", + type: "website", + locale: "en_US", + }, }; export default function RootLayout({ children, -}: Readonly<{ +}: { children: React.ReactNode; -}>) { +}) { return ( diff --git a/src/app/page.tsx b/src/app/page.tsx deleted file mode 100644 index 3093177..0000000 --- a/src/app/page.tsx +++ /dev/null @@ -1,30 +0,0 @@ -import { getProducts } from "@/lib/woocommerce"; -import Header from "@/components/layout/Header"; -import Footer from "@/components/layout/Footer"; -import Hero from "@/components/home/Hero"; -import TickerBar from "@/components/home/TickerBar"; -import ProductShowcase from "@/components/home/ProductShowcase"; -import BrandStory from "@/components/home/BrandStory"; -import Testimonials from "@/components/home/Testimonials"; -import Newsletter from "@/components/home/Newsletter"; - -export default async function Home() { - const products = await getProducts(); - - const publishedProducts = products.filter( - (p) => p.status === "publish" && p.stock_status === "instock" - ); - - return ( -
-
- - - - - - -
- ); -} diff --git a/src/app/products/[slug]/page.tsx b/src/app/products/[slug]/page.tsx deleted file mode 100644 index 3fa6091..0000000 --- a/src/app/products/[slug]/page.tsx +++ /dev/null @@ -1,45 +0,0 @@ -import { notFound } from "next/navigation"; -import { getProductBySlug, getProducts, formatPrice, getProductImage } from "@/lib/woocommerce"; -import Header from "@/components/layout/Header"; -import Footer from "@/components/layout/Footer"; -import ProductDetail from "@/components/product/ProductDetail"; - -interface Props { - params: Promise<{ slug: string }>; -} - -export async function generateMetadata({ params }: Props) { - const { slug } = await params; - const product = await getProductBySlug(slug); - - if (!product) { - return { title: "Product Not Found" }; - } - - return { - title: `${product.name} - ManoonOils`, - description: product.short_description || product.description.slice(0, 160), - }; -} - -export default async function ProductPage({ params }: Props) { - const { slug } = await params; - const product = await getProductBySlug(slug); - - if (!product) { - notFound(); - } - - const allProducts = await getProducts(); - const relatedProducts = allProducts - .filter((p) => p.id !== product.id && p.status === "publish") - .slice(0, 4); - - return ( -
-
- -
- ); -} diff --git a/src/app/robots.ts b/src/app/robots.ts index 3ca300e..4393ae3 100644 --- a/src/app/robots.ts +++ b/src/app/robots.ts @@ -11,5 +11,6 @@ export default function robots(): MetadataRoute.Robots { }, ], sitemap: `${baseUrl}/sitemap.xml`, + host: baseUrl, }; } diff --git a/src/components/cart/CartDrawer.tsx b/src/components/cart/CartDrawer.tsx index b2d4132..cf0f6ae 100644 --- a/src/components/cart/CartDrawer.tsx +++ b/src/components/cart/CartDrawer.tsx @@ -47,7 +47,7 @@ export default function CartDrawer() {

Your cart is empty

diff --git a/src/components/home/Hero.tsx b/src/components/home/Hero.tsx index 2071c0d..75cbae7 100644 --- a/src/components/home/Hero.tsx +++ b/src/components/home/Hero.tsx @@ -48,7 +48,7 @@ export default function Hero() { transition={{ duration: 0.8, delay: 0.8 }} > Shop Now diff --git a/src/components/layout/Footer.tsx b/src/components/layout/Footer.tsx index 1a70402..7a5dc8d 100644 --- a/src/components/layout/Footer.tsx +++ b/src/components/layout/Footer.tsx @@ -18,17 +18,17 @@ export default function Footer() {

Quick Links