feat: Assign colors to events (#15298)
* feat: Assign colors to events * update * final update * update * fix requested changes error * Update EventAdvancedTab.tsx * add contrast check * update * fix contrsterror message visibility * fix type error * fix * update test --------- Co-authored-by: Udit Takkar <53316345+Udit-takkar@users.noreply.github.com> Co-authored-by: sean-brydon <55134778+sean-brydon@users.noreply.github.com>
This commit is contained in:
co-authored by
Udit Takkar
sean-brydon
parent
95e2ad3007
commit
528a4fbb97
@@ -17,12 +17,14 @@ import { DuplicateDialog } from "@calcom/features/eventtypes/components/Duplicat
|
||||
import { TeamsFilter } from "@calcom/features/filters/components/TeamsFilter";
|
||||
import { getTeamsFiltersFromQuery } from "@calcom/features/filters/lib/getTeamsFiltersFromQuery";
|
||||
import Shell from "@calcom/features/shell/Shell";
|
||||
import { parseEventTypeColor } from "@calcom/lib";
|
||||
import { APP_NAME } from "@calcom/lib/constants";
|
||||
import { WEBSITE_URL } from "@calcom/lib/constants";
|
||||
import { useCompatSearchParams } from "@calcom/lib/hooks/useCompatSearchParams";
|
||||
import { useLocale } from "@calcom/lib/hooks/useLocale";
|
||||
import useMediaQuery from "@calcom/lib/hooks/useMediaQuery";
|
||||
import { useRouterQuery } from "@calcom/lib/hooks/useRouterQuery";
|
||||
import { useGetTheme } from "@calcom/lib/hooks/useTheme";
|
||||
import { useTypedQuery } from "@calcom/lib/hooks/useTypedQuery";
|
||||
import { HttpError } from "@calcom/lib/http-error";
|
||||
import type { User } from "@calcom/prisma/client";
|
||||
@@ -213,6 +215,11 @@ const Item = ({
|
||||
readOnly: boolean;
|
||||
}) => {
|
||||
const { t } = useLocale();
|
||||
const { resolvedTheme, forcedTheme } = useGetTheme();
|
||||
const hasDarkTheme = !forcedTheme && resolvedTheme === "dark";
|
||||
const parsedeventTypeColor = parseEventTypeColor(type.eventTypeColor);
|
||||
const eventTypeColor =
|
||||
parsedeventTypeColor && parsedeventTypeColor[hasDarkTheme ? "darkEventTypeColor" : "lightEventTypeColor"];
|
||||
|
||||
const content = () => (
|
||||
<div>
|
||||
@@ -238,40 +245,46 @@ const Item = ({
|
||||
</div>
|
||||
);
|
||||
|
||||
return readOnly ? (
|
||||
<div className="flex-1 overflow-hidden pr-4 text-sm">
|
||||
{content()}
|
||||
<EventTypeDescription eventType={type} shortenDescription />
|
||||
</div>
|
||||
) : (
|
||||
<Link
|
||||
href={`/event-types/${type.id}?tabName=setup`}
|
||||
className="flex-1 overflow-hidden pr-4 text-sm"
|
||||
title={type.title}>
|
||||
<div>
|
||||
<span
|
||||
className="text-default font-semibold ltr:mr-1 rtl:ml-1"
|
||||
data-testid={`event-type-title-${type.id}`}>
|
||||
{type.title}
|
||||
</span>
|
||||
{group.profile.slug ? (
|
||||
<small
|
||||
className="text-subtle hidden font-normal leading-4 sm:inline"
|
||||
data-testid={`event-type-slug-${type.id}`}>
|
||||
{`/${group.profile.slug}/${type.slug}`}
|
||||
</small>
|
||||
) : null}
|
||||
{readOnly && (
|
||||
<Badge variant="gray" className="ml-2" data-testid="readonly-badge">
|
||||
{t("readonly")}
|
||||
</Badge>
|
||||
return (
|
||||
<div className="relative flex-1 overflow-hidden pr-4 text-sm">
|
||||
{eventTypeColor && (
|
||||
<div className="absolute h-full w-0.5" style={{ backgroundColor: eventTypeColor }} />
|
||||
)}
|
||||
<div className="ml-3">
|
||||
{readOnly ? (
|
||||
<div>
|
||||
{content()}
|
||||
<EventTypeDescription eventType={type} shortenDescription />
|
||||
</div>
|
||||
) : (
|
||||
<Link href={`/event-types/${type.id}?tabName=setup`} title={type.title}>
|
||||
<div>
|
||||
<span
|
||||
className="text-default font-semibold ltr:mr-1 rtl:ml-1"
|
||||
data-testid={`event-type-title-${type.id}`}>
|
||||
{type.title}
|
||||
</span>
|
||||
{group.profile.slug ? (
|
||||
<small
|
||||
className="text-subtle hidden font-normal leading-4 sm:inline"
|
||||
data-testid={`event-type-slug-${type.id}`}>
|
||||
{`/${group.profile.slug}/${type.slug}`}
|
||||
</small>
|
||||
) : null}
|
||||
{readOnly && (
|
||||
<Badge variant="gray" className="ml-2" data-testid="readonly-badge">
|
||||
{t("readonly")}
|
||||
</Badge>
|
||||
)}
|
||||
</div>
|
||||
<EventTypeDescription
|
||||
eventType={{ ...type, descriptionAsSafeHTML: type.safeDescription }}
|
||||
shortenDescription
|
||||
/>
|
||||
</Link>
|
||||
)}
|
||||
</div>
|
||||
<EventTypeDescription
|
||||
eventType={{ ...type, descriptionAsSafeHTML: type.safeDescription }}
|
||||
shortenDescription
|
||||
/>
|
||||
</Link>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -470,7 +483,7 @@ export const EventTypeList = ({
|
||||
return (
|
||||
<li key={type.id}>
|
||||
<div className="hover:bg-muted flex w-full items-center justify-between transition">
|
||||
<div className="group flex w-full max-w-full items-center justify-between overflow-hidden px-4 py-4 sm:px-6">
|
||||
<div className="group flex w-full max-w-full items-center justify-between overflow-hidden py-4 pl-2 pr-4 sm:pl-3 sm:pr-6">
|
||||
{!(firstItem && firstItem.id === type.id) && (
|
||||
<ArrowButton onClick={() => moveEventType(index, -1)} arrowDirection="up" />
|
||||
)}
|
||||
|
||||
@@ -282,6 +282,7 @@ const EventTypePage = (props: EventTypeSetupProps & { allActiveWorkflows?: Workf
|
||||
length: eventType.length,
|
||||
hidden: eventType.hidden,
|
||||
hashedLink: eventType.hashedLink?.link || undefined,
|
||||
eventTypeColor: eventType.eventTypeColor || null,
|
||||
periodDates: {
|
||||
startDate: periodDates.startDate,
|
||||
endDate: periodDates.endDate,
|
||||
@@ -518,6 +519,8 @@ const EventTypePage = (props: EventTypeSetupProps & { allActiveWorkflows?: Workf
|
||||
const updatedFields: Partial<FormValues> = {};
|
||||
Object.keys(dirtyFields).forEach((key) => {
|
||||
const typedKey = key as keyof typeof dirtyFields;
|
||||
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
||||
// @ts-ignore
|
||||
updatedFields[typedKey] = undefined;
|
||||
const isDirty = isFieldDirty(typedKey);
|
||||
if (isDirty) {
|
||||
@@ -545,6 +548,7 @@ const EventTypePage = (props: EventTypeSetupProps & { allActiveWorkflows?: Workf
|
||||
onlyShowFirstAvailableSlot,
|
||||
durationLimits,
|
||||
recurringEvent,
|
||||
eventTypeColor,
|
||||
locations,
|
||||
metadata,
|
||||
customInputs,
|
||||
@@ -615,6 +619,7 @@ const EventTypePage = (props: EventTypeSetupProps & { allActiveWorkflows?: Workf
|
||||
bookingLimits,
|
||||
onlyShowFirstAvailableSlot,
|
||||
durationLimits,
|
||||
eventTypeColor,
|
||||
seatsPerTimeSlot,
|
||||
seatsShowAttendees,
|
||||
seatsShowAvailabilityCount,
|
||||
@@ -703,6 +708,7 @@ const EventTypePage = (props: EventTypeSetupProps & { allActiveWorkflows?: Workf
|
||||
onlyShowFirstAvailableSlot,
|
||||
durationLimits,
|
||||
recurringEvent,
|
||||
eventTypeColor,
|
||||
locations,
|
||||
metadata,
|
||||
customInputs,
|
||||
@@ -765,6 +771,7 @@ const EventTypePage = (props: EventTypeSetupProps & { allActiveWorkflows?: Workf
|
||||
bookingLimits,
|
||||
onlyShowFirstAvailableSlot,
|
||||
durationLimits,
|
||||
eventTypeColor,
|
||||
seatsPerTimeSlot,
|
||||
seatsShowAttendees,
|
||||
seatsShowAvailabilityCount,
|
||||
|
||||
Reference in New Issue
Block a user