Add busy events to calendar
parent
a9bf0d625f
commit
1b87cf80b9
|
@ -1,22 +1,57 @@
|
||||||
|
import { useSession } from "next-auth/react";
|
||||||
|
import { useMemo } from "react";
|
||||||
|
|
||||||
import dayjs from "@calcom/dayjs";
|
import dayjs from "@calcom/dayjs";
|
||||||
import { Calendar } from "@calcom/features/calendars/weeklyview";
|
import { Calendar } from "@calcom/features/calendars/weeklyview";
|
||||||
|
import { trpc } from "@calcom/trpc/react";
|
||||||
|
|
||||||
import { useTroubleshooterStore } from "../store";
|
import { useTroubleshooterStore } from "../store";
|
||||||
|
|
||||||
export const LargeCalendar = ({ extraDays }: { extraDays: number }) => {
|
export const LargeCalendar = ({ extraDays }: { extraDays: number }) => {
|
||||||
const selectedDate = useTroubleshooterStore((state) => state.selectedDate);
|
const selectedDate = useTroubleshooterStore((state) => state.selectedDate);
|
||||||
const date = selectedDate || dayjs().format("YYYY-MM-DD");
|
const { data: session } = useSession();
|
||||||
|
const date = selectedDate ? dayjs(selectedDate) : dayjs();
|
||||||
|
|
||||||
|
const { data, isLoading } = trpc.viewer.availability.user.useQuery(
|
||||||
|
{
|
||||||
|
username: session?.user?.username || "",
|
||||||
|
dateFrom: date.startOf("day").utc().format(),
|
||||||
|
dateTo: date.endOf("day").utc().format(),
|
||||||
|
withSource: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
enabled: !!session?.user?.username,
|
||||||
|
}
|
||||||
|
);
|
||||||
const startDate = selectedDate ? dayjs(selectedDate).toDate() : dayjs().toDate();
|
const startDate = selectedDate ? dayjs(selectedDate).toDate() : dayjs().toDate();
|
||||||
const endDate = dayjs(startDate)
|
const endDate = dayjs(startDate)
|
||||||
.add(extraDays - 1, "day")
|
.add(extraDays - 1, "day")
|
||||||
.toDate();
|
.toDate();
|
||||||
|
|
||||||
|
const events = useMemo(() => {
|
||||||
|
if (!data?.busy) return [];
|
||||||
|
return data?.busy.map((event) => {
|
||||||
|
const id = typeof event.start === "string" ? event.start : event.start.toISOString();
|
||||||
|
|
||||||
|
return {
|
||||||
|
id,
|
||||||
|
title: event.title ?? "Busy",
|
||||||
|
start: new Date(event.start),
|
||||||
|
end: new Date(event.end),
|
||||||
|
options: {
|
||||||
|
borderColor: "#F97417",
|
||||||
|
status: "ACCEPTED",
|
||||||
|
},
|
||||||
|
};
|
||||||
|
});
|
||||||
|
}, [data]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="h-full [--calendar-dates-sticky-offset:66px]">
|
<div className="h-full [--calendar-dates-sticky-offset:66px]">
|
||||||
<Calendar
|
<Calendar
|
||||||
startHour={0}
|
startHour={0}
|
||||||
endHour={23}
|
endHour={23}
|
||||||
events={[]}
|
events={events}
|
||||||
startDate={startDate}
|
startDate={startDate}
|
||||||
endDate={endDate}
|
endDate={endDate}
|
||||||
gridCellsPerHour={60 / 15}
|
gridCellsPerHour={60 / 15}
|
||||||
|
|
|
@ -1,10 +1,13 @@
|
||||||
import type { PropsWithChildren } from "react";
|
import type { PropsWithChildren } from "react";
|
||||||
|
|
||||||
|
import classNames from "@calcom/lib/classNames";
|
||||||
|
|
||||||
interface TroubleshooterListItemContainerProps {
|
interface TroubleshooterListItemContainerProps {
|
||||||
title: string;
|
title: string;
|
||||||
subtitle: string;
|
subtitle?: string;
|
||||||
suffixSlot?: React.ReactNode;
|
suffixSlot?: React.ReactNode;
|
||||||
prefixSlot?: React.ReactNode;
|
prefixSlot?: React.ReactNode;
|
||||||
|
className?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function TroubleshooterListItemHeader({
|
export function TroubleshooterListItemHeader({
|
||||||
|
@ -12,13 +15,14 @@ export function TroubleshooterListItemHeader({
|
||||||
title,
|
title,
|
||||||
subtitle,
|
subtitle,
|
||||||
suffixSlot,
|
suffixSlot,
|
||||||
|
className,
|
||||||
}: TroubleshooterListItemContainerProps) {
|
}: TroubleshooterListItemContainerProps) {
|
||||||
return (
|
return (
|
||||||
<div className="border-subtle flex max-w-full gap-3 border border-b-0 px-4 py-2">
|
<div className={classNames("border-subtle flex max-w-full gap-3 border border-b-0 px-4 py-2", className)}>
|
||||||
{prefixSlot}
|
{prefixSlot}
|
||||||
<div className="flex h-full max-w-full flex-1 flex-col flex-nowrap truncate text-sm leading-4">
|
<div className="flex h-full max-w-full flex-1 flex-col flex-nowrap truncate text-sm leading-4">
|
||||||
<p className="font-semibold">{title}</p>
|
<p className="font-medium">{title}</p>
|
||||||
<p className="font-normal">{subtitle}</p>
|
{subtitle && <p className="font-normal">{subtitle}</p>}
|
||||||
</div>
|
</div>
|
||||||
{suffixSlot}
|
{suffixSlot}
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -4,6 +4,8 @@ import Link from "next/link";
|
||||||
import { useLocale } from "@calcom/lib/hooks/useLocale";
|
import { useLocale } from "@calcom/lib/hooks/useLocale";
|
||||||
import { Skeleton } from "@calcom/ui";
|
import { Skeleton } from "@calcom/ui";
|
||||||
|
|
||||||
|
import { CalendarToggleContainer } from "./CalendarToggleContainer";
|
||||||
|
import { EventScheduleItem } from "./EventScheduleItem";
|
||||||
import { EventTypeSelect } from "./EventTypeSelect";
|
import { EventTypeSelect } from "./EventTypeSelect";
|
||||||
|
|
||||||
const BackButtonInSidebar = ({ name }: { name: string }) => {
|
const BackButtonInSidebar = ({ name }: { name: string }) => {
|
||||||
|
@ -30,6 +32,8 @@ export const TroubleshooterSidebar = () => {
|
||||||
<div className="relative z-10 flex w-full flex-col gap-6 py-6 pr-6">
|
<div className="relative z-10 flex w-full flex-col gap-6 py-6 pr-6">
|
||||||
<BackButtonInSidebar name={t("troubleshooter")} />
|
<BackButtonInSidebar name={t("troubleshooter")} />
|
||||||
<EventTypeSelect />
|
<EventTypeSelect />
|
||||||
|
<EventScheduleItem />
|
||||||
|
<CalendarToggleContainer />
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
|
@ -28,6 +28,24 @@ export const getScheduleByEventSlugHandler = async ({ ctx, input }: GetOptions)
|
||||||
try {
|
try {
|
||||||
// This looks kinda weird that we throw straight in the catch - its so that we can return a default schedule if the user has not completed onboarding @shiraz will loveme for this
|
// This looks kinda weird that we throw straight in the catch - its so that we can return a default schedule if the user has not completed onboarding @shiraz will loveme for this
|
||||||
if (!foundScheduleForSlug?.scheduleId) {
|
if (!foundScheduleForSlug?.scheduleId) {
|
||||||
|
const foundUserDefaultId = await ctx.prisma.user.findUnique({
|
||||||
|
where: {
|
||||||
|
id: ctx.user.id,
|
||||||
|
},
|
||||||
|
select: {
|
||||||
|
defaultScheduleId: true,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
if (foundUserDefaultId?.defaultScheduleId) {
|
||||||
|
return await getHandler({
|
||||||
|
ctx,
|
||||||
|
input: {
|
||||||
|
scheduleId: foundUserDefaultId?.defaultScheduleId,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
throw new Error("NOT_FOUND");
|
throw new Error("NOT_FOUND");
|
||||||
}
|
}
|
||||||
return await getHandler({
|
return await getHandler({
|
||||||
|
@ -37,6 +55,7 @@ export const getScheduleByEventSlugHandler = async ({ ctx, input }: GetOptions)
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
|
console.log(e);
|
||||||
return {
|
return {
|
||||||
id: -1,
|
id: -1,
|
||||||
name: "No schedules found",
|
name: "No schedules found",
|
||||||
|
@ -45,7 +64,6 @@ export const getScheduleByEventSlugHandler = async ({ ctx, input }: GetOptions)
|
||||||
timeZone: ctx.user.timeZone || "Europe/London",
|
timeZone: ctx.user.timeZone || "Europe/London",
|
||||||
workingHours: [],
|
workingHours: [],
|
||||||
isDefault: true,
|
isDefault: true,
|
||||||
hasDefaultSchedule: false, // This is the path that we take if the user has not completed onboarding
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
Loading…
Reference in New Issue