feat: implement compare functionality, checkout flow, and add 30 blog posts

This commit is contained in:
MichalC
2026-06-27 18:09:22 +02:00
parent 6bdfe18e18
commit 0c59086a6b
63 changed files with 9766 additions and 1874 deletions
+117 -29
View File
@@ -1,37 +1,125 @@
import { Metadata } from 'next';
import { HeroSection } from '@/components/sections/HeroSection';
import { ContactSection } from '@/components/sections/ContactSection';
'use client';
export const metadata: Metadata = {
title: 'Zamówienie | AirProject',
description: 'Dokończ swoje zamówienie na urządzenia i montaż, zostawiając nam swoje dane.',
alternates: {
canonical: '/zamowienie',
}
};
import { useCartStore } from '@/lib/cart-store';
import { useActionState, useEffect } from 'react';
import Link from 'next/link';
import { submitOrderForm } from './actions';
import { ArrowLeft, CheckCircle } from 'lucide-react';
export default function CheckoutPage() {
return (
<main className="bg-slate-50 min-h-screen">
<HeroSection
eyebrow="Sklep"
title="Dokończ zamówienie"
subtitle="Zgodnie z wymogami prawnymi (F-Gazy) oraz chęcią zapewnienia najwyższej jakości obsługi, wszystkie zamówienia finalizujemy po krótkim kontakcie. Zostaw swoje dane, a my zajmiemy się resztą!"
ctaText="Wróć do koszyka"
ctaLink="/koszyk"
backgroundImage="https://images.unsplash.com/photo-1556742049-0cfed4f6a45d?w=1600&q=80"
/>
const initialState = { success: false, message: '' };
<div className="py-16 md:py-24 max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
<div className="mb-12 text-center max-w-3xl mx-auto">
<h2 className="text-3xl font-extrabold text-primary font-heading mb-4">Wypełnij formularz</h2>
<p className="text-text-muted text-lg">
Nasz doradca skontaktuje się z Tobą w ciągu maksymalnie 24 godzin, aby potwierdzić
dostępność urządzeń z Twojego koszyka, omówić szczegóły montażu oraz zorganizować wysyłkę.
</p>
export default function ZamowieniePage() {
const { items, getTotal, clearCart } = useCartStore();
const [state, formAction, pending] = useActionState(submitOrderForm, initialState);
const total = getTotal();
useEffect(() => {
if (state.success) clearCart();
}, [state.success]);
if (items.length === 0 && !state.success) {
return (
<main className="min-h-screen bg-slate-50 flex items-center justify-center">
<div className="text-center">
<p className="text-text-muted mb-4">Koszyk jest pusty.</p>
<Link href="/sklep"><button className="btn btn-primary text-white font-bold">Wróć do sklepu</button></Link>
</div>
</main>
);
}
<ContactSection />
if (state.success) {
return (
<main className="min-h-screen bg-slate-50 flex items-center justify-center">
<div className="text-center max-w-md px-4">
<CheckCircle className="size-16 text-green-500 mx-auto mb-4" />
<h1 className="text-2xl font-bold text-primary font-heading mb-2">Zamówienie przyjęte!</h1>
<p className="text-text-muted mb-6">{state.message}</p>
<Link href="/sklep"><button className="btn btn-primary text-white font-bold">Wróć do sklepu</button></Link>
</div>
</main>
);
}
return (
<main className="bg-slate-50 min-h-screen py-8">
<div className="max-w-3xl mx-auto px-4 sm:px-6 lg:px-8">
<Link href="/koszyk" className="inline-flex items-center gap-2 text-sm text-text-muted hover:text-accent mb-6">
<ArrowLeft className="size-4" /> Wróć do koszyka
</Link>
<h1 className="text-2xl font-bold text-primary font-heading mb-8">Złóż zamówienie</h1>
<div className="grid grid-cols-1 gap-6">
{/* Podsumowanie produktów */}
<div className="bg-white rounded-xl border border-border p-6">
<h2 className="text-base font-bold text-primary font-heading mb-4">Zamawiane produkty</h2>
<div className="flex flex-col gap-2">
{items.map((item) => (
<div key={item.id} className="flex justify-between text-sm">
<span className="text-text-muted">{item.name} × {item.quantity}</span>
<span className="font-semibold text-primary">{(item.price * item.quantity).toLocaleString('pl-PL')} zł</span>
</div>
))}
<div className="border-t border-border pt-2 mt-2 flex justify-between font-bold text-primary">
<span>Łącznie (urządzenia)</span>
<span>{total.toLocaleString('pl-PL')} zł</span>
</div>
</div>
</div>
{/* Formularz */}
<form action={formAction} className="bg-white rounded-xl border border-border p-6 flex flex-col gap-4">
<h2 className="text-base font-bold text-primary font-heading">Twoje dane</h2>
{/* Hidden: produkty jako JSON */}
<input type="hidden" name="products" value={JSON.stringify(items)} />
<input type="hidden" name="total" value={total} />
<div className="grid grid-cols-1 sm:grid-cols-2 gap-4">
<div>
<label className="text-xs font-medium text-primary mb-1 block">Imię i nazwisko *</label>
<input name="name" required className="w-full border border-border rounded-lg px-3 py-2.5 text-sm focus:border-accent outline-none" placeholder="Jan Kowalski" />
</div>
<div>
<label className="text-xs font-medium text-primary mb-1 block">Telefon *</label>
<input name="phone" required type="tel" className="w-full border border-border rounded-lg px-3 py-2.5 text-sm focus:border-accent outline-none" placeholder="+48 600 000 000" />
</div>
</div>
<div>
<label className="text-xs font-medium text-primary mb-1 block">Email *</label>
<input name="email" required type="email" className="w-full border border-border rounded-lg px-3 py-2.5 text-sm focus:border-accent outline-none" placeholder="[email protected]" />
</div>
<div>
<label className="text-xs font-medium text-primary mb-1 block">Adres dostawy / montażu</label>
<input name="address" className="w-full border border-border rounded-lg px-3 py-2.5 text-sm focus:border-accent outline-none" placeholder="ul. Przykładowa 1, 50-000 Wrocław" />
</div>
<div>
<label className="text-xs font-medium text-primary mb-1 block">Uwagi do zamówienia</label>
<textarea name="notes" rows={3} className="w-full border border-border rounded-lg px-3 py-2.5 text-sm focus:border-accent outline-none resize-none" placeholder="Np. preferowany termin montażu, piętro, specjalne wymagania..." />
</div>
<label className="flex items-start gap-3 cursor-pointer">
<input type="checkbox" name="consent" required className="mt-0.5 accent-accent" />
<span className="text-xs text-text-muted">Wyrażam zgodę na przetwarzanie danych osobowych w celu realizacji zamówienia zgodnie z Polityką Prywatności. *</span>
</label>
{state.message && !state.success && (
<p className="text-sm text-red-500">{state.message}</p>
)}
<button type="submit" disabled={pending} className="btn btn-primary text-white font-bold w-full flex items-center justify-center gap-2">
{pending ? 'Wysyłanie...' : 'Wyślij zamówienie'}
</button>
<p className="text-xs text-text-muted text-center">
Po złożeniu zamówienia skontaktujemy się z Tobą telefonicznie w ciągu 24 godzin, aby potwierdzić szczegóły i ustalić termin montażu.
</p>
</form>
</div>
</div>
</main>
);