Add customer approval status messages and admin delete option

Customer-facing changes:
- Show approval status message when design is submitted
- Display pending approval notification with email confirmation
- Show approved confirmation when design is ready
- Show rejection message for designs needing changes

Admin-facing changes:
- Add delete button to design approval detail page
- Confirmation dialog before deletion
- Proper cleanup of design and associated messages
- Redirect to designs list after deletion

Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
This commit is contained in:
Andymick
2026-07-18 16:48:35 +01:00
co-authored by Claude Haiku 4.5
parent 95c1255811
commit 4d124b1550
4 changed files with 80 additions and 1 deletions
+5 -1
View File
@@ -48,7 +48,11 @@
"Bash(rm -rf craft2prints)",
"Bash(git commit -m 'Add design approval workflow and per-image dimension tracking *)",
"Bash(git commit -m 'Remove feedback messages to simplify design canvas layout *)",
"Bash(git commit -m 'Remove reviews section from product pages *)"
"Bash(git commit -m 'Remove reviews section from product pages *)",
"Bash(git commit -m 'Reorganize design canvas layout to be more compact *)",
"Bash(git commit -m 'Make image dimensions and font properties collapsible sections *)",
"Bash(rm -rf \"D:\\\\Craft2Prints\\\\src\\\\app\\\\api\\\\designs\\\\[id]\\\\delete\" && echo \"Deleted unnecessary delete folder\")",
"Bash(git commit -m 'Add customer approval status messages and admin delete option *)"
]
}
}
+28
View File
@@ -1,6 +1,7 @@
'use client';
import { useState, useEffect } from 'react';
import { useRouter } from 'next/navigation';
import Link from 'next/link';
import DesignApprovalChat from '@/components/DesignApprovalChat';
import AdminDesignEditor from '@/components/AdminDesignEditor';
@@ -28,9 +29,11 @@ interface DesignApproval {
}
export default function DesignDetailPage({ params }: { params: { id: string } }) {
const router = useRouter();
const [design, setDesign] = useState<DesignApproval | null>(null);
const [loading, setLoading] = useState(true);
const [approving, setApproving] = useState(false);
const [deleting, setDeleting] = useState(false);
const [editingDesign, setEditingDesign] = useState(false);
useEffect(() => {
@@ -56,6 +59,22 @@ export default function DesignDetailPage({ params }: { params: { id: string } })
}
};
const handleDelete = async () => {
if (!confirm('Are you sure you want to delete this design? This cannot be undone.')) return;
setDeleting(true);
try {
const res = await fetch(`/api/designs/${params.id}`, { method: 'DELETE' });
if (res.ok) {
router.push('/admin/designs');
} else {
alert('Failed to delete design');
}
} finally {
setDeleting(false);
}
};
const handleEditorSave = (designJson: string, previewUrl: string) => {
setDesign((prev) =>
prev
@@ -202,6 +221,15 @@ export default function DesignDetailPage({ params }: { params: { id: string } })
</button>
</div>
)}
<div className="mt-4 pt-4 border-t border-line">
<button
onClick={handleDelete}
disabled={deleting}
className="w-full bg-red-600 px-4 py-2 text-sm font-medium text-paper hover:bg-red-700 disabled:opacity-60"
>
{deleting ? 'Deleting…' : 'Delete Design'}
</button>
</div>
</div>
{/* Chat */}
+31
View File
@@ -1,5 +1,6 @@
import { NextResponse } from 'next/server';
import { prisma } from '@/lib/prisma';
import { getCurrentAdmin } from '@/lib/auth';
export async function GET(
req: Request,
@@ -24,3 +25,33 @@ export async function GET(
);
}
}
export async function DELETE(
req: Request,
{ params }: { params: { id: string } }
) {
try {
const admin = await getCurrentAdmin();
if (!admin) {
return NextResponse.json({ error: 'Unauthorized' }, { status: 401 });
}
// Delete associated messages first
await prisma.designApprovalMessage.deleteMany({
where: { designApprovalId: params.id },
});
// Delete the design approval
await prisma.designApproval.delete({
where: { id: params.id },
});
return NextResponse.json({ success: true });
} catch (err) {
console.error('Error deleting design:', err);
return NextResponse.json(
{ error: 'Failed to delete design' },
{ status: 500 }
);
}
}
+16
View File
@@ -1125,6 +1125,22 @@ export default function DesignCanvas({ product }: { product: ProductDTO }) {
</div>
</div>
{approvalStatus === 'PENDING' && (
<p className="text-sm text-orange-600 bg-orange-50 border border-orange-200 px-4 py-3 rounded">
Your design is pending admin approval. You'll receive an email when it's ready to add to your bag.
</p>
)}
{approvalStatus === 'APPROVED' && (
<p className="text-sm text-pine bg-green-50 border border-green-200 px-4 py-3 rounded">
Your design has been approved! You can now add it to your bag.
</p>
)}
{approvalStatus === 'REJECTED' && (
<p className="text-sm text-splash-pink bg-red-50 border border-splash-pink/30 px-4 py-3 rounded">
Your design needs changes. Check your messages for feedback.
</p>
)}
<div className="grid grid-cols-2 gap-4">
<div>
<p className="tag-label mb-2">Color</p>