Auto-cancel expired consulting orders and prefill re-booking

**Features Implemented:**

1. **Auto-Cancel Expired Consulting Orders:**
   - New edge function: cancel-expired-consulting-orders
   - Changes order status from 'pending' → 'cancelled'
   - Cancels all associated consulting_sessions
   - Deletes calendar events via delete-calendar-event
   - Releases consulting_time_slots (deletes booked slots)
   - Properly cleans up all resources

2. **Smart Re-Booking with Pre-filled Data:**
   - OrderDetail.tsx stores expired order data in sessionStorage:
     - fromExpiredOrder flag
     - Original orderId
     - topicCategory
     - notes
   - ConsultingBooking.tsx retrieves and pre-fills form on mount
   - Auto-clears sessionStorage after use

3. **Improved UX for Expired Orders:**
   - Clear message: "Order ini telah dibatalkan secara otomatis"
   - Helpful hint: "Kategori dan catatan akan terisi otomatis"
   - One-click re-booking with pre-filled data
   - Member only needs to select new time slot

**How It Works:**

Flow:
1. QRIS expires → Order shows expired message
2. Member clicks "Buat Booking Baru"
3. Data stored in sessionStorage (category, notes)
4. Navigates to /consulting
5. Form auto-fills with previous data
6. Member selects new time → Books new session

**Edge Function Details:**
- Finds orders where: payment_status='pending' AND qr_expires_at < NOW()
- Cancels order status
- Cancels consulting_sessions
- Deletes consulting_time_slots
- Invokes delete-calendar-event for each session
- Returns count of processed orders

**To Deploy:**
1. Deploy cancel-expired-consulting-orders edge function
2. Set up cron job to run every 5-15 minutes:
   `curl -X POST https://your-domain/functions/v1/cancel-expired-consulting-orders`

**Benefits:**
 Orders properly cancelled when QR expires
 Time slots released for other users
 Calendar events cleaned up
 Easy re-booking without re-typing data
 Better UX for expired payment situations

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
This commit is contained in:
dwindown
2025-12-28 18:13:20 +07:00
parent b88e308b84
commit 3eb53406c9
3 changed files with 180 additions and 2 deletions

View File

@@ -82,6 +82,31 @@ export default function ConsultingBooking() {
useEffect(() => {
fetchData();
// Check for pre-filled data from expired order
const expiredOrderData = sessionStorage.getItem('expiredConsultingOrder');
if (expiredOrderData) {
try {
const data = JSON.parse(expiredOrderData);
if (data.fromExpiredOrder) {
// Prefill form with expired order data
if (data.topicCategory) setSelectedCategory(data.topicCategory);
if (data.notes) setNotes(data.notes);
// Show notification to user
setTimeout(() => {
// You could add a toast notification here if you have toast set up
console.log('Pre-filled data from expired order:', data);
}, 100);
// Clear the stored data after using it
sessionStorage.removeItem('expiredConsultingOrder');
}
} catch (err) {
console.error('Error parsing expired order data:', err);
sessionStorage.removeItem('expiredConsultingOrder');
}
}
}, []);
useEffect(() => {

View File

@@ -449,15 +449,32 @@ export default function OrderDetail() {
</Alert>
{isConsultingOrder ? (
// Consulting order - show booking button
// Consulting order - show booking button with pre-filled data
<div className="text-center space-y-4">
<p className="text-sm text-muted-foreground">
Order ini telah dibatalkan secara otomatis karena waktu pembayaran habis.
</p>
<Button onClick={() => navigate("/consulting")} className="shadow-sm">
<Button
onClick={() => {
// Pass expired order data to prefill the booking form
const expiredData = {
fromExpiredOrder: true,
orderId: order.id,
topicCategory: consultingSlots[0]?.topic_category || '',
notes: consultingSlots[0]?.notes || ''
};
// Store in sessionStorage for the booking page to retrieve
sessionStorage.setItem('expiredConsultingOrder', JSON.stringify(expiredData));
navigate("/consulting");
}}
className="shadow-sm"
>
<CalendarIcon className="w-4 h-4 mr-2" />
Buat Booking Baru
</Button>
<p className="text-xs text-muted-foreground">
Kategori dan catatan akan terisi otomatis dari order sebelumnya
</p>
</div>
) : (
// Product order - show regenerate button