# Consulting Slots Migration - Code Updates Summary ## ✅ Completed Files ### 1. src/pages/ConsultingBooking.tsx ✅ - Updated interface: `ConfirmedSlot` → `ConfirmedSession` with `session_date` field - Updated `fetchConfirmedSlots()` to query `consulting_sessions` table - Updated slot creation logic to: - Create ONE `consulting_sessions` row with session-level data - Create MULTIPLE `consulting_time_slots` rows for each 45-min block - Conflict checking logic already compatible (uses `start_time`/`end_time` fields) ### 2. supabase/functions/create-meet-link/index.ts ✅ - Changed update query from `consulting_slots` to `consulting_sessions` - Updates meet_link once per session instead of once per slot ## ⏳ In Progress ### 3. src/pages/admin/AdminConsulting.tsx (PARTIAL) **Updated:** - Interface: `ConsultingSlot` → `ConsultingSession` - State: `slots` → `sessions`, `selectedSlot` → `selectedSession` - `fetchSessions()` - now queries `consulting_sessions` with profiles join - `openMeetDialog()` - uses session parameter - `saveMeetLink()` - updates `consulting_sessions` table - `createMeetLink()` - uses session fields (`session_date`, etc.) - `updateSessionStatus()` - renamed from `updateSlotStatus()` - Filtering logic - simplified (no grouping needed) - Stats sections - use `sessions` arrays - Today's Sessions Alert - uses `todaySessions` array **Still Needs Manual Update:** Replace all remaining references in the table rendering sections (lines ~428-end): ```typescript // FIND AND REPLACE THESE PATTERNS: // 1. Tabs list: Mendatang ({upcomingOrders.length}) Riwayat ({pastOrders.length}) // CHANGE TO: Mendatang ({upcomingSessions.length}) Riwayat ({pastSessions.length}) // 2. Desktop table - upcoming: {upcomingOrders.map((order) => { const firstSlot = order.slots[0]; const lastSlot = order.slots[order.slots.length - 1]; const sessionCount = order.slots.length; return ( // CHANGE TO: {upcomingSessions.map((session) => { return ( // 3. Date cell: {format(parseISO(firstSlot.date), 'd MMM yyyy', { locale: id })} {isToday(parseISO(firstSlot.date)) && Hari Ini} {isTomorrow(parseISO(firstSlot.date)) && Besok} // CHANGE TO: {format(parseISO(session.session_date), 'd MMM yyyy', { locale: id })} {isToday(parseISO(session.session_date)) && Hari Ini} {isTomorrow(parseISO(session.session_date)) && Besok} // 4. Time cell:
{firstSlot.start_time.substring(0, 5)} - {lastSlot.end_time.substring(0, 5)}
{sessionCount > 1 && (
{sessionCount} sesi
)} // CHANGE TO:
{session.start_time.substring(0, 5)} - {session.end_time.substring(0, 5)}
{session.total_blocks > 1 && (
{session.total_blocks} blok
)} // 5. Client cell:

{order.profile?.name || '-'}

{order.profile?.email}

// CHANGE TO:

{session.profiles?.name || '-'}

{session.profiles?.email}

// 6. Category cell: {firstSlot.topic_category} // CHANGE TO: {session.topic_category} // 7. Status cell: {statusLabels[firstSlot.status]?.label || firstSlot.status} // CHANGE TO: {statusLabels[session.status]?.label || session.status} // 8. Meet link cell: {order.meetLink ? ( // CHANGE TO: {session.meet_link ? ( // 9. Action buttons: onClick={() => openMeetDialog(firstSlot)} onClick={() => updateSlotStatus(firstSlot.id, 'completed')} onClick={() => updateSlotStatus(firstSlot.id, 'cancelled')} // CHANGE TO: onClick={() => openMeetDialog(session)} onClick={() => updateSessionStatus(session.id, 'completed')} onClick={() => updateSessionStatus(session.id, 'cancelled')} // 10. Empty state: Tidak ada jadwal mendatang // CHANGE TO (same colSpan): Tidak ada jadwal mendatang // 11. Mobile card layout - same pattern as desktop: {upcomingOrders.map((order) => { const firstSlot = order.slots[0]; // CHANGE TO: {upcomingSessions.map((session) => { // Then replace all: // order.orderId → session.id // order.slots[0] / firstSlot → session // order.slots[order.slots.length - 1] / lastSlot → session // order.profile → session.profiles // order.meetLink → session.meet_link // sessionCount → session.total_blocks // 12. Past sessions tab - same pattern: {pastOrders.slice(0, 20).map((order) => { // CHANGE TO: {pastSessions.slice(0, 20).map((session) => { // 13. Dialog - selectedSlot references: {selectedSlot && (

Tanggal: {format(parseISO(selectedSlot.date), 'd MMMM yyyy', { locale: id })}

Waktu: {selectedSlot.start_time.substring(0, 5)} - {selectedSlot.end_time.substring(0, 5)}

Klien: {selectedSlot.profiles?.name}

Topik: {selectedSlot.topic_category}

{selectedSlot.notes &&

Catatan: {selectedSlot.notes}

}
)} // CHANGE TO: {selectedSession && (

Tanggal: {format(parseISO(selectedSession.session_date), 'd MMMM yyyy', { locale: id })}

Waktu: {selectedSession.start_time.substring(0, 5)} - {selectedSession.end_time.substring(0, 5)}

Klien: {selectedSession.profiles?.name}

Topik: {selectedSession.topic_category}

{selectedSession.notes &&

Catatan: {selectedSession.notes}

}
)} ``` ## 📋 Remaining Files to Update ### 4. src/components/reviews/ConsultingHistory.tsx **Changes needed:** - Change query from `consulting_slots` to `consulting_sessions` - Remove grouping logic (no longer needed) - Update interface to use `ConsultingSession` with fields: - `session_date` (instead of `date`) - `total_duration_minutes` - `total_blocks` - `total_price` - Update all field references in rendering ### 5. src/pages/member/OrderDetail.tsx **Changes needed:** - Find consulting_slots query and change to consulting_sessions - Update join to include session data - Update field names in rendering (date → session_date, etc.) ### 6. supabase/functions/handle-order-paid/index.ts **Changes needed:** - Change status update from `consulting_slots` to `consulting_sessions` - Update logic to set `status = 'confirmed'` for session --- ## Quick Reference: Field Name Changes | Old (consulting_slots) | New (consulting_sessions) | |------------------------|---------------------------| | `date` | `session_date` | | `slots` array | Single `session` object | | `slots[0]` / `firstSlot` | `session` | | `slots[length-1]` / `lastSlot` | `session` | | `order_id` (for grouping) | `id` (session ID) | | `meet_link` (per slot) | `meet_link` (per session) | | Row count × 45min | `total_duration_minutes` | | Row count | `total_blocks` | --- ## Testing Checklist After migration: - [ ] Test booking flow - creates session + time slots - [ ] Test availability checking - uses sessions table - [ ] Test meet link creation - updates session - [ ] Test admin consulting page - displays sessions - [ ] Test user consulting history - displays sessions - [ ] Test order detail - shows consulting session info - [ ] Test payment confirmation - updates session status --- ## Rollback Plan (if needed) If issues arise: 1. Restore old table: `ALTER TABLE consulting_slots RENAME TO consulting_slots_backup;` 2. Create view: `CREATE VIEW consulting_slots AS SELECT ... FROM consulting_sessions JOIN consulting_time_slots;` 3. Revert code changes from git --- **Note:** All SQL tables should already be created. This document covers code changes only.