88 lines
3.2 KiB
TypeScript
88 lines
3.2 KiB
TypeScript
import Link from 'next/link';
|
|
import { prisma } from '@/lib/prisma';
|
|
import { toProductDTO } from '@/lib/product';
|
|
import { fetchActivePromotions } from '@/lib/promotions';
|
|
import AdminNav from '@/components/AdminNav';
|
|
import ProductMockup from '@/components/ProductMockup';
|
|
import { deleteProduct } from './actions';
|
|
|
|
export default async function AdminProductsPage({
|
|
searchParams,
|
|
}: {
|
|
searchParams: { error?: string };
|
|
}) {
|
|
const activePromotions = await fetchActivePromotions();
|
|
let products = [];
|
|
try {
|
|
const rows = await prisma.product.findMany();
|
|
products = rows.map((p) => toProductDTO(p, activePromotions)).sort((a, b) =>
|
|
new Date(b.createdAt).getTime() - new Date(a.createdAt).getTime()
|
|
);
|
|
} catch (err) {
|
|
console.error('Error fetching products:', err);
|
|
}
|
|
|
|
return (
|
|
<div className="mx-auto max-w-4xl px-6 py-12">
|
|
<AdminNav />
|
|
<div className="flex items-baseline justify-between">
|
|
<h1 className="font-display text-3xl">Products</h1>
|
|
<Link
|
|
href="/admin/products/new"
|
|
className="border border-ink px-4 py-2 text-sm hover:border-clay hover:bg-clay hover:text-paper"
|
|
>
|
|
+ Add product
|
|
</Link>
|
|
</div>
|
|
|
|
{searchParams.error === 'in_use' && (
|
|
<div className="mt-6 border border-splash-orange bg-splash-orange/5 p-4 text-sm">
|
|
Can't delete that product — it has existing orders or design proofs tied to it.
|
|
</div>
|
|
)}
|
|
|
|
{products.length === 0 ? (
|
|
<p className="mt-10 text-sm text-muted">No products yet.</p>
|
|
) : (
|
|
<div className="mt-8 divide-y divide-line border-t border-line">
|
|
{products.map((p) => (
|
|
<div key={p.id} className="flex items-center gap-4 py-4">
|
|
<div className="h-16 w-16 border border-line bg-surface p-1">
|
|
{(p.colorPhotos[p.colors[0]] ?? p.imageUrl) ? (
|
|
<img
|
|
src={p.colorPhotos[p.colors[0]] ?? p.imageUrl!}
|
|
alt={p.name}
|
|
className="h-full w-full object-contain"
|
|
/>
|
|
) : (
|
|
<ProductMockup mockup={p.mockup} color={p.colors[0]} />
|
|
)}
|
|
</div>
|
|
<div className="flex-1">
|
|
<p className="font-medium">{p.name}</p>
|
|
<p className="text-sm text-muted">
|
|
{p.category.replace('_', ' ')} · £${(p.basePrice / 100).toFixed(2)} · {p.colors.length}{' '}
|
|
color{p.colors.length === 1 ? '' : 's'}
|
|
{p.sizes.length > 0 && ` · ${p.sizes.join('/')}`}
|
|
</p>
|
|
</div>
|
|
<Link href={`/admin/products/${p.id}/edit`} className="tag-label hover:text-ink">
|
|
Edit →
|
|
</Link>
|
|
<Link href={`/made-to-order/${p.slug}`} className="tag-label hover:text-ink">
|
|
View →
|
|
</Link>
|
|
<form action={deleteProduct}>
|
|
<input type="hidden" name="id" value={p.id} />
|
|
<button type="submit" className="tag-label text-muted hover:text-splash-pink">
|
|
Delete
|
|
</button>
|
|
</form>
|
|
</div>
|
|
))}
|
|
</div>
|
|
)}
|
|
</div>
|
|
);
|
|
}
|