Initial commit: Craft2Prints with Stages 1-3

This commit is contained in:
Andymick
2026-07-15 18:09:59 +01:00
commit 41937ffc15
158 changed files with 16054 additions and 0 deletions
+100
View File
@@ -0,0 +1,100 @@
import { notFound } from 'next/navigation';
import { prisma } from '@/lib/prisma';
import AdminNav from '@/components/AdminNav';
import PromotionScopePicker from '@/components/PromotionScopePicker';
import { updatePromotion } from '../../actions';
export default async function EditPromotionPage({ params }: { params: { id: string } }) {
const [promotion, products] = await Promise.all([
prisma.promotion.findUnique({ where: { id: params.id }, include: { products: { select: { id: true } } } }),
prisma.product.findMany({ orderBy: { name: 'asc' } }),
]);
if (!promotion) notFound();
const selectedIds = new Set(promotion.products.map((p) => p.id));
const toDateInput = (d: Date | null) => (d ? d.toISOString().slice(0, 10) : '');
return (
<div className="mx-auto max-w-2xl px-6 py-12">
<AdminNav />
<h1 className="font-display text-3xl">Edit promotion</h1>
<p className="mt-2 text-sm text-muted">
Shown as a banner at the top of every page while its date window is active, and actually
discounts the price of whatever it covers every item, or specific ones you pick.
</p>
<form action={updatePromotion} className="mt-10 space-y-6">
<input type="hidden" name="id" value={promotion.id} />
<div>
<label htmlFor="message" className="tag-label mb-2 block">
Banner message
</label>
<textarea
id="message"
name="message"
required
rows={2}
defaultValue={promotion.message}
className="w-full border border-line bg-paper px-3 py-2 text-sm"
/>
</div>
<div>
<label htmlFor="discountPercent" className="tag-label mb-2 block">
Discount (%)
</label>
<input
id="discountPercent"
name="discountPercent"
type="number"
min={1}
max={100}
required
defaultValue={promotion.discountPercent}
className="w-full border border-line bg-paper px-3 py-2 text-sm"
/>
</div>
<PromotionScopePicker
products={products}
defaultScope={promotion.scope as 'ALL' | 'SPECIFIC'}
defaultSelectedIds={[...selectedIds]}
/>
<div className="grid grid-cols-2 gap-4">
<div>
<label htmlFor="startsAt" className="tag-label mb-2 block">
Starts (optional)
</label>
<input
id="startsAt"
name="startsAt"
type="date"
defaultValue={toDateInput(promotion.startsAt)}
className="w-full border border-line bg-paper px-3 py-2 text-sm"
/>
<p className="mt-1 text-xs text-muted">Leave blank to start immediately.</p>
</div>
<div>
<label htmlFor="endsAt" className="tag-label mb-2 block">
Ends (optional)
</label>
<input
id="endsAt"
name="endsAt"
type="date"
defaultValue={toDateInput(promotion.endsAt)}
className="w-full border border-line bg-paper px-3 py-2 text-sm"
/>
<p className="mt-1 text-xs text-muted">Leave blank for no end date.</p>
</div>
</div>
<button type="submit" className="bg-clay px-6 py-3 text-sm font-medium text-paper hover:bg-clay-dark">
Save changes
</button>
</form>
</div>
);
}