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 { useAutoAnimate } from "@formkit/auto-animate/react";
|
||||||
import type { User } from "@prisma/client";
|
import type { User } from "@prisma/client";
|
||||||
|
import type { TFunction } from "next-i18next";
|
||||||
import { Trans } from "next-i18next";
|
import { Trans } from "next-i18next";
|
||||||
import Link from "next/link";
|
import Link from "next/link";
|
||||||
import { usePathname, useRouter, useSearchParams } from "next/navigation";
|
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 { useOrgBranding } from "@calcom/features/ee/organizations/context/provider";
|
||||||
import useIntercom from "@calcom/features/ee/support/lib/intercom/useIntercom";
|
import useIntercom from "@calcom/features/ee/support/lib/intercom/useIntercom";
|
||||||
import { EventTypeEmbedButton, EventTypeEmbedDialog } from "@calcom/features/embed/EventTypeEmbed";
|
import { EventTypeEmbedButton, EventTypeEmbedDialog } from "@calcom/features/embed/EventTypeEmbed";
|
||||||
import { EventTypeDescriptionLazy as EventTypeDescription } from "@calcom/features/eventtypes/components";
|
import {
|
||||||
import CreateEventTypeDialog from "@calcom/features/eventtypes/components/CreateEventTypeDialog";
|
CreateEventTypeDialog,
|
||||||
|
EventTypeDescriptionLazy as EventTypeDescription,
|
||||||
|
} from "@calcom/features/eventtypes/components";
|
||||||
import { DuplicateDialog } from "@calcom/features/eventtypes/components/DuplicateDialog";
|
import { DuplicateDialog } from "@calcom/features/eventtypes/components/DuplicateDialog";
|
||||||
import { TeamsFilter } from "@calcom/features/filters/components/TeamsFilter";
|
import { TeamsFilter } from "@calcom/features/filters/components/TeamsFilter";
|
||||||
import { getTeamsFiltersFromQuery } from "@calcom/features/filters/lib/getTeamsFiltersFromQuery";
|
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 { useRouterQuery } from "@calcom/lib/hooks/useRouterQuery";
|
||||||
import { useTypedQuery } from "@calcom/lib/hooks/useTypedQuery";
|
import { useTypedQuery } from "@calcom/lib/hooks/useTypedQuery";
|
||||||
import { HttpError } from "@calcom/lib/http-error";
|
import { HttpError } from "@calcom/lib/http-error";
|
||||||
|
import { markdownToSafeHTML } from "@calcom/lib/markdownToSafeHTML";
|
||||||
import { SchedulingType } from "@calcom/prisma/enums";
|
import { SchedulingType } from "@calcom/prisma/enums";
|
||||||
import type { RouterOutputs } from "@calcom/trpc/react";
|
import type { RouterOutputs } from "@calcom/trpc/react";
|
||||||
import { trpc, TRPCClientError } from "@calcom/trpc/react";
|
import { trpc, TRPCClientError } from "@calcom/trpc/react";
|
||||||
|
@ -35,7 +39,6 @@ import {
|
||||||
Button,
|
Button,
|
||||||
ButtonGroup,
|
ButtonGroup,
|
||||||
ConfirmationDialogContent,
|
ConfirmationDialogContent,
|
||||||
CreateButton,
|
|
||||||
Dialog,
|
Dialog,
|
||||||
Dropdown,
|
Dropdown,
|
||||||
DropdownItem,
|
DropdownItem,
|
||||||
|
@ -53,6 +56,7 @@ import {
|
||||||
Switch,
|
Switch,
|
||||||
Tooltip,
|
Tooltip,
|
||||||
ArrowButton,
|
ArrowButton,
|
||||||
|
CreateButtonWithTeamsList,
|
||||||
} from "@calcom/ui";
|
} from "@calcom/ui";
|
||||||
import {
|
import {
|
||||||
Clipboard,
|
Clipboard,
|
||||||
|
@ -74,85 +78,99 @@ import useMeQuery from "@lib/hooks/useMeQuery";
|
||||||
import PageWrapper from "@components/PageWrapper";
|
import PageWrapper from "@components/PageWrapper";
|
||||||
import SkeletonLoader from "@components/eventtype/SkeletonLoader";
|
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 {
|
interface EventTypeListHeadingProps {
|
||||||
profile: EventTypeGroupProfile;
|
teamSlugOrUsername: string;
|
||||||
|
teamNameOrUserName: string;
|
||||||
membershipCount: number;
|
membershipCount: number;
|
||||||
teamId?: number | null;
|
teamId?: number | null;
|
||||||
orgSlug?: string;
|
orgSlug?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
type EventTypeGroup = EventTypeGroups[number];
|
type EventTypeList = RouterOutputs["viewer"]["eventTypes"]["paginate"];
|
||||||
type EventType = EventTypeGroup["eventTypes"][number];
|
type EventType = EventTypeList[number];
|
||||||
|
|
||||||
interface EventTypeListProps {
|
interface EventTypeListProps {
|
||||||
group: EventTypeGroup;
|
data: EventTypeList;
|
||||||
groupIndex: number;
|
readonly?: boolean;
|
||||||
readOnly: boolean;
|
|
||||||
types: EventType[];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
interface MobileTeamsTabProps {
|
interface MobileTeamsTabProps {
|
||||||
eventTypeGroups: EventTypeGroups;
|
teamEventTypes: EventTypeList[];
|
||||||
|
readonly?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
const querySchema = z.object({
|
const querySchema = z.object({
|
||||||
teamId: z.nullable(z.coerce.number()).optional().default(null),
|
teamId: z.nullable(z.coerce.number()).optional().default(null),
|
||||||
});
|
});
|
||||||
|
|
||||||
const MobileTeamsTab: FC<MobileTeamsTabProps> = (props) => {
|
const MobileTeamsTab: FC<MobileTeamsTabProps> = (props: MobileTeamsTabProps) => {
|
||||||
const { eventTypeGroups } = props;
|
const { teamEventTypes, readonly } = props;
|
||||||
const orgBranding = useOrgBranding();
|
const orgBranding = useOrgBranding();
|
||||||
const tabs = eventTypeGroups.map((item) => ({
|
const tabs = teamEventTypes
|
||||||
name: item.profile.name ?? "",
|
.filter((item) => item !== undefined)
|
||||||
href: item.teamId ? `/event-types?teamId=${item.teamId}` : "/event-types?noTeam",
|
.map((item) => {
|
||||||
avatar: orgBranding
|
const [firstElement] = item;
|
||||||
? `${orgBranding.fullDomain}${item.teamId ? "/team" : ""}/${item.profile.slug}/avatar.png`
|
|
||||||
: item.profile.image ?? `${WEBAPP_URL + (item.teamId && "/team")}/${item.profile.slug}/avatar.png`,
|
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 { 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 (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<HorizontalTabs tabs={tabs} />
|
<HorizontalTabs tabs={tabs} />
|
||||||
{events.length > 0 ? (
|
{events && events.length > 0 ? (
|
||||||
<EventTypeList
|
<EventTypeList data={events} readonly={readonly} />
|
||||||
types={events[0].eventTypes}
|
|
||||||
group={events[0]}
|
|
||||||
groupIndex={0}
|
|
||||||
readOnly={events[0].metadata.readOnly}
|
|
||||||
/>
|
|
||||||
) : (
|
) : (
|
||||||
<CreateFirstEventTypeView slug={eventTypeGroups[0].profile.slug ?? ""} />
|
// @TODO: fix later when we have the context provider
|
||||||
|
<CreateFirstEventTypeView slug="" />
|
||||||
)}
|
)}
|
||||||
</div>
|
</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 { t } = useLocale();
|
||||||
|
|
||||||
const content = () => (
|
const content = () => (
|
||||||
<div>
|
<div>
|
||||||
<span
|
<span
|
||||||
className="text-default font-semibold ltr:mr-1 rtl:ml-1"
|
className="text-default font-semibold ltr:mr-1 rtl:ml-1"
|
||||||
data-testid={"event-type-title-" + type.id}>
|
data-testid={"event-type-title-" + eventType.id}>
|
||||||
{type.title}
|
{eventType.title}
|
||||||
</span>
|
</span>
|
||||||
{group.profile.slug ? (
|
|
||||||
<small
|
<small
|
||||||
className="text-subtle hidden font-normal leading-4 sm:inline"
|
className="text-subtle hidden font-normal leading-4 sm:inline"
|
||||||
data-testid={"event-type-slug-" + type.id}>
|
data-testid={"event-type-slug-" + eventType.id}>
|
||||||
{`/${
|
{getEventTypeSlug(eventType, t)}
|
||||||
type.schedulingType !== SchedulingType.MANAGED ? group.profile.slug : t("username_placeholder")
|
|
||||||
}/${type.slug}`}
|
|
||||||
</small>
|
</small>
|
||||||
) : null}
|
|
||||||
{readOnly && (
|
{readonly && (
|
||||||
<Badge variant="gray" className="ml-2">
|
<Badge variant="gray" className="ml-2">
|
||||||
{t("readonly")}
|
{t("readonly")}
|
||||||
</Badge>
|
</Badge>
|
||||||
|
@ -160,34 +178,34 @@ const Item = ({ type, group, readOnly }: { type: EventType; group: EventTypeGrou
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|
||||||
return readOnly ? (
|
return readonly ? (
|
||||||
<div className="flex-1 overflow-hidden pr-4 text-sm">
|
<div className="flex-1 overflow-hidden pr-4 text-sm">
|
||||||
{content()}
|
{content()}
|
||||||
<EventTypeDescription
|
<EventTypeDescription
|
||||||
// @ts-expect-error FIXME: We have a type mismatch here @hariombalhara @sean-brydon
|
// @ts-expect-error FIXME: We have a type mismatch here @hariombalhara @sean-brydon
|
||||||
eventType={type}
|
eventType={eventType}
|
||||||
shortenDescription
|
shortenDescription
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
) : (
|
) : (
|
||||||
<Link
|
<Link
|
||||||
href={`/event-types/${type.id}?tabName=setup`}
|
href={`/event-types/${eventType?.id}?tabName=setup`}
|
||||||
className="flex-1 overflow-hidden pr-4 text-sm"
|
className="flex-1 overflow-hidden pr-4 text-sm"
|
||||||
title={type.title}>
|
title={eventType?.title}>
|
||||||
<div>
|
<div>
|
||||||
<span
|
<span
|
||||||
className="text-default font-semibold ltr:mr-1 rtl:ml-1"
|
className="text-default font-semibold ltr:mr-1 rtl:ml-1"
|
||||||
data-testid={"event-type-title-" + type.id}>
|
data-testid={"event-type-title-" + eventType?.id}>
|
||||||
{type.title}
|
{eventType?.title}
|
||||||
</span>
|
</span>
|
||||||
{group.profile.slug ? (
|
|
||||||
<small
|
<small
|
||||||
className="text-subtle hidden font-normal leading-4 sm:inline"
|
className="text-subtle hidden font-normal leading-4 sm:inline"
|
||||||
data-testid={"event-type-slug-" + type.id}>
|
data-testid={"event-type-slug-" + eventType?.id}>
|
||||||
{`/${group.profile.slug}/${type.slug}`}
|
{getEventTypeSlug(eventType, t)}
|
||||||
</small>
|
</small>
|
||||||
) : null}
|
|
||||||
{readOnly && (
|
{readonly && (
|
||||||
<Badge variant="gray" className="ml-2">
|
<Badge variant="gray" className="ml-2">
|
||||||
{t("readonly")}
|
{t("readonly")}
|
||||||
</Badge>
|
</Badge>
|
||||||
|
@ -195,7 +213,10 @@ const Item = ({ type, group, readOnly }: { type: EventType; group: EventTypeGrou
|
||||||
</div>
|
</div>
|
||||||
<EventTypeDescription
|
<EventTypeDescription
|
||||||
// @ts-expect-error FIXME: We have a type mismatch here @hariombalhara @sean-brydon
|
// @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
|
shortenDescription
|
||||||
/>
|
/>
|
||||||
</Link>
|
</Link>
|
||||||
|
@ -204,7 +225,7 @@ const Item = ({ type, group, readOnly }: { type: EventType; group: EventTypeGrou
|
||||||
|
|
||||||
const MemoizedItem = memo(Item);
|
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 { t } = useLocale();
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const pathname = usePathname();
|
const pathname = usePathname();
|
||||||
|
@ -235,18 +256,18 @@ export const EventTypeList = ({ group, groupIndex, readOnly, types }: EventTypeL
|
||||||
await utils.viewer.eventTypes.getByViewer.cancel();
|
await utils.viewer.eventTypes.getByViewer.cancel();
|
||||||
const previousValue = utils.viewer.eventTypes.getByViewer.getData();
|
const previousValue = utils.viewer.eventTypes.getByViewer.getData();
|
||||||
if (previousValue) {
|
if (previousValue) {
|
||||||
const newList = [...types];
|
const newList = [...data];
|
||||||
const itemIndex = newList.findIndex((item) => item.id === id);
|
const itemIndex = newList.findIndex((item) => item.id === id);
|
||||||
if (itemIndex !== -1 && newList[itemIndex]) {
|
if (itemIndex !== -1 && newList[itemIndex]) {
|
||||||
newList[itemIndex].hidden = !newList[itemIndex].hidden;
|
newList[itemIndex].hidden = !newList[itemIndex].hidden;
|
||||||
}
|
}
|
||||||
utils.viewer.eventTypes.getByViewer.setData(undefined, {
|
utils.viewer.eventTypes.getByViewer.setData(undefined, {
|
||||||
...previousValue,
|
...previousValue,
|
||||||
eventTypeGroups: [
|
// eventTypeGroups: [
|
||||||
...previousValue.eventTypeGroups.slice(0, groupIndex),
|
// ...previousValue.eventTypeGroups.slice(0, groupIndex),
|
||||||
{ ...group, eventTypes: newList },
|
// { ...group, eventTypes: newList },
|
||||||
...previousValue.eventTypeGroups.slice(groupIndex + 1),
|
// ...previousValue.eventTypeGroups.slice(groupIndex + 1),
|
||||||
],
|
// ],
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
return { previousValue };
|
return { previousValue };
|
||||||
|
@ -264,10 +285,10 @@ export const EventTypeList = ({ group, groupIndex, readOnly, types }: EventTypeL
|
||||||
});
|
});
|
||||||
|
|
||||||
async function moveEventType(index: number, increment: 1 | -1) {
|
async function moveEventType(index: number, increment: 1 | -1) {
|
||||||
const newList = [...types];
|
const newList = [...data];
|
||||||
|
|
||||||
const type = types[index];
|
const type = data[index];
|
||||||
const tmp = types[index + increment];
|
const tmp = data[index + increment];
|
||||||
if (tmp) {
|
if (tmp) {
|
||||||
newList[index] = tmp;
|
newList[index] = tmp;
|
||||||
newList[index + increment] = type;
|
newList[index + increment] = type;
|
||||||
|
@ -279,11 +300,11 @@ export const EventTypeList = ({ group, groupIndex, readOnly, types }: EventTypeL
|
||||||
if (previousValue) {
|
if (previousValue) {
|
||||||
utils.viewer.eventTypes.getByViewer.setData(undefined, {
|
utils.viewer.eventTypes.getByViewer.setData(undefined, {
|
||||||
...previousValue,
|
...previousValue,
|
||||||
eventTypeGroups: [
|
// eventTypeGroups: [
|
||||||
...previousValue.eventTypeGroups.slice(0, groupIndex),
|
// ...previousValue.eventTypeGroups.slice(0, groupIndex),
|
||||||
{ ...group, eventTypes: newList },
|
// { ...group, eventTypes: newList },
|
||||||
...previousValue.eventTypeGroups.slice(groupIndex + 1),
|
// ...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
|
// inject selection data into url for correct router history
|
||||||
const openDuplicateModal = (eventType: EventType, group: EventTypeGroup) => {
|
const openDuplicateModal = (eventType: EventType) => {
|
||||||
const newSearchParams = new URLSearchParams(searchParams);
|
const newSearchParams = new URLSearchParams(searchParams);
|
||||||
function setParamsIfDefined(key: string, value: string | number | boolean | null | undefined) {
|
function setParamsIfDefined(key: string, value: string | number | boolean | null | undefined) {
|
||||||
if (value) newSearchParams.set(key, value.toString());
|
if (value) newSearchParams.set(key, value.toString());
|
||||||
|
@ -310,7 +331,7 @@ export const EventTypeList = ({ group, groupIndex, readOnly, types }: EventTypeL
|
||||||
setParamsIfDefined("slug", eventType.slug);
|
setParamsIfDefined("slug", eventType.slug);
|
||||||
setParamsIfDefined("id", eventType.id);
|
setParamsIfDefined("id", eventType.id);
|
||||||
setParamsIfDefined("length", eventType.length);
|
setParamsIfDefined("length", eventType.length);
|
||||||
setParamsIfDefined("pageSlug", group.profile.slug);
|
setParamsIfDefined("pageSlug", getEventTypeSlug(eventType, t));
|
||||||
router.push(`${pathname}?${newSearchParams.toString()}`);
|
router.push(`${pathname}?${newSearchParams.toString()}`);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -323,15 +344,15 @@ export const EventTypeList = ({ group, groupIndex, readOnly, types }: EventTypeL
|
||||||
await utils.viewer.eventTypes.getByViewer.cancel();
|
await utils.viewer.eventTypes.getByViewer.cancel();
|
||||||
const previousValue = utils.viewer.eventTypes.getByViewer.getData();
|
const previousValue = utils.viewer.eventTypes.getByViewer.getData();
|
||||||
if (previousValue) {
|
if (previousValue) {
|
||||||
const newList = types.filter((item) => item.id !== id);
|
// const newList = data.filter((item) => item.id !== id);
|
||||||
|
|
||||||
utils.viewer.eventTypes.getByViewer.setData(undefined, {
|
utils.viewer.eventTypes.getByViewer.setData(undefined, {
|
||||||
...previousValue,
|
...previousValue,
|
||||||
eventTypeGroups: [
|
// eventTypeGroups: [
|
||||||
...previousValue.eventTypeGroups.slice(0, groupIndex),
|
// ...previousValue.eventTypeGroups.slice(0, groupIndex),
|
||||||
{ ...group, eventTypes: newList },
|
// { ...group, eventTypes: newList },
|
||||||
...previousValue.eventTypeGroups.slice(groupIndex + 1),
|
// ...previousValue.eventTypeGroups.slice(groupIndex + 1),
|
||||||
],
|
// ],
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
return { previousValue };
|
return { previousValue };
|
||||||
|
@ -362,88 +383,91 @@ export const EventTypeList = ({ group, groupIndex, readOnly, types }: EventTypeL
|
||||||
}
|
}
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
if (!types.length) {
|
// @TODO: Fix later after we have the context provider
|
||||||
return group.teamId ? (
|
// if (!data.length) {
|
||||||
<EmptyEventTypeList group={group} />
|
// return data[0].teamId ? (
|
||||||
) : (
|
// <EmptyEventTypeList teamId={data[0].teamId} teamSlugOrUsername={data[0].team.slug || ""} />
|
||||||
<CreateFirstEventTypeView slug={group.profile.slug ?? ""} />
|
// ) : (
|
||||||
);
|
// <CreateFirstEventTypeView slug={data[0].team.slug || []} />
|
||||||
}
|
// );
|
||||||
|
// }
|
||||||
|
|
||||||
const firstItem = types[0];
|
const firstItem = data[0];
|
||||||
const lastItem = types[types.length - 1];
|
const lastItem = data[data.length - 1];
|
||||||
const isManagedEventPrefix = () => {
|
const isManagedEventPrefix = () => {
|
||||||
return deleteDialogTypeSchedulingType === SchedulingType.MANAGED ? "_managed" : "";
|
return deleteDialogTypeSchedulingType === SchedulingType.MANAGED ? "_managed" : "";
|
||||||
};
|
};
|
||||||
return (
|
return (
|
||||||
<div className="bg-default border-subtle mb-16 flex overflow-hidden rounded-md border">
|
<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">
|
<ul ref={parent} className="divide-subtle !static w-full divide-y" data-testid="event-types">
|
||||||
{types.map((type, index) => {
|
{data.map((eventType, index) => {
|
||||||
const embedLink = `${group.profile.slug}/${type.slug}`;
|
const embedLink = `${eventType?.team?.slug || eventType.users[0].username}/${eventType.slug}`;
|
||||||
const calLink = `${orgBranding?.fullDomain ?? CAL_URL}/${embedLink}`;
|
const calLink = `${orgBranding?.fullDomain ?? CAL_URL}/${embedLink}`;
|
||||||
const isManagedEventType = type.schedulingType === SchedulingType.MANAGED;
|
|
||||||
const isChildrenManagedEventType =
|
const isManagedEventType = eventType.schedulingType === SchedulingType.MANAGED;
|
||||||
type.metadata?.managedEventConfig !== undefined && type.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 (
|
return (
|
||||||
<li key={type.id}>
|
<li key={eventType.id}>
|
||||||
<div className="hover:bg-muted flex w-full items-center justify-between">
|
<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">
|
<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" />
|
<ArrowButton onClick={() => moveEventType(index, -1)} arrowDirection="up" />
|
||||||
)}
|
)}
|
||||||
|
{!(lastItem && lastItem.id === eventType.id) && (
|
||||||
{!(lastItem && lastItem.id === type.id) && (
|
|
||||||
<ArrowButton onClick={() => moveEventType(index, 1)} arrowDirection="down" />
|
<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="mt-4 hidden sm:mt-0 sm:flex">
|
||||||
<div className="flex justify-between space-x-2 rtl:space-x-reverse">
|
<div className="flex justify-between space-x-2 rtl:space-x-reverse">
|
||||||
{type.team && !isManagedEventType && (
|
{eventType.team && !isManagedEventType && (
|
||||||
<AvatarGroup
|
<AvatarGroup
|
||||||
className="relative right-3 top-1"
|
className="relative right-3 top-1"
|
||||||
size="sm"
|
size="sm"
|
||||||
truncateAfter={4}
|
truncateAfter={4}
|
||||||
items={
|
items={hosts.map((organizer: { name: string | null; username: string | null }) => ({
|
||||||
type?.users
|
|
||||||
? type.users.map(
|
|
||||||
(organizer: { name: string | null; username: string | null }) => ({
|
|
||||||
alt: organizer.name || "",
|
alt: organizer.name || "",
|
||||||
image: `${orgBranding?.fullDomain ?? WEBAPP_URL}/${
|
image: `${orgBranding?.fullDomain ?? WEBAPP_URL}/${
|
||||||
organizer.username
|
organizer.username
|
||||||
}/avatar.png`,
|
}/avatar.png`,
|
||||||
title: organizer.name || "",
|
title: organizer.name || "",
|
||||||
})
|
}))}
|
||||||
)
|
|
||||||
: []
|
|
||||||
}
|
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
{isManagedEventType && type?.children && type.children?.length > 0 && (
|
{isManagedEventType && eventType.children?.length > 0 && (
|
||||||
<AvatarGroup
|
<AvatarGroup
|
||||||
className="relative right-3 top-1"
|
className="relative right-3 top-1"
|
||||||
size="sm"
|
size="sm"
|
||||||
truncateAfter={4}
|
truncateAfter={4}
|
||||||
items={type?.children
|
items={eventType.children.map(
|
||||||
.flatMap((ch) => ch.users)
|
({ users }: { users: Pick<User, "name" | "username">[] }) => ({
|
||||||
.map((user: Pick<User, "name" | "username">) => ({
|
alt: users[0].name || "",
|
||||||
alt: user.name || "",
|
image: `${orgBranding?.fullDomain ?? WEBAPP_URL}/${
|
||||||
image: `${orgBranding?.fullDomain ?? WEBAPP_URL}/${user.username}/avatar.png`,
|
users[0].username
|
||||||
title: user.name || "",
|
}/avatar.png`,
|
||||||
}))}
|
title: users[0].name || "",
|
||||||
|
})
|
||||||
|
)}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
<div className="flex items-center justify-between space-x-2 rtl:space-x-reverse">
|
<div className="flex items-center justify-between space-x-2 rtl:space-x-reverse">
|
||||||
{!isManagedEventType && (
|
{!isManagedEventType && (
|
||||||
<>
|
<>
|
||||||
{type.hidden && <Badge variant="gray">{t("hidden")}</Badge>}
|
{eventType.hidden && <Badge variant="gray">{t("hidden")}</Badge>}
|
||||||
<Tooltip
|
<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">
|
<div className="self-center rounded-md p-2">
|
||||||
<Switch
|
<Switch
|
||||||
name="Hidden"
|
name="Hidden"
|
||||||
checked={!type.hidden}
|
checked={!eventType.hidden}
|
||||||
onCheckedChange={() => {
|
onCheckedChange={() => {
|
||||||
setHiddenMutation.mutate({ id: type.id, hidden: !type.hidden });
|
setHiddenMutation.mutate({ id: eventType.id, hidden: !eventType.hidden });
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
@ -478,8 +502,8 @@ export const EventTypeList = ({ group, groupIndex, readOnly, types }: EventTypeL
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
<Dropdown modal={false}>
|
<Dropdown modal={isReadOnly}>
|
||||||
<DropdownMenuTrigger asChild data-testid={"event-type-options-" + type.id}>
|
<DropdownMenuTrigger asChild data-testid={"event-type-options-" + eventType.id}>
|
||||||
<Button
|
<Button
|
||||||
type="button"
|
type="button"
|
||||||
variant="icon"
|
variant="icon"
|
||||||
|
@ -489,13 +513,13 @@ export const EventTypeList = ({ group, groupIndex, readOnly, types }: EventTypeL
|
||||||
/>
|
/>
|
||||||
</DropdownMenuTrigger>
|
</DropdownMenuTrigger>
|
||||||
<DropdownMenuContent>
|
<DropdownMenuContent>
|
||||||
{!readOnly && (
|
{!isReadOnly && (
|
||||||
<DropdownMenuItem>
|
<DropdownMenuItem>
|
||||||
<DropdownItem
|
<DropdownItem
|
||||||
type="button"
|
type="button"
|
||||||
data-testid={"event-type-edit-" + type.id}
|
data-testid={"event-type-edit-" + eventType.id}
|
||||||
StartIcon={Edit2}
|
StartIcon={Edit2}
|
||||||
onClick={() => router.push("/event-types/" + type.id)}>
|
onClick={() => router.push("/event-types/" + eventType.id)}>
|
||||||
{t("edit")}
|
{t("edit")}
|
||||||
</DropdownItem>
|
</DropdownItem>
|
||||||
</DropdownMenuItem>
|
</DropdownMenuItem>
|
||||||
|
@ -505,9 +529,9 @@ export const EventTypeList = ({ group, groupIndex, readOnly, types }: EventTypeL
|
||||||
<DropdownMenuItem className="outline-none">
|
<DropdownMenuItem className="outline-none">
|
||||||
<DropdownItem
|
<DropdownItem
|
||||||
type="button"
|
type="button"
|
||||||
data-testid={"event-type-duplicate-" + type.id}
|
data-testid={"event-type-duplicate-" + eventType.id}
|
||||||
StartIcon={Copy}
|
StartIcon={Copy}
|
||||||
onClick={() => openDuplicateModal(type, group)}>
|
onClick={() => openDuplicateModal(eventType)}>
|
||||||
{t("duplicate")}
|
{t("duplicate")}
|
||||||
</DropdownItem>
|
</DropdownItem>
|
||||||
</DropdownMenuItem>
|
</DropdownMenuItem>
|
||||||
|
@ -521,14 +545,13 @@ export const EventTypeList = ({ group, groupIndex, readOnly, types }: EventTypeL
|
||||||
StartIcon={Code}
|
StartIcon={Code}
|
||||||
className="w-full rounded-none"
|
className="w-full rounded-none"
|
||||||
embedUrl={encodeURIComponent(embedLink)}
|
embedUrl={encodeURIComponent(embedLink)}
|
||||||
eventId={type.id}>
|
eventId={eventType.id}>
|
||||||
{t("embed")}
|
{t("embed")}
|
||||||
</EventTypeEmbedButton>
|
</EventTypeEmbedButton>
|
||||||
</DropdownMenuItem>
|
</DropdownMenuItem>
|
||||||
)}
|
)}
|
||||||
{/* readonly is only set when we are on a team - if we are on a user event type null will be the value. */}
|
{/* 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) &&
|
{isReadOnly && !isChildrenManagedEventType && (
|
||||||
!isChildrenManagedEventType && (
|
|
||||||
<>
|
<>
|
||||||
<DropdownMenuSeparator />
|
<DropdownMenuSeparator />
|
||||||
<DropdownMenuItem>
|
<DropdownMenuItem>
|
||||||
|
@ -536,8 +559,8 @@ export const EventTypeList = ({ group, groupIndex, readOnly, types }: EventTypeL
|
||||||
color="destructive"
|
color="destructive"
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
setDeleteDialogOpen(true);
|
setDeleteDialogOpen(true);
|
||||||
setDeleteDialogTypeId(type.id);
|
setDeleteDialogTypeId(eventType.id);
|
||||||
setDeleteDialogSchedulingType(type.schedulingType);
|
setDeleteDialogSchedulingType(eventType.schedulingType);
|
||||||
}}
|
}}
|
||||||
StartIcon={Trash}
|
StartIcon={Trash}
|
||||||
className="w-full rounded-none">
|
className="w-full rounded-none">
|
||||||
|
@ -555,7 +578,7 @@ export const EventTypeList = ({ group, groupIndex, readOnly, types }: EventTypeL
|
||||||
</div>
|
</div>
|
||||||
<div className="min-w-9 mx-5 flex sm:hidden">
|
<div className="min-w-9 mx-5 flex sm:hidden">
|
||||||
<Dropdown>
|
<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} />
|
<Button type="button" variant="icon" color="secondary" StartIcon={MoreHorizontal} />
|
||||||
</DropdownMenuTrigger>
|
</DropdownMenuTrigger>
|
||||||
<DropdownMenuPortal>
|
<DropdownMenuPortal>
|
||||||
|
@ -573,7 +596,7 @@ export const EventTypeList = ({ group, groupIndex, readOnly, types }: EventTypeL
|
||||||
</DropdownMenuItem>
|
</DropdownMenuItem>
|
||||||
<DropdownMenuItem className="outline-none">
|
<DropdownMenuItem className="outline-none">
|
||||||
<DropdownItem
|
<DropdownItem
|
||||||
data-testid={"event-type-duplicate-" + type.id}
|
data-testid={"event-type-duplicate-" + eventType.id}
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
navigator.clipboard.writeText(calLink);
|
navigator.clipboard.writeText(calLink);
|
||||||
showToast(t("link_copied"), "success");
|
showToast(t("link_copied"), "success");
|
||||||
|
@ -588,7 +611,7 @@ export const EventTypeList = ({ group, groupIndex, readOnly, types }: EventTypeL
|
||||||
{isNativeShare ? (
|
{isNativeShare ? (
|
||||||
<DropdownMenuItem className="outline-none">
|
<DropdownMenuItem className="outline-none">
|
||||||
<DropdownItem
|
<DropdownItem
|
||||||
data-testid={"event-type-duplicate-" + type.id}
|
data-testid={"event-type-duplicate-" + eventType.id}
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
navigator
|
navigator
|
||||||
.share({
|
.share({
|
||||||
|
@ -605,10 +628,10 @@ export const EventTypeList = ({ group, groupIndex, readOnly, types }: EventTypeL
|
||||||
</DropdownItem>
|
</DropdownItem>
|
||||||
</DropdownMenuItem>
|
</DropdownMenuItem>
|
||||||
) : null}
|
) : null}
|
||||||
{!readOnly && (
|
{!isReadOnly && (
|
||||||
<DropdownMenuItem className="outline-none">
|
<DropdownMenuItem className="outline-none">
|
||||||
<DropdownItem
|
<DropdownItem
|
||||||
onClick={() => router.push("/event-types/" + type.id)}
|
onClick={() => router.push("/event-types/" + eventType.id)}
|
||||||
StartIcon={Edit}
|
StartIcon={Edit}
|
||||||
className="w-full rounded-none">
|
className="w-full rounded-none">
|
||||||
{t("edit")}
|
{t("edit")}
|
||||||
|
@ -618,24 +641,23 @@ export const EventTypeList = ({ group, groupIndex, readOnly, types }: EventTypeL
|
||||||
{!isManagedEventType && !isChildrenManagedEventType && (
|
{!isManagedEventType && !isChildrenManagedEventType && (
|
||||||
<DropdownMenuItem className="outline-none">
|
<DropdownMenuItem className="outline-none">
|
||||||
<DropdownItem
|
<DropdownItem
|
||||||
onClick={() => openDuplicateModal(type, group)}
|
onClick={() => openDuplicateModal(eventType)}
|
||||||
StartIcon={Copy}
|
StartIcon={Copy}
|
||||||
data-testid={"event-type-duplicate-" + type.id}>
|
data-testid={"event-type-duplicate-" + eventType.id}>
|
||||||
{t("duplicate")}
|
{t("duplicate")}
|
||||||
</DropdownItem>
|
</DropdownItem>
|
||||||
</DropdownMenuItem>
|
</DropdownMenuItem>
|
||||||
)}
|
)}
|
||||||
{/* readonly is only set when we are on a team - if we are on a user event type null will be the value. */}
|
{/* 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) &&
|
{isReadOnly && !isChildrenManagedEventType && (
|
||||||
!isChildrenManagedEventType && (
|
|
||||||
<>
|
<>
|
||||||
<DropdownMenuItem className="outline-none">
|
<DropdownMenuItem className="outline-none">
|
||||||
<DropdownItem
|
<DropdownItem
|
||||||
color="destructive"
|
color="destructive"
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
setDeleteDialogOpen(true);
|
setDeleteDialogOpen(true);
|
||||||
setDeleteDialogTypeId(type.id);
|
setDeleteDialogTypeId(eventType.id);
|
||||||
setDeleteDialogSchedulingType(type.schedulingType);
|
setDeleteDialogSchedulingType(eventType.schedulingType);
|
||||||
}}
|
}}
|
||||||
StartIcon={Trash}
|
StartIcon={Trash}
|
||||||
className="w-full rounded-none">
|
className="w-full rounded-none">
|
||||||
|
@ -651,14 +673,14 @@ export const EventTypeList = ({ group, groupIndex, readOnly, types }: EventTypeL
|
||||||
as={Label}
|
as={Label}
|
||||||
htmlFor="hiddenSwitch"
|
htmlFor="hiddenSwitch"
|
||||||
className="mt-2 inline cursor-pointer self-center pr-2 ">
|
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>
|
</Skeleton>
|
||||||
<Switch
|
<Switch
|
||||||
id="hiddenSwitch"
|
id="hiddenSwitch"
|
||||||
name="Hidden"
|
name="Hidden"
|
||||||
checked={!type.hidden}
|
checked={!eventType.hidden}
|
||||||
onCheckedChange={() => {
|
onCheckedChange={() => {
|
||||||
setHiddenMutation.mutate({ id: type.id, hidden: !type.hidden });
|
setHiddenMutation.mutate({ id: eventType.id, hidden: !eventType.hidden });
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
@ -702,7 +724,8 @@ export const EventTypeList = ({ group, groupIndex, readOnly, types }: EventTypeL
|
||||||
};
|
};
|
||||||
|
|
||||||
const EventTypeListHeading = ({
|
const EventTypeListHeading = ({
|
||||||
profile,
|
teamSlugOrUsername,
|
||||||
|
teamNameOrUserName,
|
||||||
membershipCount,
|
membershipCount,
|
||||||
teamId,
|
teamId,
|
||||||
}: EventTypeListHeadingProps): JSX.Element => {
|
}: EventTypeListHeadingProps): JSX.Element => {
|
||||||
|
@ -711,7 +734,7 @@ const EventTypeListHeading = ({
|
||||||
const orgBranding = useOrgBranding();
|
const orgBranding = useOrgBranding();
|
||||||
|
|
||||||
const publishTeamMutation = trpc.viewer.teams.publish.useMutation({
|
const publishTeamMutation = trpc.viewer.teams.publish.useMutation({
|
||||||
onSuccess(data) {
|
onSuccess(data: { url: string }) {
|
||||||
router.push(data.url);
|
router.push(data.url);
|
||||||
},
|
},
|
||||||
onError: (error) => {
|
onError: (error) => {
|
||||||
|
@ -719,17 +742,13 @@ const EventTypeListHeading = ({
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
const bookerUrl = useBookerUrl();
|
const bookerUrl = useBookerUrl();
|
||||||
|
const slug = teamSlugOrUsername;
|
||||||
return (
|
return (
|
||||||
<div className="mb-4 flex items-center space-x-2">
|
<div className="mb-4 flex items-center space-x-2">
|
||||||
<Avatar
|
<Avatar
|
||||||
alt={profile?.name || ""}
|
alt={teamNameOrUserName}
|
||||||
href={teamId ? `/settings/teams/${teamId}/profile` : "/settings/my-account/profile"}
|
href={teamId ? `/settings/teams/${teamId}/profile` : "/settings/my-account/profile"}
|
||||||
imageSrc={
|
imageSrc={`${orgBranding?.fullDomain ?? WEBAPP_URL}/${slug}/avatar.png` || undefined}
|
||||||
orgBranding?.fullDomain
|
|
||||||
? `${orgBranding.fullDomain}${teamId ? "/team" : ""}/${profile.slug}/avatar.png`
|
|
||||||
: profile.image
|
|
||||||
}
|
|
||||||
size="md"
|
size="md"
|
||||||
className="mt-1 inline-flex justify-center"
|
className="mt-1 inline-flex justify-center"
|
||||||
/>
|
/>
|
||||||
|
@ -737,9 +756,9 @@ const EventTypeListHeading = ({
|
||||||
<Link
|
<Link
|
||||||
href={teamId ? `/settings/teams/${teamId}/profile` : "/settings/my-account/profile"}
|
href={teamId ? `/settings/teams/${teamId}/profile` : "/settings/my-account/profile"}
|
||||||
className="text-emphasis font-bold">
|
className="text-emphasis font-bold">
|
||||||
{profile?.name || ""}
|
{teamNameOrUserName}
|
||||||
</Link>
|
</Link>
|
||||||
{membershipCount && teamId && (
|
{membershipCount >= 0 && teamId && (
|
||||||
<span className="text-subtle relative -top-px me-2 ms-2 text-xs">
|
<span className="text-subtle relative -top-px me-2 ms-2 text-xs">
|
||||||
<Link href={`/settings/teams/${teamId}/members`}>
|
<Link href={`/settings/teams/${teamId}/members`}>
|
||||||
<Badge variant="gray">
|
<Badge variant="gray">
|
||||||
|
@ -749,15 +768,15 @@ const EventTypeListHeading = ({
|
||||||
</Link>
|
</Link>
|
||||||
</span>
|
</span>
|
||||||
)}
|
)}
|
||||||
{profile?.slug && (
|
{slug && (
|
||||||
<Link
|
<Link
|
||||||
href={`${orgBranding ? orgBranding.fullDomain : CAL_URL}/${profile.slug}`}
|
href={`${orgBranding ? orgBranding.fullDomain : CAL_URL}/${slug}`}
|
||||||
className="text-subtle block text-xs">
|
className="text-subtle block text-xs">
|
||||||
{`${bookerUrl.replace("https://", "").replace("http://", "")}/${profile.slug}`}
|
{`${bookerUrl.replace("https://", "").replace("http://", "")}/${slug}`}
|
||||||
</Link>
|
</Link>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
{!profile?.slug && !!teamId && (
|
{!slug && !!teamId && (
|
||||||
<button onClick={() => publishTeamMutation.mutate({ teamId })}>
|
<button onClick={() => publishTeamMutation.mutate({ teamId })}>
|
||||||
<Badge variant="gray" className="-ml-2 mb-1">
|
<Badge variant="gray" className="-ml-2 mb-1">
|
||||||
{t("upgrade")}
|
{t("upgrade")}
|
||||||
|
@ -786,30 +805,18 @@ const CreateFirstEventTypeView = ({ slug }: { slug: string }) => {
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
const CTA = ({ data }: { data: GetByViewerResponse }) => {
|
const CTA = () => {
|
||||||
const { t } = useLocale();
|
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 (
|
return (
|
||||||
<CreateButton
|
<>
|
||||||
|
<CreateButtonWithTeamsList
|
||||||
data-testid="new-event-type"
|
data-testid="new-event-type"
|
||||||
subtitle={t("create_event_on").toUpperCase()}
|
subtitle={t("create_event_on").toUpperCase()}
|
||||||
options={profileOptions}
|
createDialog={() => <CreateEventTypeDialog profileOptions={[]} />}
|
||||||
createDialog={() => <CreateEventTypeDialog profileOptions={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();
|
const { t } = useLocale();
|
||||||
|
if (!teamSlugOrUsername && !teamId) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<EmptyScreen
|
<EmptyScreen
|
||||||
headline={t("team_no_event_types")}
|
headline={t("team_no_event_types")}
|
||||||
buttonRaw={
|
buttonRaw={
|
||||||
<Button
|
<Button
|
||||||
href={`?dialog=new&eventPage=${group.profile.slug}&teamId=${group.teamId}`}
|
href={`?dialog=new&eventPage=${teamSlugOrUsername}${teamId ? `&teamId=${teamId}` : ""}`}
|
||||||
variant="button"
|
variant="button"
|
||||||
className="mt-5">
|
className="mt-5">
|
||||||
{t("create")}
|
{t("create")}
|
||||||
|
@ -868,78 +884,163 @@ const EmptyEventTypeList = ({ group }: { group: EventTypeGroup }) => {
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
const Main = ({
|
const Main = ({ filters }: { filters: ReturnType<typeof getTeamsFiltersFromQuery> }) => {
|
||||||
status,
|
|
||||||
errorMessage,
|
|
||||||
data,
|
|
||||||
filters,
|
|
||||||
}: {
|
|
||||||
status: string;
|
|
||||||
data: GetByViewerResponse;
|
|
||||||
errorMessage?: string;
|
|
||||||
filters: ReturnType<typeof getTeamsFiltersFromQuery>;
|
|
||||||
}) => {
|
|
||||||
const isMobile = useMediaQuery("(max-width: 768px)");
|
const isMobile = useMediaQuery("(max-width: 768px)");
|
||||||
const searchParams = useSearchParams();
|
const searchParams = useSearchParams();
|
||||||
const orgBranding = useOrgBranding();
|
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 />;
|
return <SkeletonLoader />;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (status === "error") {
|
if ((!!data && data.length > 1) || isFilteredByOnlyOneItem) {
|
||||||
return <Alert severity="error" title="Something went wrong" message={errorMessage} />;
|
const [firstElementPersonalEventTypes] = data;
|
||||||
}
|
const [mainUser] = firstElementPersonalEventTypes?.users || [];
|
||||||
|
|
||||||
const isFilteredByOnlyOneItem =
|
const teamEventTypesForTabs = eventTypePaginate
|
||||||
(filters?.teamIds?.length === 1 || filters?.userIds?.length === 1) && data.eventTypeGroups.length === 1;
|
.map((trpcFetch) => {
|
||||||
|
const { data } = trpcFetch;
|
||||||
|
return data || [];
|
||||||
|
})
|
||||||
|
.filter((item) => item && item.length > 0);
|
||||||
return (
|
return (
|
||||||
<>
|
|
||||||
{data.eventTypeGroups.length > 1 || isFilteredByOnlyOneItem ? (
|
|
||||||
<>
|
<>
|
||||||
{isMobile ? (
|
{isMobile ? (
|
||||||
<MobileTeamsTab eventTypeGroups={data.eventTypeGroups} />
|
<MobileTeamsTab teamEventTypes={[data, ...teamEventTypesForTabs]} />
|
||||||
) : (
|
) : (
|
||||||
data.eventTypeGroups.map((group: EventTypeGroup, index: number) => (
|
<div className="mt-4 flex flex-col">
|
||||||
<div className="mt-4 flex flex-col" key={group.profile.slug}>
|
|
||||||
<EventTypeListHeading
|
<EventTypeListHeading
|
||||||
profile={group.profile}
|
teamSlugOrUsername={mainUser.username || ""}
|
||||||
membershipCount={group.metadata.membershipCount}
|
teamNameOrUserName={mainUser.name || ""}
|
||||||
teamId={group.teamId}
|
// Single event types have no teamMembershipCount
|
||||||
|
membershipCount={0}
|
||||||
|
teamId={firstElementPersonalEventTypes.teamId}
|
||||||
orgSlug={orgBranding?.slug}
|
orgSlug={orgBranding?.slug}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
{group.eventTypes.length ? (
|
{data.length > 0 ? (
|
||||||
<EventTypeList
|
<EventTypeList data={data} />
|
||||||
types={group.eventTypes}
|
|
||||||
group={group}
|
|
||||||
groupIndex={index}
|
|
||||||
readOnly={group.metadata.readOnly}
|
|
||||||
/>
|
|
||||||
) : group.teamId ? (
|
|
||||||
<EmptyEventTypeList group={group} />
|
|
||||||
) : (
|
) : (
|
||||||
<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
|
</div>
|
||||||
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 />
|
<EventTypeEmbedDialog />
|
||||||
{searchParams?.get("dialog") === "duplicate" && <DuplicateDialog />}
|
{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 = () => {
|
const EventTypesPage = () => {
|
||||||
|
@ -952,13 +1053,6 @@ const EventTypesPage = () => {
|
||||||
const routerQuery = useRouterQuery();
|
const routerQuery = useRouterQuery();
|
||||||
const filters = getTeamsFiltersFromQuery(routerQuery);
|
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() {
|
function closeBanner() {
|
||||||
setShowProfileBanner(false);
|
setShowProfileBanner(false);
|
||||||
document.cookie = `calcom-profile-banner=1;max-age=${60 * 60 * 24 * 90}`; // 3 months
|
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")}
|
subtitle={t("event_types_page_subtitle")}
|
||||||
afterHeading={showProfileBanner && <SetupProfileBanner closeAction={closeBanner} />}
|
afterHeading={showProfileBanner && <SetupProfileBanner closeAction={closeBanner} />}
|
||||||
beforeCTAactions={<Actions />}
|
beforeCTAactions={<Actions />}
|
||||||
CTA={<CTA data={data} />}>
|
CTA={<CTA />}>
|
||||||
<HeadSeo
|
<HeadSeo
|
||||||
title="Event Types"
|
title="Event Types"
|
||||||
description="Create events to share for people to book on your calendar."
|
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>
|
</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
|
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 {
|
view BookingTimeStatus {
|
||||||
id Int @unique
|
id Int @unique
|
||||||
uid String?
|
uid String?
|
||||||
|
@ -958,14 +971,7 @@ view BookingTimeStatus {
|
||||||
eventParentId Int?
|
eventParentId Int?
|
||||||
}
|
}
|
||||||
|
|
||||||
model CalendarCache {
|
view TeamMemberCount {
|
||||||
// The key would be the unique URL that is requested by the user
|
id Int @unique
|
||||||
key String
|
count Int
|
||||||
value Json
|
|
||||||
expiresAt DateTime
|
|
||||||
credentialId Int
|
|
||||||
credential Credential? @relation(fields: [credentialId], references: [id], onDelete: Cascade)
|
|
||||||
|
|
||||||
@@id([credentialId, key])
|
|
||||||
@@unique([credentialId, key])
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -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 { ZDuplicateInputSchema } from "./duplicate.schema";
|
||||||
import { ZGetInputSchema } from "./get.schema";
|
import { ZGetInputSchema } from "./get.schema";
|
||||||
import { ZEventTypeInputSchema } from "./getByViewer.schema";
|
import { ZEventTypeInputSchema } from "./getByViewer.schema";
|
||||||
|
import { ZInfiniteEventsTypeInputSchema } from "./infiniteEventTypes.schema";
|
||||||
import { ZUpdateInputSchema } from "./update.schema";
|
import { ZUpdateInputSchema } from "./update.schema";
|
||||||
import { eventOwnerProcedure } from "./util";
|
import { eventOwnerProcedure } from "./util";
|
||||||
|
|
||||||
|
@ -23,6 +24,7 @@ type BookingsRouterHandlerCache = {
|
||||||
duplicate?: typeof import("./duplicate.handler").duplicateHandler;
|
duplicate?: typeof import("./duplicate.handler").duplicateHandler;
|
||||||
bulkEventFetch?: typeof import("./bulkEventFetch.handler").bulkEventFetchHandler;
|
bulkEventFetch?: typeof import("./bulkEventFetch.handler").bulkEventFetchHandler;
|
||||||
bulkUpdateToDefaultLocation?: typeof import("./bulkUpdateToDefaultLocation.handler").bulkUpdateToDefaultLocationHandler;
|
bulkUpdateToDefaultLocation?: typeof import("./bulkUpdateToDefaultLocation.handler").bulkUpdateToDefaultLocationHandler;
|
||||||
|
paginate?: typeof import("./infiniteEventTypes.handler").paginateHandler;
|
||||||
};
|
};
|
||||||
|
|
||||||
const UNSTABLE_HANDLER_CACHE: BookingsRouterHandlerCache = {};
|
const UNSTABLE_HANDLER_CACHE: BookingsRouterHandlerCache = {};
|
||||||
|
@ -207,4 +209,22 @@ export const eventTypesRouter = router({
|
||||||
input,
|
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
|
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 }) => ({
|
return membershipsWithoutParent.map(({ team: { inviteTokens, ..._team }, ...membership }) => ({
|
||||||
role: membership.role,
|
role: membership.role,
|
||||||
accepted: membership.accepted,
|
accepted: membership.accepted,
|
||||||
|
@ -42,6 +51,7 @@ export const listHandler = async ({ ctx }: ListOptions) => {
|
||||||
..._team,
|
..._team,
|
||||||
/** To prevent breaking we only return non-email attached token here, if we have one */
|
/** 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),
|
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" },
|
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
|
return memberships
|
||||||
.filter((mmship) => {
|
.filter((mmship) => {
|
||||||
const metadata = teamMetadataSchema.parse(mmship.team.metadata);
|
const metadata = teamMetadataSchema.parse(mmship.team.metadata);
|
||||||
|
@ -70,5 +89,6 @@ export const listHandler = async ({ ctx }: ListOptions) => {
|
||||||
..._team,
|
..._team,
|
||||||
/** To prevent breaking we only return non-email attached token here, if we have one */
|
/** 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),
|
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
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
"@algora/sdk@npm:^0.1.2":
|
"@alloc/quick-lru@npm:^5.2.0":
|
||||||
version: 0.1.2
|
version: 5.2.0
|
||||||
resolution: "@algora/sdk@npm:0.1.2"
|
resolution: "@alloc/quick-lru@npm:5.2.0"
|
||||||
dependencies:
|
checksum: bdc35758b552bcf045733ac047fb7f9a07c4678b944c641adfbd41f798b4b91fffd0fdc0df2578d9b0afc7b4d636aa6e110ead5d6281a2adc1ab90efd7f057f8
|
||||||
"@trpc/client": ^10.0.0
|
|
||||||
"@trpc/server": ^10.0.0
|
|
||||||
superjson: ^1.9.1
|
|
||||||
checksum: 0ef5c0ac7fa09c57f685a61859e263f4b5c2d69e6ee72b395f88490106fa6213a0308ca11e5673368e5b33dc4dff38411c0d226f9c65856ef91aa58bc2e0e61c
|
|
||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
|
@ -3535,15 +3531,13 @@ __metadata:
|
||||||
"@calcom/ui": "*"
|
"@calcom/ui": "*"
|
||||||
"@types/node": 16.9.1
|
"@types/node": 16.9.1
|
||||||
"@types/react": 18.0.26
|
"@types/react": 18.0.26
|
||||||
"@types/react-dom": ^18.0.9
|
"@types/react-dom": 18.0.9
|
||||||
eslint: ^8.34.0
|
eslint: ^8.34.0
|
||||||
eslint-config-next: ^13.2.1
|
eslint-config-next: ^13.2.1
|
||||||
next: ^13.4.6
|
next: ^13.2.1
|
||||||
next-auth: ^4.22.1
|
next-auth: ^4.20.1
|
||||||
postcss: ^8.4.18
|
|
||||||
react: ^18.2.0
|
react: ^18.2.0
|
||||||
react-dom: ^18.2.0
|
react-dom: ^18.2.0
|
||||||
tailwindcss: ^3.3.1
|
|
||||||
typescript: ^4.9.4
|
typescript: ^4.9.4
|
||||||
languageName: unknown
|
languageName: unknown
|
||||||
linkType: soft
|
linkType: soft
|
||||||
|
@ -3645,9 +3639,9 @@ __metadata:
|
||||||
chart.js: ^3.7.1
|
chart.js: ^3.7.1
|
||||||
client-only: ^0.0.1
|
client-only: ^0.0.1
|
||||||
eslint: ^8.34.0
|
eslint: ^8.34.0
|
||||||
next: ^13.4.6
|
next: ^13.2.1
|
||||||
next-auth: ^4.22.1
|
next-auth: ^4.20.1
|
||||||
next-i18next: ^13.2.2
|
next-i18next: ^11.3.0
|
||||||
postcss: ^8.4.18
|
postcss: ^8.4.18
|
||||||
prisma: ^5.0.0
|
prisma: ^5.0.0
|
||||||
prisma-field-encryption: ^1.4.0
|
prisma-field-encryption: ^1.4.0
|
||||||
|
@ -3655,9 +3649,9 @@ __metadata:
|
||||||
react-chartjs-2: ^4.0.1
|
react-chartjs-2: ^4.0.1
|
||||||
react-dom: ^18.2.0
|
react-dom: ^18.2.0
|
||||||
react-hook-form: ^7.43.3
|
react-hook-form: ^7.43.3
|
||||||
react-live-chat-loader: ^2.8.1
|
react-live-chat-loader: ^2.7.3
|
||||||
swr: ^1.2.2
|
swr: ^1.2.2
|
||||||
tailwindcss: ^3.3.1
|
tailwindcss: ^3.2.1
|
||||||
typescript: ^4.9.4
|
typescript: ^4.9.4
|
||||||
zod: ^3.22.2
|
zod: ^3.22.2
|
||||||
languageName: unknown
|
languageName: unknown
|
||||||
|
@ -4621,7 +4615,6 @@ __metadata:
|
||||||
version: 0.0.0-use.local
|
version: 0.0.0-use.local
|
||||||
resolution: "@calcom/website@workspace:apps/website"
|
resolution: "@calcom/website@workspace:apps/website"
|
||||||
dependencies:
|
dependencies:
|
||||||
"@algora/sdk": ^0.1.2
|
|
||||||
"@calcom/app-store": "*"
|
"@calcom/app-store": "*"
|
||||||
"@calcom/config": "*"
|
"@calcom/config": "*"
|
||||||
"@calcom/dayjs": "*"
|
"@calcom/dayjs": "*"
|
||||||
|
@ -4660,13 +4653,11 @@ __metadata:
|
||||||
"@types/node": 16.9.1
|
"@types/node": 16.9.1
|
||||||
"@types/react": 18.0.26
|
"@types/react": 18.0.26
|
||||||
"@types/react-gtm-module": ^2.0.1
|
"@types/react-gtm-module": ^2.0.1
|
||||||
"@types/xml2js": ^0.4.11
|
|
||||||
"@vercel/analytics": ^0.1.6
|
"@vercel/analytics": ^0.1.6
|
||||||
"@vercel/edge-functions-ui": ^0.2.1
|
"@vercel/edge-functions-ui": ^0.2.1
|
||||||
"@vercel/og": ^0.5.0
|
"@vercel/og": ^0.5.0
|
||||||
autoprefixer: ^10.4.12
|
autoprefixer: ^10.4.12
|
||||||
bcryptjs: ^2.4.3
|
bcryptjs: ^2.4.3
|
||||||
clsx: ^1.2.1
|
|
||||||
cobe: ^0.4.1
|
cobe: ^0.4.1
|
||||||
concurrently: ^7.6.0
|
concurrently: ^7.6.0
|
||||||
cross-env: ^7.0.3
|
cross-env: ^7.0.3
|
||||||
|
@ -4683,10 +4674,9 @@ __metadata:
|
||||||
graphql-request: ^6.1.0
|
graphql-request: ^6.1.0
|
||||||
gray-matter: ^4.0.3
|
gray-matter: ^4.0.3
|
||||||
gsap: ^3.11.0
|
gsap: ^3.11.0
|
||||||
i18n-unused: ^0.13.0
|
|
||||||
iframe-resizer-react: ^1.1.0
|
iframe-resizer-react: ^1.1.0
|
||||||
keen-slider: ^6.8.0
|
keen-slider: ^6.8.0
|
||||||
lucide-react: ^0.171.0
|
lucide-react: ^0.125.0
|
||||||
micro: ^10.0.1
|
micro: ^10.0.1
|
||||||
next: ^13.4.6
|
next: ^13.4.6
|
||||||
next-auth: ^4.22.1
|
next-auth: ^4.22.1
|
||||||
|
@ -4709,7 +4699,6 @@ __metadata:
|
||||||
react-merge-refs: 1.1.0
|
react-merge-refs: 1.1.0
|
||||||
react-twemoji: ^0.3.0
|
react-twemoji: ^0.3.0
|
||||||
react-use-measure: ^2.1.1
|
react-use-measure: ^2.1.1
|
||||||
react-wrap-balancer: ^1.0.0
|
|
||||||
remark: ^14.0.2
|
remark: ^14.0.2
|
||||||
remark-html: ^14.0.1
|
remark-html: ^14.0.1
|
||||||
remeda: ^1.24.1
|
remeda: ^1.24.1
|
||||||
|
@ -7761,6 +7750,20 @@ __metadata:
|
||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
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":
|
"@next/env@npm:13.4.6":
|
||||||
version: 13.4.6
|
version: 13.4.6
|
||||||
resolution: "@next/env@npm:13.4.6"
|
resolution: "@next/env@npm:13.4.6"
|
||||||
|
@ -7777,6 +7780,34 @@ __metadata:
|
||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
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":
|
"@next/swc-darwin-arm64@npm:13.4.6":
|
||||||
version: 13.4.6
|
version: 13.4.6
|
||||||
resolution: "@next/swc-darwin-arm64@npm:13.4.6"
|
resolution: "@next/swc-darwin-arm64@npm:13.4.6"
|
||||||
|
@ -7784,6 +7815,20 @@ __metadata:
|
||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
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":
|
"@next/swc-darwin-x64@npm:13.4.6":
|
||||||
version: 13.4.6
|
version: 13.4.6
|
||||||
resolution: "@next/swc-darwin-x64@npm:13.4.6"
|
resolution: "@next/swc-darwin-x64@npm:13.4.6"
|
||||||
|
@ -7791,6 +7836,34 @@ __metadata:
|
||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
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":
|
"@next/swc-linux-arm64-gnu@npm:13.4.6":
|
||||||
version: 13.4.6
|
version: 13.4.6
|
||||||
resolution: "@next/swc-linux-arm64-gnu@npm:13.4.6"
|
resolution: "@next/swc-linux-arm64-gnu@npm:13.4.6"
|
||||||
|
@ -7798,6 +7871,20 @@ __metadata:
|
||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
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":
|
"@next/swc-linux-arm64-musl@npm:13.4.6":
|
||||||
version: 13.4.6
|
version: 13.4.6
|
||||||
resolution: "@next/swc-linux-arm64-musl@npm:13.4.6"
|
resolution: "@next/swc-linux-arm64-musl@npm:13.4.6"
|
||||||
|
@ -7805,6 +7892,20 @@ __metadata:
|
||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
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":
|
"@next/swc-linux-x64-gnu@npm:13.4.6":
|
||||||
version: 13.4.6
|
version: 13.4.6
|
||||||
resolution: "@next/swc-linux-x64-gnu@npm:13.4.6"
|
resolution: "@next/swc-linux-x64-gnu@npm:13.4.6"
|
||||||
|
@ -7812,6 +7913,20 @@ __metadata:
|
||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
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":
|
"@next/swc-linux-x64-musl@npm:13.4.6":
|
||||||
version: 13.4.6
|
version: 13.4.6
|
||||||
resolution: "@next/swc-linux-x64-musl@npm:13.4.6"
|
resolution: "@next/swc-linux-x64-musl@npm:13.4.6"
|
||||||
|
@ -7819,6 +7934,20 @@ __metadata:
|
||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
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":
|
"@next/swc-win32-arm64-msvc@npm:13.4.6":
|
||||||
version: 13.4.6
|
version: 13.4.6
|
||||||
resolution: "@next/swc-win32-arm64-msvc@npm:13.4.6"
|
resolution: "@next/swc-win32-arm64-msvc@npm:13.4.6"
|
||||||
|
@ -7826,6 +7955,20 @@ __metadata:
|
||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
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":
|
"@next/swc-win32-ia32-msvc@npm:13.4.6":
|
||||||
version: 13.4.6
|
version: 13.4.6
|
||||||
resolution: "@next/swc-win32-ia32-msvc@npm:13.4.6"
|
resolution: "@next/swc-win32-ia32-msvc@npm:13.4.6"
|
||||||
|
@ -7833,6 +7976,20 @@ __metadata:
|
||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
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":
|
"@next/swc-win32-x64-msvc@npm:13.4.6":
|
||||||
version: 13.4.6
|
version: 13.4.6
|
||||||
resolution: "@next/swc-win32-x64-msvc@npm:13.4.6"
|
resolution: "@next/swc-win32-x64-msvc@npm:13.4.6"
|
||||||
|
@ -12040,6 +12197,15 @@ __metadata:
|
||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
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":
|
"@swc/helpers@npm:0.5.1":
|
||||||
version: 0.5.1
|
version: 0.5.1
|
||||||
resolution: "@swc/helpers@npm:0.5.1"
|
resolution: "@swc/helpers@npm:0.5.1"
|
||||||
|
@ -17449,7 +17615,7 @@ __metadata:
|
||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
"clsx@npm:^1.0.4, clsx@npm:^1.2.1":
|
"clsx@npm:^1.0.4":
|
||||||
version: 1.2.1
|
version: 1.2.1
|
||||||
resolution: "clsx@npm:1.2.1"
|
resolution: "clsx@npm:1.2.1"
|
||||||
checksum: 30befca8019b2eb7dbad38cff6266cf543091dae2825c856a62a8ccf2c3ab9c2907c4d12b288b73101196767f66812365400a227581484a05f968b0307cfaf12
|
checksum: 30befca8019b2eb7dbad38cff6266cf543091dae2825c856a62a8ccf2c3ab9c2907c4d12b288b73101196767f66812365400a227581484a05f968b0307cfaf12
|
||||||
|
@ -23885,6 +24051,13 @@ __metadata:
|
||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
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":
|
"i18next-fs-backend@npm:^2.1.1":
|
||||||
version: 2.1.3
|
version: 2.1.3
|
||||||
resolution: "i18next-fs-backend@npm:2.1.3"
|
resolution: "i18next-fs-backend@npm:2.1.3"
|
||||||
|
@ -23892,6 +24065,15 @@ __metadata:
|
||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
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":
|
"i18next@npm:^23.2.3":
|
||||||
version: 23.2.3
|
version: 23.2.3
|
||||||
resolution: "i18next@npm:23.2.3"
|
resolution: "i18next@npm:23.2.3"
|
||||||
|
@ -24564,7 +24746,7 @@ __metadata:
|
||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
"is-core-module@npm:^2.11.0":
|
"is-core-module@npm:^2.13.0":
|
||||||
version: 2.13.0
|
version: 2.13.0
|
||||||
resolution: "is-core-module@npm:2.13.0"
|
resolution: "is-core-module@npm:2.13.0"
|
||||||
dependencies:
|
dependencies:
|
||||||
|
@ -25535,6 +25717,15 @@ __metadata:
|
||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
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":
|
"joi@npm:^17.7.0":
|
||||||
version: 17.10.2
|
version: 17.10.2
|
||||||
resolution: "joi@npm:17.10.2"
|
resolution: "joi@npm:17.10.2"
|
||||||
|
@ -26699,6 +26890,13 @@ __metadata:
|
||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
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":
|
"limiter@npm:^1.1.5":
|
||||||
version: 1.1.5
|
version: 1.1.5
|
||||||
resolution: "limiter@npm:1.1.5"
|
resolution: "limiter@npm:1.1.5"
|
||||||
|
@ -27372,6 +27570,15 @@ __metadata:
|
||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
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":
|
"lucide-react@npm:^0.171.0":
|
||||||
version: 0.171.0
|
version: 0.171.0
|
||||||
resolution: "lucide-react@npm:0.171.0"
|
resolution: "lucide-react@npm:0.171.0"
|
||||||
|
@ -29120,6 +29327,31 @@ __metadata:
|
||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
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":
|
"next-auth@npm:^4.22.1":
|
||||||
version: 4.22.1
|
version: 4.22.1
|
||||||
resolution: "next-auth@npm:4.22.1"
|
resolution: "next-auth@npm:4.22.1"
|
||||||
|
@ -29169,6 +29401,24 @@ __metadata:
|
||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
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":
|
"next-i18next@npm:^13.2.2":
|
||||||
version: 13.3.0
|
version: 13.3.0
|
||||||
resolution: "next-i18next@npm:13.3.0"
|
resolution: "next-i18next@npm:13.3.0"
|
||||||
|
@ -29250,6 +29500,62 @@ __metadata:
|
||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
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":
|
"next@npm:^13.4.6":
|
||||||
version: 13.4.6
|
version: 13.4.6
|
||||||
resolution: "next@npm:13.4.6"
|
resolution: "next@npm:13.4.6"
|
||||||
|
@ -29309,6 +29615,77 @@ __metadata:
|
||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
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":
|
"nice-try@npm:^1.0.4":
|
||||||
version: 1.0.5
|
version: 1.0.5
|
||||||
resolution: "nice-try@npm:1.0.5"
|
resolution: "nice-try@npm:1.0.5"
|
||||||
|
@ -31271,6 +31648,19 @@ __metadata:
|
||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
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":
|
"postcss-js@npm:^4.0.0":
|
||||||
version: 4.0.0
|
version: 4.0.0
|
||||||
resolution: "postcss-js@npm:4.0.0"
|
resolution: "postcss-js@npm:4.0.0"
|
||||||
|
@ -31282,6 +31672,17 @@ __metadata:
|
||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
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":
|
"postcss-load-config@npm:^3.1.4":
|
||||||
version: 3.1.4
|
version: 3.1.4
|
||||||
resolution: "postcss-load-config@npm:3.1.4"
|
resolution: "postcss-load-config@npm:3.1.4"
|
||||||
|
@ -31300,6 +31701,24 @@ __metadata:
|
||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
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":
|
"postcss-loader@npm:^4.2.0":
|
||||||
version: 4.3.0
|
version: 4.3.0
|
||||||
resolution: "postcss-loader@npm:4.3.0"
|
resolution: "postcss-loader@npm:4.3.0"
|
||||||
|
@ -31426,6 +31845,17 @@ __metadata:
|
||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
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":
|
"postcss-pseudo-companion-classes@npm:^0.1.1":
|
||||||
version: 0.1.1
|
version: 0.1.1
|
||||||
resolution: "postcss-pseudo-companion-classes@npm:0.1.1"
|
resolution: "postcss-pseudo-companion-classes@npm:0.1.1"
|
||||||
|
@ -32717,6 +33147,24 @@ __metadata:
|
||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
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":
|
"react-i18next@npm:^12.2.0":
|
||||||
version: 12.3.1
|
version: 12.3.1
|
||||||
resolution: "react-i18next@npm:12.3.1"
|
resolution: "react-i18next@npm:12.3.1"
|
||||||
|
@ -32840,7 +33288,7 @@ __metadata:
|
||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
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
|
version: 2.8.1
|
||||||
resolution: "react-live-chat-loader@npm:2.8.1"
|
resolution: "react-live-chat-loader@npm:2.8.1"
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
|
@ -34092,6 +34540,19 @@ __metadata:
|
||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
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":
|
"resolve@npm:^2.0.0-next.3":
|
||||||
version: 2.0.0-next.3
|
version: 2.0.0-next.3
|
||||||
resolution: "resolve@npm:2.0.0-next.3"
|
resolution: "resolve@npm:2.0.0-next.3"
|
||||||
|
@ -34141,6 +34602,19 @@ __metadata:
|
||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
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>":
|
"resolve@patch:resolve@^2.0.0-next.3#~builtin<compat/resolve>":
|
||||||
version: 2.0.0-next.3
|
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"
|
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
|
languageName: node
|
||||||
linkType: hard
|
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":
|
"superagent@npm:^5.1.1":
|
||||||
version: 5.3.1
|
version: 5.3.1
|
||||||
resolution: "superagent@npm:5.3.1"
|
resolution: "superagent@npm:5.3.1"
|
||||||
|
@ -36620,6 +37112,39 @@ __metadata:
|
||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
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":
|
"tailwindcss@npm:^3.3.1":
|
||||||
version: 3.3.1
|
version: 3.3.1
|
||||||
resolution: "tailwindcss@npm:3.3.1"
|
resolution: "tailwindcss@npm:3.3.1"
|
||||||
|
@ -40360,16 +40885,6 @@ __metadata:
|
||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
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":
|
"xml@npm:=1.0.1":
|
||||||
version: 1.0.1
|
version: 1.0.1
|
||||||
resolution: "xml@npm:1.0.1"
|
resolution: "xml@npm:1.0.1"
|
||||||
|
|
Loading…
Reference in New Issue
Block a user