Add design approval workflow and per-image dimension tracking
- Add DesignApproval and DesignApprovalMessage models for design review workflow - Add design approval admin interface (list, detail, chat, approve/reject) - Add per-image dimension tracking to OrderItem - Add design submission API endpoint - Add AdminDesignEditor for admin-side design modifications - Add DesignApprovalChat component for customer-admin communication - Update design specification generation with image dimension details - Add design persistence across login with next parameter redirect - Add font properties UI with font size and color display Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Haiku 4.5
parent
10764f3a5b
commit
5c4774be84
@@ -0,0 +1,70 @@
|
||||
import Link from 'next/link';
|
||||
import { prisma } from '@/lib/prisma';
|
||||
import AdminNav from '@/components/AdminNav';
|
||||
|
||||
export default async function DesignsPage() {
|
||||
const designs = await prisma.designApproval.findMany({
|
||||
include: {
|
||||
product: true,
|
||||
messages: { orderBy: { createdAt: 'desc' }, take: 1 },
|
||||
},
|
||||
orderBy: { createdAt: 'desc' },
|
||||
});
|
||||
|
||||
const pending = designs.filter((d) => d.status === 'PENDING');
|
||||
const approved = designs.filter((d) => d.status === 'APPROVED');
|
||||
const rejected = designs.filter((d) => d.status === 'REJECTED');
|
||||
|
||||
const DesignList = ({ items, status }: { items: typeof designs; status: string }) => (
|
||||
<div className="mt-8">
|
||||
<h2 className="font-display text-lg">{status}</h2>
|
||||
{items.length === 0 ? (
|
||||
<p className="mt-4 text-sm text-muted">No designs.</p>
|
||||
) : (
|
||||
<div className="mt-4 divide-y divide-line border-t border-line">
|
||||
{items.map((d) => {
|
||||
const last = d.messages[0];
|
||||
return (
|
||||
<Link
|
||||
key={d.id}
|
||||
href={`/admin/designs/${d.id}`}
|
||||
className="flex items-center gap-4 py-4 hover:bg-surface"
|
||||
>
|
||||
<img
|
||||
src={d.designPreviewUrl}
|
||||
alt="design preview"
|
||||
className="h-14 w-14 border border-line object-cover"
|
||||
/>
|
||||
<div className="flex-1">
|
||||
<p className="font-medium">{d.customerName || d.customerEmail}</p>
|
||||
<p className="truncate text-sm text-muted">
|
||||
{last ? (
|
||||
<>
|
||||
{last.sender === 'ADMIN' ? 'You: ' : ''}
|
||||
{last.body}
|
||||
</>
|
||||
) : (
|
||||
'No messages yet'
|
||||
)}
|
||||
</p>
|
||||
</div>
|
||||
<span className="tag-label">{d.product.name}</span>
|
||||
</Link>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
|
||||
return (
|
||||
<div className="mx-auto max-w-4xl px-6 py-12">
|
||||
<AdminNav />
|
||||
<h1 className="font-display text-3xl">Design Approvals</h1>
|
||||
|
||||
<DesignList items={pending} status={`Pending (${pending.length})`} />
|
||||
<DesignList items={approved} status={`Approved (${approved.length})`} />
|
||||
<DesignList items={rejected} status={`Rejected (${rejected.length})`} />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user