"use client"; import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query"; import { useCallback } from "react"; import { createAppointment, getAvailableDates, listAppointments, getUserAppointments, getUserAppointmentStats, getAppointmentDetail, scheduleAppointment, rejectAppointment, getAdminAvailability, updateAdminAvailability, getAppointmentStats, getJitsiMeetingInfo, getWeeklyAvailability, getAvailabilityConfig, checkDateAvailability, getAvailabilityOverview, } from "@/lib/actions/appointments"; import type { CreateAppointmentInput, ScheduleAppointmentInput, RejectAppointmentInput, UpdateAvailabilityInput, } from "@/lib/schema/appointments"; import type { Appointment, AdminAvailability, AppointmentStats, UserAppointmentStats, AvailableDatesResponse, JitsiMeetingInfo, WeeklyAvailabilityResponse, AvailabilityConfig, CheckDateAvailabilityResponse, AvailabilityOverview, } from "@/lib/models/appointments"; export function useAppointments(options?: { enableAvailableDates?: boolean; enableStats?: boolean; enableConfig?: boolean; enableWeeklyAvailability?: boolean; enableOverview?: boolean; }) { const queryClient = useQueryClient(); const enableAvailableDates = options?.enableAvailableDates ?? false; const enableStats = options?.enableStats ?? true; const enableConfig = options?.enableConfig ?? true; const enableWeeklyAvailability = options?.enableWeeklyAvailability ?? true; const enableOverview = options?.enableOverview ?? true; // Get available dates query (optional, disabled by default - using weekly_availability as primary source) // Can be enabled when explicitly needed (e.g., on admin booking page) const availableDatesQuery = useQuery({ queryKey: ["appointments", "available-dates"], queryFn: () => getAvailableDates(), enabled: enableAvailableDates, // Can be enabled when needed staleTime: 5 * 60 * 1000, // 5 minutes retry: 0, // Don't retry failed requests }); // Get weekly availability query const weeklyAvailabilityQuery = useQuery({ queryKey: ["appointments", "weekly-availability"], queryFn: async () => { const data = await getWeeklyAvailability(); // Normalize response format - ensure it's always an object with week array if (Array.isArray(data)) { return { week: data }; } return data; }, enabled: enableWeeklyAvailability, staleTime: 5 * 60 * 1000, // 5 minutes }); // Get availability config query const availabilityConfigQuery = useQuery({ queryKey: ["appointments", "availability-config"], queryFn: () => getAvailabilityConfig(), enabled: enableConfig, staleTime: 60 * 60 * 1000, // 1 hour (config rarely changes) }); // Get availability overview query const availabilityOverviewQuery = useQuery({ queryKey: ["appointments", "availability-overview"], queryFn: () => getAvailabilityOverview(), enabled: enableOverview, staleTime: 5 * 60 * 1000, // 5 minutes }); // List appointments query const appointmentsQuery = useQuery({ queryKey: ["appointments", "list"], queryFn: async () => { const data = await listAppointments(); return data || []; }, enabled: true, // Enable by default to fetch user appointments staleTime: 30 * 1000, // 30 seconds retry: 1, // Retry once on failure refetchOnMount: true, // Always refetch when component mounts }); // Get user appointments query (disabled - using listAppointments instead) const userAppointmentsQuery = useQuery({ queryKey: ["appointments", "user"], queryFn: () => getUserAppointments(), enabled: false, // Disabled - using listAppointments endpoint instead staleTime: 30 * 1000, // 30 seconds }); // Get appointment detail query const useAppointmentDetail = (id: string | null) => { return useQuery({ queryKey: ["appointments", "detail", id], queryFn: () => getAppointmentDetail(id!), enabled: !!id, }); }; // Get admin availability query const adminAvailabilityQuery = useQuery({ queryKey: ["appointments", "admin", "availability"], queryFn: () => getAdminAvailability(), staleTime: 5 * 60 * 1000, // 5 minutes }); // Get appointment stats query const appointmentStatsQuery = useQuery({ queryKey: ["appointments", "stats"], queryFn: () => getAppointmentStats(), staleTime: 1 * 60 * 1000, // 1 minute }); // Get user appointment stats query const userAppointmentStatsQuery = useQuery({ queryKey: ["appointments", "user", "stats"], queryFn: () => getUserAppointmentStats(), enabled: enableStats, staleTime: 1 * 60 * 1000, // 1 minute }); // Get Jitsi meeting info query const useJitsiMeetingInfo = (id: string | null) => { return useQuery({ queryKey: ["appointments", "jitsi", id], queryFn: () => getJitsiMeetingInfo(id!), enabled: !!id, staleTime: 30 * 1000, // 30 seconds }); }; // Create appointment mutation const createAppointmentMutation = useMutation({ mutationFn: (input: CreateAppointmentInput) => createAppointment(input), onSuccess: () => { queryClient.invalidateQueries({ queryKey: ["appointments"] }); }, }); // Schedule appointment mutation const scheduleAppointmentMutation = useMutation({ mutationFn: ({ id, input }: { id: string; input: ScheduleAppointmentInput }) => scheduleAppointment(id, input), onSuccess: () => { queryClient.invalidateQueries({ queryKey: ["appointments"] }); }, }); // Reject appointment mutation const rejectAppointmentMutation = useMutation({ mutationFn: ({ id, input }: { id: string; input: RejectAppointmentInput }) => rejectAppointment(id, input), onSuccess: () => { queryClient.invalidateQueries({ queryKey: ["appointments"] }); }, }); // Update admin availability mutation const updateAdminAvailabilityMutation = useMutation({ mutationFn: (input: UpdateAvailabilityInput) => updateAdminAvailability(input), onSuccess: () => { queryClient.invalidateQueries({ queryKey: ["appointments", "admin", "availability"] }); queryClient.invalidateQueries({ queryKey: ["appointments", "available-dates"] }); }, }); // Convenience functions const create = useCallback( async (input: CreateAppointmentInput) => { return await createAppointmentMutation.mutateAsync(input); }, [createAppointmentMutation] ); const schedule = useCallback( async (id: string, input: ScheduleAppointmentInput) => { return await scheduleAppointmentMutation.mutateAsync({ id, input }); }, [scheduleAppointmentMutation] ); const reject = useCallback( async (id: string, input: RejectAppointmentInput) => { return await rejectAppointmentMutation.mutateAsync({ id, input }); }, [rejectAppointmentMutation] ); const updateAvailability = useCallback( async (input: UpdateAvailabilityInput) => { return await updateAdminAvailabilityMutation.mutateAsync(input); }, [updateAdminAvailabilityMutation] ); const fetchAppointments = useCallback( async (email?: string) => { const data = await listAppointments(email); queryClient.setQueryData(["appointments", "list"], data); return data; }, [queryClient] ); return { // Queries availableDates: availableDatesQuery.data?.dates || [], availableDatesResponse: availableDatesQuery.data, weeklyAvailability: weeklyAvailabilityQuery.data, availabilityConfig: availabilityConfigQuery.data, availabilityOverview: availabilityOverviewQuery.data, appointments: appointmentsQuery.data || [], userAppointments: userAppointmentsQuery.data || [], adminAvailability: adminAvailabilityQuery.data, appointmentStats: appointmentStatsQuery.data, userAppointmentStats: userAppointmentStatsQuery.data, // Query states isLoadingAvailableDates: availableDatesQuery.isLoading, isLoadingWeeklyAvailability: weeklyAvailabilityQuery.isLoading, isLoadingAvailabilityConfig: availabilityConfigQuery.isLoading, isLoadingAvailabilityOverview: availabilityOverviewQuery.isLoading, isLoadingAppointments: appointmentsQuery.isLoading, isLoadingUserAppointments: userAppointmentsQuery.isLoading, isLoadingAdminAvailability: adminAvailabilityQuery.isLoading, isLoadingStats: appointmentStatsQuery.isLoading, isLoadingUserStats: userAppointmentStatsQuery.isLoading, // Query refetch functions refetchAvailableDates: availableDatesQuery.refetch, refetchWeeklyAvailability: weeklyAvailabilityQuery.refetch, refetchAvailabilityConfig: availabilityConfigQuery.refetch, refetchAvailabilityOverview: availabilityOverviewQuery.refetch, refetchAppointments: appointmentsQuery.refetch, refetchUserAppointments: userAppointmentsQuery.refetch, refetchAdminAvailability: adminAvailabilityQuery.refetch, refetchStats: appointmentStatsQuery.refetch, refetchUserStats: userAppointmentStatsQuery.refetch, // Helper functions checkDateAvailability: async (date: string) => { return await checkDateAvailability(date); }, // Hooks for specific queries useAppointmentDetail, useJitsiMeetingInfo, // Mutations create, schedule, reject, updateAvailability, fetchAppointments, // Mutation states isCreating: createAppointmentMutation.isPending, isScheduling: scheduleAppointmentMutation.isPending, isRejecting: rejectAppointmentMutation.isPending, isUpdatingAvailability: updateAdminAvailabilityMutation.isPending, // Direct mutation access (if needed) createAppointmentMutation, scheduleAppointmentMutation, rejectAppointmentMutation, updateAdminAvailabilityMutation, }; }