Feature: Add 24-hour cleanup for incomplete orders and update status display
- Create cleanupOrders utility to delete pending orders older than 24 hours - Update admin notifications to only count recent pending orders (< 24h old) - Automatically call cleanup when customer initiates checkout - Change status display from "PENDING" to "Waiting payment" for customer-facing views - Update both customer account page and admin orders page with new status label - Incomplete orders automatically purged, reducing admin clutter Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Haiku 4.5
parent
fa202db4a7
commit
3e90928986
@@ -88,7 +88,8 @@
|
||||
"Bash(git commit -m 'Add: Prominent '\\\\''Shop plain items'\\\\'' section to homepage *)",
|
||||
"Bash(git commit -m 'Feature: Royal Mail shipping integration with weight-based postage *)",
|
||||
"Bash(git commit -m 'Add: Weight field to product admin pages *)",
|
||||
"Bash(git commit -m 'Add: Shipping selector component and checkout integration *)"
|
||||
"Bash(git commit -m 'Add: Shipping selector component and checkout integration *)",
|
||||
"Bash(node clear-pending-orders.js)"
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,6 +13,7 @@ function formatPrice(cents: number) {
|
||||
function statusLabel(status: string) {
|
||||
if (status === 'PAID') return 'Confirmed';
|
||||
if (status === 'FAILED') return 'Failed';
|
||||
if (status === 'PENDING') return 'Waiting payment';
|
||||
return 'Processing';
|
||||
}
|
||||
|
||||
|
||||
@@ -7,6 +7,13 @@ function formatPrice(cents: number) {
|
||||
return `£${(cents / 100).toFixed(2)}`;
|
||||
}
|
||||
|
||||
function statusLabel(status: string) {
|
||||
if (status === 'PAID') return 'Confirmed';
|
||||
if (status === 'FAILED') return 'Failed';
|
||||
if (status === 'PENDING') return 'Waiting payment';
|
||||
return 'Processing';
|
||||
}
|
||||
|
||||
const STATUS_STYLES: Record<string, string> = {
|
||||
PAID: 'bg-splash-blue/10 text-splash-blue',
|
||||
PENDING: 'bg-splash-orange/10 text-splash-orange',
|
||||
@@ -121,7 +128,7 @@ export default async function OrdersPage({ searchParams }: { searchParams: { arc
|
||||
)}
|
||||
<span className="font-mono text-sm">{formatPrice(order.total)}</span>
|
||||
<span className={`tag-label rounded-full px-3 py-1 ${STATUS_STYLES[order.status] ?? ''}`}>
|
||||
{order.status}
|
||||
{statusLabel(order.status)}
|
||||
</span>
|
||||
<form action={showArchived ? unarchiveOrder : archiveOrder}>
|
||||
<input type="hidden" name="id" value={order.id} />
|
||||
|
||||
@@ -6,6 +6,7 @@ import { getEffectivePrice } from '@/lib/pricing';
|
||||
import { fetchActivePromotions } from '@/lib/promotions';
|
||||
import { checkRateLimit, getClientIp } from '@/lib/rateLimit';
|
||||
import { getRoyalMailShippingQuotes } from '@/lib/royalmail-shipping';
|
||||
import { cleanupPendingOrders } from '@/lib/cleanupOrders';
|
||||
|
||||
type CheckoutCartItem = {
|
||||
productId: string;
|
||||
@@ -51,6 +52,9 @@ export async function POST(req: Request) {
|
||||
);
|
||||
}
|
||||
|
||||
// Clean up old incomplete orders (non-blocking)
|
||||
cleanupPendingOrders().catch((err) => console.error('Cleanup error:', err));
|
||||
|
||||
const body = await req.json();
|
||||
console.log('Checkout request received with items:', body.items?.length, 'customerId:', body.customerId);
|
||||
const items: CheckoutCartItem[] = body.items ?? [];
|
||||
|
||||
@@ -1,15 +1,24 @@
|
||||
import { prisma } from '@/lib/prisma';
|
||||
import { cleanupPendingOrders } from '@/lib/cleanupOrders';
|
||||
import AdminNotificationsBadge from './AdminNotificationsBadge';
|
||||
|
||||
export default async function AdminNotifications() {
|
||||
try {
|
||||
// Clean up old incomplete orders (older than 24 hours)
|
||||
await cleanupPendingOrders();
|
||||
|
||||
// Only count pending orders that are less than 24 hours old (still waiting for payment)
|
||||
const recentThreshold = new Date(Date.now() - 24 * 60 * 60 * 1000);
|
||||
const [
|
||||
pendingOrders,
|
||||
designApprovalsInReview,
|
||||
photoRequests,
|
||||
] = await Promise.all([
|
||||
prisma.order.count({
|
||||
where: { status: 'PENDING' },
|
||||
where: {
|
||||
status: 'PENDING',
|
||||
createdAt: { gte: recentThreshold },
|
||||
},
|
||||
}),
|
||||
prisma.designApproval.count({
|
||||
where: { status: 'IN_REVIEW' },
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
import { prisma } from './prisma';
|
||||
|
||||
export async function cleanupPendingOrders() {
|
||||
try {
|
||||
const twentyFourHoursAgo = new Date(Date.now() - 24 * 60 * 60 * 1000);
|
||||
|
||||
const result = await prisma.order.deleteMany({
|
||||
where: {
|
||||
status: 'PENDING',
|
||||
createdAt: { lt: twentyFourHoursAgo },
|
||||
},
|
||||
});
|
||||
|
||||
if (result.count > 0) {
|
||||
console.log(`✓ Cleaned up ${result.count} incomplete orders older than 24 hours`);
|
||||
}
|
||||
|
||||
return result.count;
|
||||
} catch (error) {
|
||||
console.error('Error cleaning up pending orders:', error);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user