update availability component view
This commit is contained in:
parent
8cbcb3fc32
commit
8eaccf83a5
|
@ -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" />
|
||||
{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>
|
||||
);
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue
Block a user