update availability component view

This commit is contained in:
Ryukemeister 2023-12-20 16:13:43 +05:30
parent 8cbcb3fc32
commit 8eaccf83a5

View File

@ -1,19 +1,21 @@
import { LargeScreenCTA } from "availability/cta/large-screen";
import { SmallScreenCTA } from "availability/cta/small-screen";
import { useClientSchedule } from "availability/hooks/useClientSchedule";
import { useProfileInfo } from "availability/hooks/useProfileInfo";
import { Timezone } from "availability/timezone";
import { Troubleshooter } from "availability/troubleshooter";
import { useState } from "react";
import { useForm, Controller } from "react-hook-form";
import { Fragment } from "react";
import Shell from "@calcom/features/shell/Shell";
import { availabilityAsString } from "@calcom/lib/availability";
import type { Schedule as ScheduleType, TimeRange } from "@calcom/types/schedule";
import { SkeletonText, VerticalDivider, Button, Form } from "@calcom/ui";
import { MoreVertical } from "@calcom/ui/components/icon";
import {
Badge,
Button,
Dropdown,
DropdownMenuContent,
DropdownMenuItem,
DropdownItem,
DropdownMenuTrigger,
showToast,
} from "@calcom/ui";
import { Globe, MoreHorizontal, Star, Copy, Trash } from "@calcom/ui/components/icon";
import EditableHeading from "../../../../apps/web/components/ui/EditableHeading";
import { useApiKey } from "../cal-provider";
export type AvailabilityFormValues = {
@ -26,24 +28,20 @@ export type AvailabilityFormValues = {
type AvailabilityProps = {
id?: string;
isDeletable?: boolean;
};
export function Availability({ id }: AvailabilityProps) {
export function Availability({ id, isDeletable = true }: AvailabilityProps) {
const { key, error } = useApiKey();
// if user doesnt provide a scheduleId we use the default schedule id
// since we know there will always be one default schedule so schedule cant be empty
const { isLoading, data: schedule } = useClientSchedule(id ? id : "1", key);
const user = useProfileInfo(key);
const { timeFormat } = user.data || { timeFormat: null };
const [openSidebar, setOpenSidebar] = useState(false);
const form = useForm<AvailabilityFormValues>({
values: schedule && {
...schedule,
schedule: schedule?.availability || [],
},
});
const displayOptions = {
hour12: user.data?.timeFormat ? user.data.timeFormat === 12 : undefined,
timeZone: user.data?.timeZone,
};
if (error === "no_key") return <>You havent entered a key</>;
@ -52,67 +50,90 @@ export function Availability({ id }: AvailabilityProps) {
if (isLoading) return <>Loading...</>;
return (
<Shell
title={schedule?.name ? `${schedule.name} | Availability` : "Availability"}
heading={
<Controller
control={form.control}
name="name"
render={({ field }) => (
<EditableHeading isReady={!isLoading} {...field} data-testid="availablity-title" />
<div className="hover:bg-muted flex items-center justify-between py-5 transition ltr:pl-4 rtl:pr-4 sm:ltr:pl-0 sm:rtl:pr-0">
<div className="group flex w-full items-center justify-between sm:px-6">
<div className="space-x-2 rtl:space-x-reverse">
<span className="text-emphasis truncate font-medium">{schedule.name}</span>
{schedule.isDefault && (
<Badge variant="success" className="text-xs">
Default
</Badge>
)}
/>
}
subtitle={
schedule ? (
schedule.schedule
</div>
<p className="text-subtle mt-1">
{schedule.availability
.filter((availability: any) => !!availability.days.length)
.map((availability: any) => (
<span key={availability.id}>
{availabilityAsString(availability, { hour12: timeFormat === 12 })}
<Fragment key={availability.id}>
{availabilityAsString(availability, {
hour12: displayOptions?.hour12,
})}
<br />
</span>
))
) : (
<SkeletonText className="h-4 w-48" />
)
}
CTA={
<div className="flex items-center justify-end">
<LargeScreenCTA
isSwitchDisabled={isLoading || schedule?.isDefault}
isSwitchChecked={form.watch("isDefault")}
onSwitchCheckedChange={(e) => {
form.setValue("isDefault", e);
}}
/>
<VerticalDivider className="hidden sm:inline" />
<SmallScreenCTA isSidebarOpen={openSidebar} toggleSidebar={() => setOpenSidebar(false)} />
<div className="border-default border-l-2" />
<Button className="ml-4 lg:ml-0" type="submit" form="availability-form">
Save
</Button>
</Fragment>
))}
{(schedule.timeZone || displayOptions?.timeZone) && (
<p className="my-1 flex items-center first-letter:text-xs">
<Globe className="h-3.5 w-3.5" />
&nbsp;{schedule.timeZone ?? displayOptions?.timeZone}
</p>
)}
</p>
</div>
<Dropdown>
<DropdownMenuTrigger asChild>
<Button
className="ml-3 sm:hidden"
StartIcon={MoreVertical}
data-testid="schedule-more"
className="mx-5"
type="button"
variant="icon"
color="secondary"
onClick={() => setOpenSidebar(true)}
StartIcon={MoreHorizontal}
/>
</div>
}>
<div className="mt-4 w-full md:mt-0">
<Form form={form} id="availability-form" className="flex flex-col sm:mx-0 xl:flex-row xl:space-x-6">
<div className="flex-1 flex-row xl:mr-0" />
<div className="min-w-40 col-span-3 hidden space-y-2 md:block lg:col-span-1">
<div className="xl:max-w-80 w-full pr-4 sm:ml-0 sm:mr-36 sm:p-0">
<Timezone />
<hr className="border-subtle my-6 mr-8" />
<Troubleshooter isDisplayBlock={false} />
</div>
</div>
</Form>
</div>
</Shell>
</DropdownMenuTrigger>
{!isLoading && schedule && (
<DropdownMenuContent>
<DropdownMenuItem className="min-w-40 focus:ring-muted">
{!schedule.isDefault && (
<DropdownItem
type="button"
StartIcon={Star}
onClick={() => {
// set to default function goes here
}}>
Set as default
</DropdownItem>
)}
</DropdownMenuItem>
<DropdownMenuItem className="outline-none">
<DropdownItem
type="button"
data-testid={`schedule-duplicate${schedule.id}`}
StartIcon={Copy}
onClick={() => {
// duplication function goes here
}}>
Duplicate
</DropdownItem>
</DropdownMenuItem>
<DropdownMenuItem className="min-w-40 focus:ring-muted">
<DropdownItem
type="button"
color="destructive"
StartIcon={Trash}
data-testid="delete-schedule"
onClick={() => {
if (!isDeletable) {
showToast("You are required to have at least one schedule", "error");
} else {
// deletion function goes here
}
}}>
Delete
</DropdownItem>
</DropdownMenuItem>
</DropdownMenuContent>
)}
</Dropdown>
</div>
);
}