first commit
This commit is contained in:
@@ -0,0 +1,38 @@
|
||||
import { useLocale } from "@calcom/lib/hooks/useLocale";
|
||||
import { Badge, Button, Switch } from "@calcom/ui";
|
||||
|
||||
import { TroubleshooterListItemContainer } from "./TroubleshooterListItemContainer";
|
||||
|
||||
function AvailabiltyItem() {
|
||||
const { t } = useLocale();
|
||||
return (
|
||||
<TroubleshooterListItemContainer
|
||||
title="Office Hours"
|
||||
subtitle="Mon-Fri; 9:00 AM - 5:00 PM"
|
||||
suffixSlot={
|
||||
<div>
|
||||
<Badge variant="green" withDot size="sm">
|
||||
Connected
|
||||
</Badge>
|
||||
</div>
|
||||
}>
|
||||
<div className="flex flex-col gap-3">
|
||||
<p className="text-subtle text-sm font-medium leading-none">{t("date_overrides")}</p>
|
||||
<Switch label="google@calendar.com" />
|
||||
</div>
|
||||
</TroubleshooterListItemContainer>
|
||||
);
|
||||
}
|
||||
|
||||
export function AvailabiltySchedulesContainer() {
|
||||
const { t } = useLocale();
|
||||
return (
|
||||
<div className="flex flex-col space-y-3">
|
||||
<p className="text-sm font-medium leading-none">{t("availabilty_schedules")}</p>
|
||||
<AvailabiltyItem />
|
||||
<Button color="secondary" className="justify-center gap-2">
|
||||
{t("manage_availabilty_schedules")}
|
||||
</Button>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,122 @@
|
||||
import { useLocale } from "@calcom/lib/hooks/useLocale";
|
||||
import { trpc } from "@calcom/trpc/react";
|
||||
import { Badge, Button, Switch } from "@calcom/ui";
|
||||
|
||||
import { TroubleshooterListItemContainer } from "./TroubleshooterListItemContainer";
|
||||
|
||||
const SELECTION_COLORS = ["#f97316", "#84cc16", "#06b6d4", "#8b5cf6", "#ec4899", "#f43f5e"];
|
||||
|
||||
interface CalendarToggleItemProps {
|
||||
title: string;
|
||||
subtitle: string;
|
||||
colorDot?: string;
|
||||
status: "connected" | "not_found";
|
||||
calendars?: {
|
||||
active?: boolean;
|
||||
name?: string;
|
||||
}[];
|
||||
}
|
||||
function CalendarToggleItem(props: CalendarToggleItemProps) {
|
||||
const badgeStatus = props.status === "connected" ? "green" : "orange";
|
||||
const badgeText = props.status === "connected" ? "Connected" : "Not found";
|
||||
return (
|
||||
<TroubleshooterListItemContainer
|
||||
title={props.title}
|
||||
subtitle={props.subtitle}
|
||||
prefixSlot={
|
||||
<>
|
||||
<div
|
||||
className="h-4 w-4 self-center rounded-[4px]"
|
||||
style={{
|
||||
backgroundColor: props.colorDot,
|
||||
}}
|
||||
/>
|
||||
</>
|
||||
}
|
||||
suffixSlot={
|
||||
<div>
|
||||
<Badge variant={badgeStatus} withDot size="sm">
|
||||
{badgeText}
|
||||
</Badge>
|
||||
</div>
|
||||
}>
|
||||
<div className="[&>*]:text-emphasis flex flex-col gap-3">
|
||||
{props.calendars?.map((calendar) => {
|
||||
return <Switch key={calendar.name} checked={calendar.active} label={calendar.name} disabled />;
|
||||
})}
|
||||
</div>
|
||||
</TroubleshooterListItemContainer>
|
||||
);
|
||||
}
|
||||
|
||||
function EmptyCalendarToggleItem() {
|
||||
const { t } = useLocale();
|
||||
|
||||
return (
|
||||
<TroubleshooterListItemContainer
|
||||
title={t("installed", { count: 0 })}
|
||||
subtitle={t("please_install_a_calendar")}
|
||||
prefixSlot={
|
||||
<>
|
||||
<div className="h-4 w-4 self-center rounded-[4px] bg-blue-500" />
|
||||
</>
|
||||
}
|
||||
suffixSlot={
|
||||
<div>
|
||||
<Badge variant="orange" withDot size="sm">
|
||||
{t("unavailable")}
|
||||
</Badge>
|
||||
</div>
|
||||
}>
|
||||
<div className="flex flex-col gap-3">
|
||||
<Button color="secondary" className="justify-center gap-2" href="/apps/categories/calendar">
|
||||
{t("install_calendar")}
|
||||
</Button>
|
||||
</div>
|
||||
</TroubleshooterListItemContainer>
|
||||
);
|
||||
}
|
||||
|
||||
export function CalendarToggleContainer() {
|
||||
const { t } = useLocale();
|
||||
const { data, isLoading } = trpc.viewer.connectedCalendars.useQuery();
|
||||
|
||||
const hasConnectedCalendars = data && data?.connectedCalendars.length > 0;
|
||||
|
||||
return (
|
||||
<div className="flex flex-col space-y-3">
|
||||
<p className="text-sm font-medium leading-none">{t("calendars_were_checking_for_conflicts")}</p>
|
||||
{hasConnectedCalendars && !isLoading ? (
|
||||
<>
|
||||
{data.connectedCalendars.map((calendar) => {
|
||||
const foundPrimary = calendar.calendars?.find((item) => item.primary);
|
||||
// Will be used when getAvailbility is modified to use externalId instead of appId for source.
|
||||
// const color = SELECTION_COLORS[idx] || "#000000";
|
||||
// // Add calendar to color map using externalId (what we use on the backend to determine source)
|
||||
// addToColorMap(foundPrimary?.externalId, color);
|
||||
return (
|
||||
<CalendarToggleItem
|
||||
key={calendar.credentialId}
|
||||
title={calendar.integration.name}
|
||||
colorDot="#000000"
|
||||
subtitle={foundPrimary?.name ?? "Nameless Calendar"}
|
||||
status={calendar.error ? "not_found" : "connected"}
|
||||
calendars={calendar.calendars?.map((item) => {
|
||||
return {
|
||||
active: item.isSelected,
|
||||
name: item.name,
|
||||
};
|
||||
})}
|
||||
/>
|
||||
);
|
||||
})}
|
||||
<Button color="secondary" className="justify-center gap-2" href="/settings/my-account/calendars">
|
||||
{t("manage_calendars")}
|
||||
</Button>
|
||||
</>
|
||||
) : (
|
||||
<EmptyCalendarToggleItem />
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
import { useLocale } from "@calcom/lib/hooks/useLocale";
|
||||
import { Badge } from "@calcom/ui";
|
||||
|
||||
import { TroubleshooterListItemHeader } from "./TroubleshooterListItemContainer";
|
||||
|
||||
function ConnectedAppsItem() {
|
||||
return (
|
||||
<TroubleshooterListItemHeader
|
||||
title="Google Cal"
|
||||
subtitle="google@calendar.com"
|
||||
prefixSlot={
|
||||
<>
|
||||
<div className="h-4 w-4 self-center rounded-[4px] bg-blue-500" />
|
||||
</>
|
||||
}
|
||||
suffixSlot={
|
||||
<div>
|
||||
<Badge variant="green" withDot size="sm">
|
||||
Connected
|
||||
</Badge>
|
||||
</div>
|
||||
}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
export function ConnectedAppsContainer() {
|
||||
const { t } = useLocale();
|
||||
return (
|
||||
<div className="flex flex-col space-y-3">
|
||||
<p className="text-sm font-medium leading-none">{t("other_apps")}</p>
|
||||
<div className="[&>*:first-child]:rounded-t-md [&>*:last-child]:rounded-b-md [&>*:last-child]:border-b">
|
||||
<ConnectedAppsItem />
|
||||
<ConnectedAppsItem />
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
import Link from "next/link";
|
||||
|
||||
import { useLocale } from "@calcom/lib/hooks/useLocale";
|
||||
import { trpc } from "@calcom/trpc/react";
|
||||
import { Badge, Label } from "@calcom/ui";
|
||||
|
||||
import { useTroubleshooterStore } from "../store";
|
||||
import { TroubleshooterListItemHeader } from "./TroubleshooterListItemContainer";
|
||||
|
||||
export function EventScheduleItem() {
|
||||
const { t } = useLocale();
|
||||
const selectedEventType = useTroubleshooterStore((state) => state.event);
|
||||
|
||||
const { data: schedule } = trpc.viewer.availability.schedule.getScheduleByEventSlug.useQuery(
|
||||
{
|
||||
eventSlug: selectedEventType?.slug as string,
|
||||
},
|
||||
{
|
||||
enabled: !!selectedEventType?.slug,
|
||||
}
|
||||
);
|
||||
|
||||
return (
|
||||
<div>
|
||||
<Label>Availability Schedule</Label>
|
||||
<TroubleshooterListItemHeader
|
||||
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>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,74 @@
|
||||
import { useMemo, useEffect, startTransition } 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, isPending } = trpc.viewer.eventTypes.list.useQuery();
|
||||
const selectedEventType = useTroubleshooterStore((state) => state.event);
|
||||
const setSelectedEventType = useTroubleshooterStore((state) => state.setEvent);
|
||||
|
||||
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 (!selectedEventType && eventTypes && eventTypes[0] && !selectedEventQueryParam) {
|
||||
const { id, slug, length } = eventTypes[0];
|
||||
setSelectedEventType({
|
||||
id,
|
||||
slug,
|
||||
duration: length,
|
||||
});
|
||||
}
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [eventTypes]);
|
||||
|
||||
useEffect(() => {
|
||||
if (selectedEventQueryParam) {
|
||||
// ensure that the update is deferred until the Suspense boundary has finished hydrating
|
||||
startTransition(() => {
|
||||
const foundEventType = eventTypes?.find((et) => et.slug === selectedEventQueryParam);
|
||||
if (foundEventType) {
|
||||
const { id, slug, length } = foundEventType;
|
||||
setSelectedEventType({ id, slug, duration: length });
|
||||
} else if (eventTypes && eventTypes[0]) {
|
||||
const { id, slug, length } = eventTypes[0];
|
||||
setSelectedEventType({
|
||||
id,
|
||||
slug,
|
||||
duration: length,
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
}, [eventTypes, selectedEventQueryParam, setSelectedEventType]);
|
||||
|
||||
return (
|
||||
<SelectField
|
||||
label="Event Type"
|
||||
options={options}
|
||||
isDisabled={isPending || options.length === 0}
|
||||
value={options.find((option) => option.value === selectedEventType?.slug) || options[0]}
|
||||
onChange={(option) => {
|
||||
if (!option) return;
|
||||
setSelectedEventType({
|
||||
slug: option.value,
|
||||
id: option.id,
|
||||
duration: option.duration,
|
||||
});
|
||||
}}
|
||||
/>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,143 @@
|
||||
import { useSession } from "next-auth/react";
|
||||
import { useMemo } from "react";
|
||||
|
||||
import dayjs from "@calcom/dayjs";
|
||||
import { Calendar } from "@calcom/features/calendars/weeklyview";
|
||||
import type { CalendarAvailableTimeslots } from "@calcom/features/calendars/weeklyview/types/state";
|
||||
import { BookingStatus } from "@calcom/prisma/enums";
|
||||
import { trpc } from "@calcom/trpc";
|
||||
|
||||
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 calendarToColorMap = useTroubleshooterStore((state) => state.calendarToColorMap);
|
||||
const { data: session } = useSession();
|
||||
const startDate = selectedDate ? dayjs(selectedDate) : dayjs();
|
||||
|
||||
const { data: busyEvents } = trpc.viewer.availability.user.useQuery(
|
||||
{
|
||||
username: session?.user?.username || "",
|
||||
dateFrom: startDate.startOf("day").utc().format(),
|
||||
dateTo: startDate
|
||||
.endOf("day")
|
||||
.add(extraDays - 1, "day")
|
||||
.utc()
|
||||
.format(),
|
||||
withSource: true,
|
||||
},
|
||||
{
|
||||
enabled: !!session?.user?.username,
|
||||
}
|
||||
);
|
||||
|
||||
const { data: schedule } = useSchedule({
|
||||
username: session?.user.username || "",
|
||||
eventSlug: event?.slug,
|
||||
eventId: event?.id,
|
||||
timezone,
|
||||
month: startDate.format("YYYY-MM"),
|
||||
orgSlug: session?.user.org?.slug,
|
||||
});
|
||||
|
||||
const endDate = dayjs(startDate)
|
||||
.add(extraDays - 1, "day")
|
||||
.toDate();
|
||||
|
||||
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 (!busyEvents?.busy) return [];
|
||||
|
||||
// TODO: Add buffer times in here as well just requires a bit of logic for fetching event type and then adding buffer time
|
||||
// start: dayjs(startTime)
|
||||
// .subtract((eventType?.beforeEventBuffer || 0) + (afterEventBuffer || 0), "minute")
|
||||
// .toDate(),
|
||||
// end: dayjs(endTime)
|
||||
// .add((eventType?.afterEventBuffer || 0) + (beforeEventBuffer || 0), "minute")
|
||||
// .toDate(),
|
||||
|
||||
const calendarEvents = busyEvents?.busy.map((event, idx) => {
|
||||
return {
|
||||
id: idx,
|
||||
title: event.title ?? `Busy`,
|
||||
start: new Date(event.start),
|
||||
end: new Date(event.end),
|
||||
options: {
|
||||
borderColor:
|
||||
event.source && calendarToColorMap[event.source] ? calendarToColorMap[event.source] : "black",
|
||||
status: BookingStatus.ACCEPTED,
|
||||
"data-test-id": "troubleshooter-busy-event",
|
||||
},
|
||||
};
|
||||
});
|
||||
|
||||
if (busyEvents.dateOverrides) {
|
||||
busyEvents.dateOverrides.forEach((dateOverride) => {
|
||||
const dateOverrideStart = dayjs(dateOverride.start);
|
||||
const dateOverrideEnd = dayjs(dateOverride.end);
|
||||
|
||||
if (!dateOverrideStart.isSame(dateOverrideEnd)) {
|
||||
return;
|
||||
}
|
||||
|
||||
const dayOfWeekNum = dateOverrideStart.day();
|
||||
|
||||
const workingHoursForDay = busyEvents.workingHours.find((workingHours) =>
|
||||
workingHours.days.includes(dayOfWeekNum)
|
||||
);
|
||||
|
||||
if (!workingHoursForDay) return;
|
||||
|
||||
calendarEvents.push({
|
||||
id: calendarEvents.length,
|
||||
title: "Date Override",
|
||||
start: dateOverrideStart.add(workingHoursForDay.startTime, "minutes").toDate(),
|
||||
end: dateOverrideEnd.add(workingHoursForDay.endTime, "minutes").toDate(),
|
||||
options: {
|
||||
borderColor: "black",
|
||||
status: BookingStatus.ACCEPTED,
|
||||
"data-test-id": "troubleshooter-busy-time",
|
||||
},
|
||||
});
|
||||
});
|
||||
}
|
||||
return calendarEvents;
|
||||
}, [busyEvents, calendarToColorMap]);
|
||||
|
||||
return (
|
||||
<div className="h-full [--calendar-dates-sticky-offset:66px]">
|
||||
<Calendar
|
||||
sortEvents
|
||||
startHour={0}
|
||||
endHour={23}
|
||||
events={events}
|
||||
availableTimeslots={availableSlots}
|
||||
startDate={startDate.toDate()}
|
||||
endDate={endDate}
|
||||
gridCellsPerHour={60 / (event?.duration || 15)}
|
||||
hoverEventDuration={30}
|
||||
hideHeader
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,79 @@
|
||||
import { useMemo } from "react";
|
||||
|
||||
import dayjs from "@calcom/dayjs";
|
||||
import { useLocale } from "@calcom/lib/hooks/useLocale";
|
||||
import { Button, ButtonGroup } from "@calcom/ui";
|
||||
|
||||
import { useTroubleshooterStore } from "../store";
|
||||
|
||||
export function TroubleshooterHeader({ extraDays, isMobile }: { extraDays: number; isMobile: boolean }) {
|
||||
const { t, i18n } = useLocale();
|
||||
const selectedDateString = useTroubleshooterStore((state) => state.selectedDate);
|
||||
const setSelectedDate = useTroubleshooterStore((state) => state.setSelectedDate);
|
||||
const addToSelectedDate = useTroubleshooterStore((state) => state.addToSelectedDate);
|
||||
const selectedDate = selectedDateString ? dayjs(selectedDateString) : dayjs();
|
||||
const today = dayjs();
|
||||
const selectedDateMin3DaysDifference = useMemo(() => {
|
||||
const diff = today.diff(selectedDate, "days");
|
||||
return diff > 3 || diff < -3;
|
||||
}, [today, selectedDate]);
|
||||
|
||||
if (isMobile) return null;
|
||||
|
||||
const endDate = selectedDate.add(extraDays - 1, "days");
|
||||
|
||||
const isSameMonth = () => {
|
||||
return selectedDate.format("MMM") === endDate.format("MMM");
|
||||
};
|
||||
|
||||
const isSameYear = () => {
|
||||
return selectedDate.format("YYYY") === endDate.format("YYYY");
|
||||
};
|
||||
const formattedMonth = new Intl.DateTimeFormat(i18n.language, { month: "short" });
|
||||
const FormattedSelectedDateRange = () => {
|
||||
return (
|
||||
<h3 className="min-w-[150px] text-base font-semibold leading-4">
|
||||
{formattedMonth.format(selectedDate.toDate())} {selectedDate.format("D")}
|
||||
{!isSameYear() && <span className="text-subtle">, {selectedDate.format("YYYY")} </span>}-{" "}
|
||||
{!isSameMonth() && formattedMonth.format(endDate.toDate())} {endDate.format("D")},{" "}
|
||||
<span className="text-subtle">
|
||||
{isSameYear() ? selectedDate.format("YYYY") : endDate.format("YYYY")}
|
||||
</span>
|
||||
</h3>
|
||||
);
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="border-default relative z-10 flex border-b px-5 py-4 ltr:border-l rtl:border-r">
|
||||
<div className="flex items-center gap-5 rtl:flex-grow">
|
||||
<FormattedSelectedDateRange />
|
||||
<ButtonGroup>
|
||||
<Button
|
||||
className="group rtl:ml-1 rtl:rotate-180"
|
||||
variant="icon"
|
||||
color="minimal"
|
||||
StartIcon="chevron-left"
|
||||
aria-label="Previous Day"
|
||||
onClick={() => addToSelectedDate(-extraDays)}
|
||||
/>
|
||||
<Button
|
||||
className="group rtl:mr-1 rtl:rotate-180"
|
||||
variant="icon"
|
||||
color="minimal"
|
||||
StartIcon="chevron-right"
|
||||
aria-label="Next Day"
|
||||
onClick={() => addToSelectedDate(extraDays)}
|
||||
/>
|
||||
{selectedDateMin3DaysDifference && (
|
||||
<Button
|
||||
className="capitalize ltr:ml-2 rtl:mr-2"
|
||||
color="secondary"
|
||||
onClick={() => setSelectedDate(today.format("YYYY-MM-DD"))}>
|
||||
{t("today")}
|
||||
</Button>
|
||||
)}
|
||||
</ButtonGroup>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
import type { PropsWithChildren } from "react";
|
||||
|
||||
import classNames from "@calcom/lib/classNames";
|
||||
|
||||
interface TroubleshooterListItemContainerProps {
|
||||
title: string;
|
||||
subtitle?: string;
|
||||
suffixSlot?: React.ReactNode;
|
||||
prefixSlot?: React.ReactNode;
|
||||
className?: string;
|
||||
}
|
||||
|
||||
export function TroubleshooterListItemHeader({
|
||||
prefixSlot,
|
||||
title,
|
||||
subtitle,
|
||||
suffixSlot,
|
||||
className,
|
||||
}: TroubleshooterListItemContainerProps) {
|
||||
return (
|
||||
<div className={classNames("border-subtle flex max-w-full gap-3 border border-b-0 px-4 py-2", className)}>
|
||||
{prefixSlot}
|
||||
<div className="flex h-full max-w-full flex-1 flex-col flex-nowrap truncate text-sm leading-4">
|
||||
<p className="font-medium">{title}</p>
|
||||
{subtitle && <p className="font-normal">{subtitle}</p>}
|
||||
</div>
|
||||
{suffixSlot}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export function TroubleshooterListItemContainer({
|
||||
children,
|
||||
...rest
|
||||
}: PropsWithChildren<TroubleshooterListItemContainerProps>) {
|
||||
return (
|
||||
<div className="[&>*:first-child]:rounded-t-md ">
|
||||
<TroubleshooterListItemHeader {...rest} />
|
||||
<div className="border-subtle flex flex-col space-y-3 rounded-b-md border p-4">{children}</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
import Link from "next/link";
|
||||
|
||||
import { useLocale } from "@calcom/lib/hooks/useLocale";
|
||||
import { Icon, Skeleton } from "@calcom/ui";
|
||||
|
||||
import { CalendarToggleContainer } from "./CalendarToggleContainer";
|
||||
import { EventScheduleItem } from "./EventScheduleItem";
|
||||
import { EventTypeSelect } from "./EventTypeSelect";
|
||||
|
||||
const BackButtonInSidebar = ({ name }: { name: string }) => {
|
||||
return (
|
||||
<Link
|
||||
href="/availability"
|
||||
className="hover:bg-subtle group-hover:text-default text-emphasis group flex h-6 max-h-6 w-full flex-row items-center rounded-md px-3 py-2">
|
||||
<Icon
|
||||
name="arrow-left"
|
||||
className="h-4 w-4 stroke-[2px] ltr:mr-[10px] rtl:ml-[10px] rtl:rotate-180 md:mt-0"
|
||||
/>
|
||||
<Skeleton
|
||||
title={name}
|
||||
as="p"
|
||||
className="max-w-36 min-h-4 truncate font-semibold"
|
||||
loadingClassName="ms-3">
|
||||
{name}
|
||||
</Skeleton>
|
||||
</Link>
|
||||
);
|
||||
};
|
||||
|
||||
export const TroubleshooterSidebar = () => {
|
||||
const { t } = useLocale();
|
||||
|
||||
return (
|
||||
<div className="relative z-10 hidden h-screen w-full flex-col gap-6 overflow-y-auto py-6 pl-4 pr-6 sm:flex md:pl-0">
|
||||
<BackButtonInSidebar name={t("troubleshooter")} />
|
||||
<EventTypeSelect />
|
||||
<EventScheduleItem />
|
||||
<CalendarToggleContainer />
|
||||
</div>
|
||||
);
|
||||
};
|
||||
Reference in New Issue
Block a user