Initial commit: Kottgard testing website code

This commit is contained in:
2026-06-19 15:46:24 +00:00
commit bd885cf0fa
196 changed files with 29799 additions and 0 deletions
+164
View File
@@ -0,0 +1,164 @@
'use client';
import { useEffect } from 'react';
import Link from 'next/link';
import { useRouter } from 'next/navigation';
import { User, Package, MapPin, Phone, Mail, LogOut, Heart } from 'lucide-react';
import Button from '@/components/ui/Button';
import { useAuth } from '@/presentation/hooks/useAuth';
import { formatPrice, formatDate, getFormatLocale } from '@/lib/utils';
import { useTranslation } from '@/hooks/useTranslation';
import { localizeProduct } from '@/lib/product-i18n';
export default function AccountPage() {
const router = useRouter();
const { user, isAuthenticated, orders, logout } = useAuth();
const { t, locale } = useTranslation();
useEffect(() => {
if (!isAuthenticated) {
router.push('/login');
}
}, [isAuthenticated, router]);
if (!isAuthenticated || !user) {
return null;
}
const handleLogout = () => {
logout();
router.push('/');
};
const fmt = (n: number) => formatPrice(n, getFormatLocale(locale));
return (
<div className="bg-gray-50">
<div className="border-b border-gray-100 bg-white">
<div className="mx-auto max-w-7xl px-4 py-12 sm:px-6 lg:px-8">
<h1 className="section-heading">{t('account.title')}</h1>
<p className="text-gray-500">{t('account.welcome', { name: user.name })}</p>
</div>
</div>
<div className="mx-auto max-w-7xl px-4 py-10 sm:px-6 lg:px-8">
<div className="grid gap-8 lg:grid-cols-3">
<div className="space-y-6">
<div className="card-premium p-6">
<div className="mb-4 flex items-center gap-3">
<div className="flex h-12 w-12 items-center justify-center rounded-full bg-brand-100">
<User className="h-6 w-6 text-brand-700" />
</div>
<div>
<h2 className="font-display text-lg font-semibold">{user.name}</h2>
<p className="text-sm text-gray-500">
{t('account.memberSince', { date: formatDate(user.createdAt) })}
</p>
</div>
</div>
<div className="space-y-3 border-t border-gray-100 pt-4">
<div className="flex items-center gap-2 text-sm text-gray-600">
<Mail className="h-4 w-4 text-brand-600" />
{user.email}
</div>
<div className="flex items-center gap-2 text-sm text-gray-600">
<Phone className="h-4 w-4 text-brand-600" />
{user.phone}
</div>
<div className="flex items-start gap-2 text-sm text-gray-600">
<MapPin className="mt-0.5 h-4 w-4 shrink-0 text-brand-600" />
{user.address.street}, {user.address.city}, {user.address.state}{' '}
{user.address.zip}
</div>
</div>
</div>
<div className="card-premium p-4">
<Link
href="/wishlist"
className="flex items-center gap-3 rounded-lg px-3 py-2 text-sm font-medium text-gray-600 transition-colors hover:bg-brand-50 hover:text-brand-700"
>
<Heart className="h-4 w-4" />
{t('account.myWishlist')}
</Link>
<button
onClick={handleLogout}
className="flex w-full items-center gap-3 rounded-lg px-3 py-2 text-sm font-medium text-red-500 transition-colors hover:bg-red-50"
>
<LogOut className="h-4 w-4" />
{t('account.signOut')}
</button>
</div>
</div>
<div className="lg:col-span-2" id="orders">
<div className="card-premium p-6">
<div className="mb-6 flex items-center gap-2">
<Package className="h-5 w-5 text-brand-700" />
<h2 className="font-display text-lg font-semibold">
{t('account.orderHistory')}
</h2>
</div>
{orders.length === 0 ? (
<div className="py-12 text-center">
<p className="mb-2 text-gray-500">{t('account.noOrders')}</p>
<Link href="/shop">
<Button variant="primary">{t('account.startShopping')}</Button>
</Link>
</div>
) : (
<div className="space-y-4">
{orders.map((order) => (
<div
key={order.id}
className="rounded-xl border border-gray-100 p-4 transition-colors hover:border-brand-200"
>
<div className="mb-3 flex items-center justify-between">
<div>
<p className="text-sm font-semibold text-brand-900">{order.id}</p>
<p className="text-xs text-gray-400">
{formatDate(order.createdAt)}
</p>
</div>
<div className="text-end">
<p className="font-bold text-brand-800">{fmt(order.total)}</p>
<span className="inline-block rounded-full bg-brand-50 px-2 py-0.5 text-xs font-medium capitalize text-brand-700">
{t(`orderStatus.${order.status}`)}
</span>
</div>
</div>
<div className="space-y-1">
{order.items.map((item) => {
const localized = localizeProduct(item.product, t);
return (
<div
key={item.id}
className="flex justify-between text-sm text-gray-600"
>
<Link
href={`/product/${item.product.slug}`}
className="hover:text-brand-700"
>
{localized.name} × {item.quantity}
<span className="ms-2 text-xs text-gold-600">
({item.customizationLabel})
</span>
</Link>
<span>{fmt(item.product.price * item.quantity)}</span>
</div>
);
})}
</div>
</div>
))}
</div>
)}
</div>
</div>
</div>
</div>
</div>
);
}