xtablo-source/ui/src/hooks/availabilities.ts
Arthur Belleville 374a1ec4b8
Fix lint
2025-10-10 11:10:28 +02:00

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,
};
}