From aa07b64c80e27a3abf26cf4a92c67c7cc418fb22 Mon Sep 17 00:00:00 2001 From: "diana.dolgolyova" Date: Tue, 24 Mar 2026 17:52:21 +0300 Subject: [PATCH] fix: dashboard counters refresh after status changes When a booking status is changed, confirmed, or deleted in any tab, the dashboard summary cards re-fetch to show updated counts. Previously the dashboard was stale until page reload. --- src/app/admin/bookings/GenericBookingsList.tsx | 4 ++++ src/app/admin/bookings/McRegistrationsTab.tsx | 3 ++- src/app/admin/bookings/OpenDayBookingsTab.tsx | 3 ++- src/app/admin/bookings/page.tsx | 14 +++++++++----- 4 files changed, 17 insertions(+), 7 deletions(-) diff --git a/src/app/admin/bookings/GenericBookingsList.tsx b/src/app/admin/bookings/GenericBookingsList.tsx index 0ec973f..40e2f4f 100644 --- a/src/app/admin/bookings/GenericBookingsList.tsx +++ b/src/app/admin/bookings/GenericBookingsList.tsx @@ -14,6 +14,7 @@ interface GenericBookingsListProps { endpoint: string; filter: BookingFilter; onItemsChange: (fn: (prev: T[]) => T[]) => void; + onDataChange?: () => void; groups?: BookingGroup[]; renderExtra?: (item: T) => React.ReactNode; onConfirm?: (id: number) => void; @@ -24,6 +25,7 @@ export function GenericBookingsList({ endpoint, filter, onItemsChange, + onDataChange, groups, renderExtra, onConfirm, @@ -47,6 +49,7 @@ export function GenericBookingsList({ body: JSON.stringify({ action: "set-status", id, status }), }); if (!res.ok) throw new Error(); + onDataChange?.(); } catch { if (prevStatus) onItemsChange((list) => list.map((b) => b.id === id ? { ...b, status: prevStatus } : b)); showError("Не удалось обновить статус"); @@ -58,6 +61,7 @@ export function GenericBookingsList({ const res = await adminFetch(`${endpoint}?id=${id}`, { method: "DELETE" }); if (!res.ok) throw new Error(); onItemsChange((list) => list.filter((b) => b.id !== id)); + onDataChange?.(); } catch { showError("Не удалось удалить запись"); } diff --git a/src/app/admin/bookings/McRegistrationsTab.tsx b/src/app/admin/bookings/McRegistrationsTab.tsx index 151e54f..eb3cf2c 100644 --- a/src/app/admin/bookings/McRegistrationsTab.tsx +++ b/src/app/admin/bookings/McRegistrationsTab.tsx @@ -13,7 +13,7 @@ interface McRegistration extends BaseBooking { interface McSlot { date: string; startTime: string } interface McItem { title: string; slots: McSlot[] } -export function McRegistrationsTab({ filter }: { filter: BookingFilter }) { +export function McRegistrationsTab({ filter, onDataChange }: { filter: BookingFilter; onDataChange?: () => void }) { const [regs, setRegs] = useState([]); const [mcDates, setMcDates] = useState>({}); const [loading, setLoading] = useState(true); @@ -75,6 +75,7 @@ export function McRegistrationsTab({ filter }: { filter: BookingFilter }) { endpoint="/api/admin/mc-registrations" filter={filter} onItemsChange={setRegs} + onDataChange={onDataChange} groups={groups} /> ); diff --git a/src/app/admin/bookings/OpenDayBookingsTab.tsx b/src/app/admin/bookings/OpenDayBookingsTab.tsx index ec3ec62..a9a63b6 100644 --- a/src/app/admin/bookings/OpenDayBookingsTab.tsx +++ b/src/app/admin/bookings/OpenDayBookingsTab.tsx @@ -17,7 +17,7 @@ interface OpenDayBooking extends BaseBooking { interface EventInfo { id: number; date: string; title?: string } -export function OpenDayBookingsTab({ filter }: { filter: BookingFilter }) { +export function OpenDayBookingsTab({ filter, onDataChange }: { filter: BookingFilter; onDataChange?: () => void }) { const [bookings, setBookings] = useState([]); const [events, setEvents] = useState([]); const [loading, setLoading] = useState(true); @@ -81,6 +81,7 @@ export function OpenDayBookingsTab({ filter }: { filter: BookingFilter }) { endpoint="/api/admin/open-day/bookings" filter={filter} onItemsChange={setBookings} + onDataChange={onDataChange} groups={groups} /> ); diff --git a/src/app/admin/bookings/page.tsx b/src/app/admin/bookings/page.tsx index d3d9dbe..6e5f5d3 100644 --- a/src/app/admin/bookings/page.tsx +++ b/src/app/admin/bookings/page.tsx @@ -230,7 +230,7 @@ function ConfirmModal({ interface ScheduleClassInfo { type: string; trainer: string; time: string; day: string; hall: string; address: string; groupId?: string } interface ScheduleLocation { name: string; address: string; days: { day: string; classes: { time: string; trainer: string; type: string; groupId?: string }[] }[] } -function GroupBookingsTab({ filter }: { filter: BookingFilter }) { +function GroupBookingsTab({ filter, onDataChange }: { filter: BookingFilter; onDataChange?: () => void }) { const [bookings, setBookings] = useState([]); const [allClasses, setAllClasses] = useState([]); const [loading, setLoading] = useState(true); @@ -284,6 +284,7 @@ function GroupBookingsTab({ filter }: { filter: BookingFilter }) { }) : Promise.resolve(), ]); setConfirmingId(null); + onDataChange?.(); } if (loading) return ; @@ -296,6 +297,7 @@ function GroupBookingsTab({ filter }: { filter: BookingFilter }) { endpoint="/api/admin/group-bookings" filter={filter} onItemsChange={setBookings} + onDataChange={onDataChange} onConfirm={(id) => setConfirmingId(id)} renderExtra={(b) => ( <> @@ -700,6 +702,8 @@ function BookingsPageInner() { const [searchResults, setSearchResults] = useState(null); const [statusFilter, setStatusFilter] = useState("all"); const [refreshKey, setRefreshKey] = useState(0); + const [dashboardKey, setDashboardKey] = useState(0); + const refreshDashboard = useCallback(() => setDashboardKey((k) => k + 1), []); const lastTotalRef = useRef(null); const { showError } = useToast(); @@ -814,7 +818,7 @@ function BookingsPageInner() { ) : ( <> {/* Dashboard — what needs attention */} - + {/* Tabs */}
@@ -839,9 +843,9 @@ function BookingsPageInner() { {/* Tab content — auto-refreshes when new bookings detected */}
{tab === "reminders" && } - {tab === "classes" && } - {tab === "master-classes" && } - {tab === "open-day" && } + {tab === "classes" && } + {tab === "master-classes" && } + {tab === "open-day" && }
)}