website/hooks/useAppointments.ts

222 lines
6.8 KiB
TypeScript
Raw Normal View History

"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,
} from "@/lib/actions/appointments";
import type {
CreateAppointmentInput,
ScheduleAppointmentInput,
RejectAppointmentInput,
UpdateAvailabilityInput,
} from "@/lib/schema/appointments";
import type {
Appointment,
AdminAvailability,
AppointmentStats,
UserAppointmentStats,
AvailableDatesResponse,
JitsiMeetingInfo,
} from "@/lib/models/appointments";
export function useAppointments() {
const queryClient = useQueryClient();
// Get available dates query
const availableDatesQuery = useQuery<AvailableDatesResponse>({
queryKey: ["appointments", "available-dates"],
queryFn: () => getAvailableDates(),
staleTime: 5 * 60 * 1000, // 5 minutes
});
// List appointments query
const appointmentsQuery = useQuery<Appointment[]>({
queryKey: ["appointments", "list"],
queryFn: () => listAppointments(),
enabled: false, // Only fetch when explicitly called
});
// Get user appointments query
const userAppointmentsQuery = useQuery<Appointment[]>({
queryKey: ["appointments", "user"],
queryFn: () => getUserAppointments(),
staleTime: 30 * 1000, // 30 seconds
});
// Get appointment detail query
const useAppointmentDetail = (id: string | null) => {
return useQuery<Appointment>({
queryKey: ["appointments", "detail", id],
queryFn: () => getAppointmentDetail(id!),
enabled: !!id,
});
};
// Get admin availability query
const adminAvailabilityQuery = useQuery<AdminAvailability>({
queryKey: ["appointments", "admin", "availability"],
queryFn: () => getAdminAvailability(),
staleTime: 5 * 60 * 1000, // 5 minutes
});
// Get appointment stats query
const appointmentStatsQuery = useQuery<AppointmentStats>({
queryKey: ["appointments", "stats"],
queryFn: () => getAppointmentStats(),
staleTime: 1 * 60 * 1000, // 1 minute
});
// Get user appointment stats query
const userAppointmentStatsQuery = useQuery<UserAppointmentStats>({
queryKey: ["appointments", "user", "stats"],
queryFn: () => getUserAppointmentStats(),
staleTime: 1 * 60 * 1000, // 1 minute
});
// Get Jitsi meeting info query
const useJitsiMeetingInfo = (id: string | null) => {
return useQuery<JitsiMeetingInfo>({
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,
appointments: appointmentsQuery.data || [],
userAppointments: userAppointmentsQuery.data || [],
adminAvailability: adminAvailabilityQuery.data,
appointmentStats: appointmentStatsQuery.data,
userAppointmentStats: userAppointmentStatsQuery.data,
// Query states
isLoadingAvailableDates: availableDatesQuery.isLoading,
isLoadingAppointments: appointmentsQuery.isLoading,
isLoadingUserAppointments: userAppointmentsQuery.isLoading,
isLoadingAdminAvailability: adminAvailabilityQuery.isLoading,
isLoadingStats: appointmentStatsQuery.isLoading,
isLoadingUserStats: userAppointmentStatsQuery.isLoading,
// Query refetch functions
refetchAvailableDates: availableDatesQuery.refetch,
refetchAppointments: appointmentsQuery.refetch,
refetchUserAppointments: userAppointmentsQuery.refetch,
refetchAdminAvailability: adminAvailabilityQuery.refetch,
refetchStats: appointmentStatsQuery.refetch,
refetchUserStats: userAppointmentStatsQuery.refetch,
// 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,
};
}