Availability and booking info text format fixes (#4000)
* Recurring info format * More mismatch visual bugs when booking * More tweaks * Prettier * Prettier cont Co-authored-by: Peer Richelsen <peeroke@gmail.com> Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com>
This commit is contained in:
parent
00c00a9aee
commit
e4e4ec5ffc
|
@ -1,9 +1,10 @@
|
|||
import { getEventLocationType, locationKeyToString } from "@calcom/app-store/locations";
|
||||
import { classNames } from "@calcom/lib";
|
||||
|
||||
import { Props } from "./pages/AvailabilityPage";
|
||||
|
||||
export function AvailableEventLocations({ locations }: { locations: Props["eventType"]["locations"] }) {
|
||||
return (
|
||||
return locations.length ? (
|
||||
<div>
|
||||
<div className="flex-warp mr-6 flex break-words text-sm text-gray-600 dark:text-white">
|
||||
<p className="w-full">
|
||||
|
@ -14,10 +15,13 @@ export function AvailableEventLocations({ locations }: { locations: Props["event
|
|||
return null;
|
||||
}
|
||||
return (
|
||||
<span key={location.type} className="flex flex-row items-center pt-1">
|
||||
<span key={location.type} className="flex flex-row items-center text-sm font-medium">
|
||||
<img
|
||||
src={eventLocationType.iconUrl}
|
||||
className="mr-[10px] ml-[2px] h-4 w-4"
|
||||
className={classNames(
|
||||
"mr-[10px] ml-[2px] h-4 w-4 opacity-70 dark:opacity-100",
|
||||
!eventLocationType.iconUrl?.includes("api") ? "dark:invert" : ""
|
||||
)}
|
||||
alt={`${eventLocationType.label} icon`}
|
||||
/>
|
||||
<span key={location.type}>{locationKeyToString(location)} </span>
|
||||
|
@ -27,5 +31,7 @@ export function AvailableEventLocations({ locations }: { locations: Props["event
|
|||
</p>
|
||||
</div>
|
||||
</div>
|
||||
) : (
|
||||
<></>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -239,15 +239,15 @@ function TimezoneDropdown({
|
|||
};
|
||||
|
||||
return (
|
||||
<Collapsible.Root open={isTimeOptionsOpen} onOpenChange={setIsTimeOptionsOpen}>
|
||||
<Collapsible.Trigger className="min-w-32 dark:text-darkgray-600 mb-1 -ml-2 px-2 py-1 text-left text-gray-600">
|
||||
<p className="py-1 text-sm font-medium ">
|
||||
<Icon.FiGlobe className="mr-[10px] ml-[2px] -mt-1 inline-block h-4 w-4 " />
|
||||
<Collapsible.Root open={isTimeOptionsOpen} onOpenChange={setIsTimeOptionsOpen} className="flex">
|
||||
<Collapsible.Trigger className="min-w-32 mb-2 -ml-2 px-2 text-left text-gray-600 dark:text-white">
|
||||
<p className="text-sm font-medium">
|
||||
<Icon.FiGlobe className="mr-[10px] ml-[2px] -mt-[2px] inline-block h-4 w-4" />
|
||||
{timeZone}
|
||||
{isTimeOptionsOpen ? (
|
||||
<Icon.FiChevronUp className="ml-1 -mt-1 inline-block h-4 w-4 " />
|
||||
<Icon.FiChevronUp className="ml-1 inline-block h-4 w-4 " />
|
||||
) : (
|
||||
<Icon.FiChevronDown className="ml-1 -mt-1 inline-block h-4 w-4 " />
|
||||
<Icon.FiChevronDown className="ml-1 inline-block h-4 w-4 " />
|
||||
)}
|
||||
</p>
|
||||
</Collapsible.Trigger>
|
||||
|
@ -379,10 +379,7 @@ const AvailabilityPage = ({ profile, eventType }: Props) => {
|
|||
shouldAlignCentrally ? "mx-auto" : "",
|
||||
isEmbed
|
||||
? classNames(maxWidth)
|
||||
: classNames(
|
||||
"transition-max-width dark:bg- mx-auto my-0 duration-500 ease-in-out md:my-24",
|
||||
maxWidth
|
||||
)
|
||||
: classNames("transition-max-width mx-auto my-0 duration-500 ease-in-out md:my-24", maxWidth)
|
||||
)}>
|
||||
<div
|
||||
style={availabilityDatePickerEmbedStyles}
|
||||
|
@ -411,27 +408,27 @@ const AvailabilityPage = ({ profile, eventType }: Props) => {
|
|||
</h1>
|
||||
<div className="flex flex-col space-y-2">
|
||||
{eventType?.description && (
|
||||
<div className="dark:text-darkgray-600 flex py-1 text-sm font-medium text-gray-600">
|
||||
<div className="flex py-1 text-sm font-medium text-gray-600 dark:text-white">
|
||||
<div>
|
||||
<Icon.FiInfo className="dark:text-darkgray-600 mr-[10px] ml-[2px] -mt-1 inline-block h-4 w-4 text-gray-400" />
|
||||
<Icon.FiInfo className="mr-[10px] ml-[2px] inline-block h-4 w-4" />
|
||||
</div>
|
||||
<EventTypeDescriptionSafeHTML eventType={eventType} />
|
||||
</div>
|
||||
)}
|
||||
{eventType?.requiresConfirmation && (
|
||||
<p className="dark:text-darkgray-600 text-gray-600">
|
||||
<Icon.FiCheckSquare className="dark:text-darkgray-600 mr-[10px] ml-[2px] -mt-1 inline-block h-4 w-4 text-gray-500" />
|
||||
<p className="dark:text-darkgray-600 text-gray-600 dark:text-white">
|
||||
<Icon.FiCheckSquare className="mr-[10px] ml-[2px] -mt-1 inline-block h-4 w-4" />
|
||||
{t("requires_confirmation")}
|
||||
</p>
|
||||
)}
|
||||
<AvailableEventLocations locations={eventType.locations} />
|
||||
<p className="text-gray-600 dark:text-white">
|
||||
<Icon.FiClock className="mr-[10px] -mt-1 ml-[2px] inline-block h-4 w-4 text-gray-500" />
|
||||
<Icon.FiClock className="mr-[10px] -mt-1 ml-[2px] inline-block h-4 w-4" />
|
||||
{eventType.length} {t("minutes")}
|
||||
</p>
|
||||
{eventType.price > 0 && (
|
||||
<div className="dark:text-darkgray-600 text-gray-600">
|
||||
<Icon.FiCreditCard className="dark:text-darkgray-600 mr-[10px] ml-[2px] -mt-1 inline-block h-4 w-4" />
|
||||
<div className="text-gray-600 dark:text-white">
|
||||
<Icon.FiCreditCard className="mr-[10px] ml-[2px] -mt-1 inline-block h-4 w-4" />
|
||||
<IntlProvider locale="en">
|
||||
<FormattedNumber
|
||||
value={eventType.price / 100.0}
|
||||
|
@ -511,15 +508,15 @@ const AvailabilityPage = ({ profile, eventType }: Props) => {
|
|||
</h1>
|
||||
<div className="flex flex-col space-y-2">
|
||||
{eventType?.description && (
|
||||
<div className="dark:text-darkgray-600 flex py-1 text-sm font-medium text-gray-600">
|
||||
<div className="flex text-sm font-medium text-gray-600 dark:text-white">
|
||||
<div>
|
||||
<Icon.FiInfo className="dark:text-darkgray-600 mr-[10px] ml-[2px] -mt-1 inline-block h-4 w-4 text-gray-500" />
|
||||
<Icon.FiInfo className="mr-[10px] ml-[2px] inline-block h-4 w-4" />
|
||||
</div>
|
||||
<EventTypeDescriptionSafeHTML eventType={eventType} />
|
||||
</div>
|
||||
)}
|
||||
{eventType?.requiresConfirmation && (
|
||||
<div className="dark:text-darkgray-600 flex items-center text-sm font-medium text-gray-600">
|
||||
<div className="flex items-center text-sm font-medium text-gray-600 dark:text-white">
|
||||
<div>
|
||||
<Icon.FiCheckSquare className="mr-[10px] ml-[2px] -mt-1 inline-block h-4 w-4 " />
|
||||
</div>
|
||||
|
@ -527,13 +524,13 @@ const AvailabilityPage = ({ profile, eventType }: Props) => {
|
|||
</div>
|
||||
)}
|
||||
<AvailableEventLocations locations={eventType.locations} />
|
||||
<p className="py-1 text-sm font-medium text-gray-600 dark:text-white">
|
||||
<Icon.FiClock className="mr-[10px] -mt-1 ml-[2px] inline-block h-4 w-4 text-gray-500" />
|
||||
<p className="text-sm font-medium text-gray-600 dark:text-white">
|
||||
<Icon.FiClock className="mr-[10px] -mt-1 ml-[2px] inline-block h-4 w-4" />
|
||||
{eventType.length} {t("minutes")}
|
||||
</p>
|
||||
{!rescheduleUid && eventType.recurringEvent && (
|
||||
<div className="dark:text-darkgray-600 flex items-center text-gray-600">
|
||||
<Icon.FiRefreshCcw className="float-left mr-[10px] mt-1 ml-[2px] inline-block h-4 w-4 " />
|
||||
<div className="flex items-start text-sm font-medium text-gray-600 dark:text-white">
|
||||
<Icon.FiRefreshCcw className="float-left mr-[10px] mt-[7px] ml-[2px] inline-block h-4 w-4 " />
|
||||
<div>
|
||||
<p className="mb-1 -ml-2 inline px-2 py-1">
|
||||
{getRecurringFreq({ t, recurringEvent: eventType.recurringEvent })}
|
||||
|
@ -542,13 +539,13 @@ const AvailabilityPage = ({ profile, eventType }: Props) => {
|
|||
type="number"
|
||||
min="1"
|
||||
max={eventType.recurringEvent.count}
|
||||
className="w-15 dark:text-darkgray-600 h-7 rounded-sm border-gray-300 bg-white text-sm text-gray-600 [appearance:textfield] ltr:mr-2 rtl:ml-2 dark:border-gray-500 dark:bg-gray-600"
|
||||
className="w-15 dark:bg-darkgray-200 h-7 rounded-sm border-gray-300 bg-white text-sm font-medium [appearance:textfield] ltr:mr-2 rtl:ml-2 dark:border-gray-500"
|
||||
defaultValue={eventType.recurringEvent.count}
|
||||
onChange={(event) => {
|
||||
setRecurringEventCount(parseInt(event?.target.value));
|
||||
}}
|
||||
/>
|
||||
<p className="dark:text-darkgray-600 inline text-gray-600">
|
||||
<p className="inline">
|
||||
{t("occurrence", {
|
||||
count: recurringEventCount,
|
||||
})}
|
||||
|
@ -557,7 +554,7 @@ const AvailabilityPage = ({ profile, eventType }: Props) => {
|
|||
</div>
|
||||
)}
|
||||
{eventType.price > 0 && (
|
||||
<p className="dark:text-darkgray-600 -ml-2 px-2 py-1 text-gray-600">
|
||||
<p className="-ml-2 px-2 text-sm font-medium text-gray-600 dark:text-white">
|
||||
<Icon.FiCreditCard className="mr-[10px] ml-[2px] -mt-1 inline-block h-4 w-4" />
|
||||
<IntlProvider locale="en">
|
||||
<FormattedNumber
|
||||
|
|
|
@ -50,6 +50,7 @@ import { parseDate, parseRecurringDates } from "@lib/parseDate";
|
|||
import slugify from "@lib/slugify";
|
||||
|
||||
import { UserAvatars } from "@components/booking/UserAvatars";
|
||||
import EventTypeDescriptionSafeHTML from "@components/eventtype/EventTypeDescriptionSafeHTML";
|
||||
|
||||
import { BookPageProps } from "../../../pages/[user]/book";
|
||||
import { HashLinkPageProps } from "../../../pages/d/[link]/book";
|
||||
|
@ -472,12 +473,13 @@ const BookingPage = ({
|
|||
profile={profile}
|
||||
users={eventType.users}
|
||||
showMembers={eventType.schedulingType !== SchedulingType.ROUND_ROBIN}
|
||||
size={14}
|
||||
size={10}
|
||||
truncateAfter={3}
|
||||
/>
|
||||
<h2 className="font-cal text-bookinglight mt-2 font-medium dark:text-gray-300">
|
||||
<h2 className="mt-2 break-words text-sm font-medium text-gray-500 dark:text-gray-300">
|
||||
{profile.name}
|
||||
</h2>
|
||||
<h1 className="text-bookingdark mb-4 text-xl font-semibold dark:text-white">
|
||||
<h1 className="font-cal dark:text-darkgray-900 mb-6 break-words text-2xl text-gray-900 ">
|
||||
{eventType.title}
|
||||
</h1>
|
||||
{!!eventType.seatsPerTimeSlot && (
|
||||
|
@ -496,83 +498,89 @@ const BookingPage = ({
|
|||
</p>
|
||||
)}
|
||||
{eventType?.description && (
|
||||
<p className="text-bookinglight mb-2 text-sm ">
|
||||
<Icon.FiInfo className="mr-[10px] ml-[2px] -mt-1 inline-block h-4 w-4" />
|
||||
{eventType.description}
|
||||
</p>
|
||||
<div className="dark:text-darkgray-600 flex py-1 text-sm font-medium text-gray-600">
|
||||
<div>
|
||||
<Icon.FiInfo className="dark:text-darkgray-600 mr-[10px] ml-[2px] -mt-1 inline-block h-4 w-4 text-gray-500" />
|
||||
</div>
|
||||
<EventTypeDescriptionSafeHTML eventType={eventType} />
|
||||
</div>
|
||||
)}
|
||||
{eventType?.requiresConfirmation && (
|
||||
<p className="text-bookinglight mb-2 text-sm ">
|
||||
<Icon.FiClipboard className="mr-[10px] ml-[2px] -mt-1 inline-block h-4 w-4" />
|
||||
<div className="dark:text-darkgray-600 flex items-center text-sm font-medium text-gray-600">
|
||||
<div>
|
||||
<Icon.FiCheckSquare className="mr-[10px] ml-[2px] -mt-1 inline-block h-4 w-4 " />
|
||||
</div>
|
||||
{t("requires_confirmation")}
|
||||
</p>
|
||||
</div>
|
||||
)}
|
||||
<p className="text-bookinglight mb-2 text-sm ">
|
||||
<Icon.FiClock className="mr-[10px] -mt-1 ml-[2px] inline-block h-4 w-4" />
|
||||
{eventType.length} {t("minutes")}
|
||||
</p>
|
||||
{eventType.price > 0 && (
|
||||
<p className="text-bookinglight mb-1 -ml-2 px-2 py-1 text-sm ">
|
||||
<Icon.FiCreditCard className="mr-[10px] ml-[2px] -mt-1 inline-block h-4 w-4" />
|
||||
<IntlProvider locale="en">
|
||||
<FormattedNumber
|
||||
value={eventType.price / 100.0}
|
||||
style="currency"
|
||||
currency={eventType.currency.toUpperCase()}
|
||||
/>
|
||||
</IntlProvider>
|
||||
<div className="flex flex-col space-y-2">
|
||||
<p className="text-sm font-medium text-gray-600 dark:text-white">
|
||||
<Icon.FiClock className="mr-[10px] -mt-1 ml-[2px] inline-block h-4 w-4" />
|
||||
{eventType.length} {t("minutes")}
|
||||
</p>
|
||||
)}
|
||||
{!rescheduleUid && eventType.recurringEvent?.freq && recurringEventCount && (
|
||||
<div className="mb-3 text-sm text-gray-600 ">
|
||||
<Icon.FiRefreshCw className="mr-[10px] -mt-1 ml-[2px] inline-block h-4 w-4" />
|
||||
<p className="mb-1 -ml-2 inline px-2 py-1">
|
||||
{getEveryFreqFor({
|
||||
t,
|
||||
recurringEvent: eventType.recurringEvent,
|
||||
recurringCount: recurringEventCount,
|
||||
})}
|
||||
{eventType.price > 0 && (
|
||||
<p className="text-bookinglight -ml-2 px-2 text-sm ">
|
||||
<Icon.FiCreditCard className="mr-[10px] ml-[2px] -mt-1 inline-block h-4 w-4" />
|
||||
<IntlProvider locale="en">
|
||||
<FormattedNumber
|
||||
value={eventType.price / 100.0}
|
||||
style="currency"
|
||||
currency={eventType.currency.toUpperCase()}
|
||||
/>
|
||||
</IntlProvider>
|
||||
</p>
|
||||
)}
|
||||
{!rescheduleUid && eventType.recurringEvent?.freq && recurringEventCount && (
|
||||
<div className="items-start text-sm font-medium text-gray-600 dark:text-white">
|
||||
<Icon.FiRefreshCw className="mr-[10px] ml-[2px] inline-block h-4 w-4" />
|
||||
<p className="-ml-2 inline-block items-center px-2">
|
||||
{getEveryFreqFor({
|
||||
t,
|
||||
recurringEvent: eventType.recurringEvent,
|
||||
recurringCount: recurringEventCount,
|
||||
})}
|
||||
</p>
|
||||
</div>
|
||||
)}
|
||||
<div className="text-bookinghighlight flex items-start text-sm">
|
||||
<Icon.FiCalendar className="mr-[10px] ml-[2px] mt-[2px] inline-block h-4 w-4" />
|
||||
<div className="text-sm font-medium">
|
||||
{(rescheduleUid || !eventType.recurringEvent?.freq) &&
|
||||
parseDate(dayjs(date).tz(timeZone()), i18n)}
|
||||
{!rescheduleUid &&
|
||||
eventType.recurringEvent?.freq &&
|
||||
recurringStrings.slice(0, 5).map((aDate, key) => <p key={key}>{aDate}</p>)}
|
||||
{!rescheduleUid && eventType.recurringEvent?.freq && recurringStrings.length > 5 && (
|
||||
<div className="flex">
|
||||
<Tooltip
|
||||
content={recurringStrings.slice(5).map((aDate, key) => (
|
||||
<p key={key}>{aDate}</p>
|
||||
))}>
|
||||
<p className="dark:text-darkgray-600 text-sm">
|
||||
{t("plus_more", { count: recurringStrings.length - 5 })}
|
||||
</p>
|
||||
</Tooltip>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
<div className="text-bookinghighlight mb-4 flex items-center text-sm">
|
||||
<Icon.FiCalendar className="mr-[10px] ml-[2px] inline-block h-4 w-4" />
|
||||
<div>
|
||||
{(rescheduleUid || !eventType.recurringEvent?.freq) &&
|
||||
parseDate(dayjs(date).tz(timeZone()), i18n)}
|
||||
{!rescheduleUid &&
|
||||
eventType.recurringEvent?.freq &&
|
||||
recurringStrings.slice(0, 5).map((aDate, key) => <p key={key}>{aDate}</p>)}
|
||||
{!rescheduleUid && eventType.recurringEvent?.freq && recurringStrings.length > 5 && (
|
||||
<div className="flex">
|
||||
<Tooltip
|
||||
content={recurringStrings.slice(5).map((aDate, key) => (
|
||||
<p key={key}>{aDate}</p>
|
||||
))}>
|
||||
<p className="dark:text-darkgray-600 text-sm">
|
||||
{t("plus_more", { count: recurringStrings.length - 5 })}
|
||||
</p>
|
||||
</Tooltip>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
{eventTypeDetail.isWeb3Active && eventType.metadata.smartContractAddress && (
|
||||
<p className="text-bookinglight mb-1 -ml-2 px-2">
|
||||
{t("requires_ownership_of_a_token") + " " + eventType.metadata.smartContractAddress}
|
||||
</p>
|
||||
)}
|
||||
{booking?.startTime && rescheduleUid && (
|
||||
<div>
|
||||
<p className="mt-8 mb-2 text-sm " data-testid="former_time_p">
|
||||
{t("former_time")}
|
||||
</p>
|
||||
<p className="line-through ">
|
||||
<Icon.FiCalendar className="mr-[10px] ml-[2px] -mt-1 inline-block h-4 w-4" />
|
||||
{typeof booking.startTime === "string" && parseDate(dayjs(booking.startTime), i18n)}
|
||||
</p>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
{eventTypeDetail.isWeb3Active && eventType.metadata.smartContractAddress && (
|
||||
<p className="text-bookinglight mb-1 -ml-2 px-2 py-1">
|
||||
{t("requires_ownership_of_a_token") + " " + eventType.metadata.smartContractAddress}
|
||||
</p>
|
||||
)}
|
||||
{booking?.startTime && rescheduleUid && (
|
||||
<div>
|
||||
<p className="mt-8 mb-2 text-sm " data-testid="former_time_p">
|
||||
{t("former_time")}
|
||||
</p>
|
||||
<p className="line-through ">
|
||||
<Icon.FiCalendar className="mr-[10px] ml-[2px] -mt-1 inline-block h-4 w-4" />
|
||||
{typeof booking.startTime === "string" && parseDate(dayjs(booking.startTime), i18n)}
|
||||
</p>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
<div className="p-6 sm:w-1/2">
|
||||
<Form form={bookingForm} handleSubmit={bookEvent}>
|
||||
|
|
Loading…
Reference in New Issue
Block a user