feat: Made booker layout settings more user friendly (#9397)
* Made booker layout settings more user friendly * Fixed tyeps and default values in appearance form for booker layout * Enable all layouts by default
This commit is contained in:
parent
7f13fc58b9
commit
93fc036d2c
|
@ -1,5 +1,6 @@
|
|||
import { useState } from "react";
|
||||
import { Controller, useForm } from "react-hook-form";
|
||||
import type { z } from "zod";
|
||||
|
||||
import { BookerLayoutSelector } from "@calcom/features/settings/BookerLayoutSelector";
|
||||
import ThemeLabel from "@calcom/features/settings/ThemeLabel";
|
||||
|
@ -9,6 +10,7 @@ import { checkWCAGContrastColor } from "@calcom/lib/getBrandColours";
|
|||
import { useHasPaidPlan } from "@calcom/lib/hooks/useHasPaidPlan";
|
||||
import { useLocale } from "@calcom/lib/hooks/useLocale";
|
||||
import { validateBookerLayouts } from "@calcom/lib/validateBookerLayouts";
|
||||
import type { userMetadata } from "@calcom/prisma/zod-utils";
|
||||
import { trpc } from "@calcom/trpc/react";
|
||||
import {
|
||||
Alert,
|
||||
|
@ -64,7 +66,7 @@ const AppearanceView = () => {
|
|||
brandColor: user?.brandColor || "#292929",
|
||||
darkBrandColor: user?.darkBrandColor || "#fafafa",
|
||||
hideBranding: user?.hideBranding,
|
||||
defaultBookerLayouts: user?.defaultBookerLayouts,
|
||||
metadata: user?.metadata as z.infer<typeof userMetadata>,
|
||||
},
|
||||
});
|
||||
|
||||
|
@ -99,7 +101,7 @@ const AppearanceView = () => {
|
|||
<Form
|
||||
form={formMethods}
|
||||
handleSubmit={(values) => {
|
||||
const layoutError = validateBookerLayouts(values.defaultBookerLayouts || null);
|
||||
const layoutError = validateBookerLayouts(values?.metadata?.defaultBookerLayouts || null);
|
||||
if (layoutError) throw new Error(t(layoutError));
|
||||
|
||||
mutation.mutate({
|
||||
|
|
|
@ -5,9 +5,8 @@ import StickyBox from "react-sticky-box";
|
|||
import { shallow } from "zustand/shallow";
|
||||
|
||||
import classNames from "@calcom/lib/classNames";
|
||||
import { useLocale } from "@calcom/lib/hooks/useLocale";
|
||||
import useMediaQuery from "@calcom/lib/hooks/useMediaQuery";
|
||||
import { BookerLayouts, bookerLayoutOptions } from "@calcom/prisma/zod-utils";
|
||||
import { BookerLayouts, defaultBookerLayoutSettings } from "@calcom/prisma/zod-utils";
|
||||
|
||||
import { AvailableTimeSlots } from "./components/AvailableTimeSlots";
|
||||
import { BookEventForm } from "./components/BookEventForm";
|
||||
|
@ -35,7 +34,6 @@ const BookerComponent = ({
|
|||
rescheduleBooking,
|
||||
hideBranding = false,
|
||||
}: BookerProps) => {
|
||||
const { t } = useLocale();
|
||||
const isMobile = useMediaQuery("(max-width: 768px)");
|
||||
const isTablet = useMediaQuery("(max-width: 1024px)");
|
||||
const timeslotsRef = useRef<HTMLDivElement>(null);
|
||||
|
@ -51,10 +49,7 @@ const BookerComponent = ({
|
|||
shallow
|
||||
);
|
||||
const extraDays = layout === BookerLayouts.COLUMN_VIEW ? (isTablet ? 2 : 4) : 0;
|
||||
const bookerLayouts = event.data?.profile?.bookerLayouts || {
|
||||
defaultLayout: BookerLayouts.MONTH_VIEW,
|
||||
enabledLayouts: bookerLayoutOptions,
|
||||
};
|
||||
const bookerLayouts = event.data?.profile?.bookerLayouts || defaultBookerLayoutSettings;
|
||||
|
||||
const animationScope = useBookerResizeAnimation(layout, bookerState);
|
||||
|
||||
|
|
|
@ -7,7 +7,7 @@ import { Controller, useFormContext } from "react-hook-form";
|
|||
import { useFlagMap } from "@calcom/features/flags/context/provider";
|
||||
import { classNames } from "@calcom/lib";
|
||||
import { useLocale } from "@calcom/lib/hooks/useLocale";
|
||||
import { BookerLayouts } from "@calcom/prisma/zod-utils";
|
||||
import { BookerLayouts, defaultBookerLayoutSettings } from "@calcom/prisma/zod-utils";
|
||||
import { bookerLayoutOptions, type BookerLayoutSettings } from "@calcom/prisma/zod-utils";
|
||||
import useMeQuery from "@calcom/trpc/react/hooks/useMeQuery";
|
||||
import { Label, Checkbox, Button } from "@calcom/ui";
|
||||
|
@ -85,19 +85,28 @@ const BookerLayoutFields = ({ settings, onChange, showUserSettings }: BookerLayo
|
|||
// Converts the settings array into a boolean object, which can be used as form values.
|
||||
const toggleValues: BookerLayoutState = bookerLayoutOptions.reduce((layouts, layout) => {
|
||||
layouts[layout] = !shownSettings?.enabledLayouts
|
||||
? true
|
||||
? defaultBookerLayoutSettings.enabledLayouts.indexOf(layout) > -1
|
||||
: shownSettings.enabledLayouts.indexOf(layout) > -1;
|
||||
return layouts;
|
||||
}, {} as BookerLayoutState);
|
||||
|
||||
const onLayoutToggleChange = useCallback(
|
||||
(changedLayout: BookerLayouts, checked: boolean) => {
|
||||
const newEnabledLayouts = Object.keys(toggleValues).filter((layout) => {
|
||||
if (changedLayout === layout) return checked === true;
|
||||
return toggleValues[layout as BookerLayouts] === true;
|
||||
}) as BookerLayouts[];
|
||||
|
||||
const isDefaultLayoutToggledOff = newEnabledLayouts.indexOf(defaultLayout) === -1;
|
||||
const firstEnabledLayout = newEnabledLayouts[0];
|
||||
|
||||
onChange({
|
||||
enabledLayouts: Object.keys(toggleValues).filter((layout) => {
|
||||
if (changedLayout === layout) return checked === true;
|
||||
return toggleValues[layout as BookerLayouts] === true;
|
||||
}) as BookerLayouts[],
|
||||
defaultLayout,
|
||||
enabledLayouts: newEnabledLayouts,
|
||||
// If default layout is toggled off, we set the default layout to the first enabled layout
|
||||
// if there's none enabled, we set it to month view.
|
||||
defaultLayout: isDefaultLayoutToggledOff
|
||||
? firstEnabledLayout || BookerLayouts.MONTH_VIEW
|
||||
: defaultLayout,
|
||||
});
|
||||
},
|
||||
[defaultLayout, onChange, toggleValues]
|
||||
|
@ -149,6 +158,7 @@ const BookerLayoutFields = ({ settings, onChange, showUserSettings }: BookerLayo
|
|||
))}
|
||||
</div>
|
||||
<div
|
||||
hidden={Object.values(toggleValues).filter((value) => value === true).length <= 1}
|
||||
className={classNames(
|
||||
"transition-opacity",
|
||||
disableFields && "pointer-events-none opacity-40",
|
||||
|
@ -162,7 +172,8 @@ const BookerLayoutFields = ({ settings, onChange, showUserSettings }: BookerLayo
|
|||
onValueChange={(layout: BookerLayouts) => onDefaultLayoutChange(layout)}>
|
||||
{bookerLayoutOptions.map((layout) => (
|
||||
<RadioGroup.Item
|
||||
className="aria-checked:bg-emphasis hover:bg-subtle focus:bg-subtle w-full rounded-[4px] p-1 text-sm transition-colors"
|
||||
className="aria-checked:bg-emphasis hover:[&:not(:disabled)]:bg-subtle focus:[&:not(:disabled)]:bg-subtle w-full rounded-[4px] p-1 text-sm transition-colors disabled:cursor-not-allowed disabled:opacity-40"
|
||||
disabled={toggleValues[layout] === false}
|
||||
key={layout}
|
||||
value={layout}>
|
||||
{t(`bookerlayout_${layout}`)}
|
||||
|
|
|
@ -55,6 +55,12 @@ export const bookerLayouts = z
|
|||
})
|
||||
.nullable();
|
||||
|
||||
export const defaultBookerLayoutSettings = {
|
||||
defaultLayout: BookerLayouts.MONTH_VIEW,
|
||||
// if the user has no explicit layouts set (not in user profile and not in event settings), all layouts are enabled.
|
||||
enabledLayouts: bookerLayoutOptions,
|
||||
};
|
||||
|
||||
export type BookerLayoutSettings = z.infer<typeof bookerLayouts>;
|
||||
|
||||
export const RequiresConfirmationThresholdUnits: z.ZodType<UnitTypeLongPlural> = z.enum(["hours", "minutes"]);
|
||||
|
|
|
@ -4,10 +4,12 @@ import type { NextApiResponse, GetServerSidePropsContext } from "next";
|
|||
import stripe from "@calcom/app-store/stripepayment/lib/server";
|
||||
import { getPremiumPlanProductId } from "@calcom/app-store/stripepayment/lib/utils";
|
||||
import hasKeyInMetadata from "@calcom/lib/hasKeyInMetadata";
|
||||
import { getTranslation } from "@calcom/lib/server";
|
||||
import { checkUsername } from "@calcom/lib/server/checkUsername";
|
||||
import { resizeBase64Image } from "@calcom/lib/server/resizeBase64Image";
|
||||
import slugify from "@calcom/lib/slugify";
|
||||
import { updateWebUser as syncServicesUpdateWebUser } from "@calcom/lib/sync/SyncServiceManager";
|
||||
import { validateBookerLayouts } from "@calcom/lib/validateBookerLayouts";
|
||||
import { prisma } from "@calcom/prisma";
|
||||
import { userMetadata } from "@calcom/prisma/zod-utils";
|
||||
import type { TrpcSessionUser } from "@calcom/trpc/server/trpc";
|
||||
|
@ -32,6 +34,13 @@ export const updateProfileHandler = async ({ ctx, input }: UpdateProfileOptions)
|
|||
};
|
||||
|
||||
let isPremiumUsername = false;
|
||||
|
||||
const layoutError = validateBookerLayouts(input?.metadata?.defaultBookerLayouts || null);
|
||||
if (layoutError) {
|
||||
const t = await getTranslation("en", "common");
|
||||
throw new TRPCError({ code: "BAD_REQUEST", message: t(layoutError) });
|
||||
}
|
||||
|
||||
if (input.username) {
|
||||
const username = slugify(input.username);
|
||||
// Only validate if we're changing usernames
|
||||
|
|
Loading…
Reference in New Issue
Block a user