Compare commits
20 Commits
main
...
refactor-e
Author | SHA1 | Date | |
---|---|---|---|
|
dea991a80c | ||
|
1166948016 | ||
|
472b955ef4 | ||
|
49944c223f | ||
|
198c7174e4 | ||
|
4df1064f4c | ||
|
1c2211e2bf | ||
|
2a2cb14f6c | ||
|
9d1ebbebd1 | ||
|
3cdd210ee4 | ||
|
5776d8b495 | ||
|
247df0c69e | ||
|
b48934b126 | ||
|
932723abe6 | ||
|
4652b3ee01 | ||
|
74fd513e44 | ||
|
35502c0784 | ||
|
0ae4604a6b | ||
|
40d3c605e2 | ||
|
d632d7881a |
|
@ -1,5 +1,6 @@
|
|||
import { useAutoAnimate } from "@formkit/auto-animate/react";
|
||||
import type { User } from "@prisma/client";
|
||||
import type { TFunction } from "next-i18next";
|
||||
import { Trans } from "next-i18next";
|
||||
import Link from "next/link";
|
||||
import { usePathname, useRouter, useSearchParams } from "next/navigation";
|
||||
|
@ -11,8 +12,10 @@ import { getLayout } from "@calcom/features/MainLayout";
|
|||
import { useOrgBranding } from "@calcom/features/ee/organizations/context/provider";
|
||||
import useIntercom from "@calcom/features/ee/support/lib/intercom/useIntercom";
|
||||
import { EventTypeEmbedButton, EventTypeEmbedDialog } from "@calcom/features/embed/EventTypeEmbed";
|
||||
import { EventTypeDescriptionLazy as EventTypeDescription } from "@calcom/features/eventtypes/components";
|
||||
import CreateEventTypeDialog from "@calcom/features/eventtypes/components/CreateEventTypeDialog";
|
||||
import {
|
||||
CreateEventTypeDialog,
|
||||
EventTypeDescriptionLazy as EventTypeDescription,
|
||||
} from "@calcom/features/eventtypes/components";
|
||||
import { DuplicateDialog } from "@calcom/features/eventtypes/components/DuplicateDialog";
|
||||
import { TeamsFilter } from "@calcom/features/filters/components/TeamsFilter";
|
||||
import { getTeamsFiltersFromQuery } from "@calcom/features/filters/lib/getTeamsFiltersFromQuery";
|
||||
|
@ -24,6 +27,7 @@ import useMediaQuery from "@calcom/lib/hooks/useMediaQuery";
|
|||
import { useRouterQuery } from "@calcom/lib/hooks/useRouterQuery";
|
||||
import { useTypedQuery } from "@calcom/lib/hooks/useTypedQuery";
|
||||
import { HttpError } from "@calcom/lib/http-error";
|
||||
import { markdownToSafeHTML } from "@calcom/lib/markdownToSafeHTML";
|
||||
import { SchedulingType } from "@calcom/prisma/enums";
|
||||
import type { RouterOutputs } from "@calcom/trpc/react";
|
||||
import { trpc, TRPCClientError } from "@calcom/trpc/react";
|
||||
|
@ -35,7 +39,6 @@ import {
|
|||
Button,
|
||||
ButtonGroup,
|
||||
ConfirmationDialogContent,
|
||||
CreateButton,
|
||||
Dialog,
|
||||
Dropdown,
|
||||
DropdownItem,
|
||||
|
@ -53,6 +56,7 @@ import {
|
|||
Switch,
|
||||
Tooltip,
|
||||
ArrowButton,
|
||||
CreateButtonWithTeamsList,
|
||||
} from "@calcom/ui";
|
||||
import {
|
||||
Clipboard,
|
||||
|
@ -74,85 +78,99 @@ import useMeQuery from "@lib/hooks/useMeQuery";
|
|||
import PageWrapper from "@components/PageWrapper";
|
||||
import SkeletonLoader from "@components/eventtype/SkeletonLoader";
|
||||
|
||||
type EventTypeGroups = RouterOutputs["viewer"]["eventTypes"]["getByViewer"]["eventTypeGroups"];
|
||||
type EventTypeGroupProfile = EventTypeGroups[number]["profile"];
|
||||
type GetByViewerResponse = RouterOutputs["viewer"]["eventTypes"]["getByViewer"] | undefined;
|
||||
|
||||
interface EventTypeListHeadingProps {
|
||||
profile: EventTypeGroupProfile;
|
||||
teamSlugOrUsername: string;
|
||||
teamNameOrUserName: string;
|
||||
membershipCount: number;
|
||||
teamId?: number | null;
|
||||
orgSlug?: string;
|
||||
}
|
||||
|
||||
type EventTypeGroup = EventTypeGroups[number];
|
||||
type EventType = EventTypeGroup["eventTypes"][number];
|
||||
type EventTypeList = RouterOutputs["viewer"]["eventTypes"]["paginate"];
|
||||
type EventType = EventTypeList[number];
|
||||
|
||||
interface EventTypeListProps {
|
||||
group: EventTypeGroup;
|
||||
groupIndex: number;
|
||||
readOnly: boolean;
|
||||
types: EventType[];
|
||||
data: EventTypeList;
|
||||
readonly?: boolean;
|
||||
}
|
||||
|
||||
interface MobileTeamsTabProps {
|
||||
eventTypeGroups: EventTypeGroups;
|
||||
teamEventTypes: EventTypeList[];
|
||||
readonly?: boolean;
|
||||
}
|
||||
|
||||
const querySchema = z.object({
|
||||
teamId: z.nullable(z.coerce.number()).optional().default(null),
|
||||
});
|
||||
|
||||
const MobileTeamsTab: FC<MobileTeamsTabProps> = (props) => {
|
||||
const { eventTypeGroups } = props;
|
||||
const MobileTeamsTab: FC<MobileTeamsTabProps> = (props: MobileTeamsTabProps) => {
|
||||
const { teamEventTypes, readonly } = props;
|
||||
const orgBranding = useOrgBranding();
|
||||
const tabs = eventTypeGroups.map((item) => ({
|
||||
name: item.profile.name ?? "",
|
||||
href: item.teamId ? `/event-types?teamId=${item.teamId}` : "/event-types?noTeam",
|
||||
avatar: orgBranding
|
||||
? `${orgBranding.fullDomain}${item.teamId ? "/team" : ""}/${item.profile.slug}/avatar.png`
|
||||
: item.profile.image ?? `${WEBAPP_URL + (item.teamId && "/team")}/${item.profile.slug}/avatar.png`,
|
||||
}));
|
||||
const tabs = teamEventTypes
|
||||
.filter((item) => item !== undefined)
|
||||
.map((item) => {
|
||||
const [firstElement] = item;
|
||||
|
||||
const [mainUser] = firstElement?.users ?? [];
|
||||
const teamSlugOrUsername = firstElement?.team?.slug || mainUser?.username || "";
|
||||
const teamNameOrUserName = firstElement?.team?.name || mainUser?.name || "";
|
||||
const teamId = firstElement?.team?.id;
|
||||
return {
|
||||
name: teamNameOrUserName,
|
||||
href: teamId ? `/event-types?teamId=${teamId}` : "/event-types",
|
||||
avatar: teamId
|
||||
? `${orgBranding?.fullDomain ?? WEBAPP_URL}/${teamSlugOrUsername}/avatar.png`
|
||||
: `${WEBAPP_URL}/${teamSlugOrUsername}/avatar.png`,
|
||||
};
|
||||
});
|
||||
const { data } = useTypedQuery(querySchema);
|
||||
const events = eventTypeGroups.filter((item) => item.teamId === data.teamId);
|
||||
const eventsIndex = teamEventTypes.findIndex((item) => item[0]?.team?.id === data?.teamId);
|
||||
|
||||
const events = teamEventTypes[eventsIndex > -1 ? eventsIndex : 0];
|
||||
|
||||
return (
|
||||
<div>
|
||||
<HorizontalTabs tabs={tabs} />
|
||||
{events.length > 0 ? (
|
||||
<EventTypeList
|
||||
types={events[0].eventTypes}
|
||||
group={events[0]}
|
||||
groupIndex={0}
|
||||
readOnly={events[0].metadata.readOnly}
|
||||
/>
|
||||
{events && events.length > 0 ? (
|
||||
<EventTypeList data={events} readonly={readonly} />
|
||||
) : (
|
||||
<CreateFirstEventTypeView slug={eventTypeGroups[0].profile.slug ?? ""} />
|
||||
// @TODO: fix later when we have the context provider
|
||||
<CreateFirstEventTypeView slug="" />
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
const Item = ({ type, group, readOnly }: { type: EventType; group: EventTypeGroup; readOnly: boolean }) => {
|
||||
const getEventTypeSlug = (eventType: EventType, t: TFunction) => {
|
||||
const { team, schedulingType, users } = eventType;
|
||||
|
||||
if (team?.slug) {
|
||||
return `/${team.slug}/${eventType.slug}`;
|
||||
} else if (schedulingType === SchedulingType.MANAGED) {
|
||||
return t("username_placeholder");
|
||||
} else {
|
||||
return `/${users[0].username}/${eventType.slug}`;
|
||||
}
|
||||
};
|
||||
|
||||
const Item = ({ eventType, readonly }: { eventType: EventType; readonly?: boolean }) => {
|
||||
const { t } = useLocale();
|
||||
|
||||
const content = () => (
|
||||
<div>
|
||||
<span
|
||||
className="text-default font-semibold ltr:mr-1 rtl:ml-1"
|
||||
data-testid={"event-type-title-" + type.id}>
|
||||
{type.title}
|
||||
data-testid={"event-type-title-" + eventType.id}>
|
||||
{eventType.title}
|
||||
</span>
|
||||
{group.profile.slug ? (
|
||||
|
||||
<small
|
||||
className="text-subtle hidden font-normal leading-4 sm:inline"
|
||||
data-testid={"event-type-slug-" + type.id}>
|
||||
{`/${
|
||||
type.schedulingType !== SchedulingType.MANAGED ? group.profile.slug : t("username_placeholder")
|
||||
}/${type.slug}`}
|
||||
data-testid={"event-type-slug-" + eventType.id}>
|
||||
{getEventTypeSlug(eventType, t)}
|
||||
</small>
|
||||
) : null}
|
||||
{readOnly && (
|
||||
|
||||
{readonly && (
|
||||
<Badge variant="gray" className="ml-2">
|
||||
{t("readonly")}
|
||||
</Badge>
|
||||
|
@ -160,34 +178,34 @@ const Item = ({ type, group, readOnly }: { type: EventType; group: EventTypeGrou
|
|||
</div>
|
||||
);
|
||||
|
||||
return readOnly ? (
|
||||
return readonly ? (
|
||||
<div className="flex-1 overflow-hidden pr-4 text-sm">
|
||||
{content()}
|
||||
<EventTypeDescription
|
||||
// @ts-expect-error FIXME: We have a type mismatch here @hariombalhara @sean-brydon
|
||||
eventType={type}
|
||||
eventType={eventType}
|
||||
shortenDescription
|
||||
/>
|
||||
</div>
|
||||
) : (
|
||||
<Link
|
||||
href={`/event-types/${type.id}?tabName=setup`}
|
||||
href={`/event-types/${eventType?.id}?tabName=setup`}
|
||||
className="flex-1 overflow-hidden pr-4 text-sm"
|
||||
title={type.title}>
|
||||
title={eventType?.title}>
|
||||
<div>
|
||||
<span
|
||||
className="text-default font-semibold ltr:mr-1 rtl:ml-1"
|
||||
data-testid={"event-type-title-" + type.id}>
|
||||
{type.title}
|
||||
data-testid={"event-type-title-" + eventType?.id}>
|
||||
{eventType?.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}`}
|
||||
data-testid={"event-type-slug-" + eventType?.id}>
|
||||
{getEventTypeSlug(eventType, t)}
|
||||
</small>
|
||||
) : null}
|
||||
{readOnly && (
|
||||
|
||||
{readonly && (
|
||||
<Badge variant="gray" className="ml-2">
|
||||
{t("readonly")}
|
||||
</Badge>
|
||||
|
@ -195,7 +213,10 @@ const Item = ({ type, group, readOnly }: { type: EventType; group: EventTypeGrou
|
|||
</div>
|
||||
<EventTypeDescription
|
||||
// @ts-expect-error FIXME: We have a type mismatch here @hariombalhara @sean-brydon
|
||||
eventType={{ ...type, descriptionAsSafeHTML: type.safeDescription }}
|
||||
eventType={{
|
||||
...eventType,
|
||||
descriptionAsSafeHTML: eventType?.description ? markdownToSafeHTML(eventType?.description) : "",
|
||||
}}
|
||||
shortenDescription
|
||||
/>
|
||||
</Link>
|
||||
|
@ -204,7 +225,7 @@ const Item = ({ type, group, readOnly }: { type: EventType; group: EventTypeGrou
|
|||
|
||||
const MemoizedItem = memo(Item);
|
||||
|
||||
export const EventTypeList = ({ group, groupIndex, readOnly, types }: EventTypeListProps): JSX.Element => {
|
||||
export const EventTypeList = ({ data, readonly }: EventTypeListProps): JSX.Element => {
|
||||
const { t } = useLocale();
|
||||
const router = useRouter();
|
||||
const pathname = usePathname();
|
||||
|
@ -235,18 +256,18 @@ export const EventTypeList = ({ group, groupIndex, readOnly, types }: EventTypeL
|
|||
await utils.viewer.eventTypes.getByViewer.cancel();
|
||||
const previousValue = utils.viewer.eventTypes.getByViewer.getData();
|
||||
if (previousValue) {
|
||||
const newList = [...types];
|
||||
const newList = [...data];
|
||||
const itemIndex = newList.findIndex((item) => item.id === id);
|
||||
if (itemIndex !== -1 && newList[itemIndex]) {
|
||||
newList[itemIndex].hidden = !newList[itemIndex].hidden;
|
||||
}
|
||||
utils.viewer.eventTypes.getByViewer.setData(undefined, {
|
||||
...previousValue,
|
||||
eventTypeGroups: [
|
||||
...previousValue.eventTypeGroups.slice(0, groupIndex),
|
||||
{ ...group, eventTypes: newList },
|
||||
...previousValue.eventTypeGroups.slice(groupIndex + 1),
|
||||
],
|
||||
// eventTypeGroups: [
|
||||
// ...previousValue.eventTypeGroups.slice(0, groupIndex),
|
||||
// { ...group, eventTypes: newList },
|
||||
// ...previousValue.eventTypeGroups.slice(groupIndex + 1),
|
||||
// ],
|
||||
});
|
||||
}
|
||||
return { previousValue };
|
||||
|
@ -264,10 +285,10 @@ export const EventTypeList = ({ group, groupIndex, readOnly, types }: EventTypeL
|
|||
});
|
||||
|
||||
async function moveEventType(index: number, increment: 1 | -1) {
|
||||
const newList = [...types];
|
||||
const newList = [...data];
|
||||
|
||||
const type = types[index];
|
||||
const tmp = types[index + increment];
|
||||
const type = data[index];
|
||||
const tmp = data[index + increment];
|
||||
if (tmp) {
|
||||
newList[index] = tmp;
|
||||
newList[index + increment] = type;
|
||||
|
@ -279,11 +300,11 @@ export const EventTypeList = ({ group, groupIndex, readOnly, types }: EventTypeL
|
|||
if (previousValue) {
|
||||
utils.viewer.eventTypes.getByViewer.setData(undefined, {
|
||||
...previousValue,
|
||||
eventTypeGroups: [
|
||||
...previousValue.eventTypeGroups.slice(0, groupIndex),
|
||||
{ ...group, eventTypes: newList },
|
||||
...previousValue.eventTypeGroups.slice(groupIndex + 1),
|
||||
],
|
||||
// eventTypeGroups: [
|
||||
// ...previousValue.eventTypeGroups.slice(0, groupIndex),
|
||||
// { ...group, eventTypes: newList },
|
||||
// ...previousValue.eventTypeGroups.slice(groupIndex + 1),
|
||||
// ],
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -298,7 +319,7 @@ export const EventTypeList = ({ group, groupIndex, readOnly, types }: EventTypeL
|
|||
}
|
||||
|
||||
// inject selection data into url for correct router history
|
||||
const openDuplicateModal = (eventType: EventType, group: EventTypeGroup) => {
|
||||
const openDuplicateModal = (eventType: EventType) => {
|
||||
const newSearchParams = new URLSearchParams(searchParams);
|
||||
function setParamsIfDefined(key: string, value: string | number | boolean | null | undefined) {
|
||||
if (value) newSearchParams.set(key, value.toString());
|
||||
|
@ -310,7 +331,7 @@ export const EventTypeList = ({ group, groupIndex, readOnly, types }: EventTypeL
|
|||
setParamsIfDefined("slug", eventType.slug);
|
||||
setParamsIfDefined("id", eventType.id);
|
||||
setParamsIfDefined("length", eventType.length);
|
||||
setParamsIfDefined("pageSlug", group.profile.slug);
|
||||
setParamsIfDefined("pageSlug", getEventTypeSlug(eventType, t));
|
||||
router.push(`${pathname}?${newSearchParams.toString()}`);
|
||||
};
|
||||
|
||||
|
@ -323,15 +344,15 @@ export const EventTypeList = ({ group, groupIndex, readOnly, types }: EventTypeL
|
|||
await utils.viewer.eventTypes.getByViewer.cancel();
|
||||
const previousValue = utils.viewer.eventTypes.getByViewer.getData();
|
||||
if (previousValue) {
|
||||
const newList = types.filter((item) => item.id !== id);
|
||||
// const newList = data.filter((item) => item.id !== id);
|
||||
|
||||
utils.viewer.eventTypes.getByViewer.setData(undefined, {
|
||||
...previousValue,
|
||||
eventTypeGroups: [
|
||||
...previousValue.eventTypeGroups.slice(0, groupIndex),
|
||||
{ ...group, eventTypes: newList },
|
||||
...previousValue.eventTypeGroups.slice(groupIndex + 1),
|
||||
],
|
||||
// eventTypeGroups: [
|
||||
// ...previousValue.eventTypeGroups.slice(0, groupIndex),
|
||||
// { ...group, eventTypes: newList },
|
||||
// ...previousValue.eventTypeGroups.slice(groupIndex + 1),
|
||||
// ],
|
||||
});
|
||||
}
|
||||
return { previousValue };
|
||||
|
@ -362,88 +383,91 @@ export const EventTypeList = ({ group, groupIndex, readOnly, types }: EventTypeL
|
|||
}
|
||||
}, []);
|
||||
|
||||
if (!types.length) {
|
||||
return group.teamId ? (
|
||||
<EmptyEventTypeList group={group} />
|
||||
) : (
|
||||
<CreateFirstEventTypeView slug={group.profile.slug ?? ""} />
|
||||
);
|
||||
}
|
||||
// @TODO: Fix later after we have the context provider
|
||||
// if (!data.length) {
|
||||
// return data[0].teamId ? (
|
||||
// <EmptyEventTypeList teamId={data[0].teamId} teamSlugOrUsername={data[0].team.slug || ""} />
|
||||
// ) : (
|
||||
// <CreateFirstEventTypeView slug={data[0].team.slug || []} />
|
||||
// );
|
||||
// }
|
||||
|
||||
const firstItem = types[0];
|
||||
const lastItem = types[types.length - 1];
|
||||
const firstItem = data[0];
|
||||
const lastItem = data[data.length - 1];
|
||||
const isManagedEventPrefix = () => {
|
||||
return deleteDialogTypeSchedulingType === SchedulingType.MANAGED ? "_managed" : "";
|
||||
};
|
||||
return (
|
||||
<div className="bg-default border-subtle mb-16 flex overflow-hidden rounded-md border">
|
||||
<ul ref={parent} className="divide-subtle !static w-full divide-y" data-testid="event-types">
|
||||
{types.map((type, index) => {
|
||||
const embedLink = `${group.profile.slug}/${type.slug}`;
|
||||
{data.map((eventType, index) => {
|
||||
const embedLink = `${eventType?.team?.slug || eventType.users[0].username}/${eventType.slug}`;
|
||||
const calLink = `${orgBranding?.fullDomain ?? CAL_URL}/${embedLink}`;
|
||||
const isManagedEventType = type.schedulingType === SchedulingType.MANAGED;
|
||||
const isChildrenManagedEventType =
|
||||
type.metadata?.managedEventConfig !== undefined && type.schedulingType !== SchedulingType.MANAGED;
|
||||
|
||||
const isManagedEventType = eventType.schedulingType === SchedulingType.MANAGED;
|
||||
|
||||
const isChildrenManagedEventType = !!eventType.parentId;
|
||||
const isReadOnly = readonly || isChildrenManagedEventType;
|
||||
const hosts = !!eventType?.hosts?.length
|
||||
? eventType?.hosts.map((user) => user.user)
|
||||
: eventType.users;
|
||||
return (
|
||||
<li key={type.id}>
|
||||
<li key={eventType.id}>
|
||||
<div className="hover:bg-muted flex w-full items-center justify-between">
|
||||
<div className="group flex w-full max-w-full items-center justify-between overflow-hidden px-4 py-4 sm:px-6">
|
||||
{!(firstItem && firstItem.id === type.id) && (
|
||||
{!(firstItem && firstItem.id === eventType.id) && (
|
||||
<ArrowButton onClick={() => moveEventType(index, -1)} arrowDirection="up" />
|
||||
)}
|
||||
|
||||
{!(lastItem && lastItem.id === type.id) && (
|
||||
{!(lastItem && lastItem.id === eventType.id) && (
|
||||
<ArrowButton onClick={() => moveEventType(index, 1)} arrowDirection="down" />
|
||||
)}
|
||||
<MemoizedItem type={type} group={group} readOnly={readOnly} />
|
||||
<MemoizedItem eventType={eventType} readonly={isReadOnly} />
|
||||
<div className="mt-4 hidden sm:mt-0 sm:flex">
|
||||
<div className="flex justify-between space-x-2 rtl:space-x-reverse">
|
||||
{type.team && !isManagedEventType && (
|
||||
{eventType.team && !isManagedEventType && (
|
||||
<AvatarGroup
|
||||
className="relative right-3 top-1"
|
||||
size="sm"
|
||||
truncateAfter={4}
|
||||
items={
|
||||
type?.users
|
||||
? type.users.map(
|
||||
(organizer: { name: string | null; username: string | null }) => ({
|
||||
items={hosts.map((organizer: { name: string | null; username: string | null }) => ({
|
||||
alt: organizer.name || "",
|
||||
image: `${orgBranding?.fullDomain ?? WEBAPP_URL}/${
|
||||
organizer.username
|
||||
}/avatar.png`,
|
||||
title: organizer.name || "",
|
||||
})
|
||||
)
|
||||
: []
|
||||
}
|
||||
}))}
|
||||
/>
|
||||
)}
|
||||
{isManagedEventType && type?.children && type.children?.length > 0 && (
|
||||
{isManagedEventType && eventType.children?.length > 0 && (
|
||||
<AvatarGroup
|
||||
className="relative right-3 top-1"
|
||||
size="sm"
|
||||
truncateAfter={4}
|
||||
items={type?.children
|
||||
.flatMap((ch) => ch.users)
|
||||
.map((user: Pick<User, "name" | "username">) => ({
|
||||
alt: user.name || "",
|
||||
image: `${orgBranding?.fullDomain ?? WEBAPP_URL}/${user.username}/avatar.png`,
|
||||
title: user.name || "",
|
||||
}))}
|
||||
items={eventType.children.map(
|
||||
({ users }: { users: Pick<User, "name" | "username">[] }) => ({
|
||||
alt: users[0].name || "",
|
||||
image: `${orgBranding?.fullDomain ?? WEBAPP_URL}/${
|
||||
users[0].username
|
||||
}/avatar.png`,
|
||||
title: users[0].name || "",
|
||||
})
|
||||
)}
|
||||
/>
|
||||
)}
|
||||
<div className="flex items-center justify-between space-x-2 rtl:space-x-reverse">
|
||||
{!isManagedEventType && (
|
||||
<>
|
||||
{type.hidden && <Badge variant="gray">{t("hidden")}</Badge>}
|
||||
{eventType.hidden && <Badge variant="gray">{t("hidden")}</Badge>}
|
||||
<Tooltip
|
||||
content={type.hidden ? t("show_eventtype_on_profile") : t("hide_from_profile")}>
|
||||
content={
|
||||
eventType.hidden ? t("show_eventtype_on_profile") : t("hide_from_profile")
|
||||
}>
|
||||
<div className="self-center rounded-md p-2">
|
||||
<Switch
|
||||
name="Hidden"
|
||||
checked={!type.hidden}
|
||||
checked={!eventType.hidden}
|
||||
onCheckedChange={() => {
|
||||
setHiddenMutation.mutate({ id: type.id, hidden: !type.hidden });
|
||||
setHiddenMutation.mutate({ id: eventType.id, hidden: !eventType.hidden });
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
|
@ -478,8 +502,8 @@ export const EventTypeList = ({ group, groupIndex, readOnly, types }: EventTypeL
|
|||
</Tooltip>
|
||||
</>
|
||||
)}
|
||||
<Dropdown modal={false}>
|
||||
<DropdownMenuTrigger asChild data-testid={"event-type-options-" + type.id}>
|
||||
<Dropdown modal={isReadOnly}>
|
||||
<DropdownMenuTrigger asChild data-testid={"event-type-options-" + eventType.id}>
|
||||
<Button
|
||||
type="button"
|
||||
variant="icon"
|
||||
|
@ -489,13 +513,13 @@ export const EventTypeList = ({ group, groupIndex, readOnly, types }: EventTypeL
|
|||
/>
|
||||
</DropdownMenuTrigger>
|
||||
<DropdownMenuContent>
|
||||
{!readOnly && (
|
||||
{!isReadOnly && (
|
||||
<DropdownMenuItem>
|
||||
<DropdownItem
|
||||
type="button"
|
||||
data-testid={"event-type-edit-" + type.id}
|
||||
data-testid={"event-type-edit-" + eventType.id}
|
||||
StartIcon={Edit2}
|
||||
onClick={() => router.push("/event-types/" + type.id)}>
|
||||
onClick={() => router.push("/event-types/" + eventType.id)}>
|
||||
{t("edit")}
|
||||
</DropdownItem>
|
||||
</DropdownMenuItem>
|
||||
|
@ -505,9 +529,9 @@ export const EventTypeList = ({ group, groupIndex, readOnly, types }: EventTypeL
|
|||
<DropdownMenuItem className="outline-none">
|
||||
<DropdownItem
|
||||
type="button"
|
||||
data-testid={"event-type-duplicate-" + type.id}
|
||||
data-testid={"event-type-duplicate-" + eventType.id}
|
||||
StartIcon={Copy}
|
||||
onClick={() => openDuplicateModal(type, group)}>
|
||||
onClick={() => openDuplicateModal(eventType)}>
|
||||
{t("duplicate")}
|
||||
</DropdownItem>
|
||||
</DropdownMenuItem>
|
||||
|
@ -521,14 +545,13 @@ export const EventTypeList = ({ group, groupIndex, readOnly, types }: EventTypeL
|
|||
StartIcon={Code}
|
||||
className="w-full rounded-none"
|
||||
embedUrl={encodeURIComponent(embedLink)}
|
||||
eventId={type.id}>
|
||||
eventId={eventType.id}>
|
||||
{t("embed")}
|
||||
</EventTypeEmbedButton>
|
||||
</DropdownMenuItem>
|
||||
)}
|
||||
{/* readonly is only set when we are on a team - if we are on a user event type null will be the value. */}
|
||||
{(group.metadata?.readOnly === false || group.metadata.readOnly === null) &&
|
||||
!isChildrenManagedEventType && (
|
||||
{isReadOnly && !isChildrenManagedEventType && (
|
||||
<>
|
||||
<DropdownMenuSeparator />
|
||||
<DropdownMenuItem>
|
||||
|
@ -536,8 +559,8 @@ export const EventTypeList = ({ group, groupIndex, readOnly, types }: EventTypeL
|
|||
color="destructive"
|
||||
onClick={() => {
|
||||
setDeleteDialogOpen(true);
|
||||
setDeleteDialogTypeId(type.id);
|
||||
setDeleteDialogSchedulingType(type.schedulingType);
|
||||
setDeleteDialogTypeId(eventType.id);
|
||||
setDeleteDialogSchedulingType(eventType.schedulingType);
|
||||
}}
|
||||
StartIcon={Trash}
|
||||
className="w-full rounded-none">
|
||||
|
@ -555,7 +578,7 @@ export const EventTypeList = ({ group, groupIndex, readOnly, types }: EventTypeL
|
|||
</div>
|
||||
<div className="min-w-9 mx-5 flex sm:hidden">
|
||||
<Dropdown>
|
||||
<DropdownMenuTrigger asChild data-testid={"event-type-options-" + type.id}>
|
||||
<DropdownMenuTrigger asChild data-testid={"event-type-options-" + eventType.id}>
|
||||
<Button type="button" variant="icon" color="secondary" StartIcon={MoreHorizontal} />
|
||||
</DropdownMenuTrigger>
|
||||
<DropdownMenuPortal>
|
||||
|
@ -573,7 +596,7 @@ export const EventTypeList = ({ group, groupIndex, readOnly, types }: EventTypeL
|
|||
</DropdownMenuItem>
|
||||
<DropdownMenuItem className="outline-none">
|
||||
<DropdownItem
|
||||
data-testid={"event-type-duplicate-" + type.id}
|
||||
data-testid={"event-type-duplicate-" + eventType.id}
|
||||
onClick={() => {
|
||||
navigator.clipboard.writeText(calLink);
|
||||
showToast(t("link_copied"), "success");
|
||||
|
@ -588,7 +611,7 @@ export const EventTypeList = ({ group, groupIndex, readOnly, types }: EventTypeL
|
|||
{isNativeShare ? (
|
||||
<DropdownMenuItem className="outline-none">
|
||||
<DropdownItem
|
||||
data-testid={"event-type-duplicate-" + type.id}
|
||||
data-testid={"event-type-duplicate-" + eventType.id}
|
||||
onClick={() => {
|
||||
navigator
|
||||
.share({
|
||||
|
@ -605,10 +628,10 @@ export const EventTypeList = ({ group, groupIndex, readOnly, types }: EventTypeL
|
|||
</DropdownItem>
|
||||
</DropdownMenuItem>
|
||||
) : null}
|
||||
{!readOnly && (
|
||||
{!isReadOnly && (
|
||||
<DropdownMenuItem className="outline-none">
|
||||
<DropdownItem
|
||||
onClick={() => router.push("/event-types/" + type.id)}
|
||||
onClick={() => router.push("/event-types/" + eventType.id)}
|
||||
StartIcon={Edit}
|
||||
className="w-full rounded-none">
|
||||
{t("edit")}
|
||||
|
@ -618,24 +641,23 @@ export const EventTypeList = ({ group, groupIndex, readOnly, types }: EventTypeL
|
|||
{!isManagedEventType && !isChildrenManagedEventType && (
|
||||
<DropdownMenuItem className="outline-none">
|
||||
<DropdownItem
|
||||
onClick={() => openDuplicateModal(type, group)}
|
||||
onClick={() => openDuplicateModal(eventType)}
|
||||
StartIcon={Copy}
|
||||
data-testid={"event-type-duplicate-" + type.id}>
|
||||
data-testid={"event-type-duplicate-" + eventType.id}>
|
||||
{t("duplicate")}
|
||||
</DropdownItem>
|
||||
</DropdownMenuItem>
|
||||
)}
|
||||
{/* readonly is only set when we are on a team - if we are on a user event type null will be the value. */}
|
||||
{(group.metadata?.readOnly === false || group.metadata.readOnly === null) &&
|
||||
!isChildrenManagedEventType && (
|
||||
{isReadOnly && !isChildrenManagedEventType && (
|
||||
<>
|
||||
<DropdownMenuItem className="outline-none">
|
||||
<DropdownItem
|
||||
color="destructive"
|
||||
onClick={() => {
|
||||
setDeleteDialogOpen(true);
|
||||
setDeleteDialogTypeId(type.id);
|
||||
setDeleteDialogSchedulingType(type.schedulingType);
|
||||
setDeleteDialogTypeId(eventType.id);
|
||||
setDeleteDialogSchedulingType(eventType.schedulingType);
|
||||
}}
|
||||
StartIcon={Trash}
|
||||
className="w-full rounded-none">
|
||||
|
@ -651,14 +673,14 @@ export const EventTypeList = ({ group, groupIndex, readOnly, types }: EventTypeL
|
|||
as={Label}
|
||||
htmlFor="hiddenSwitch"
|
||||
className="mt-2 inline cursor-pointer self-center pr-2 ">
|
||||
{type.hidden ? t("show_eventtype_on_profile") : t("hide_from_profile")}
|
||||
{eventType.hidden ? t("show_eventtype_on_profile") : t("hide_from_profile")}
|
||||
</Skeleton>
|
||||
<Switch
|
||||
id="hiddenSwitch"
|
||||
name="Hidden"
|
||||
checked={!type.hidden}
|
||||
checked={!eventType.hidden}
|
||||
onCheckedChange={() => {
|
||||
setHiddenMutation.mutate({ id: type.id, hidden: !type.hidden });
|
||||
setHiddenMutation.mutate({ id: eventType.id, hidden: !eventType.hidden });
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
|
@ -702,7 +724,8 @@ export const EventTypeList = ({ group, groupIndex, readOnly, types }: EventTypeL
|
|||
};
|
||||
|
||||
const EventTypeListHeading = ({
|
||||
profile,
|
||||
teamSlugOrUsername,
|
||||
teamNameOrUserName,
|
||||
membershipCount,
|
||||
teamId,
|
||||
}: EventTypeListHeadingProps): JSX.Element => {
|
||||
|
@ -711,7 +734,7 @@ const EventTypeListHeading = ({
|
|||
const orgBranding = useOrgBranding();
|
||||
|
||||
const publishTeamMutation = trpc.viewer.teams.publish.useMutation({
|
||||
onSuccess(data) {
|
||||
onSuccess(data: { url: string }) {
|
||||
router.push(data.url);
|
||||
},
|
||||
onError: (error) => {
|
||||
|
@ -719,17 +742,13 @@ const EventTypeListHeading = ({
|
|||
},
|
||||
});
|
||||
const bookerUrl = useBookerUrl();
|
||||
|
||||
const slug = teamSlugOrUsername;
|
||||
return (
|
||||
<div className="mb-4 flex items-center space-x-2">
|
||||
<Avatar
|
||||
alt={profile?.name || ""}
|
||||
alt={teamNameOrUserName}
|
||||
href={teamId ? `/settings/teams/${teamId}/profile` : "/settings/my-account/profile"}
|
||||
imageSrc={
|
||||
orgBranding?.fullDomain
|
||||
? `${orgBranding.fullDomain}${teamId ? "/team" : ""}/${profile.slug}/avatar.png`
|
||||
: profile.image
|
||||
}
|
||||
imageSrc={`${orgBranding?.fullDomain ?? WEBAPP_URL}/${slug}/avatar.png` || undefined}
|
||||
size="md"
|
||||
className="mt-1 inline-flex justify-center"
|
||||
/>
|
||||
|
@ -737,9 +756,9 @@ const EventTypeListHeading = ({
|
|||
<Link
|
||||
href={teamId ? `/settings/teams/${teamId}/profile` : "/settings/my-account/profile"}
|
||||
className="text-emphasis font-bold">
|
||||
{profile?.name || ""}
|
||||
{teamNameOrUserName}
|
||||
</Link>
|
||||
{membershipCount && teamId && (
|
||||
{membershipCount >= 0 && teamId && (
|
||||
<span className="text-subtle relative -top-px me-2 ms-2 text-xs">
|
||||
<Link href={`/settings/teams/${teamId}/members`}>
|
||||
<Badge variant="gray">
|
||||
|
@ -749,15 +768,15 @@ const EventTypeListHeading = ({
|
|||
</Link>
|
||||
</span>
|
||||
)}
|
||||
{profile?.slug && (
|
||||
{slug && (
|
||||
<Link
|
||||
href={`${orgBranding ? orgBranding.fullDomain : CAL_URL}/${profile.slug}`}
|
||||
href={`${orgBranding ? orgBranding.fullDomain : CAL_URL}/${slug}`}
|
||||
className="text-subtle block text-xs">
|
||||
{`${bookerUrl.replace("https://", "").replace("http://", "")}/${profile.slug}`}
|
||||
{`${bookerUrl.replace("https://", "").replace("http://", "")}/${slug}`}
|
||||
</Link>
|
||||
)}
|
||||
</div>
|
||||
{!profile?.slug && !!teamId && (
|
||||
{!slug && !!teamId && (
|
||||
<button onClick={() => publishTeamMutation.mutate({ teamId })}>
|
||||
<Badge variant="gray" className="-ml-2 mb-1">
|
||||
{t("upgrade")}
|
||||
|
@ -786,30 +805,18 @@ const CreateFirstEventTypeView = ({ slug }: { slug: string }) => {
|
|||
);
|
||||
};
|
||||
|
||||
const CTA = ({ data }: { data: GetByViewerResponse }) => {
|
||||
const CTA = () => {
|
||||
const { t } = useLocale();
|
||||
|
||||
if (!data) return null;
|
||||
|
||||
const profileOptions = data.profiles
|
||||
.filter((profile) => !profile.readOnly)
|
||||
.map((profile) => {
|
||||
return {
|
||||
teamId: profile.teamId,
|
||||
label: profile.name || profile.slug,
|
||||
image: profile.image,
|
||||
membershipRole: profile.membershipRole,
|
||||
slug: profile.slug,
|
||||
};
|
||||
});
|
||||
|
||||
return (
|
||||
<CreateButton
|
||||
<>
|
||||
<CreateButtonWithTeamsList
|
||||
data-testid="new-event-type"
|
||||
subtitle={t("create_event_on").toUpperCase()}
|
||||
options={profileOptions}
|
||||
createDialog={() => <CreateEventTypeDialog profileOptions={profileOptions} />}
|
||||
createDialog={() => <CreateEventTypeDialog profileOptions={[]} />}
|
||||
/>
|
||||
<CreateEventTypeDialog profileOptions={[]} />
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
|
@ -849,15 +856,24 @@ const SetupProfileBanner = ({ closeAction }: { closeAction: () => void }) => {
|
|||
);
|
||||
};
|
||||
|
||||
const EmptyEventTypeList = ({ group }: { group: EventTypeGroup }) => {
|
||||
const EmptyEventTypeList = ({
|
||||
teamSlugOrUsername,
|
||||
teamId,
|
||||
}: {
|
||||
teamSlugOrUsername: string | null;
|
||||
teamId?: number | null;
|
||||
}) => {
|
||||
const { t } = useLocale();
|
||||
if (!teamSlugOrUsername && !teamId) {
|
||||
return null;
|
||||
}
|
||||
return (
|
||||
<>
|
||||
<EmptyScreen
|
||||
headline={t("team_no_event_types")}
|
||||
buttonRaw={
|
||||
<Button
|
||||
href={`?dialog=new&eventPage=${group.profile.slug}&teamId=${group.teamId}`}
|
||||
href={`?dialog=new&eventPage=${teamSlugOrUsername}${teamId ? `&teamId=${teamId}` : ""}`}
|
||||
variant="button"
|
||||
className="mt-5">
|
||||
{t("create")}
|
||||
|
@ -868,78 +884,163 @@ const EmptyEventTypeList = ({ group }: { group: EventTypeGroup }) => {
|
|||
);
|
||||
};
|
||||
|
||||
const Main = ({
|
||||
status,
|
||||
errorMessage,
|
||||
data,
|
||||
filters,
|
||||
}: {
|
||||
status: string;
|
||||
data: GetByViewerResponse;
|
||||
errorMessage?: string;
|
||||
filters: ReturnType<typeof getTeamsFiltersFromQuery>;
|
||||
}) => {
|
||||
const Main = ({ filters }: { filters: ReturnType<typeof getTeamsFiltersFromQuery> }) => {
|
||||
const isMobile = useMediaQuery("(max-width: 768px)");
|
||||
const searchParams = useSearchParams();
|
||||
const orgBranding = useOrgBranding();
|
||||
|
||||
if (!data || status === "loading") {
|
||||
// const isFilteredByOnlyOneItem =
|
||||
// (filters?.teamIds?.length === 1 || filters?.userIds?.length === 1) && data?.eventTypeGroups.length === 1;
|
||||
const isFilteredByOnlyOneItem = false;
|
||||
|
||||
// We first load user event types and then team event types
|
||||
const { data, status, error } = trpc.viewer.eventTypes.paginate.useQuery(
|
||||
{
|
||||
page: 1,
|
||||
pageSize: 10,
|
||||
},
|
||||
{
|
||||
trpc: {
|
||||
context: { skipBatch: true },
|
||||
},
|
||||
}
|
||||
);
|
||||
|
||||
// Then we load teams
|
||||
const { data: teams } = trpc.viewer.teams.list.useQuery(undefined, {
|
||||
// Teams don't change that frequently
|
||||
refetchOnWindowFocus: false,
|
||||
trpc: {
|
||||
context: { skipBatch: true },
|
||||
},
|
||||
});
|
||||
|
||||
// After teams are fetched we then load event types for each team
|
||||
const eventTypePaginate = trpc.useQueries(
|
||||
(t) =>
|
||||
teams?.map((team) => t.viewer.eventTypes.paginate({ page: 1, pageSize: 10, teamIds: [team.id] }), {
|
||||
enabled: teams.length > 0,
|
||||
}) || []
|
||||
);
|
||||
|
||||
if (status === "error") {
|
||||
return <Alert severity="error" title="Something went wrong" message={error.message} />;
|
||||
}
|
||||
if (status === "loading") {
|
||||
return <SkeletonLoader />;
|
||||
}
|
||||
|
||||
if (status === "error") {
|
||||
return <Alert severity="error" title="Something went wrong" message={errorMessage} />;
|
||||
}
|
||||
if ((!!data && data.length > 1) || isFilteredByOnlyOneItem) {
|
||||
const [firstElementPersonalEventTypes] = data;
|
||||
const [mainUser] = firstElementPersonalEventTypes?.users || [];
|
||||
|
||||
const isFilteredByOnlyOneItem =
|
||||
(filters?.teamIds?.length === 1 || filters?.userIds?.length === 1) && data.eventTypeGroups.length === 1;
|
||||
const teamEventTypesForTabs = eventTypePaginate
|
||||
.map((trpcFetch) => {
|
||||
const { data } = trpcFetch;
|
||||
return data || [];
|
||||
})
|
||||
.filter((item) => item && item.length > 0);
|
||||
return (
|
||||
<>
|
||||
{data.eventTypeGroups.length > 1 || isFilteredByOnlyOneItem ? (
|
||||
<>
|
||||
{isMobile ? (
|
||||
<MobileTeamsTab eventTypeGroups={data.eventTypeGroups} />
|
||||
<MobileTeamsTab teamEventTypes={[data, ...teamEventTypesForTabs]} />
|
||||
) : (
|
||||
data.eventTypeGroups.map((group: EventTypeGroup, index: number) => (
|
||||
<div className="mt-4 flex flex-col" key={group.profile.slug}>
|
||||
<div className="mt-4 flex flex-col">
|
||||
<EventTypeListHeading
|
||||
profile={group.profile}
|
||||
membershipCount={group.metadata.membershipCount}
|
||||
teamId={group.teamId}
|
||||
teamSlugOrUsername={mainUser.username || ""}
|
||||
teamNameOrUserName={mainUser.name || ""}
|
||||
// Single event types have no teamMembershipCount
|
||||
membershipCount={0}
|
||||
teamId={firstElementPersonalEventTypes.teamId}
|
||||
orgSlug={orgBranding?.slug}
|
||||
/>
|
||||
|
||||
{group.eventTypes.length ? (
|
||||
<EventTypeList
|
||||
types={group.eventTypes}
|
||||
group={group}
|
||||
groupIndex={index}
|
||||
readOnly={group.metadata.readOnly}
|
||||
/>
|
||||
) : group.teamId ? (
|
||||
<EmptyEventTypeList group={group} />
|
||||
{data.length > 0 ? (
|
||||
<EventTypeList data={data} />
|
||||
) : (
|
||||
<CreateFirstEventTypeView slug={data.profiles[0].slug ?? ""} />
|
||||
<EmptyEventTypeList teamSlugOrUsername={mainUser.username ?? ""} />
|
||||
)}
|
||||
</div>
|
||||
))
|
||||
|
||||
{/* Then we list team event types */}
|
||||
{eventTypePaginate.map((trpcFetch, index) => {
|
||||
const { data: teamEventTypes } = trpcFetch;
|
||||
const [firstElementTeamEventTypes] = teamEventTypes || [];
|
||||
|
||||
if (!teamEventTypes || teamEventTypes.length === 0 || !firstElementTeamEventTypes.team) {
|
||||
return null;
|
||||
}
|
||||
const teamDataMatchWithEventType = teams && teams.length > 0 ? teams[index] : null;
|
||||
const membershipCount = teamDataMatchWithEventType
|
||||
? teamDataMatchWithEventType?.membershipCount
|
||||
: 0;
|
||||
|
||||
return (
|
||||
<>
|
||||
<EventTypeListHeading
|
||||
key={index}
|
||||
teamSlugOrUsername={firstElementTeamEventTypes.team.slug || ""}
|
||||
teamNameOrUserName={firstElementTeamEventTypes.team.name || ""}
|
||||
membershipCount={membershipCount}
|
||||
teamId={firstElementTeamEventTypes.teamId}
|
||||
orgSlug={orgBranding?.slug}
|
||||
/>
|
||||
|
||||
{teamEventTypes.length > 0 ? (
|
||||
<EventTypeList
|
||||
data={teamEventTypes}
|
||||
key={index}
|
||||
readonly={
|
||||
teamDataMatchWithEventType ? "MEMBER" === teamDataMatchWithEventType.role : false
|
||||
}
|
||||
/>
|
||||
) : (
|
||||
<EmptyEventTypeList
|
||||
teamId={firstElementTeamEventTypes.teamId}
|
||||
teamSlugOrUsername={firstElementTeamEventTypes.team.slug || ""}
|
||||
key={index}
|
||||
/>
|
||||
)}
|
||||
</>
|
||||
) : (
|
||||
data.eventTypeGroups.length === 1 && (
|
||||
<EventTypeList
|
||||
types={data.eventTypeGroups[0].eventTypes}
|
||||
group={data.eventTypeGroups[0]}
|
||||
groupIndex={0}
|
||||
readOnly={data.eventTypeGroups[0].metadata.readOnly}
|
||||
/>
|
||||
)
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
)}
|
||||
{data.eventTypeGroups.length === 0 && <CreateFirstEventTypeView slug={data.profiles[0].slug ?? ""} />}
|
||||
<EventTypeEmbedDialog />
|
||||
{searchParams?.get("dialog") === "duplicate" && <DuplicateDialog />}
|
||||
</>
|
||||
);
|
||||
} else if (!!data && data.length === 1) {
|
||||
return <EventTypeList data={data} />;
|
||||
} else if (!!data && data.length === 0) {
|
||||
// @TODO:
|
||||
return <CreateFirstEventTypeView slug="fixlater" />;
|
||||
} else {
|
||||
return <></>;
|
||||
}
|
||||
// ) : group.teamId ? (
|
||||
// <EmptyEventTypeList group={group} />
|
||||
// ) : (
|
||||
// <CreateFirstEventTypeView slug={data.profiles[0].slug ?? ""} />
|
||||
// )}
|
||||
// </div>
|
||||
// ))
|
||||
// )}
|
||||
// </>
|
||||
// ) : (
|
||||
// data.eventTypeGroups.length === 1 && (
|
||||
// <EventTypeList
|
||||
// types={data.eventTypeGroups[0].eventTypes}
|
||||
// group={data.eventTypeGroups[0]}
|
||||
// groupIndex={0}
|
||||
// readOnly={data.eventTypeGroups[0].metadata.readOnly}
|
||||
// />
|
||||
// )
|
||||
// )}
|
||||
// {data.eventTypeGroups.length === 0 && <CreateFirstEventTypeView slug={data.profiles[0].slug ?? ""} />}
|
||||
// <EventTypeEmbedDialog />
|
||||
// {searchParams?.get("dialog") === "duplicate" && <DuplicateDialog />}
|
||||
// </>
|
||||
// );
|
||||
};
|
||||
|
||||
const EventTypesPage = () => {
|
||||
|
@ -952,13 +1053,6 @@ const EventTypesPage = () => {
|
|||
const routerQuery = useRouterQuery();
|
||||
const filters = getTeamsFiltersFromQuery(routerQuery);
|
||||
|
||||
// TODO: Maybe useSuspenseQuery to focus on success case only? Remember that it would crash the page when there is an error in query. Also, it won't support skeleton
|
||||
const { data, status, error } = trpc.viewer.eventTypes.getByViewer.useQuery(filters && { filters }, {
|
||||
refetchOnWindowFocus: false,
|
||||
cacheTime: 1 * 60 * 60 * 1000,
|
||||
staleTime: 1 * 60 * 60 * 1000,
|
||||
});
|
||||
|
||||
function closeBanner() {
|
||||
setShowProfileBanner(false);
|
||||
document.cookie = `calcom-profile-banner=1;max-age=${60 * 60 * 24 * 90}`; // 3 months
|
||||
|
@ -986,12 +1080,12 @@ const EventTypesPage = () => {
|
|||
subtitle={t("event_types_page_subtitle")}
|
||||
afterHeading={showProfileBanner && <SetupProfileBanner closeAction={closeBanner} />}
|
||||
beforeCTAactions={<Actions />}
|
||||
CTA={<CTA data={data} />}>
|
||||
CTA={<CTA />}>
|
||||
<HeadSeo
|
||||
title="Event Types"
|
||||
description="Create events to share for people to book on your calendar."
|
||||
/>
|
||||
<Main data={data} status={status} errorMessage={error?.message} filters={filters} />
|
||||
<Main filters={filters} />
|
||||
</ShellMain>
|
||||
);
|
||||
};
|
||||
|
|
|
@ -0,0 +1,12 @@
|
|||
-- View: public.TeamMemberCount
|
||||
|
||||
-- DROP VIEW public."TeamMemberCount";
|
||||
|
||||
CREATE OR REPLACE VIEW public."TeamMemberCount"
|
||||
AS
|
||||
SELECT t.id,
|
||||
count(*) AS count
|
||||
FROM "Membership" m
|
||||
LEFT JOIN "Team" t ON t.id = m."teamId"
|
||||
WHERE m.accepted = true
|
||||
GROUP BY t.id;
|
|
@ -938,6 +938,19 @@ enum AccessScope {
|
|||
READ_PROFILE
|
||||
}
|
||||
|
||||
model CalendarCache {
|
||||
// The key would be the unique URL that is requested by the user
|
||||
key String
|
||||
value Json
|
||||
expiresAt DateTime
|
||||
credentialId Int
|
||||
credential Credential? @relation(fields: [credentialId], references: [id], onDelete: Cascade)
|
||||
|
||||
@@id([credentialId, key])
|
||||
@@unique([credentialId, key])
|
||||
}
|
||||
|
||||
// Let's keep views at the bottom of the schema
|
||||
view BookingTimeStatus {
|
||||
id Int @unique
|
||||
uid String?
|
||||
|
@ -958,14 +971,7 @@ view BookingTimeStatus {
|
|||
eventParentId Int?
|
||||
}
|
||||
|
||||
model CalendarCache {
|
||||
// The key would be the unique URL that is requested by the user
|
||||
key String
|
||||
value Json
|
||||
expiresAt DateTime
|
||||
credentialId Int
|
||||
credential Credential? @relation(fields: [credentialId], references: [id], onDelete: Cascade)
|
||||
|
||||
@@id([credentialId, key])
|
||||
@@unique([credentialId, key])
|
||||
view TeamMemberCount {
|
||||
id Int @unique
|
||||
count Int
|
||||
}
|
||||
|
|
|
@ -0,0 +1,221 @@
|
|||
/**
|
||||
* This script can be used to seed the database with a lot of data for performance testing.
|
||||
* TODO: Make it more structured and configurable from CLI
|
||||
* Run it as `npx ts-node --transpile-only ./seed-event-types-and-teams.ts`
|
||||
*/
|
||||
import type { Prisma } from "@prisma/client";
|
||||
|
||||
import prisma from ".";
|
||||
|
||||
async function createEventTypesForUserAndForTeams() {
|
||||
const selectedUser = await prisma.user.findFirst({
|
||||
where: {
|
||||
username: "teampro",
|
||||
},
|
||||
});
|
||||
|
||||
if (!selectedUser) {
|
||||
throw new Error("No user found");
|
||||
}
|
||||
|
||||
// Create randomized event types for the user
|
||||
await createManyEventTypes({ userId: selectedUser.id });
|
||||
|
||||
// Create randomized event types for the teams
|
||||
await createManyTeams(selectedUser.id);
|
||||
}
|
||||
|
||||
async function createManyEventTypes({ userId, teamId }: { userId?: number; teamId?: number }) {
|
||||
// If teamId is provided then we fetch membership users from that team
|
||||
|
||||
const membershipUsers: number[] = [];
|
||||
if (teamId) {
|
||||
const memberships = await prisma.membership.findMany({ where: { teamId } });
|
||||
for (const membership of memberships) {
|
||||
if (!membership.userId) {
|
||||
// Do nothing
|
||||
} else {
|
||||
membershipUsers.push(membership.userId);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const eventTypesPromises: Promise<
|
||||
Prisma.EventTypeGetPayload<{
|
||||
select: {
|
||||
id: true;
|
||||
schedulingType: true;
|
||||
teamId: true;
|
||||
};
|
||||
}>
|
||||
>[] = [];
|
||||
|
||||
for (let i = 0; i < 20; i++) {
|
||||
const schedulingType = randomSchedulingType();
|
||||
eventTypesPromises.push(
|
||||
prisma.eventType.create({
|
||||
data: {
|
||||
title: `${schedulingType.toLowerCase() ?? ""} Event Type ${i + 1} - ${
|
||||
teamId ? `Team ${teamId}` : ""
|
||||
}`,
|
||||
slug: `event-type-${teamId ? `team-${teamId}` : ""}${i + 1}`,
|
||||
userId: teamId ? null : userId,
|
||||
teamId: teamId ? teamId : null,
|
||||
length: 30,
|
||||
description: "This is a description",
|
||||
...(teamId ? { schedulingType: schedulingType } : {}),
|
||||
},
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
const resultEventTypes = await Promise.all(eventTypesPromises);
|
||||
|
||||
const updateRelationships: Promise<any>[] = [];
|
||||
for (const eventType of resultEventTypes) {
|
||||
const schedulingType = eventType.schedulingType;
|
||||
updateRelationships.push(
|
||||
prisma.eventType.update({
|
||||
where: {
|
||||
id: eventType.id,
|
||||
},
|
||||
data: {
|
||||
users: {
|
||||
connect: {
|
||||
id: userId,
|
||||
},
|
||||
},
|
||||
...(schedulingType === "COLLECTIVE" || schedulingType === "ROUND_ROBIN"
|
||||
? {
|
||||
hosts: {
|
||||
create: membershipUsers.map((userId) => ({
|
||||
userId,
|
||||
isFixed: schedulingType === "COLLECTIVE" ? true : false,
|
||||
})),
|
||||
},
|
||||
}
|
||||
: {}),
|
||||
},
|
||||
})
|
||||
);
|
||||
}
|
||||
await Promise.all(updateRelationships);
|
||||
}
|
||||
|
||||
async function createManyTeams(userId: number) {
|
||||
const teamsPromises: Promise<
|
||||
Prisma.TeamGetPayload<{
|
||||
select: {
|
||||
id: true;
|
||||
};
|
||||
}>
|
||||
>[] = [];
|
||||
for (let i = 0; i < 20; i++) {
|
||||
teamsPromises.push(
|
||||
prisma.team.create({
|
||||
data: {
|
||||
name: `Team ${i + 1}`,
|
||||
slug: `team-${i + 1}`,
|
||||
},
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
const result = await Promise.all(teamsPromises);
|
||||
if (result.length > 0) {
|
||||
console.log(`👥 Created ${result.length} teams`);
|
||||
}
|
||||
const teamIds = result.map((team) => team.id);
|
||||
|
||||
const usersForTeam = await createManyUsers();
|
||||
|
||||
if (usersForTeam.length > 0) {
|
||||
console.log(`👥 Created ${usersForTeam.length} users for teams`);
|
||||
}
|
||||
|
||||
// Create memberships for the user
|
||||
const memberships: Prisma.MembershipUncheckedCreateInput[] = [];
|
||||
|
||||
for (const teamId of teamIds) {
|
||||
for (const userId of usersForTeam) {
|
||||
memberships.push({
|
||||
userId: userId,
|
||||
teamId: teamId,
|
||||
role: randomTeamRole(),
|
||||
accepted: true,
|
||||
});
|
||||
}
|
||||
// Add main user to all teams as Owner
|
||||
memberships.push({
|
||||
userId: userId,
|
||||
teamId: teamId,
|
||||
role: "OWNER",
|
||||
accepted: true,
|
||||
});
|
||||
}
|
||||
|
||||
await prisma.membership.createMany({
|
||||
data: memberships,
|
||||
});
|
||||
|
||||
// Create event Types for those teams
|
||||
// Load memberships
|
||||
const membershipsFound = await prisma.membership.findMany({
|
||||
where: {
|
||||
userId,
|
||||
},
|
||||
select: {
|
||||
teamId: true,
|
||||
},
|
||||
});
|
||||
|
||||
if (!membershipsFound.length) {
|
||||
throw new Error("No memberships found");
|
||||
}
|
||||
|
||||
for (const membership of membershipsFound) {
|
||||
await createManyEventTypes({ userId, teamId: membership.teamId });
|
||||
}
|
||||
}
|
||||
|
||||
async function createManyUsers() {
|
||||
const userPromises: Promise<
|
||||
Prisma.UserGetPayload<{
|
||||
select: { id: true };
|
||||
}>
|
||||
>[] = [];
|
||||
for (let i = 0; i < 20; i++) {
|
||||
userPromises.push(
|
||||
prisma.user.create({
|
||||
data: {
|
||||
username: `user-${i + 1}`,
|
||||
email: `user-${i + 1}`,
|
||||
password: "password",
|
||||
name: `User ${i + 1}`,
|
||||
role: randomUserRole(),
|
||||
completedOnboarding: true,
|
||||
},
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
const result = await Promise.all(userPromises);
|
||||
return result.map((user) => user.id);
|
||||
}
|
||||
|
||||
createEventTypesForUserAndForTeams();
|
||||
|
||||
function randomUserRole(): any {
|
||||
const roles = ["USER", "ADMIN"];
|
||||
return roles[Math.floor(Math.random() * roles.length)];
|
||||
}
|
||||
|
||||
function randomTeamRole(): any {
|
||||
const roles = ["ADMIN", "OWNER", "MEMBER"];
|
||||
return roles[Math.floor(Math.random() * roles.length)];
|
||||
}
|
||||
|
||||
function randomSchedulingType(): any {
|
||||
const roles = ["MANAGED", "COLLECTIVE", "ROUND_ROBIN"];
|
||||
return roles[Math.floor(Math.random() * roles.length)];
|
||||
}
|
|
@ -9,6 +9,7 @@ import { ZDeleteInputSchema } from "./delete.schema";
|
|||
import { ZDuplicateInputSchema } from "./duplicate.schema";
|
||||
import { ZGetInputSchema } from "./get.schema";
|
||||
import { ZEventTypeInputSchema } from "./getByViewer.schema";
|
||||
import { ZInfiniteEventsTypeInputSchema } from "./infiniteEventTypes.schema";
|
||||
import { ZUpdateInputSchema } from "./update.schema";
|
||||
import { eventOwnerProcedure } from "./util";
|
||||
|
||||
|
@ -23,6 +24,7 @@ type BookingsRouterHandlerCache = {
|
|||
duplicate?: typeof import("./duplicate.handler").duplicateHandler;
|
||||
bulkEventFetch?: typeof import("./bulkEventFetch.handler").bulkEventFetchHandler;
|
||||
bulkUpdateToDefaultLocation?: typeof import("./bulkUpdateToDefaultLocation.handler").bulkUpdateToDefaultLocationHandler;
|
||||
paginate?: typeof import("./infiniteEventTypes.handler").paginateHandler;
|
||||
};
|
||||
|
||||
const UNSTABLE_HANDLER_CACHE: BookingsRouterHandlerCache = {};
|
||||
|
@ -207,4 +209,22 @@ export const eventTypesRouter = router({
|
|||
input,
|
||||
});
|
||||
}),
|
||||
|
||||
paginate: authedProcedure.input(ZInfiniteEventsTypeInputSchema).query(async ({ ctx, input }) => {
|
||||
if (!UNSTABLE_HANDLER_CACHE.paginate) {
|
||||
UNSTABLE_HANDLER_CACHE.paginate = await import("./infiniteEventTypes.handler").then(
|
||||
(mod) => mod.paginateHandler
|
||||
);
|
||||
}
|
||||
|
||||
// Unreachable code but required for type safety
|
||||
if (!UNSTABLE_HANDLER_CACHE.paginate) {
|
||||
throw new Error("Failed to load handler");
|
||||
}
|
||||
|
||||
return UNSTABLE_HANDLER_CACHE.paginate({
|
||||
ctx,
|
||||
input,
|
||||
});
|
||||
}),
|
||||
});
|
||||
|
|
|
@ -0,0 +1,103 @@
|
|||
import { checkRateLimitAndThrowError } from "@calcom/lib/checkRateLimitAndThrowError";
|
||||
import { prisma } from "@calcom/prisma";
|
||||
|
||||
import type { TrpcSessionUser } from "../../../trpc";
|
||||
import type { TInfiniteEventTypesInputSchema } from "./infiniteEventTypes.schema";
|
||||
import type { Prisma } from ".prisma/client";
|
||||
|
||||
interface EventTypesPaginateProps {
|
||||
ctx: {
|
||||
user: NonNullable<TrpcSessionUser>;
|
||||
};
|
||||
input: TInfiniteEventTypesInputSchema;
|
||||
}
|
||||
|
||||
export const paginateHandler = async ({ ctx, input }: EventTypesPaginateProps) => {
|
||||
await checkRateLimitAndThrowError({
|
||||
identifier: `eventTypes:paginate:${ctx.user.id}`,
|
||||
rateLimitingType: "common",
|
||||
});
|
||||
const userId = ctx.user.id;
|
||||
|
||||
const { teamIds, pageSize = 20, page: pageFromInput = 1 } = input;
|
||||
let page = 1;
|
||||
if (pageFromInput < 1) {
|
||||
page = 1;
|
||||
}
|
||||
|
||||
let teamConditional: Prisma.EventTypeWhereInput = {};
|
||||
|
||||
const whereConditional: Prisma.EventTypeWhereInput = {
|
||||
userId,
|
||||
};
|
||||
|
||||
if (teamIds && teamIds.length === 1) {
|
||||
whereConditional.userId = null;
|
||||
teamConditional = { teamId: teamIds[0] };
|
||||
} else if (teamIds && teamIds.length > 1) {
|
||||
teamConditional = { teamId: { in: teamIds } };
|
||||
}
|
||||
|
||||
// const skip = (page - 1) * pageSize;
|
||||
|
||||
const result = await prisma.eventType.findMany({
|
||||
where: {
|
||||
...whereConditional,
|
||||
...teamConditional,
|
||||
},
|
||||
select: {
|
||||
id: true,
|
||||
title: true,
|
||||
description: true,
|
||||
length: true,
|
||||
schedulingType: true,
|
||||
slug: true,
|
||||
hidden: true,
|
||||
metadata: true,
|
||||
teamId: true,
|
||||
parentId: true,
|
||||
users: {
|
||||
select: {
|
||||
id: true,
|
||||
username: true,
|
||||
name: true,
|
||||
},
|
||||
},
|
||||
hosts: {
|
||||
select: {
|
||||
user: {
|
||||
select: {
|
||||
id: true,
|
||||
username: true,
|
||||
name: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
children: {
|
||||
select: {
|
||||
id: true,
|
||||
users: {
|
||||
select: {
|
||||
id: true,
|
||||
username: true,
|
||||
name: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
team: {
|
||||
select: {
|
||||
id: true,
|
||||
slug: true,
|
||||
name: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
// Temporarily disabled until we can figure out how to do this properly
|
||||
// skip,
|
||||
// take: pageSize,
|
||||
});
|
||||
|
||||
return result;
|
||||
};
|
|
@ -0,0 +1,9 @@
|
|||
import { z } from "zod";
|
||||
|
||||
export const ZInfiniteEventsTypeInputSchema = z.object({
|
||||
teamIds: z.number().array().optional(),
|
||||
page: z.number().optional(),
|
||||
pageSize: z.number().optional(),
|
||||
});
|
||||
|
||||
export type TInfiniteEventTypesInputSchema = z.infer<typeof ZInfiniteEventsTypeInputSchema>;
|
|
@ -35,6 +35,15 @@ export const listHandler = async ({ ctx }: ListOptions) => {
|
|||
|
||||
const isOrgAdmin = !!(await isOrganisationAdmin(ctx.user.id, ctx.user.organization.id)); // Org id exists here as we're inside a conditional TS complaining for some reason
|
||||
|
||||
// This can be optimized by using a custom view between membership and team and teamMemberCount
|
||||
const membershipCount = await prisma.teamMemberCount.findMany({
|
||||
where: {
|
||||
id: {
|
||||
in: membershipsWithoutParent.map((m) => m.teamId),
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
return membershipsWithoutParent.map(({ team: { inviteTokens, ..._team }, ...membership }) => ({
|
||||
role: membership.role,
|
||||
accepted: membership.accepted,
|
||||
|
@ -42,6 +51,7 @@ export const listHandler = async ({ ctx }: ListOptions) => {
|
|||
..._team,
|
||||
/** To prevent breaking we only return non-email attached token here, if we have one */
|
||||
inviteToken: inviteTokens.find((token) => token.identifier === "invite-link-for-teamId-" + _team.id),
|
||||
membershipCount: membershipCount.find((m) => m.id === _team.id)?.count || 0,
|
||||
}));
|
||||
}
|
||||
|
||||
|
@ -59,6 +69,15 @@ export const listHandler = async ({ ctx }: ListOptions) => {
|
|||
orderBy: { role: "desc" },
|
||||
});
|
||||
|
||||
// This can be optimized by using a custom view between membership and team and teamMemberCount
|
||||
const membershipCount = await prisma.teamMemberCount.findMany({
|
||||
where: {
|
||||
id: {
|
||||
in: memberships.map((m) => m.teamId),
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
return memberships
|
||||
.filter((mmship) => {
|
||||
const metadata = teamMetadataSchema.parse(mmship.team.metadata);
|
||||
|
@ -70,5 +89,6 @@ export const listHandler = async ({ ctx }: ListOptions) => {
|
|||
..._team,
|
||||
/** To prevent breaking we only return non-email attached token here, if we have one */
|
||||
inviteToken: inviteTokens.find((token) => token.identifier === "invite-link-for-teamId-" + _team.id),
|
||||
membershipCount: membershipCount.find((m) => m.id === _team.id)?.count || 0,
|
||||
}));
|
||||
};
|
||||
|
|
589
yarn.lock
589
yarn.lock
|
@ -80,14 +80,10 @@ __metadata:
|
|||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@algora/sdk@npm:^0.1.2":
|
||||
version: 0.1.2
|
||||
resolution: "@algora/sdk@npm:0.1.2"
|
||||
dependencies:
|
||||
"@trpc/client": ^10.0.0
|
||||
"@trpc/server": ^10.0.0
|
||||
superjson: ^1.9.1
|
||||
checksum: 0ef5c0ac7fa09c57f685a61859e263f4b5c2d69e6ee72b395f88490106fa6213a0308ca11e5673368e5b33dc4dff38411c0d226f9c65856ef91aa58bc2e0e61c
|
||||
"@alloc/quick-lru@npm:^5.2.0":
|
||||
version: 5.2.0
|
||||
resolution: "@alloc/quick-lru@npm:5.2.0"
|
||||
checksum: bdc35758b552bcf045733ac047fb7f9a07c4678b944c641adfbd41f798b4b91fffd0fdc0df2578d9b0afc7b4d636aa6e110ead5d6281a2adc1ab90efd7f057f8
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
|
@ -3535,15 +3531,13 @@ __metadata:
|
|||
"@calcom/ui": "*"
|
||||
"@types/node": 16.9.1
|
||||
"@types/react": 18.0.26
|
||||
"@types/react-dom": ^18.0.9
|
||||
"@types/react-dom": 18.0.9
|
||||
eslint: ^8.34.0
|
||||
eslint-config-next: ^13.2.1
|
||||
next: ^13.4.6
|
||||
next-auth: ^4.22.1
|
||||
postcss: ^8.4.18
|
||||
next: ^13.2.1
|
||||
next-auth: ^4.20.1
|
||||
react: ^18.2.0
|
||||
react-dom: ^18.2.0
|
||||
tailwindcss: ^3.3.1
|
||||
typescript: ^4.9.4
|
||||
languageName: unknown
|
||||
linkType: soft
|
||||
|
@ -3645,9 +3639,9 @@ __metadata:
|
|||
chart.js: ^3.7.1
|
||||
client-only: ^0.0.1
|
||||
eslint: ^8.34.0
|
||||
next: ^13.4.6
|
||||
next-auth: ^4.22.1
|
||||
next-i18next: ^13.2.2
|
||||
next: ^13.2.1
|
||||
next-auth: ^4.20.1
|
||||
next-i18next: ^11.3.0
|
||||
postcss: ^8.4.18
|
||||
prisma: ^5.0.0
|
||||
prisma-field-encryption: ^1.4.0
|
||||
|
@ -3655,9 +3649,9 @@ __metadata:
|
|||
react-chartjs-2: ^4.0.1
|
||||
react-dom: ^18.2.0
|
||||
react-hook-form: ^7.43.3
|
||||
react-live-chat-loader: ^2.8.1
|
||||
react-live-chat-loader: ^2.7.3
|
||||
swr: ^1.2.2
|
||||
tailwindcss: ^3.3.1
|
||||
tailwindcss: ^3.2.1
|
||||
typescript: ^4.9.4
|
||||
zod: ^3.22.2
|
||||
languageName: unknown
|
||||
|
@ -4621,7 +4615,6 @@ __metadata:
|
|||
version: 0.0.0-use.local
|
||||
resolution: "@calcom/website@workspace:apps/website"
|
||||
dependencies:
|
||||
"@algora/sdk": ^0.1.2
|
||||
"@calcom/app-store": "*"
|
||||
"@calcom/config": "*"
|
||||
"@calcom/dayjs": "*"
|
||||
|
@ -4660,13 +4653,11 @@ __metadata:
|
|||
"@types/node": 16.9.1
|
||||
"@types/react": 18.0.26
|
||||
"@types/react-gtm-module": ^2.0.1
|
||||
"@types/xml2js": ^0.4.11
|
||||
"@vercel/analytics": ^0.1.6
|
||||
"@vercel/edge-functions-ui": ^0.2.1
|
||||
"@vercel/og": ^0.5.0
|
||||
autoprefixer: ^10.4.12
|
||||
bcryptjs: ^2.4.3
|
||||
clsx: ^1.2.1
|
||||
cobe: ^0.4.1
|
||||
concurrently: ^7.6.0
|
||||
cross-env: ^7.0.3
|
||||
|
@ -4683,10 +4674,9 @@ __metadata:
|
|||
graphql-request: ^6.1.0
|
||||
gray-matter: ^4.0.3
|
||||
gsap: ^3.11.0
|
||||
i18n-unused: ^0.13.0
|
||||
iframe-resizer-react: ^1.1.0
|
||||
keen-slider: ^6.8.0
|
||||
lucide-react: ^0.171.0
|
||||
lucide-react: ^0.125.0
|
||||
micro: ^10.0.1
|
||||
next: ^13.4.6
|
||||
next-auth: ^4.22.1
|
||||
|
@ -4709,7 +4699,6 @@ __metadata:
|
|||
react-merge-refs: 1.1.0
|
||||
react-twemoji: ^0.3.0
|
||||
react-use-measure: ^2.1.1
|
||||
react-wrap-balancer: ^1.0.0
|
||||
remark: ^14.0.2
|
||||
remark-html: ^14.0.1
|
||||
remeda: ^1.24.1
|
||||
|
@ -7761,6 +7750,20 @@ __metadata:
|
|||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@next/env@npm:13.2.4":
|
||||
version: 13.2.4
|
||||
resolution: "@next/env@npm:13.2.4"
|
||||
checksum: 4123e08a79e66d6144006972027a9ceb8f3fdd782c4a869df1eb3b91b59ad9f4a44082d3f8e421f4df5214c6bc7190b52b94881369452d65eb4580485f33b9e6
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@next/env@npm:13.4.16":
|
||||
version: 13.4.16
|
||||
resolution: "@next/env@npm:13.4.16"
|
||||
checksum: 2fc506a0c2e4b0596297fc488b9f589cd0d7757b87a1876e77dd83f52b1240aa8932cbd81fb88e1dc9eacec7489d9d2d7dcb063e3b2bcd8099136d6700bcc2f8
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@next/env@npm:13.4.6":
|
||||
version: 13.4.6
|
||||
resolution: "@next/env@npm:13.4.6"
|
||||
|
@ -7777,6 +7780,34 @@ __metadata:
|
|||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@next/swc-android-arm-eabi@npm:13.2.4":
|
||||
version: 13.2.4
|
||||
resolution: "@next/swc-android-arm-eabi@npm:13.2.4"
|
||||
conditions: os=android & cpu=arm
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@next/swc-android-arm64@npm:13.2.4":
|
||||
version: 13.2.4
|
||||
resolution: "@next/swc-android-arm64@npm:13.2.4"
|
||||
conditions: os=android & cpu=arm64
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@next/swc-darwin-arm64@npm:13.2.4":
|
||||
version: 13.2.4
|
||||
resolution: "@next/swc-darwin-arm64@npm:13.2.4"
|
||||
conditions: os=darwin & cpu=arm64
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@next/swc-darwin-arm64@npm:13.4.16":
|
||||
version: 13.4.16
|
||||
resolution: "@next/swc-darwin-arm64@npm:13.4.16"
|
||||
conditions: os=darwin & cpu=arm64
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@next/swc-darwin-arm64@npm:13.4.6":
|
||||
version: 13.4.6
|
||||
resolution: "@next/swc-darwin-arm64@npm:13.4.6"
|
||||
|
@ -7784,6 +7815,20 @@ __metadata:
|
|||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@next/swc-darwin-x64@npm:13.2.4":
|
||||
version: 13.2.4
|
||||
resolution: "@next/swc-darwin-x64@npm:13.2.4"
|
||||
conditions: os=darwin & cpu=x64
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@next/swc-darwin-x64@npm:13.4.16":
|
||||
version: 13.4.16
|
||||
resolution: "@next/swc-darwin-x64@npm:13.4.16"
|
||||
conditions: os=darwin & cpu=x64
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@next/swc-darwin-x64@npm:13.4.6":
|
||||
version: 13.4.6
|
||||
resolution: "@next/swc-darwin-x64@npm:13.4.6"
|
||||
|
@ -7791,6 +7836,34 @@ __metadata:
|
|||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@next/swc-freebsd-x64@npm:13.2.4":
|
||||
version: 13.2.4
|
||||
resolution: "@next/swc-freebsd-x64@npm:13.2.4"
|
||||
conditions: os=freebsd & cpu=x64
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@next/swc-linux-arm-gnueabihf@npm:13.2.4":
|
||||
version: 13.2.4
|
||||
resolution: "@next/swc-linux-arm-gnueabihf@npm:13.2.4"
|
||||
conditions: os=linux & cpu=arm
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@next/swc-linux-arm64-gnu@npm:13.2.4":
|
||||
version: 13.2.4
|
||||
resolution: "@next/swc-linux-arm64-gnu@npm:13.2.4"
|
||||
conditions: os=linux & cpu=arm64 & libc=glibc
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@next/swc-linux-arm64-gnu@npm:13.4.16":
|
||||
version: 13.4.16
|
||||
resolution: "@next/swc-linux-arm64-gnu@npm:13.4.16"
|
||||
conditions: os=linux & cpu=arm64 & libc=glibc
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@next/swc-linux-arm64-gnu@npm:13.4.6":
|
||||
version: 13.4.6
|
||||
resolution: "@next/swc-linux-arm64-gnu@npm:13.4.6"
|
||||
|
@ -7798,6 +7871,20 @@ __metadata:
|
|||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@next/swc-linux-arm64-musl@npm:13.2.4":
|
||||
version: 13.2.4
|
||||
resolution: "@next/swc-linux-arm64-musl@npm:13.2.4"
|
||||
conditions: os=linux & cpu=arm64 & libc=musl
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@next/swc-linux-arm64-musl@npm:13.4.16":
|
||||
version: 13.4.16
|
||||
resolution: "@next/swc-linux-arm64-musl@npm:13.4.16"
|
||||
conditions: os=linux & cpu=arm64 & libc=musl
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@next/swc-linux-arm64-musl@npm:13.4.6":
|
||||
version: 13.4.6
|
||||
resolution: "@next/swc-linux-arm64-musl@npm:13.4.6"
|
||||
|
@ -7805,6 +7892,20 @@ __metadata:
|
|||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@next/swc-linux-x64-gnu@npm:13.2.4":
|
||||
version: 13.2.4
|
||||
resolution: "@next/swc-linux-x64-gnu@npm:13.2.4"
|
||||
conditions: os=linux & cpu=x64 & libc=glibc
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@next/swc-linux-x64-gnu@npm:13.4.16":
|
||||
version: 13.4.16
|
||||
resolution: "@next/swc-linux-x64-gnu@npm:13.4.16"
|
||||
conditions: os=linux & cpu=x64 & libc=glibc
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@next/swc-linux-x64-gnu@npm:13.4.6":
|
||||
version: 13.4.6
|
||||
resolution: "@next/swc-linux-x64-gnu@npm:13.4.6"
|
||||
|
@ -7812,6 +7913,20 @@ __metadata:
|
|||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@next/swc-linux-x64-musl@npm:13.2.4":
|
||||
version: 13.2.4
|
||||
resolution: "@next/swc-linux-x64-musl@npm:13.2.4"
|
||||
conditions: os=linux & cpu=x64 & libc=musl
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@next/swc-linux-x64-musl@npm:13.4.16":
|
||||
version: 13.4.16
|
||||
resolution: "@next/swc-linux-x64-musl@npm:13.4.16"
|
||||
conditions: os=linux & cpu=x64 & libc=musl
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@next/swc-linux-x64-musl@npm:13.4.6":
|
||||
version: 13.4.6
|
||||
resolution: "@next/swc-linux-x64-musl@npm:13.4.6"
|
||||
|
@ -7819,6 +7934,20 @@ __metadata:
|
|||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@next/swc-win32-arm64-msvc@npm:13.2.4":
|
||||
version: 13.2.4
|
||||
resolution: "@next/swc-win32-arm64-msvc@npm:13.2.4"
|
||||
conditions: os=win32 & cpu=arm64
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@next/swc-win32-arm64-msvc@npm:13.4.16":
|
||||
version: 13.4.16
|
||||
resolution: "@next/swc-win32-arm64-msvc@npm:13.4.16"
|
||||
conditions: os=win32 & cpu=arm64
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@next/swc-win32-arm64-msvc@npm:13.4.6":
|
||||
version: 13.4.6
|
||||
resolution: "@next/swc-win32-arm64-msvc@npm:13.4.6"
|
||||
|
@ -7826,6 +7955,20 @@ __metadata:
|
|||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@next/swc-win32-ia32-msvc@npm:13.2.4":
|
||||
version: 13.2.4
|
||||
resolution: "@next/swc-win32-ia32-msvc@npm:13.2.4"
|
||||
conditions: os=win32 & cpu=ia32
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@next/swc-win32-ia32-msvc@npm:13.4.16":
|
||||
version: 13.4.16
|
||||
resolution: "@next/swc-win32-ia32-msvc@npm:13.4.16"
|
||||
conditions: os=win32 & cpu=ia32
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@next/swc-win32-ia32-msvc@npm:13.4.6":
|
||||
version: 13.4.6
|
||||
resolution: "@next/swc-win32-ia32-msvc@npm:13.4.6"
|
||||
|
@ -7833,6 +7976,20 @@ __metadata:
|
|||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@next/swc-win32-x64-msvc@npm:13.2.4":
|
||||
version: 13.2.4
|
||||
resolution: "@next/swc-win32-x64-msvc@npm:13.2.4"
|
||||
conditions: os=win32 & cpu=x64
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@next/swc-win32-x64-msvc@npm:13.4.16":
|
||||
version: 13.4.16
|
||||
resolution: "@next/swc-win32-x64-msvc@npm:13.4.16"
|
||||
conditions: os=win32 & cpu=x64
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@next/swc-win32-x64-msvc@npm:13.4.6":
|
||||
version: 13.4.6
|
||||
resolution: "@next/swc-win32-x64-msvc@npm:13.4.6"
|
||||
|
@ -12040,6 +12197,15 @@ __metadata:
|
|||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@swc/helpers@npm:0.4.14":
|
||||
version: 0.4.14
|
||||
resolution: "@swc/helpers@npm:0.4.14"
|
||||
dependencies:
|
||||
tslib: ^2.4.0
|
||||
checksum: 273fd3f3fc461a92f3790cc551ea054745c6d6959afbe1232e6d7aa1c722bbc114d308aab96bef5c78fc0303c85c7b472ef00e2253251cc89737f3b1af56e5a5
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@swc/helpers@npm:0.5.1":
|
||||
version: 0.5.1
|
||||
resolution: "@swc/helpers@npm:0.5.1"
|
||||
|
@ -17449,7 +17615,7 @@ __metadata:
|
|||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"clsx@npm:^1.0.4, clsx@npm:^1.2.1":
|
||||
"clsx@npm:^1.0.4":
|
||||
version: 1.2.1
|
||||
resolution: "clsx@npm:1.2.1"
|
||||
checksum: 30befca8019b2eb7dbad38cff6266cf543091dae2825c856a62a8ccf2c3ab9c2907c4d12b288b73101196767f66812365400a227581484a05f968b0307cfaf12
|
||||
|
@ -23885,6 +24051,13 @@ __metadata:
|
|||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"i18next-fs-backend@npm:^1.1.4":
|
||||
version: 1.2.0
|
||||
resolution: "i18next-fs-backend@npm:1.2.0"
|
||||
checksum: da74d20f2b007f8e34eaf442fa91ad12aaff3b9891e066c6addd6d111b37e370c62370dfbc656730ab2f8afd988f2e7ea1c48301ebb19ccb716fb5965600eddf
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"i18next-fs-backend@npm:^2.1.1":
|
||||
version: 2.1.3
|
||||
resolution: "i18next-fs-backend@npm:2.1.3"
|
||||
|
@ -23892,6 +24065,15 @@ __metadata:
|
|||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"i18next@npm:^21.8.13":
|
||||
version: 21.10.0
|
||||
resolution: "i18next@npm:21.10.0"
|
||||
dependencies:
|
||||
"@babel/runtime": ^7.17.2
|
||||
checksum: f997985e2d4d15a62a0936a82ff6420b97f3f971e776fe685bdd50b4de0cb4dc2198bc75efe6b152844794ebd5040d8060d6d152506a687affad534834836d81
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"i18next@npm:^23.2.3":
|
||||
version: 23.2.3
|
||||
resolution: "i18next@npm:23.2.3"
|
||||
|
@ -24564,7 +24746,7 @@ __metadata:
|
|||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"is-core-module@npm:^2.11.0":
|
||||
"is-core-module@npm:^2.13.0":
|
||||
version: 2.13.0
|
||||
resolution: "is-core-module@npm:2.13.0"
|
||||
dependencies:
|
||||
|
@ -25535,6 +25717,15 @@ __metadata:
|
|||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"jiti@npm:^1.18.2":
|
||||
version: 1.19.1
|
||||
resolution: "jiti@npm:1.19.1"
|
||||
bin:
|
||||
jiti: bin/jiti.js
|
||||
checksum: fdf55e315f9e81c04ae902416642062851d92c6cdcc17a59d5d1d35e1a0842e4e79be38da86613c5776fa18c579954542a441b93d1c347a50137dee2e558cbd0
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"joi@npm:^17.7.0":
|
||||
version: 17.10.2
|
||||
resolution: "joi@npm:17.10.2"
|
||||
|
@ -26699,6 +26890,13 @@ __metadata:
|
|||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"lilconfig@npm:^2.1.0":
|
||||
version: 2.1.0
|
||||
resolution: "lilconfig@npm:2.1.0"
|
||||
checksum: 8549bb352b8192375fed4a74694cd61ad293904eee33f9d4866c2192865c44c4eb35d10782966242634e0cbc1e91fe62b1247f148dc5514918e3a966da7ea117
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"limiter@npm:^1.1.5":
|
||||
version: 1.1.5
|
||||
resolution: "limiter@npm:1.1.5"
|
||||
|
@ -27372,6 +27570,15 @@ __metadata:
|
|||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"lucide-react@npm:^0.125.0":
|
||||
version: 0.125.0
|
||||
resolution: "lucide-react@npm:0.125.0"
|
||||
peerDependencies:
|
||||
react: ^16.5.1 || ^17.0.0 || ^18.0.0
|
||||
checksum: 6d86330fd4316a42624d537cc07adc3c51c18a699a02ef3abbd221c3140ae5ac5685396e1f5cb20f5f5ba80fa100523a5a6811c22a51bd13bbfdf65546cfffdf
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"lucide-react@npm:^0.171.0":
|
||||
version: 0.171.0
|
||||
resolution: "lucide-react@npm:0.171.0"
|
||||
|
@ -29120,6 +29327,31 @@ __metadata:
|
|||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"next-auth@npm:^4.20.1":
|
||||
version: 4.23.1
|
||||
resolution: "next-auth@npm:4.23.1"
|
||||
dependencies:
|
||||
"@babel/runtime": ^7.20.13
|
||||
"@panva/hkdf": ^1.0.2
|
||||
cookie: ^0.5.0
|
||||
jose: ^4.11.4
|
||||
oauth: ^0.9.15
|
||||
openid-client: ^5.4.0
|
||||
preact: ^10.6.3
|
||||
preact-render-to-string: ^5.1.19
|
||||
uuid: ^8.3.2
|
||||
peerDependencies:
|
||||
next: ^12.2.5 || ^13
|
||||
nodemailer: ^6.6.5
|
||||
react: ^17.0.2 || ^18
|
||||
react-dom: ^17.0.2 || ^18
|
||||
peerDependenciesMeta:
|
||||
nodemailer:
|
||||
optional: true
|
||||
checksum: 995114797c257ccf71a82d19fb6316fb7709b552aaaf66444591c505a4b8e00b0cae3f4db4316b63a8cc439076044cc391ab171c4f6ee2e086709c5b3bbfed24
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"next-auth@npm:^4.22.1":
|
||||
version: 4.22.1
|
||||
resolution: "next-auth@npm:4.22.1"
|
||||
|
@ -29169,6 +29401,24 @@ __metadata:
|
|||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"next-i18next@npm:^11.3.0":
|
||||
version: 11.3.0
|
||||
resolution: "next-i18next@npm:11.3.0"
|
||||
dependencies:
|
||||
"@babel/runtime": ^7.18.6
|
||||
"@types/hoist-non-react-statics": ^3.3.1
|
||||
core-js: ^3
|
||||
hoist-non-react-statics: ^3.3.2
|
||||
i18next: ^21.8.13
|
||||
i18next-fs-backend: ^1.1.4
|
||||
react-i18next: ^11.18.0
|
||||
peerDependencies:
|
||||
next: ">= 10.0.0"
|
||||
react: ">= 16.8.0"
|
||||
checksum: fbce97a4fbf9ad846c08652471a833c7f173c3e7ddc7cafa1423625b4a684715bb85f76ae06fe9cbed3e70f12b8e78e2459e5bc1a3c3f5c517743f17648f8939
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"next-i18next@npm:^13.2.2":
|
||||
version: 13.3.0
|
||||
resolution: "next-i18next@npm:13.3.0"
|
||||
|
@ -29250,6 +29500,62 @@ __metadata:
|
|||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"next@npm:^13.2.1":
|
||||
version: 13.4.16
|
||||
resolution: "next@npm:13.4.16"
|
||||
dependencies:
|
||||
"@next/env": 13.4.16
|
||||
"@next/swc-darwin-arm64": 13.4.16
|
||||
"@next/swc-darwin-x64": 13.4.16
|
||||
"@next/swc-linux-arm64-gnu": 13.4.16
|
||||
"@next/swc-linux-arm64-musl": 13.4.16
|
||||
"@next/swc-linux-x64-gnu": 13.4.16
|
||||
"@next/swc-linux-x64-musl": 13.4.16
|
||||
"@next/swc-win32-arm64-msvc": 13.4.16
|
||||
"@next/swc-win32-ia32-msvc": 13.4.16
|
||||
"@next/swc-win32-x64-msvc": 13.4.16
|
||||
"@swc/helpers": 0.5.1
|
||||
busboy: 1.6.0
|
||||
caniuse-lite: ^1.0.30001406
|
||||
postcss: 8.4.14
|
||||
styled-jsx: 5.1.1
|
||||
watchpack: 2.4.0
|
||||
zod: 3.21.4
|
||||
peerDependencies:
|
||||
"@opentelemetry/api": ^1.1.0
|
||||
react: ^18.2.0
|
||||
react-dom: ^18.2.0
|
||||
sass: ^1.3.0
|
||||
dependenciesMeta:
|
||||
"@next/swc-darwin-arm64":
|
||||
optional: true
|
||||
"@next/swc-darwin-x64":
|
||||
optional: true
|
||||
"@next/swc-linux-arm64-gnu":
|
||||
optional: true
|
||||
"@next/swc-linux-arm64-musl":
|
||||
optional: true
|
||||
"@next/swc-linux-x64-gnu":
|
||||
optional: true
|
||||
"@next/swc-linux-x64-musl":
|
||||
optional: true
|
||||
"@next/swc-win32-arm64-msvc":
|
||||
optional: true
|
||||
"@next/swc-win32-ia32-msvc":
|
||||
optional: true
|
||||
"@next/swc-win32-x64-msvc":
|
||||
optional: true
|
||||
peerDependenciesMeta:
|
||||
"@opentelemetry/api":
|
||||
optional: true
|
||||
sass:
|
||||
optional: true
|
||||
bin:
|
||||
next: dist/bin/next
|
||||
checksum: b9e346061969531401a1b3a81819adad0018fd33e52954032cc96a3d703821ee1c39a5807dcd73fab8df197424b409d51f837910df225341c1f83735614a811f
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"next@npm:^13.4.6":
|
||||
version: 13.4.6
|
||||
resolution: "next@npm:13.4.6"
|
||||
|
@ -29309,6 +29615,77 @@ __metadata:
|
|||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"next@npm:~13.2.1":
|
||||
version: 13.2.4
|
||||
resolution: "next@npm:13.2.4"
|
||||
dependencies:
|
||||
"@next/env": 13.2.4
|
||||
"@next/swc-android-arm-eabi": 13.2.4
|
||||
"@next/swc-android-arm64": 13.2.4
|
||||
"@next/swc-darwin-arm64": 13.2.4
|
||||
"@next/swc-darwin-x64": 13.2.4
|
||||
"@next/swc-freebsd-x64": 13.2.4
|
||||
"@next/swc-linux-arm-gnueabihf": 13.2.4
|
||||
"@next/swc-linux-arm64-gnu": 13.2.4
|
||||
"@next/swc-linux-arm64-musl": 13.2.4
|
||||
"@next/swc-linux-x64-gnu": 13.2.4
|
||||
"@next/swc-linux-x64-musl": 13.2.4
|
||||
"@next/swc-win32-arm64-msvc": 13.2.4
|
||||
"@next/swc-win32-ia32-msvc": 13.2.4
|
||||
"@next/swc-win32-x64-msvc": 13.2.4
|
||||
"@swc/helpers": 0.4.14
|
||||
caniuse-lite: ^1.0.30001406
|
||||
postcss: 8.4.14
|
||||
styled-jsx: 5.1.1
|
||||
peerDependencies:
|
||||
"@opentelemetry/api": ^1.4.0
|
||||
fibers: ">= 3.1.0"
|
||||
node-sass: ^6.0.0 || ^7.0.0
|
||||
react: ^18.2.0
|
||||
react-dom: ^18.2.0
|
||||
sass: ^1.3.0
|
||||
dependenciesMeta:
|
||||
"@next/swc-android-arm-eabi":
|
||||
optional: true
|
||||
"@next/swc-android-arm64":
|
||||
optional: true
|
||||
"@next/swc-darwin-arm64":
|
||||
optional: true
|
||||
"@next/swc-darwin-x64":
|
||||
optional: true
|
||||
"@next/swc-freebsd-x64":
|
||||
optional: true
|
||||
"@next/swc-linux-arm-gnueabihf":
|
||||
optional: true
|
||||
"@next/swc-linux-arm64-gnu":
|
||||
optional: true
|
||||
"@next/swc-linux-arm64-musl":
|
||||
optional: true
|
||||
"@next/swc-linux-x64-gnu":
|
||||
optional: true
|
||||
"@next/swc-linux-x64-musl":
|
||||
optional: true
|
||||
"@next/swc-win32-arm64-msvc":
|
||||
optional: true
|
||||
"@next/swc-win32-ia32-msvc":
|
||||
optional: true
|
||||
"@next/swc-win32-x64-msvc":
|
||||
optional: true
|
||||
peerDependenciesMeta:
|
||||
"@opentelemetry/api":
|
||||
optional: true
|
||||
fibers:
|
||||
optional: true
|
||||
node-sass:
|
||||
optional: true
|
||||
sass:
|
||||
optional: true
|
||||
bin:
|
||||
next: dist/bin/next
|
||||
checksum: 8531dee41b60181b582f5ee80858907b102f083ef8808ff9352d589dd39e6b3a96f7a11b3776a03eef3a28430cff768336fa2e3ff2c6f8fcd699fbc891749051
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"nice-try@npm:^1.0.4":
|
||||
version: 1.0.5
|
||||
resolution: "nice-try@npm:1.0.5"
|
||||
|
@ -31271,6 +31648,19 @@ __metadata:
|
|||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"postcss-import@npm:^15.1.0":
|
||||
version: 15.1.0
|
||||
resolution: "postcss-import@npm:15.1.0"
|
||||
dependencies:
|
||||
postcss-value-parser: ^4.0.0
|
||||
read-cache: ^1.0.0
|
||||
resolve: ^1.1.7
|
||||
peerDependencies:
|
||||
postcss: ^8.0.0
|
||||
checksum: 7bd04bd8f0235429009d0022cbf00faebc885de1d017f6d12ccb1b021265882efc9302006ba700af6cab24c46bfa2f3bc590be3f9aee89d064944f171b04e2a3
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"postcss-js@npm:^4.0.0":
|
||||
version: 4.0.0
|
||||
resolution: "postcss-js@npm:4.0.0"
|
||||
|
@ -31282,6 +31672,17 @@ __metadata:
|
|||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"postcss-js@npm:^4.0.1":
|
||||
version: 4.0.1
|
||||
resolution: "postcss-js@npm:4.0.1"
|
||||
dependencies:
|
||||
camelcase-css: ^2.0.1
|
||||
peerDependencies:
|
||||
postcss: ^8.4.21
|
||||
checksum: 5c1e83efeabeb5a42676193f4357aa9c88f4dc1b3c4a0332c132fe88932b33ea58848186db117cf473049fc233a980356f67db490bd0a7832ccba9d0b3fd3491
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"postcss-load-config@npm:^3.1.4":
|
||||
version: 3.1.4
|
||||
resolution: "postcss-load-config@npm:3.1.4"
|
||||
|
@ -31300,6 +31701,24 @@ __metadata:
|
|||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"postcss-load-config@npm:^4.0.1":
|
||||
version: 4.0.1
|
||||
resolution: "postcss-load-config@npm:4.0.1"
|
||||
dependencies:
|
||||
lilconfig: ^2.0.5
|
||||
yaml: ^2.1.1
|
||||
peerDependencies:
|
||||
postcss: ">=8.0.9"
|
||||
ts-node: ">=9.0.0"
|
||||
peerDependenciesMeta:
|
||||
postcss:
|
||||
optional: true
|
||||
ts-node:
|
||||
optional: true
|
||||
checksum: b61f890499ed7dcda1e36c20a9582b17d745bad5e2b2c7bc96942465e406bc43ae03f270c08e60d1e29dab1ee50cb26970b5eb20c9aae30e066e20bd607ae4e4
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"postcss-loader@npm:^4.2.0":
|
||||
version: 4.3.0
|
||||
resolution: "postcss-loader@npm:4.3.0"
|
||||
|
@ -31426,6 +31845,17 @@ __metadata:
|
|||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"postcss-nested@npm:^6.0.1":
|
||||
version: 6.0.1
|
||||
resolution: "postcss-nested@npm:6.0.1"
|
||||
dependencies:
|
||||
postcss-selector-parser: ^6.0.11
|
||||
peerDependencies:
|
||||
postcss: ^8.2.14
|
||||
checksum: 7ddb0364cd797de01e38f644879189e0caeb7ea3f78628c933d91cc24f327c56d31269384454fc02ecaf503b44bfa8e08870a7c4cc56b23bc15640e1894523fa
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"postcss-pseudo-companion-classes@npm:^0.1.1":
|
||||
version: 0.1.1
|
||||
resolution: "postcss-pseudo-companion-classes@npm:0.1.1"
|
||||
|
@ -32717,6 +33147,24 @@ __metadata:
|
|||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"react-i18next@npm:^11.18.0":
|
||||
version: 11.18.6
|
||||
resolution: "react-i18next@npm:11.18.6"
|
||||
dependencies:
|
||||
"@babel/runtime": ^7.14.5
|
||||
html-parse-stringify: ^3.0.1
|
||||
peerDependencies:
|
||||
i18next: ">= 19.0.0"
|
||||
react: ">= 16.8.0"
|
||||
peerDependenciesMeta:
|
||||
react-dom:
|
||||
optional: true
|
||||
react-native:
|
||||
optional: true
|
||||
checksum: 624c0a0313fac4e0d18560b83c99a8bd0a83abc02e5db8d01984e0643ac409d178668aa3a4720d01f7a0d9520d38598dcbff801d6f69a970bae67461de6cd852
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"react-i18next@npm:^12.2.0":
|
||||
version: 12.3.1
|
||||
resolution: "react-i18next@npm:12.3.1"
|
||||
|
@ -32840,7 +33288,7 @@ __metadata:
|
|||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"react-live-chat-loader@npm:^2.8.1":
|
||||
"react-live-chat-loader@npm:^2.7.3, react-live-chat-loader@npm:^2.8.1":
|
||||
version: 2.8.1
|
||||
resolution: "react-live-chat-loader@npm:2.8.1"
|
||||
peerDependencies:
|
||||
|
@ -34092,6 +34540,19 @@ __metadata:
|
|||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"resolve@npm:^1.22.2":
|
||||
version: 1.22.4
|
||||
resolution: "resolve@npm:1.22.4"
|
||||
dependencies:
|
||||
is-core-module: ^2.13.0
|
||||
path-parse: ^1.0.7
|
||||
supports-preserve-symlinks-flag: ^1.0.0
|
||||
bin:
|
||||
resolve: bin/resolve
|
||||
checksum: 23f25174c2736ce24c6d918910e0d1f89b6b38fefa07a995dff864acd7863d59a7f049e691f93b4b2ee29696303390d921552b6d1b841ed4a8101f517e1d0124
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"resolve@npm:^2.0.0-next.3":
|
||||
version: 2.0.0-next.3
|
||||
resolution: "resolve@npm:2.0.0-next.3"
|
||||
|
@ -34141,6 +34602,19 @@ __metadata:
|
|||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"resolve@patch:resolve@^1.22.2#~builtin<compat/resolve>":
|
||||
version: 1.22.4
|
||||
resolution: "resolve@patch:resolve@npm%3A1.22.4#~builtin<compat/resolve>::version=1.22.4&hash=c3c19d"
|
||||
dependencies:
|
||||
is-core-module: ^2.13.0
|
||||
path-parse: ^1.0.7
|
||||
supports-preserve-symlinks-flag: ^1.0.0
|
||||
bin:
|
||||
resolve: bin/resolve
|
||||
checksum: c45f2545fdc4d21883861b032789e20aa67a2f2692f68da320cc84d5724cd02f2923766c5354b3210897e88f1a7b3d6d2c7c22faeead8eed7078e4c783a444bc
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"resolve@patch:resolve@^2.0.0-next.3#~builtin<compat/resolve>":
|
||||
version: 2.0.0-next.3
|
||||
resolution: "resolve@patch:resolve@npm%3A2.0.0-next.3#~builtin<compat/resolve>::version=2.0.0-next.3&hash=c3c19d"
|
||||
|
@ -36259,6 +36733,24 @@ __metadata:
|
|||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"sucrase@npm:^3.32.0":
|
||||
version: 3.34.0
|
||||
resolution: "sucrase@npm:3.34.0"
|
||||
dependencies:
|
||||
"@jridgewell/gen-mapping": ^0.3.2
|
||||
commander: ^4.0.0
|
||||
glob: 7.1.6
|
||||
lines-and-columns: ^1.1.6
|
||||
mz: ^2.7.0
|
||||
pirates: ^4.0.1
|
||||
ts-interface-checker: ^0.1.9
|
||||
bin:
|
||||
sucrase: bin/sucrase
|
||||
sucrase-node: bin/sucrase-node
|
||||
checksum: 61860063bdf6103413698e13247a3074d25843e91170825a9752e4af7668ffadd331b6e99e92fc32ee5b3c484ee134936f926fa9039d5711fafff29d017a2110
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"superagent@npm:^5.1.1":
|
||||
version: 5.3.1
|
||||
resolution: "superagent@npm:5.3.1"
|
||||
|
@ -36620,6 +37112,39 @@ __metadata:
|
|||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"tailwindcss@npm:^3.2.1":
|
||||
version: 3.3.3
|
||||
resolution: "tailwindcss@npm:3.3.3"
|
||||
dependencies:
|
||||
"@alloc/quick-lru": ^5.2.0
|
||||
arg: ^5.0.2
|
||||
chokidar: ^3.5.3
|
||||
didyoumean: ^1.2.2
|
||||
dlv: ^1.1.3
|
||||
fast-glob: ^3.2.12
|
||||
glob-parent: ^6.0.2
|
||||
is-glob: ^4.0.3
|
||||
jiti: ^1.18.2
|
||||
lilconfig: ^2.1.0
|
||||
micromatch: ^4.0.5
|
||||
normalize-path: ^3.0.0
|
||||
object-hash: ^3.0.0
|
||||
picocolors: ^1.0.0
|
||||
postcss: ^8.4.23
|
||||
postcss-import: ^15.1.0
|
||||
postcss-js: ^4.0.1
|
||||
postcss-load-config: ^4.0.1
|
||||
postcss-nested: ^6.0.1
|
||||
postcss-selector-parser: ^6.0.11
|
||||
resolve: ^1.22.2
|
||||
sucrase: ^3.32.0
|
||||
bin:
|
||||
tailwind: lib/cli.js
|
||||
tailwindcss: lib/cli.js
|
||||
checksum: 0195c7a3ebb0de5e391d2a883d777c78a4749f0c532d204ee8aea9129f2ed8e701d8c0c276aa5f7338d07176a3c2a7682c1d0ab9c8a6c2abe6d9325c2954eb50
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"tailwindcss@npm:^3.3.1":
|
||||
version: 3.3.1
|
||||
resolution: "tailwindcss@npm:3.3.1"
|
||||
|
@ -40360,16 +40885,6 @@ __metadata:
|
|||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"xml2js@npm:^0.6.0":
|
||||
version: 0.6.2
|
||||
resolution: "xml2js@npm:0.6.2"
|
||||
dependencies:
|
||||
sax: ">=0.6.0"
|
||||
xmlbuilder: ~11.0.0
|
||||
checksum: 458a83806193008edff44562c0bdb982801d61ee7867ae58fd35fab781e69e17f40dfeb8fc05391a4648c9c54012066d3955fe5d993ffbe4dc63399023f32ac2
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"xml@npm:=1.0.1":
|
||||
version: 1.0.1
|
||||
resolution: "xml@npm:1.0.1"
|
||||
|
|
Loading…
Reference in New Issue
Block a user