A comprehensive order management system for TEDx merchandise sales with automated email notifications and payment verification.
This Next.js application provides an admin dashboard to manage customer orders for TEDx merchandise. It features payment screenshot verification, order status management, automated email confirmations with a robust retry mechanism, and seamless integration with Cloudflare R2 for storage.
- Real-time Dashboard: View all orders with filtering, searching, and sorting capabilities
- Payment Verification: Review payment screenshots before accepting/rejecting orders
- Multi-status Support: Pending, Accepted, and Rejected order states
- Order Details: Comprehensive view of customer info, product details, and payment information
- Automated Emails: Send professional confirmation emails when orders are accepted
- Email Status Tracking: Monitor email delivery with status indicators (Sent/Failed/Not Sent)
- Smart Retry Mechanism: Automatic retry with up to 5 attempts for failed emails
- Email Resend: Manual resend option for failed email deliveries
- Dark Mode Support: Email templates remain consistent across light/dark modes
- Search by customer name, phone, order ID, or transaction ID
- Filter by product, size, order status, and email status
- Quick access to orders with failed emails requiring attention
- Total orders count
- Accepted, pending, and rejected orders
- Total revenue from accepted orders
- Real-time filtering results
- Framework: Next.js 15 with App Router
- Language: TypeScript
- Styling: Tailwind CSS
- Storage: Cloudflare R2 (S3-compatible)
- Email: Nodemailer with SMTP
- SDK: AWS SDK v3 for S3 operations
- Node.js 18+
- npm/yarn/pnpm
- Cloudflare R2 bucket
- SMTP email server credentials
npm install
# or
yarn install
# or
pnpm installCreate a .env file in the root directory:
# Cloudflare R2 Configuration
R2_ACCOUNT_ID=your_account_id
R2_ACCESS_KEY_ID=your_access_key
R2_SECRET_ACCESS_KEY=your_secret_key
R2_BUCKET_NAME=your_bucket_name
# SMTP Email Configuration
SMTP_HOST=smtp.gmail.com
SMTP_PORT=587
SMTP_SECURE=false
SMTP_USER=[email protected]
SMTP_PASS=your_app_password
SMTP_FROM=[email protected]
# Application URL
NEXT_PUBLIC_BASE_URL=http://localhost:3000
# Email Logo URL (optional)
EMAIL_LOGO_URL=https://your-logo-url.com/logo.pngnpm run devOpen http://localhost:3000 to access the dashboard.
order-details/
βββ app/
β βββ api/
β β βββ email/
β β β βββ route.ts # Email sending endpoint
β β β βββ resend/
β β β βββ route.ts # Email resend endpoint
β β βββ image/
β β β βββ route.ts # Image proxy for R2
β β βββ orders/
β β βββ route.ts # List all orders
β β βββ [orderId]/
β β βββ route.ts # Update order status
β βββ types/
β β βββ order.ts # TypeScript interfaces
β βββ globals.css # Global styles
β βββ layout.tsx # Root layout
β βββ page.tsx # Main dashboard
βββ public/
β βββ tedx-logo.png # TEDx logo
βββ .env # Environment variables
βββ README.md
Retrieve all orders from R2 storage.
Response:
{
"success": true,
"orders": [...],
"total": 10
}Update order status (accept/reject) and trigger email notification.
Request:
{
"status": "accepted" | "rejected" | "pending"
}Response:
{
"success": true,
"message": "Order status updated to accepted",
"order": {...},
"emailSent": true,
"emailStatus": "sent"
}Send confirmation email for an order.
Request:
{
"order": {...},
"type": "accepted"
}Response:
{
"success": true,
"message": "Confirmation email sent to [email protected]",
"emailStatus": "sent",
"messageId": "..."
}Resend email for a specific order (max 5 attempts).
Request:
{
"orderId": "ORDER123"
}Response:
{
"success": true,
"message": "Email resent successfully",
"emailStatus": "sent",
"attempts": 2,
"remainingAttempts": 3
}Check email status for an order.
Response:
{
"success": true,
"orderId": "ORDER123",
"orderStatus": "accepted",
"email": {
"status": "failed",
"attempts": 2,
"lastAttempt": "2026-01-23T10:00:00Z",
"error": "Connection timeout"
},
"canResend": true,
"maxAttempts": 5
}Each order tracks:
- Status:
not_sent,sent, orfailed - Attempts: Number of send attempts (max 5)
- Last Attempt: Timestamp of last send
- Error: Error message if failed
- Email sending is attempted when order is accepted
- Failed attempts are logged with error details
- Manual resend available for up to 5 total attempts
- Prevents infinite retry loops
- Professional HTML design
- Responsive and mobile-friendly
- Dark mode resistant (stays consistent)
- Includes order details, customer info, and delivery address
- TEDx branded with logo
- Total orders
- Accepted/Pending/Rejected counts
- Accepted revenue
- Filtered results count
- Customer information
- Product and size
- Price and date
- Order status badge
- Email status indicator
- Quick view action
- Search bar (name, phone, order ID, transaction ID)
- Product filter
- Size filter
- Order status filter
- Email status filter (All/Sent/Failed/Not Sent)
- Full customer and product information
- Payment screenshot viewer
- Order status management
- Email status section (for accepted orders):
- Current email status
- Attempt counter
- Last attempt timestamp
- Error messages
- Resend button (when applicable)
- Success/error feedback
Orders are stored as JSON files:
orders/
βββ ORDER123.json
βββ ORDER124.json
βββ ...
{
orderId: string;
timestamp: string;
verified: boolean;
status: 'pending' | 'accepted' | 'rejected';
customer: {
name: string;
email: string;
phone: string;
address: string;
};
product: {
id: string;
name: string;
size: string;
price: number;
};
payment: {
transactionId: string;
screenshotUrl: string;
};
email?: {
status: 'not_sent' | 'sent' | 'failed';
attempts: number;
lastAttempt: string | null;
error: string | null;
};
}If you see ETIMEDOUT errors:
- Check if Cloudflare R2 is accessible from your network
- Verify VPN/firewall settings
- Test connection:
Test-NetConnection -ComputerName r2.cloudflarestorage.com -Port 443 - Try using mobile hotspot if on restricted network
- Verify SMTP credentials
- For Gmail: Use App Password
- Check email status in order details
- Use resend feature for failed emails
- Ensure all required environment variables are set
- Restart dev server after
.envchanges
The email field was added to track email delivery status. This is:
- Optional in the schema (
email?: EmailInfo) - Backward compatible with existing orders
- Auto-initialized by
normalizeOrder()function
No database migration required - new field is added automatically.
- Environment variables should never be committed
- SMTP credentials should use app passwords, not main passwords
- R2 access keys should have minimal required permissions
- Production deployments should use HTTPS
This project is maintained for TEDx event merchandise management. For issues or feature requests, please contact the development team.
Proprietary - TEDx Event Management System