141 lines
3.9 KiB
TypeScript
141 lines
3.9 KiB
TypeScript
import { useMutation, useQuery } from "@tanstack/react-query";
|
|
import { useSession } from "@ui/contexts/SessionContext";
|
|
import { supabase } from "@ui/hooks/auth";
|
|
import { queryClient } from "@ui/lib/api";
|
|
import { Database } from "@ui/types/database.types";
|
|
import { useEffect, useState } from "react";
|
|
|
|
export type TimeRange = {
|
|
start: string;
|
|
end: string;
|
|
};
|
|
|
|
export type DayAvailability = {
|
|
enabled: boolean;
|
|
timeRanges: TimeRange[];
|
|
};
|
|
|
|
export type WeeklyAvailability = {
|
|
[key: number]: DayAvailability;
|
|
};
|
|
|
|
export type Exception = {
|
|
date: string;
|
|
} & (
|
|
| {
|
|
type: "hours";
|
|
hours: TimeRange[];
|
|
}
|
|
| {
|
|
type: "day";
|
|
}
|
|
);
|
|
|
|
const DAYS_OF_WEEK = [0, 1, 2, 3, 4, 5, 6];
|
|
|
|
export const DEFAULT_AVAILABILITIES: WeeklyAvailability = DAYS_OF_WEEK.reduce((acc, day) => {
|
|
acc[day] = {
|
|
enabled: true,
|
|
timeRanges: [{ start: "09:00", end: "17:00" }],
|
|
};
|
|
return acc;
|
|
}, {} as WeeklyAvailability);
|
|
|
|
export function useAvailabilities() {
|
|
const { session } = useSession();
|
|
|
|
const { data: availabilities, isLoading } = useQuery<
|
|
Database["public"]["Tables"]["availabilities"]["Row"]
|
|
>({
|
|
queryKey: ["availabilities"],
|
|
queryFn: async () => {
|
|
const { data, error } = await supabase
|
|
.from("availabilities")
|
|
.select("*")
|
|
.eq("user_id", session?.user.id)
|
|
.limit(1);
|
|
if (error) throw error;
|
|
return data?.[0] as Database["public"]["Tables"]["availabilities"]["Row"];
|
|
},
|
|
enabled: !!session?.user.id,
|
|
});
|
|
|
|
const { mutate: updateAvailabilities } = useMutation<
|
|
void,
|
|
Error,
|
|
{
|
|
updatedAvailabilities: WeeklyAvailability;
|
|
newException?: Exception | null;
|
|
}
|
|
>({
|
|
mutationFn: async ({
|
|
updatedAvailabilities,
|
|
newException = null,
|
|
}: {
|
|
updatedAvailabilities: WeeklyAvailability;
|
|
newException?: Exception | null;
|
|
}) => {
|
|
const newAvailabilities = updatedAvailabilities || DEFAULT_AVAILABILITIES;
|
|
let newExceptions: Exception[] = [];
|
|
if (newException) {
|
|
newExceptions = [
|
|
...((availabilities?.exceptions as Exception[] | null) || []),
|
|
newException,
|
|
];
|
|
}
|
|
const { error } = await supabase.from("availabilities").upsert(
|
|
{
|
|
availability_data: newAvailabilities,
|
|
exceptions: newExceptions,
|
|
user_id: session?.user.id,
|
|
},
|
|
{
|
|
onConflict: "user_id",
|
|
}
|
|
);
|
|
if (error) throw error;
|
|
},
|
|
onSuccess: () => {
|
|
queryClient.invalidateQueries({ queryKey: ["availabilities"] });
|
|
},
|
|
});
|
|
|
|
const { mutate: deleteException } = useMutation<void, Error, { exceptionIndex: number }>({
|
|
mutationFn: async ({ exceptionIndex }: { exceptionIndex: number }) => {
|
|
const currentExceptions = (availabilities?.exceptions as Exception[] | null) || [];
|
|
const updatedExceptions = currentExceptions.filter((_, index) => index !== exceptionIndex);
|
|
|
|
const { error } = await supabase.from("availabilities").upsert(
|
|
{
|
|
availability_data: availabilities?.availability_data || DEFAULT_AVAILABILITIES,
|
|
exceptions: updatedExceptions,
|
|
user_id: session?.user.id,
|
|
},
|
|
{
|
|
onConflict: "user_id",
|
|
}
|
|
);
|
|
if (error) throw error;
|
|
},
|
|
onSuccess: () => {
|
|
queryClient.invalidateQueries({ queryKey: ["availabilities"] });
|
|
},
|
|
});
|
|
|
|
const [draftAvailabilities, setDraftAvailabilities] = useState<WeeklyAvailability | null>(null);
|
|
|
|
useEffect(() => {
|
|
if (availabilities?.availability_data) {
|
|
setDraftAvailabilities(availabilities.availability_data as WeeklyAvailability);
|
|
}
|
|
}, [availabilities?.availability_data]);
|
|
|
|
return {
|
|
isLoading,
|
|
updateAvailabilities,
|
|
draftAvailabilities: draftAvailabilities || DEFAULT_AVAILABILITIES,
|
|
setDraftAvailabilities,
|
|
exceptions: (availabilities?.exceptions as Exception[] | null) || [],
|
|
deleteException,
|
|
};
|
|
}
|