Store more event info than just slug

feat/troubleshooter-v2
Sean Brydon 2023-10-26 10:17:57 +01:00
parent 61eb439fa0
commit 2904230009
4 changed files with 86 additions and 58 deletions

View File

@ -1,18 +1,22 @@
import Link from "next/link";
import { useLocale } from "@calcom/lib/hooks/useLocale";
import { trpc } from "@calcom/trpc/react";
import { Label } from "@calcom/ui";
import { Badge, Label } from "@calcom/ui";
import { useTroubleshooterStore } from "../store";
import { TroubleshooterListItemHeader } from "./TroubleshooterListItemContainer";
export function EventScheduleItem() {
const selectedEventType = useTroubleshooterStore((state) => state.eventSlug);
const { t } = useLocale();
const selectedEventType = useTroubleshooterStore((state) => state.event);
const { data: schedule, isLoading } = trpc.viewer.availability.schedule.getScheduleByEventSlug.useQuery(
const { data: schedule } = trpc.viewer.availability.schedule.getScheduleByEventSlug.useQuery(
{
eventSlug: selectedEventType as string, // Only enabled when selectedEventType is not null
eventSlug: selectedEventType?.slug as string,
},
{
enabled: !!selectedEventType,
enabled: !!selectedEventType?.slug,
}
);
@ -20,9 +24,18 @@ export function EventScheduleItem() {
<div>
<Label>Availability Schedule</Label>
<TroubleshooterListItemHeader
className="rounded-md border-b " // Target paragraph inside nested children to make medium (saves us from creating a new component)
className="group rounded-md border-b"
prefixSlot={<div className="w-4 rounded-[4px] bg-black" />}
title={schedule?.name ?? "Loading"}
suffixSlot={
schedule && (
<Link href={`/availability/${schedule.id}`} className="inline-flex">
<Badge color="orange" size="sm" className="hidden hover:cursor-pointer group-hover:inline-flex">
{t("edit")}
</Badge>
</Link>
)
}
/>
</div>
);

View File

@ -1,40 +1,39 @@
import { useMemo, useEffect } from "react";
import { useMemo } from "react";
import { trpc } from "@calcom/trpc";
import { SelectField } from "@calcom/ui";
import { getQueryParam } from "../../bookings/Booker/utils/query-param";
import { useTroubleshooterStore } from "../store";
export function EventTypeSelect() {
const { data: eventTypes } = trpc.viewer.eventTypes.list.useQuery();
const selectedEventType = useTroubleshooterStore((state) => state.eventSlug);
const setSelectedEventType = useTroubleshooterStore((state) => state.setEventSlug);
const selectedEventType = useTroubleshooterStore((state) => state.event);
const setSelectedEventType = useTroubleshooterStore((state) => state.setEvent);
const selectedEventQueryParam = getQueryParam("eventType");
// const selectedEventQueryParam = getQueryParam("eventType");
const options = useMemo(() => {
if (!eventTypes) return [];
return eventTypes.map((e) => ({
label: e.title,
value: e.slug,
id: e.id,
duration: e.length,
}));
}, [eventTypes]);
useEffect(() => {
if (selectedEventQueryParam !== selectedEventType && selectedEventQueryParam) {
setSelectedEventType(selectedEventQueryParam);
}
}, [selectedEventQueryParam, selectedEventType, setSelectedEventType]);
return (
<SelectField
label="Event Type"
options={options}
value={options.find((option) => option.value === selectedEventType) || options[0]}
value={options.find((option) => option.value === selectedEventType?.slug) || options[0]}
onChange={(option) => {
if (!option) return;
setSelectedEventType(option.value);
setSelectedEventType({
slug: option.value,
id: option.id,
duration: option.duration,
});
}}
/>
);

View File

@ -3,62 +3,72 @@ import { useMemo } from "react";
import dayjs from "@calcom/dayjs";
import { Calendar } from "@calcom/features/calendars/weeklyview";
import { BookingStatus } from "@calcom/prisma/enums";
import { trpc } from "@calcom/trpc/react";
import type { CalendarAvailableTimeslots } from "@calcom/features/calendars/weeklyview/types/state";
import { useTimePreferences } from "../../bookings/lib/timePreferences";
import { useSchedule } from "../../schedules/lib/use-schedule";
import { useTroubleshooterStore } from "../store";
export const LargeCalendar = ({ extraDays }: { extraDays: number }) => {
const { timezone } = useTimePreferences();
const selectedDate = useTroubleshooterStore((state) => state.selectedDate);
const event = useTroubleshooterStore((state) => state.event);
const { data: session } = useSession();
const date = selectedDate ? dayjs(selectedDate) : dayjs();
const { data: schedule } = useSchedule({
username: session?.user.username || "",
eventSlug: eventSlug,
eventId: event.data?.id ?? eventId,
monthCount,
rescheduleUid,
eventSlug: event?.slug,
eventId: event?.id,
timezone,
month: date.format("YYYY-MM"),
});
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 endDate = dayjs(startDate)
.add(extraDays - 1, "day")
.toDate();
const events = useMemo(() => {
if (!data?.busy) return [];
return data?.busy.map((event, idx) => {
return {
id: idx,
title: event.title ?? "Busy",
start: new Date(event.start),
end: new Date(event.end),
options: {
borderColor: "#F97417",
status: BookingStatus.ACCEPTED,
},
};
});
}, [data]);
const availableSlots = useMemo(() => {
const availableTimeslots: CalendarAvailableTimeslots = {};
if (!schedule) return availableTimeslots;
if (!schedule?.slots) return availableTimeslots;
for (const day in schedule.slots) {
availableTimeslots[day] = schedule.slots[day].map((slot) => ({
start: dayjs(slot.time).toDate(),
end: dayjs(slot.time)
.add(event?.duration ?? 30, "minutes")
.toDate(),
}));
}
return availableTimeslots;
}, [schedule, event]);
// const events = useMemo(() => {
// if (!data?.busy) return [];
// return data?.busy.map((event, idx) => {
// return {
// id: idx,
// title: event.title ?? "Busy",
// start: new Date(event.start),
// end: new Date(event.end),
// options: {
// borderColor: "#F97417",
// status: BookingStatus.ACCEPTED,
// },
// };
// });
// }, [data]);
return (
<div className="h-full [--calendar-dates-sticky-offset:66px]">
<Calendar
startHour={0}
endHour={23}
events={events}
events={[]}
availableTimeslots={availableSlots}
startDate={startDate}
endDate={endDate}
gridCellsPerHour={60 / 15}

View File

@ -13,9 +13,15 @@ type StoreInitializeType = {
month: string | null;
};
type EventType = {
id: number;
slug: string;
duration: number;
};
export type TroubleshooterStore = {
eventSlug: string | null;
setEventSlug: (eventSlug: string | null) => void;
event: EventType | null;
setEvent: (eventSlug: EventType) => void;
month: string | null;
setMonth: (month: string | null) => void;
selectedDate: string | null;
@ -64,10 +70,10 @@ export const useTroubleshooterStore = create<TroubleshooterStore>((set, get) =>
set({ selectedDate: newSelectionFormatted });
updateQueryParam("date", newSelectionFormatted);
},
eventSlug: null,
setEventSlug: (eventSlug: string | null) => {
set({ eventSlug });
updateQueryParam("eventType", eventSlug ?? "");
event: null,
setEvent: (event: EventType) => {
set({ event });
updateQueryParam("eventType", event.slug ?? "");
},
month: getQueryParam("month") || getQueryParam("date") || dayjs().format("YYYY-MM"),
setMonth: (month: string | null) => {