feat: add date overrides to availability settings atom (#15459)

* remove console.log

* fixup: logic to convert overrides was not calling functions

* refactor handleSubmit function

* add portal to platform dialog component

* cleanup

* add props to enable and disable date overrides

* show date overrides for availability settings atom

* fix: date overrides formatting for api request

---------

Co-authored-by: Rajiv Sahal <rajivsahal@Rajivs-MacBook-Pro.local>
Co-authored-by: supalarry <laurisskraucis@gmail.com>
Co-authored-by: Morgan <33722304+ThyMinimalDev@users.noreply.github.com>
This commit is contained in:
Rajiv Sahal
2024-06-19 12:19:25 +00:00
committed by GitHub
co-authored by Rajiv Sahal supalarry Morgan
parent 87d2ec9e75
commit d2d7453962
7 changed files with 74 additions and 50 deletions
@@ -108,11 +108,18 @@ const DateOverrideForm = ({
<Form
form={form}
handleSubmit={(values) => {
if (selectedDates.length === 0) return;
const datesInRanges: TimeRange[] = [];
if (!datesUnavailable) {
if (selectedDates.length === 0) return;
if (datesUnavailable) {
selectedDates.map((date) => {
datesInRanges.push({
start: date.utc(true).startOf("day").toDate(),
end: date.utc(true).startOf("day").toDate(),
});
});
} else {
selectedDates.map((date) => {
values.range.map((item) => {
datesInRanges.push({
@@ -127,16 +134,7 @@ const DateOverrideForm = ({
});
}
onChange(
datesUnavailable
? selectedDates.map((date) => {
return {
start: date.utc(true).startOf("day").toDate(),
end: date.utc(true).startOf("day").toDate(),
};
})
: datesInRanges
);
onChange(datesInRanges);
setSelectedDates([]);
}}
className="p-6 sm:flex sm:p-0 xl:flex-row">
@@ -89,6 +89,7 @@ type AvailabilitySettingsProps = {
isPlatform?: boolean;
customClassNames?: CustomClassNames;
disableEditableHeading?: boolean;
enableOverrides?: boolean;
};
const DeleteDialogButton = ({
@@ -234,6 +235,7 @@ export function AvailabilitySettings({
isPlatform = false,
customClassNames,
disableEditableHeading = false,
enableOverrides = false,
}: AvailabilitySettingsProps) {
const [openSidebar, setOpenSidebar] = useState(false);
const { t, i18n } = useLocale();
@@ -248,7 +250,6 @@ export function AvailabilitySettings({
useEffect(() => {
const subscription = form.watch(
(value, { name }) => {
console.log(name);
if (!!name && name.split(".")[0] !== "schedule" && name !== "name")
handleSubmit(value as AvailabilityFormValues);
},
@@ -507,23 +508,17 @@ export function AvailabilitySettings({
)}
</div>
</div>
{!isPlatform ? (
<div className="border-subtle my-6 rounded-md border">
{schedule?.workingHours && (
<DateOverride
workingHours={schedule.workingHours}
userTimeFormat={timeFormat}
travelSchedules={travelSchedules}
weekStart={
["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"].indexOf(
weekStart
) as 0 | 1 | 2 | 3 | 4 | 5 | 6
}
/>
)}
</div>
) : (
<></>
{enableOverrides && (
<DateOverride
workingHours={schedule.workingHours}
userTimeFormat={timeFormat}
travelSchedules={travelSchedules}
weekStart={
["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"].indexOf(
weekStart
) as 0 | 1 | 2 | 3 | 4 | 5 | 6
}
/>
)}
</div>
<div className="min-w-40 col-span-3 hidden space-y-2 md:block lg:col-span-1">
@@ -12,11 +12,7 @@ export function transformAtomScheduleForApi(body: AvailabilityFormValues): Updat
const overrides =
dateOverrides.flatMap(
(dateOverridesRanges) =>
dateOverridesRanges?.ranges?.map((range) => ({
date: `${range.start.getUTCFullYear}-${range.start.getUTCMonth}-${range.start.getUTCDate}`,
startTime: `${range.start.getUTCHours}-${range.start.getUTCMinutes}`,
endTime: `${range.end.getUTCHours}-${range.end.getUTCMinutes}`,
})) ?? []
dateOverridesRanges?.ranges?.map((range) => transfromAtomOverrideForApi(range)) ?? []
) ?? [];
const availability = formatScheduleTime(schedule);
@@ -24,6 +20,32 @@ export function transformAtomScheduleForApi(body: AvailabilityFormValues): Updat
return { name, timeZone, isDefault, availability, overrides };
}
type AtomDateOverride = {
start: Date;
end: Date;
};
function transfromAtomOverrideForApi(override: AtomDateOverride) {
const date = `${override.start.getUTCFullYear()}-${(override.start.getUTCMonth() + 1)
.toString()
.padStart(2, "0")}-${override.start.getUTCDate().toString().padStart(2, "0")}`;
return {
date,
startTime: padHoursMinutesWithZeros(`${override.start.getUTCHours()}:${override.start.getUTCMinutes()}`),
endTime: padHoursMinutesWithZeros(`${override.end.getUTCHours()}:${override.end.getUTCMinutes()}`),
};
}
function padHoursMinutesWithZeros(hhMM: string) {
const [hours, minutes] = hhMM.split(":");
const formattedHours = hours.padStart(2, "0");
const formattedMinutes = minutes.padStart(2, "0");
return `${formattedHours}:${formattedMinutes}`;
}
function formatScheduleTime(
weekSchedule: AvailabilityFormValues["schedule"]
): UpdateScheduleInput_2024_06_11["availability"] {
@@ -26,6 +26,7 @@ type AvailabilitySettingsPlatformWrapperProps = {
onDeleteSuccess?: (res: ApiResponse) => void;
onDeleteError?: (err: ApiErrorResponse) => void;
disableEditableHeading?: boolean;
enableOverrides?: boolean;
};
export const AvailabilitySettingsPlatformWrapper = ({
@@ -36,6 +37,7 @@ export const AvailabilitySettingsPlatformWrapper = ({
onUpdateError,
onUpdateSuccess,
disableEditableHeading = false,
enableOverrides = false,
}: AvailabilitySettingsPlatformWrapperProps) => {
const { isLoading, data: schedule } = useSchedule(id);
const { data: schedules } = useSchedules();
@@ -99,6 +101,7 @@ export const AvailabilitySettingsPlatformWrapper = ({
}}
weekStart="Sunday"
timeFormat={timeFormat}
enableOverrides={enableOverrides}
isLoading={isLoading}
schedule={{
name: atomSchedule.name,
@@ -86,6 +86,7 @@ export const AvailabilitySettingsWebWrapper = () => {
isDeleting={deleteMutation.isPending}
isLoading={isPending}
isSaving={updateMutation.isPending}
enableOverrides={true}
timeFormat={timeFormat}
weekStart={me.data?.weekStart || "Sunday"}
backPath={fromEventType ? true : "/availability"}
@@ -33,20 +33,24 @@ const DialogContent = React.forwardRef<
React.ComponentPropsWithoutRef<typeof DialogPrimitive.Content>
>(({ className, children, ...props }, ref) => (
<>
<DialogOverlay />
<DialogPrimitive.Content
ref={ref}
className={cn(
"bg-background data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[state=closed]:slide-out-to-left-1/2 data-[state=closed]:slide-out-to-top-[48%] data-[state=open]:slide-in-from-left-1/2 data-[state=open]:slide-in-from-top-[48%] fixed left-[50%] top-[50%] z-50 grid w-full max-w-lg translate-x-[-50%] translate-y-[-50%] gap-4 border p-6 shadow-lg duration-200 sm:rounded-lg",
className
)}
{...props}>
{children}
<DialogPrimitive.Close className="ring-offset-background focus:ring-ring data-[state=open]:bg-accent data-[state=open]:text-muted-foreground absolute right-4 top-4 rounded-sm opacity-70 transition-opacity hover:opacity-100 focus:outline-none focus:ring-2 focus:ring-offset-2 disabled:pointer-events-none">
<Icon name="x" className="h-4 w-4" />
<span className="sr-only">Close</span>
</DialogPrimitive.Close>
</DialogPrimitive.Content>
<DialogPortal>
<div className="calcom-atoms">
<DialogOverlay />
<DialogPrimitive.Content
ref={ref}
className={cn(
"bg-background data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[state=closed]:slide-out-to-left-1/2 data-[state=closed]:slide-out-to-top-[48%] data-[state=open]:slide-in-from-left-1/2 data-[state=open]:slide-in-from-top-[48%] fixed left-[50%] top-[50%] z-50 grid w-full max-w-lg translate-x-[-50%] translate-y-[-50%] gap-4 border p-6 shadow-lg duration-200 sm:rounded-lg",
className
)}
{...props}>
{children}
<DialogPrimitive.Close className="ring-offset-background focus:ring-ring data-[state=open]:bg-accent data-[state=open]:text-muted-foreground absolute right-4 top-4 rounded-sm opacity-70 transition-opacity hover:opacity-100 focus:outline-none focus:ring-2 focus:ring-offset-2 disabled:pointer-events-none">
<Icon name="x" className="h-4 w-4" />
<span className="sr-only">Close</span>
</DialogPrimitive.Close>
</DialogPrimitive.Content>
</div>
</DialogPortal>
</>
));
DialogContent.displayName = DialogPrimitive.Content.displayName;
@@ -11,6 +11,7 @@ export default function Availability(props: { calUsername: string; calEmail: str
<Navbar username={props.calUsername} />
<div>
<AvailabilitySettings
enableOverrides={true}
customClassNames={{
subtitlesClassName: "text-red-500",
ctaClassName: "border p-4 rounded-md",