Merge branch 'main' into testE2E-timezone
This commit is contained in:
commit
0ad9e3fabb
|
@ -266,7 +266,7 @@ CALCOM_WEBHOOK_SECRET=""
|
|||
CALCOM_WEBHOOK_HEADER_NAME="calcom-webhook-secret"
|
||||
CALCOM_CREDENTIAL_SYNC_ENDPOINT=""
|
||||
# Key should match on Cal.com and your application
|
||||
# must be 32 bytes for AES256 encryption algorithm
|
||||
# must be 24 bytes for AES256 encryption algorithm
|
||||
# You can use: `openssl rand -base64 24` to generate one
|
||||
CALCOM_APP_CREDENTIAL_ENCRYPTION_KEY=""
|
||||
|
||||
|
|
|
@ -32,6 +32,7 @@ type AppListCardProps = {
|
|||
invalidCredential?: boolean;
|
||||
children?: ReactNode;
|
||||
credentialOwner?: CredentialOwner;
|
||||
className?: string;
|
||||
} & ShouldHighlight;
|
||||
|
||||
const schema = z.object({ hl: z.string().optional() });
|
||||
|
@ -50,6 +51,7 @@ export default function AppListCard(props: AppListCardProps) {
|
|||
invalidCredential,
|
||||
children,
|
||||
credentialOwner,
|
||||
className,
|
||||
} = props;
|
||||
const {
|
||||
data: { hl },
|
||||
|
@ -83,7 +85,7 @@ export default function AppListCard(props: AppListCardProps) {
|
|||
}, [highlight, pathname, router, searchParams, shouldHighlight]);
|
||||
|
||||
return (
|
||||
<div className={classNames(highlight && "dark:bg-muted bg-yellow-100")}>
|
||||
<div className={classNames(highlight && "dark:bg-muted bg-yellow-100", className)}>
|
||||
<div className="flex items-center gap-x-3 px-4 py-4 sm:px-6">
|
||||
{logo ? (
|
||||
<img
|
||||
|
|
|
@ -14,8 +14,9 @@ import {
|
|||
List,
|
||||
AppSkeletonLoader as SkeletonLoader,
|
||||
ShellSubHeading,
|
||||
Label,
|
||||
} from "@calcom/ui";
|
||||
import { Calendar, Plus } from "@calcom/ui/components/icon";
|
||||
import { Calendar } from "@calcom/ui/components/icon";
|
||||
|
||||
import { QueryCell } from "@lib/QueryCell";
|
||||
|
||||
|
@ -27,6 +28,7 @@ type Props = {
|
|||
onChanged: () => unknown | Promise<unknown>;
|
||||
fromOnboarding?: boolean;
|
||||
destinationCalendarId?: string;
|
||||
isLoading?: boolean;
|
||||
};
|
||||
|
||||
function CalendarList(props: Props) {
|
||||
|
@ -70,8 +72,9 @@ function ConnectedCalendarsList(props: Props) {
|
|||
const { t } = useLocale();
|
||||
const query = trpc.viewer.connectedCalendars.useQuery(undefined, {
|
||||
suspense: true,
|
||||
refetchOnWindowFocus: false,
|
||||
});
|
||||
const { fromOnboarding } = props;
|
||||
const { fromOnboarding, isLoading } = props;
|
||||
return (
|
||||
<QueryCell
|
||||
query={query}
|
||||
|
@ -82,74 +85,94 @@ function ConnectedCalendarsList(props: Props) {
|
|||
}
|
||||
|
||||
return (
|
||||
<List>
|
||||
{data.connectedCalendars.map((item) => (
|
||||
<Fragment key={item.credentialId}>
|
||||
{item.calendars ? (
|
||||
<AppListCard
|
||||
shouldHighlight
|
||||
slug={item.integration.slug}
|
||||
title={item.integration.name}
|
||||
logo={item.integration.logo}
|
||||
description={item.primary?.email ?? item.integration.description}
|
||||
actions={
|
||||
<div className="flex w-32 justify-end">
|
||||
<DisconnectIntegration
|
||||
credentialId={item.credentialId}
|
||||
trashIcon
|
||||
onSuccess={props.onChanged}
|
||||
buttonProps={{ className: "border border-default" }}
|
||||
/>
|
||||
</div>
|
||||
}>
|
||||
<div className="border-subtle border-t">
|
||||
{!fromOnboarding && (
|
||||
<>
|
||||
<p className="text-subtle px-5 pt-4 text-sm">{t("toggle_calendars_conflict")}</p>
|
||||
<ul className="space-y-4 px-5 py-4">
|
||||
{item.calendars.map((cal) => (
|
||||
<CalendarSwitch
|
||||
key={cal.externalId}
|
||||
externalId={cal.externalId}
|
||||
title={cal.name || "Nameless calendar"}
|
||||
name={cal.name || "Nameless calendar"}
|
||||
type={item.integration.type}
|
||||
isChecked={cal.isSelected}
|
||||
destination={cal.externalId === props.destinationCalendarId}
|
||||
credentialId={cal.credentialId}
|
||||
/>
|
||||
))}
|
||||
</ul>
|
||||
</>
|
||||
)}
|
||||
<div className="border-subtle mt-6 rounded-lg border">
|
||||
<div className="border-subtle border-b p-6">
|
||||
<div className="flex items-center justify-between">
|
||||
<div>
|
||||
<h4 className="text-emphasis text-base font-semibold leading-5">
|
||||
{t("check_for_conflicts")}
|
||||
</h4>
|
||||
<p className="text-default text-sm leading-tight">{t("select_calendars")}</p>
|
||||
</div>
|
||||
<div className="flex flex-col xl:flex-row xl:space-x-5">
|
||||
{!!data.connectedCalendars.length && (
|
||||
<div className="flex items-center">
|
||||
<AdditionalCalendarSelector isLoading={isLoading} />
|
||||
</div>
|
||||
</AppListCard>
|
||||
) : (
|
||||
<Alert
|
||||
severity="warning"
|
||||
title={t("something_went_wrong")}
|
||||
message={
|
||||
<span>
|
||||
<Link href={`/apps/${item.integration.slug}`}>{item.integration.name}</Link>:{" "}
|
||||
{t("calendar_error")}
|
||||
</span>
|
||||
}
|
||||
iconClassName="h-10 w-10 ml-2 mr-1 mt-0.5"
|
||||
actions={
|
||||
<div className="flex w-32 justify-end md:pr-1">
|
||||
<DisconnectIntegration
|
||||
credentialId={item.credentialId}
|
||||
trashIcon
|
||||
onSuccess={props.onChanged}
|
||||
buttonProps={{ className: "border border-default" }}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<List noBorderTreatment className="p-6 pt-2">
|
||||
{data.connectedCalendars.map((item) => (
|
||||
<Fragment key={item.credentialId}>
|
||||
{item.calendars ? (
|
||||
<AppListCard
|
||||
shouldHighlight
|
||||
slug={item.integration.slug}
|
||||
title={item.integration.name}
|
||||
logo={item.integration.logo}
|
||||
description={item.primary?.email ?? item.integration.description}
|
||||
className="border-subtle mt-4 rounded-lg border"
|
||||
actions={
|
||||
<div className="flex w-32 justify-end">
|
||||
<DisconnectIntegration
|
||||
credentialId={item.credentialId}
|
||||
trashIcon
|
||||
onSuccess={props.onChanged}
|
||||
buttonProps={{ className: "border border-default" }}
|
||||
/>
|
||||
</div>
|
||||
}>
|
||||
<div className="border-subtle border-t">
|
||||
{!fromOnboarding && (
|
||||
<>
|
||||
<p className="text-subtle px-5 pt-4 text-sm">{t("toggle_calendars_conflict")}</p>
|
||||
<ul className="space-y-4 px-5 py-4">
|
||||
{item.calendars.map((cal) => (
|
||||
<CalendarSwitch
|
||||
key={cal.externalId}
|
||||
externalId={cal.externalId}
|
||||
title={cal.name || "Nameless calendar"}
|
||||
name={cal.name || "Nameless calendar"}
|
||||
type={item.integration.type}
|
||||
isChecked={cal.isSelected}
|
||||
destination={cal.externalId === props.destinationCalendarId}
|
||||
credentialId={cal.credentialId}
|
||||
/>
|
||||
))}
|
||||
</ul>
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
}
|
||||
/>
|
||||
)}
|
||||
</Fragment>
|
||||
))}
|
||||
</List>
|
||||
</AppListCard>
|
||||
) : (
|
||||
<Alert
|
||||
severity="warning"
|
||||
title={t("something_went_wrong")}
|
||||
message={
|
||||
<span>
|
||||
<Link href={`/apps/${item.integration.slug}`}>{item.integration.name}</Link>:{" "}
|
||||
{t("calendar_error")}
|
||||
</span>
|
||||
}
|
||||
iconClassName="h-10 w-10 ml-2 mr-1 mt-0.5"
|
||||
actions={
|
||||
<div className="flex w-32 justify-end md:pr-1">
|
||||
<DisconnectIntegration
|
||||
credentialId={item.credentialId}
|
||||
trashIcon
|
||||
onSuccess={props.onChanged}
|
||||
buttonProps={{ className: "border border-default" }}
|
||||
/>
|
||||
</div>
|
||||
}
|
||||
/>
|
||||
)}
|
||||
</Fragment>
|
||||
))}
|
||||
</List>
|
||||
</div>
|
||||
);
|
||||
}}
|
||||
/>
|
||||
|
@ -187,42 +210,28 @@ export function CalendarListContainer(props: { heading?: boolean; fromOnboarding
|
|||
{!!data.connectedCalendars.length || !!installedCalendars.data?.items.length ? (
|
||||
<>
|
||||
{heading && (
|
||||
<div className="border-default flex flex-col gap-6 rounded-md border p-7">
|
||||
<ShellSubHeading
|
||||
title={t("calendar")}
|
||||
subtitle={t("installed_app_calendar_description")}
|
||||
className="mb-0 flex flex-wrap items-center gap-4 sm:flex-nowrap md:mb-3 md:gap-0"
|
||||
actions={
|
||||
<div className="flex flex-col xl:flex-row xl:space-x-5">
|
||||
{!!data.connectedCalendars.length && (
|
||||
<div className="flex items-center">
|
||||
<AdditionalCalendarSelector isLoading={mutation.isLoading} />
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
}
|
||||
/>
|
||||
<div className="bg-muted border-subtle flex justify-between rounded-md border p-4">
|
||||
<div className="flex w-full flex-col items-start gap-4 md:flex-row md:items-center">
|
||||
<div className="bg-default border-subtle relative rounded-md border p-1.5">
|
||||
<Calendar className="text-default h-8 w-8" strokeWidth="1" />
|
||||
<Plus
|
||||
className="text-emphasis absolute left-4 top-1/2 ml-0.5 mt-[1px] h-2 w-2"
|
||||
strokeWidth="4"
|
||||
/>
|
||||
</div>
|
||||
<div className="md:w-6/12">
|
||||
<h1 className="text-emphasis text-sm font-semibold">{t("create_events_on")}</h1>
|
||||
<p className="text-default text-sm font-normal">{t("set_calendar")}</p>
|
||||
</div>
|
||||
<div className="justify-end md:w-6/12">
|
||||
<DestinationCalendarSelector
|
||||
onChange={mutation.mutate}
|
||||
hidePlaceholder
|
||||
isLoading={mutation.isLoading}
|
||||
value={data.destinationCalendar?.externalId}
|
||||
hideAdvancedText
|
||||
/>
|
||||
<>
|
||||
<div className="border-subtle mb-6 mt-8 rounded-lg border">
|
||||
<div className="p-6">
|
||||
<h2 className="text-emphasis mb-1 text-base font-bold leading-5 tracking-wide">
|
||||
{t("add_to_calendar")}
|
||||
</h2>
|
||||
|
||||
<p className="text-subtle text-sm leading-tight">
|
||||
{t("add_to_calendar_description")}
|
||||
</p>
|
||||
</div>
|
||||
<div className="border-t">
|
||||
<div className="border-subtle flex w-full flex-col space-y-3 border-y-0 p-6">
|
||||
<div>
|
||||
<Label className="text-default mb-0 font-medium">{t("add_events_to")}</Label>
|
||||
<DestinationCalendarSelector
|
||||
hidePlaceholder
|
||||
value={data.destinationCalendar?.externalId}
|
||||
onChange={mutation.mutate}
|
||||
isLoading={mutation.isLoading}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -230,8 +239,9 @@ export function CalendarListContainer(props: { heading?: boolean; fromOnboarding
|
|||
onChanged={onChanged}
|
||||
fromOnboarding={fromOnboarding}
|
||||
destinationCalendarId={data.destinationCalendar?.externalId}
|
||||
isLoading={mutation.isLoading}
|
||||
/>
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
</>
|
||||
) : fromOnboarding ? (
|
||||
|
|
|
@ -262,15 +262,21 @@ function BookingListItem(booking: BookingItemProps) {
|
|||
|
||||
const title = booking.title;
|
||||
|
||||
const showRecordingsButtons = !!(booking.isRecorded && isPast && isConfirmed);
|
||||
const showViewRecordingsButton = !!(booking.isRecorded && isPast && isConfirmed);
|
||||
const showCheckRecordingButton =
|
||||
isPast &&
|
||||
isConfirmed &&
|
||||
!booking.isRecorded &&
|
||||
(!booking.location || booking.location === "integrations:daily" || booking?.location?.trim() === "");
|
||||
|
||||
const showRecordingActions: ActionType[] = [
|
||||
{
|
||||
id: "view_recordings",
|
||||
label: t("view_recordings"),
|
||||
label: showCheckRecordingButton ? t("check_for_recordings") : t("view_recordings"),
|
||||
onClick: () => {
|
||||
setViewRecordingsDialogIsOpen(true);
|
||||
},
|
||||
color: showCheckRecordingButton ? "secondary" : "primary",
|
||||
disabled: mutation.isLoading,
|
||||
},
|
||||
];
|
||||
|
@ -298,7 +304,7 @@ function BookingListItem(booking: BookingItemProps) {
|
|||
paymentCurrency={booking.payment[0].currency}
|
||||
/>
|
||||
)}
|
||||
{showRecordingsButtons && (
|
||||
{(showViewRecordingsButton || showCheckRecordingButton) && (
|
||||
<ViewRecordingsDialog
|
||||
booking={booking}
|
||||
isOpenDialog={viewRecordingsDialogIsOpen}
|
||||
|
@ -478,7 +484,9 @@ function BookingListItem(booking: BookingItemProps) {
|
|||
</>
|
||||
) : null}
|
||||
{isPast && isPending && !isConfirmed ? <TableActions actions={bookedActions} /> : null}
|
||||
{showRecordingsButtons && <TableActions actions={showRecordingActions} />}
|
||||
{(showViewRecordingsButton || showCheckRecordingButton) && (
|
||||
<TableActions actions={showRecordingActions} />
|
||||
)}
|
||||
{isCancelled && booking.rescheduled && (
|
||||
<div className="hidden h-full items-center md:flex">
|
||||
<RequestSentMessage />
|
||||
|
|
|
@ -130,7 +130,6 @@
|
|||
"tailwindcss-radix": "^2.6.0",
|
||||
"turndown": "^7.1.1",
|
||||
"uuid": "^8.3.2",
|
||||
"web3": "^1.7.5",
|
||||
"zod": "^3.22.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
|
|
|
@ -54,8 +54,8 @@ const IntegrationsContainer = ({
|
|||
automation: Share2,
|
||||
analytics: BarChart,
|
||||
payment: CreditCard,
|
||||
web3: BarChart, // deprecated
|
||||
other: Grid,
|
||||
web3: CreditCard, // deprecated
|
||||
video: Video, // deprecated
|
||||
messaging: Mail,
|
||||
crm: Contact,
|
||||
|
|
|
@ -1,37 +1,12 @@
|
|||
import { Trans } from "next-i18next";
|
||||
import Link from "next/link";
|
||||
import { useRouter } from "next/navigation";
|
||||
import { Fragment, useState, useEffect } from "react";
|
||||
import { Fragment } from "react";
|
||||
|
||||
import DisconnectIntegration from "@calcom/features/apps/components/DisconnectIntegration";
|
||||
import { CalendarSwitch } from "@calcom/features/calendars/CalendarSwitch";
|
||||
import DestinationCalendarSelector from "@calcom/features/calendars/DestinationCalendarSelector";
|
||||
import SectionBottomActions from "@calcom/features/settings/SectionBottomActions";
|
||||
import { getLayout } from "@calcom/features/settings/layouts/SettingsLayout";
|
||||
import { classNames } from "@calcom/lib";
|
||||
import { useLocale } from "@calcom/lib/hooks/useLocale";
|
||||
import { trpc } from "@calcom/trpc/react";
|
||||
import {
|
||||
Alert,
|
||||
Badge,
|
||||
Button,
|
||||
EmptyScreen,
|
||||
List,
|
||||
ListItem,
|
||||
ListItemText,
|
||||
ListItemTitle,
|
||||
Meta,
|
||||
SkeletonButton,
|
||||
SkeletonContainer,
|
||||
SkeletonText,
|
||||
showToast,
|
||||
Label,
|
||||
} from "@calcom/ui";
|
||||
import { Plus, Calendar } from "@calcom/ui/components/icon";
|
||||
|
||||
import { QueryCell } from "@lib/QueryCell";
|
||||
import { Button, Meta, SkeletonButton, SkeletonContainer, SkeletonText } from "@calcom/ui";
|
||||
import { Plus } from "@calcom/ui/components/icon";
|
||||
|
||||
import PageWrapper from "@components/PageWrapper";
|
||||
import { CalendarListContainer } from "@components/apps/CalendarListContainer";
|
||||
|
||||
const SkeletonLoader = () => {
|
||||
return (
|
||||
|
@ -62,37 +37,6 @@ const AddCalendarButton = () => {
|
|||
|
||||
const CalendarsView = () => {
|
||||
const { t } = useLocale();
|
||||
const router = useRouter();
|
||||
|
||||
const utils = trpc.useContext();
|
||||
|
||||
const query = trpc.viewer.connectedCalendars.useQuery();
|
||||
|
||||
const [selectedDestinationCalendarOption, setSelectedDestinationCalendar] = useState<{
|
||||
integration: string;
|
||||
externalId: string;
|
||||
} | null>(null);
|
||||
|
||||
useEffect(() => {
|
||||
if (query?.data?.destinationCalendar) {
|
||||
setSelectedDestinationCalendar({
|
||||
integration: query.data.destinationCalendar.integration,
|
||||
externalId: query.data.destinationCalendar.externalId,
|
||||
});
|
||||
}
|
||||
}, [query?.isLoading, query?.data?.destinationCalendar]);
|
||||
|
||||
const mutation = trpc.viewer.setDestinationCalendar.useMutation({
|
||||
async onSettled() {
|
||||
await utils.viewer.connectedCalendars.invalidate();
|
||||
},
|
||||
onSuccess: async () => {
|
||||
showToast(t("calendar_updated_successfully"), "success");
|
||||
},
|
||||
onError: () => {
|
||||
showToast(t("unexpected_error_try_again"), "error");
|
||||
},
|
||||
});
|
||||
|
||||
return (
|
||||
<>
|
||||
|
@ -102,167 +46,9 @@ const CalendarsView = () => {
|
|||
CTA={<AddCalendarButton />}
|
||||
borderInShellHeader={false}
|
||||
/>
|
||||
<QueryCell
|
||||
query={query}
|
||||
customLoader={<SkeletonLoader />}
|
||||
success={({ data }) => {
|
||||
const isDestinationUpdateBtnDisabled =
|
||||
selectedDestinationCalendarOption?.externalId === query?.data?.destinationCalendar?.externalId;
|
||||
return data.connectedCalendars.length ? (
|
||||
<div>
|
||||
<div className="border-subtle mt-8 rounded-t-lg border px-4 py-6 sm:px-6">
|
||||
<h2 className="text-emphasis mb-1 text-base font-bold leading-5 tracking-wide">
|
||||
{t("add_to_calendar")}
|
||||
</h2>
|
||||
<p className="text-subtle text-sm leading-tight">{t("add_to_calendar_description")}</p>
|
||||
</div>
|
||||
<div className="border-subtle flex w-full flex-col space-y-3 border border-x border-y-0 px-4 py-6 sm:px-6">
|
||||
<div>
|
||||
<Label className="text-default mb-0 font-medium">{t("add_events_to")}</Label>
|
||||
<DestinationCalendarSelector
|
||||
hidePlaceholder
|
||||
value={selectedDestinationCalendarOption?.externalId}
|
||||
onChange={(option) => {
|
||||
setSelectedDestinationCalendar(option);
|
||||
}}
|
||||
isLoading={mutation.isLoading}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<SectionBottomActions align="end">
|
||||
<Button
|
||||
loading={mutation.isLoading}
|
||||
disabled={isDestinationUpdateBtnDisabled}
|
||||
color="primary"
|
||||
onClick={() => {
|
||||
if (selectedDestinationCalendarOption) mutation.mutate(selectedDestinationCalendarOption);
|
||||
}}>
|
||||
{t("update")}
|
||||
</Button>
|
||||
</SectionBottomActions>
|
||||
|
||||
<div className="border-subtle mt-8 rounded-t-lg border px-4 py-6 sm:px-6">
|
||||
<h4 className="text-emphasis text-base font-semibold leading-5">
|
||||
{t("check_for_conflicts")}
|
||||
</h4>
|
||||
<p className="text-default text-sm leading-tight">{t("select_calendars")}</p>
|
||||
</div>
|
||||
|
||||
<List
|
||||
className="border-subtle flex flex-col gap-6 rounded-b-lg border border-t-0 p-6"
|
||||
noBorderTreatment>
|
||||
{data.connectedCalendars.map((item) => (
|
||||
<Fragment key={item.credentialId}>
|
||||
{item.error && item.error.message && (
|
||||
<Alert
|
||||
severity="warning"
|
||||
key={item.credentialId}
|
||||
title={t("calendar_connection_fail")}
|
||||
message={item.error.message}
|
||||
className="mb-4 mt-4"
|
||||
actions={
|
||||
<>
|
||||
{/* @TODO: add a reconnect button, that calls add api and delete old credential */}
|
||||
<DisconnectIntegration
|
||||
credentialId={item.credentialId}
|
||||
trashIcon
|
||||
onSuccess={() => query.refetch()}
|
||||
buttonProps={{
|
||||
className: "border border-default py-[2px]",
|
||||
color: "secondary",
|
||||
}}
|
||||
/>
|
||||
</>
|
||||
}
|
||||
/>
|
||||
)}
|
||||
{item?.error === undefined && item.calendars && (
|
||||
<ListItem className="flex-col rounded-lg">
|
||||
<div className="flex w-full flex-1 items-center space-x-3 p-4 rtl:space-x-reverse">
|
||||
{
|
||||
// eslint-disable-next-line @next/next/no-img-element
|
||||
item.integration.logo && (
|
||||
<img
|
||||
className={classNames(
|
||||
"h-10 w-10",
|
||||
item.integration.logo.includes("-dark") && "dark:invert"
|
||||
)}
|
||||
src={item.integration.logo}
|
||||
alt={item.integration.title}
|
||||
/>
|
||||
)
|
||||
}
|
||||
<div className="flex-grow truncate pl-2">
|
||||
<ListItemTitle component="h3" className="mb-1 space-x-2 rtl:space-x-reverse">
|
||||
<Link href={`/apps/${item.integration.slug}`}>
|
||||
{item.integration.name || item.integration.title}
|
||||
</Link>
|
||||
{data?.destinationCalendar?.credentialId === item.credentialId && (
|
||||
<Badge variant="green">Default</Badge>
|
||||
)}
|
||||
</ListItemTitle>
|
||||
<ListItemText component="p">{item.integration.description}</ListItemText>
|
||||
</div>
|
||||
<div>
|
||||
<DisconnectIntegration
|
||||
trashIcon
|
||||
credentialId={item.credentialId}
|
||||
buttonProps={{ className: "border border-default" }}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div className="border-subtle w-full border-t">
|
||||
<p className="text-subtle px-2 pt-4 text-sm">{t("toggle_calendars_conflict")}</p>
|
||||
<ul className="space-y-4 p-4">
|
||||
{item.calendars.map((cal) => (
|
||||
<CalendarSwitch
|
||||
key={cal.externalId}
|
||||
credentialId={cal.credentialId}
|
||||
externalId={cal.externalId}
|
||||
title={cal.name || "Nameless calendar"}
|
||||
name={cal.name || "Nameless calendar"}
|
||||
type={item.integration.type}
|
||||
isChecked={
|
||||
cal.isSelected || cal.externalId === data?.destinationCalendar?.externalId
|
||||
}
|
||||
/>
|
||||
))}
|
||||
</ul>
|
||||
</div>
|
||||
</ListItem>
|
||||
)}
|
||||
</Fragment>
|
||||
))}
|
||||
</List>
|
||||
</div>
|
||||
) : (
|
||||
<EmptyScreen
|
||||
Icon={Calendar}
|
||||
headline={t("no_calendar_installed")}
|
||||
description={t("no_calendar_installed_description")}
|
||||
buttonText={t("add_a_calendar")}
|
||||
buttonOnClick={() => router.push("/apps/categories/calendar")}
|
||||
className="mt-6"
|
||||
/>
|
||||
);
|
||||
}}
|
||||
error={() => {
|
||||
return (
|
||||
<Alert
|
||||
message={
|
||||
<Trans i18nKey="fetching_calendars_error">
|
||||
An error ocurred while fetching your Calendars.
|
||||
<a className="cursor-pointer underline" onClick={() => query.refetch()}>
|
||||
try again
|
||||
</a>
|
||||
.
|
||||
</Trans>
|
||||
}
|
||||
severity="error"
|
||||
/>
|
||||
);
|
||||
}}
|
||||
/>
|
||||
<div className="mt-8">
|
||||
<CalendarListContainer />
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
|
|
@ -801,7 +801,7 @@
|
|||
"cal_provide_tandem_meeting_url": "سيوفر {{appName}} رابطًا للاجتماع عبر Tandem.",
|
||||
"cal_provide_video_meeting_url": "سيوفر {{appName}} رابطًا للاجتماع عبر الفيديو على Daily.",
|
||||
"cal_provide_jitsi_meeting_url": "سنوفر لك رابطًا للاجتماع عبر Jitsi Meet.",
|
||||
"cal_provide_huddle01_meeting_url": "سيوفر {{appName}} رابطًا للاجتماع عبر الفيديو على Huddle01 web3.",
|
||||
"cal_provide_huddle01_meeting_url": "سيوفر {{appName}} رابطًا للاجتماع عبر الفيديو على Huddle01.",
|
||||
"cal_provide_teams_meeting_url": "سيوفر {{appName}} عنوان URL لاجتماعات MS Teams. ملاحظة: يجب أن يكون لديك حساب عمل أو حساب مدرسة",
|
||||
"require_payment": "يلزم الدفع",
|
||||
"you_need_to_add_a_name": "تحتاج إلى إضافة اسم",
|
||||
|
@ -904,7 +904,6 @@
|
|||
"no_category_apps_description_analytics": "إضافة تطبيق تحليلات لصفحات الحجز الخاصة بك",
|
||||
"no_category_apps_description_automation": "إضافة تطبيق أتمتة لاستخدامه",
|
||||
"no_category_apps_description_other": "أضف أي نوع آخر من التطبيقات للقيام بأي شيء",
|
||||
"no_category_apps_description_web3": "إضافة تطبيق web3 لصفحات الحجز لديك",
|
||||
"no_category_apps_description_messaging": "إضافة تطبيق مراسلة لإعداد الإشعارات والتذكيرات المخصصة",
|
||||
"no_category_apps_description_crm": "إضافة تطبيق CRM لتتبع من قابلته",
|
||||
"installed_app_calendar_description": "قم بتعيين التقويمات للتحقق من وجود تعارضات لمنع الحجوزات المزدوجة.",
|
||||
|
@ -913,7 +912,6 @@
|
|||
"installed_app_other_description": "جميع تطبيقاتك المثبتة من الفئات الأخرى.",
|
||||
"installed_app_conferencing_description": "تكوين تطبيقات المؤتمرات المراد استخدامها",
|
||||
"installed_app_automation_description": "تهيئة تطبيقات الأتمتة التي سيتم استخدامها",
|
||||
"installed_app_web3_description": "تهيئة تطبيقات web3 التي يمكن استخدامها لصفحات الحجز لديك",
|
||||
"installed_app_messaging_description": "تكوين تطبيقات المراسلة المراد استخدامها لإعداد الإشعارات والتذكيرات المخصصة",
|
||||
"installed_app_crm_description": "تهيئة تطبيقات CRM التي يمكن استخدامها لتتبع من قابلته",
|
||||
"analytics": "التحليلات",
|
||||
|
@ -1304,7 +1302,6 @@
|
|||
"profile_picture": "صورة الملف الشخصي",
|
||||
"upload": "تحميل",
|
||||
"add_profile_photo": "إضافة صورة الملف الشخصي",
|
||||
"web3": "Web3",
|
||||
"token_address": "عنوان الرمز المميز",
|
||||
"blockchain": "سلسلة الكتل",
|
||||
"old_password": "كلمة مرور قديمة",
|
||||
|
@ -1346,7 +1343,6 @@
|
|||
"connect_automation_apps": "توصيل تطبيقات الأتمتة",
|
||||
"connect_analytics_apps": "توصيل تطبيقات التحليلات",
|
||||
"connect_other_apps": "ربط تطبيقات أخرى",
|
||||
"connect_web3_apps": "ربط تطبيقات web3",
|
||||
"connect_messaging_apps": "ربط تطبيقات المراسلة",
|
||||
"connect_crm_apps": "ربط تطبيقات CRM",
|
||||
"current_step_of_total": "الخطوة {{currentStep}} من {{maxSteps}}",
|
||||
|
|
|
@ -801,7 +801,7 @@
|
|||
"cal_provide_tandem_meeting_url": "{{appName}} poskytne URL Tandem meetingu.",
|
||||
"cal_provide_video_meeting_url": "{{appName}} poskytne URL Daily video meetingu.",
|
||||
"cal_provide_jitsi_meeting_url": "{{appName}} poskytne URL Jitsi Meet video meetingu.",
|
||||
"cal_provide_huddle01_meeting_url": "{{appName}} poskytne URL Huddle01 web3 video meetingu.",
|
||||
"cal_provide_huddle01_meeting_url": "{{appName}} poskytne URL Huddle01 video meetingu.",
|
||||
"cal_provide_teams_meeting_url": "{{appName}} poskytne URL schůzky aplikace MS Teams. POZNÁMKA: MUSÍ SE JEDNAT O PRACOVNÍ NEBO ŠKOLNÍ ÚČET",
|
||||
"require_payment": "Vyžadovat platbu",
|
||||
"you_need_to_add_a_name": "Musíte přidat název",
|
||||
|
@ -904,7 +904,6 @@
|
|||
"no_category_apps_description_analytics": "Přidejte analytickou aplikaci pro vaše rezervační stránky",
|
||||
"no_category_apps_description_automation": "Přidejte aplikaci pro automatizaci",
|
||||
"no_category_apps_description_other": "Přidejte jakýkoli jiný typ aplikace pro nejrůznější činnosti",
|
||||
"no_category_apps_description_web3": "Přidejte aplikaci web3 pro vaše rezervační stránky",
|
||||
"no_category_apps_description_messaging": "Přidejte aplikaci pro zasílání zpráv a nastavte vlastní oznámení a připomenutí",
|
||||
"no_category_apps_description_crm": "Přidejte aplikaci CRM, ať jste v obraze, s kým jste se setkali",
|
||||
"installed_app_calendar_description": "Nastavte si kalendáře, ať můžete kontrolovat konflikty a zabránit tak dvojím rezervacím.",
|
||||
|
@ -913,7 +912,6 @@
|
|||
"installed_app_other_description": "Všechny vaše nainstalované aplikace z ostatních kategorií.",
|
||||
"installed_app_conferencing_description": "Nakonfigurujte konferenční aplikace, které chcete používat",
|
||||
"installed_app_automation_description": "Konfigurovat aplikace pro automatizaci",
|
||||
"installed_app_web3_description": "Nakonfigurujte aplikace web3, které se mají použít pro vaše rezervační stránky",
|
||||
"installed_app_messaging_description": "Nakonfigurujte aplikace pro zasílání zpráv a nastavte vlastní oznámení a připomenutí",
|
||||
"installed_app_crm_description": "Nakonfigurujte aplikace CRM, které se mají používat ke sledování toho, s kým jste se setkali",
|
||||
"analytics": "Analytické nástroje",
|
||||
|
@ -1304,7 +1302,6 @@
|
|||
"profile_picture": "Profilová fotka",
|
||||
"upload": "Nahrát",
|
||||
"add_profile_photo": "Přidat profilovou fotku",
|
||||
"web3": "Web3",
|
||||
"token_address": "Adresa tokenu",
|
||||
"blockchain": "Blockchain",
|
||||
"old_password": "Staré heslo",
|
||||
|
@ -1346,7 +1343,6 @@
|
|||
"connect_automation_apps": "Připojit aplikace pro automatizaci",
|
||||
"connect_analytics_apps": "Připojit analytické aplikace",
|
||||
"connect_other_apps": "Propojit další aplikace",
|
||||
"connect_web3_apps": "Připojení aplikací web3",
|
||||
"connect_messaging_apps": "Připojení aplikací pro zasílání zpráv",
|
||||
"connect_crm_apps": "Připojení aplikací CRM",
|
||||
"current_step_of_total": "Krok {{currentStep}} / {{maxSteps}}",
|
||||
|
|
|
@ -681,7 +681,7 @@
|
|||
"cal_provide_tandem_meeting_url": "{{appName}} angiver en URL-adresse for Tandem-mødet.",
|
||||
"cal_provide_video_meeting_url": "{{appName}} angiver en URL-adresse for videomødet.",
|
||||
"cal_provide_jitsi_meeting_url": "Vi genererer en Jitsi Meet URL til dig.",
|
||||
"cal_provide_huddle01_meeting_url": "{{appName}} vil levere en Huddle01 web3 videomøde-URL.",
|
||||
"cal_provide_huddle01_meeting_url": "{{appName}} vil levere en Huddle01 videomøde-URL.",
|
||||
"cal_provide_teams_meeting_url": "{{appName}} vil levere en MS Teams møde URL. BEMÆRK: SKAL HA EN ARBEJDS- ELLER SKOLE KONTO",
|
||||
"require_payment": "Kræv Betaling",
|
||||
"commission_per_transaction": "provision pr. transaktion",
|
||||
|
@ -770,13 +770,11 @@
|
|||
"no_category_apps_description_analytics": "Tilføj en analyseapp til dine bookingsider",
|
||||
"no_category_apps_description_automation": "Tilføj en automatiseringsapp til brug",
|
||||
"no_category_apps_description_other": "Tilføj enhver anden type app for at gøre alle mulige ting",
|
||||
"no_category_apps_description_web3": "Tilføj en web3 app til dine bookingsider",
|
||||
"installed_app_calendar_description": "Indstil kalenderne til at tjekke for konflikter, for at forhindre dobbeltbookinger.",
|
||||
"installed_app_payment_description": "Indstil hvilke betalingsbehandlingstjenester der skal bruges, når du opkræver betaling fra dine kunder.",
|
||||
"installed_app_analytics_description": "Indstil hvilke analyseapps der skal bruges til dine bookingsider",
|
||||
"installed_app_other_description": "Alle dine installerede apps fra andre kategorier.",
|
||||
"installed_app_automation_description": "Indstil hvilke automatiseringsapps der skal bruges",
|
||||
"installed_app_web3_description": "Indstil hvilke web3 apps der skal bruges til dine bookingsider",
|
||||
"analytics": "Analyser",
|
||||
"empty_installed_apps_headline": "Ingen apps installeret",
|
||||
"empty_installed_apps_description": "Apps giver dig mulighed for at forbedre din arbejdsgang og forbedre dit planlægningsliv betydeligt.",
|
||||
|
@ -1132,7 +1130,6 @@
|
|||
"profile_picture": "Profilbillede",
|
||||
"upload": "Upload",
|
||||
"add_profile_photo": "Tilføj profilbillede",
|
||||
"web3": "Web3",
|
||||
"token_address": "Token Adresse",
|
||||
"blockchain": "Blockchain",
|
||||
"old_password": "Gammel adgangskode",
|
||||
|
@ -1171,7 +1168,6 @@
|
|||
"connect_automation_apps": "Tilslut automatiseringsapps",
|
||||
"connect_analytics_apps": "Tilslut analyseapps",
|
||||
"connect_other_apps": "Tilslut andre apps",
|
||||
"connect_web3_apps": "Tilslut web3 apps",
|
||||
"current_step_of_total": "Trin {{currentStep}} af {{maxSteps}}",
|
||||
"add_variable": "Tilføj variabel",
|
||||
"custom_phone_number": "Brugerdefineret telefonnummer",
|
||||
|
@ -1534,5 +1530,7 @@
|
|||
"this_will_be_the_placeholder": "Dette vil være pladsholderen",
|
||||
"verification_code": "Bekræftelseskode",
|
||||
"verify": "Bekræft",
|
||||
"confirm_your_details": "Bekræft dine oplysninger",
|
||||
"overlay_my_calendar": "Vis min kalender",
|
||||
"need_help": "Brug for hjælp?"
|
||||
}
|
||||
|
|
|
@ -801,7 +801,7 @@
|
|||
"cal_provide_tandem_meeting_url": "{{appName}} wird eine Tandem Meeting URL zur Verfügung stellen.",
|
||||
"cal_provide_video_meeting_url": "{{appName}} wird eine Video-Meeting URL zur Verfügung stellen.",
|
||||
"cal_provide_jitsi_meeting_url": "Cal stellt eine Jitsi Meet URL zur Verfügung.",
|
||||
"cal_provide_huddle01_meeting_url": "{{appName}} wird eine Huddle01 web3 Video-Meeting URL zur Verfügung stellen.",
|
||||
"cal_provide_huddle01_meeting_url": "{{appName}} wird eine Huddle01 Video-Meeting URL zur Verfügung stellen.",
|
||||
"cal_provide_teams_meeting_url": "{{appName}} wird eine MS Teams Meeting-URL zur Verfügung stellen. HINWEIS: SIE BRAUCHEN EIN BERUFS- ODER SCHULKONTO",
|
||||
"require_payment": "Zahlung erforderlich",
|
||||
"you_need_to_add_a_name": "Sie müssen einen Namen hinzufügen",
|
||||
|
@ -904,7 +904,6 @@
|
|||
"no_category_apps_description_analytics": "Fügen Sie eine Analyse-App für Ihre Buchungsseiten hinzu",
|
||||
"no_category_apps_description_automation": "Fügen Sie eine Automatisierungs-App hinzu, die verwendet werden soll",
|
||||
"no_category_apps_description_other": "Füge jede beliebige andere Art von App hinzu, um alle möglichen Dinge zu tun",
|
||||
"no_category_apps_description_web3": "Fügen Sie eine web3-App für Ihre Buchungsseiten hinzu",
|
||||
"no_category_apps_description_messaging": "Fügen Sie eine Nachrichten-App hinzu, um benutzerdefinierte Benachrichtigungen und Erinnerungen einzurichten",
|
||||
"no_category_apps_description_crm": "Fügen Sie eine CRM-App hinzu, um einen Überblick über die Personen zu behalten, mit denen Sie sich getroffen haben",
|
||||
"installed_app_calendar_description": "Legen Sie den/die Kalender in denen nach Konflikten gesucht werden sollen fest, um Doppelbuchungen zu vermeiden.",
|
||||
|
@ -913,7 +912,6 @@
|
|||
"installed_app_other_description": "Alle von Ihnen installierten Apps aus anderen Kategorien.",
|
||||
"installed_app_conferencing_description": "Konfigurieren Sie, welche Konferenz-Apps verwendet werden sollen",
|
||||
"installed_app_automation_description": "Konfigurieren Sie, welche Automatisierungs-Apps verwendet werden sollen",
|
||||
"installed_app_web3_description": "Konfigurieren Sie, welche web3-Apps für Ihre Buchungsseiten verwendet werden sollen",
|
||||
"installed_app_messaging_description": "Konfigurieren Sie zur Einrichtung benutzerdefinierter Benachrichtigungen und Erinnerungen, welche Nachrichten-Apps verwendet werden sollen",
|
||||
"installed_app_crm_description": "Konfigurieren Sie, welche CRM-Apps verwendet werden sollen, um einen Überblick über die Personen zu behalten, mit denen Sie sich getroffen haben",
|
||||
"analytics": "Analyse",
|
||||
|
@ -1304,7 +1302,6 @@
|
|||
"profile_picture": "Profilbild",
|
||||
"upload": "Upload",
|
||||
"add_profile_photo": "Profilbild hinzufügen",
|
||||
"web3": "Web3",
|
||||
"token_address": "Adresse des Token",
|
||||
"blockchain": "Blockchain",
|
||||
"old_password": "Altes Passwort",
|
||||
|
@ -1346,7 +1343,6 @@
|
|||
"connect_automation_apps": "Automatisierungs-Apps verbinden",
|
||||
"connect_analytics_apps": "Analyse-Apps verbinden",
|
||||
"connect_other_apps": "Andere Apps verbinden",
|
||||
"connect_web3_apps": "web3-Apps verbinden",
|
||||
"connect_messaging_apps": "Nachrichten-Apps verbinden",
|
||||
"connect_crm_apps": "CRM-Apps verbinden",
|
||||
"current_step_of_total": "Schritt {{currentStep}} von {{maxSteps}}",
|
||||
|
|
|
@ -818,7 +818,7 @@
|
|||
"cal_provide_tandem_meeting_url": "{{appName}} will provide a Tandem meeting URL.",
|
||||
"cal_provide_video_meeting_url": "{{appName}} will provide a video meeting URL.",
|
||||
"cal_provide_jitsi_meeting_url": "We will generate a Jitsi Meet URL for you.",
|
||||
"cal_provide_huddle01_meeting_url": "{{appName}} will provide a Huddle01 web3 video meeting URL.",
|
||||
"cal_provide_huddle01_meeting_url": "{{appName}} will provide a Huddle01 video meeting URL.",
|
||||
"cal_provide_teams_meeting_url": "{{appName}} will provide a MS Teams meeting URL. NOTE: MUST HAVE A WORK OR SCHOOL ACCOUNT",
|
||||
"require_payment": "Require Payment",
|
||||
"you_need_to_add_a_name": "You need to add a name",
|
||||
|
@ -922,7 +922,6 @@
|
|||
"no_category_apps_description_analytics": "Add an analytics app for your booking pages",
|
||||
"no_category_apps_description_automation": "Add an automation app to use",
|
||||
"no_category_apps_description_other": "Add any other type of app to do all sorts of things",
|
||||
"no_category_apps_description_web3": "Add a web3 app for your booking pages",
|
||||
"no_category_apps_description_messaging": "Add a messaging app to set up custom notifications & reminders",
|
||||
"no_category_apps_description_crm": "Add a CRM app to keep track of who you've met with",
|
||||
"installed_app_calendar_description": "Set the calendars to check for conflicts to prevent double bookings.",
|
||||
|
@ -931,7 +930,6 @@
|
|||
"installed_app_other_description": "All your installed apps from other categories.",
|
||||
"installed_app_conferencing_description": "Configure which conferencing apps to use",
|
||||
"installed_app_automation_description": "Configure which automation apps to use",
|
||||
"installed_app_web3_description": "Configure which web3 apps to use for your booking pages",
|
||||
"installed_app_messaging_description": "Configure which messaging apps to use for setting up custom notifications & reminders",
|
||||
"installed_app_crm_description": "Configure which CRM apps to use for keeping track of who you've met with",
|
||||
"analytics": "Analytics",
|
||||
|
@ -1324,7 +1322,6 @@
|
|||
"profile_picture": "Profile Picture",
|
||||
"upload": "Upload",
|
||||
"add_profile_photo": "Add profile photo",
|
||||
"web3": "Web3",
|
||||
"token_address": "Token Address",
|
||||
"blockchain": "Blockchain",
|
||||
"old_password": "Old password",
|
||||
|
@ -1366,7 +1363,6 @@
|
|||
"connect_automation_apps": "Connect automation apps",
|
||||
"connect_analytics_apps": "Connect analytics apps",
|
||||
"connect_other_apps": "Connect other apps",
|
||||
"connect_web3_apps": "Connect web3 apps",
|
||||
"connect_messaging_apps": "Connect messaging apps",
|
||||
"connect_crm_apps": "Connect CRM apps",
|
||||
"current_step_of_total": "Step {{currentStep}} of {{maxSteps}}",
|
||||
|
|
|
@ -904,7 +904,6 @@
|
|||
"no_category_apps_description_analytics": "Añada una aplicación de análisis para sus páginas de reserva",
|
||||
"no_category_apps_description_automation": "Añada una aplicación de automatización para utilizar",
|
||||
"no_category_apps_description_other": "Añade cualquier otro tipo de aplicación para hacer todo tipo de tareas",
|
||||
"no_category_apps_description_web3": "Agregue una aplicación web3 para sus páginas de reserva",
|
||||
"no_category_apps_description_messaging": "Agregue una aplicación de mensajería para configurar notificaciones y recordatorios personalizados",
|
||||
"no_category_apps_description_crm": "Agregue una aplicación CRM para realizar un seguimiento de con quiénes se ha reunido",
|
||||
"installed_app_calendar_description": "Configure el(los) calendario(s) para comprobar conflictos y evitar reservas duplicadas.",
|
||||
|
@ -913,7 +912,6 @@
|
|||
"installed_app_other_description": "Todas tus aplicaciones instaladas de otras categorías.",
|
||||
"installed_app_conferencing_description": "Configure qué aplicaciones de conferencia usará",
|
||||
"installed_app_automation_description": "Configure qué aplicaciones de automatización va a utilizar",
|
||||
"installed_app_web3_description": "Configure qué aplicaciones web3 usar para sus páginas de reserva",
|
||||
"installed_app_messaging_description": "Configure qué aplicaciones de mensajería usar para configurar notificaciones y recordatorios personalizados",
|
||||
"installed_app_crm_description": "Configure qué aplicaciones de CRM usar para realizar un seguimiento de las personas con las que se ha reunido",
|
||||
"analytics": "Análisis",
|
||||
|
@ -1304,7 +1302,6 @@
|
|||
"profile_picture": "Imagen de perfil",
|
||||
"upload": "Cargar",
|
||||
"add_profile_photo": "Agregar foto de perfil",
|
||||
"web3": "Web3",
|
||||
"token_address": "Dirección del token",
|
||||
"blockchain": "Blockchain",
|
||||
"old_password": "Contraseña anterior",
|
||||
|
@ -1346,7 +1343,6 @@
|
|||
"connect_automation_apps": "Conecte aplicaciones de automatización",
|
||||
"connect_analytics_apps": "Conecte aplicaciones de análisis",
|
||||
"connect_other_apps": "Conectar otras aplicaciones",
|
||||
"connect_web3_apps": "Conectar aplicaciones web3",
|
||||
"connect_messaging_apps": "Conectar aplicaciones de mensajería",
|
||||
"connect_crm_apps": "Conectar aplicaciones CRM",
|
||||
"current_step_of_total": "Paso {{currentStep}} de {{maxSteps}}",
|
||||
|
|
|
@ -679,7 +679,6 @@
|
|||
"profile_picture": "Profileko irudia",
|
||||
"upload": "Kargatu",
|
||||
"add_profile_photo": "Gehitu profileko argazkia",
|
||||
"web3": "Web3",
|
||||
"old_password": "Pasahitz zaharra",
|
||||
"secure_password": "Zure pasahitz berri super segurua",
|
||||
"error_updating_password": "Errorea pasahitza eguneratzean",
|
||||
|
|
|
@ -67,6 +67,7 @@
|
|||
"cannot_repackage_codebase": "Vous ne pouvez pas restructurer ou vendre la base de code",
|
||||
"acquire_license": "Obtenez une licence commerciale pour supprimer ces termes en envoyant un e-mail",
|
||||
"terms_summary": "Résumé des conditions",
|
||||
"signing_up_terms": "En vous inscrivant, vous acceptez nos <2>Conditions d'utilisation</2> et notre <3>Politique de confidentialité</3>.",
|
||||
"open_env": "Ouvrez le fichier .env et acceptez notre licence",
|
||||
"env_changed": "J'ai modifié mon fichier .env",
|
||||
"accept_license": "Accepter la licence",
|
||||
|
@ -229,6 +230,7 @@
|
|||
"reset_your_password": "Définissez votre nouveau mot de passe avec les instructions envoyées à votre adresse e-mail.",
|
||||
"email_change": "Reconnectez-vous avec votre nouvelle adresse e-mail et votre nouveau mot de passe.",
|
||||
"create_your_account": "Créez votre compte",
|
||||
"create_your_calcom_account": "Créez votre compte Cal.com",
|
||||
"sign_up": "S'inscrire",
|
||||
"youve_been_logged_out": "Vous avez été déconnecté",
|
||||
"hope_to_see_you_soon": "Nous espérons vous revoir bientôt !",
|
||||
|
@ -266,6 +268,9 @@
|
|||
"nearly_there_instructions": "Pour finir, une brève description de vous et une photo vous aideront vraiment à obtenir des réservations et à faire savoir aux gens avec qui ils prennent rendez-vous.",
|
||||
"set_availability_instructions": "Définissez des plages de temps pendant lesquelles vous êtes disponible de manière récurrente. Vous pourrez en créer d'autres ultérieurement et les assigner à différents calendriers.",
|
||||
"set_availability": "Définissez vos disponibilités",
|
||||
"set_availbility_description": "Définissez des horaires pour les périodes où vous souhaitez être réservé.",
|
||||
"share_a_link_or_embed": "Partagez un lien ou une intégration",
|
||||
"share_a_link_or_embed_description": "Partagez votre lien ou intégration {{appName}} sur votre site.",
|
||||
"availability_settings": "Paramètres de disponibilité",
|
||||
"continue_without_calendar": "Continuer sans calendrier",
|
||||
"continue_with": "Continuer avec {{appName}}",
|
||||
|
@ -800,7 +805,7 @@
|
|||
"cal_provide_tandem_meeting_url": "{{appName}} fournira un lien de rendez-vous Tandem.",
|
||||
"cal_provide_video_meeting_url": "{{appName}} fournira un lien de rendez-vous vidéo.",
|
||||
"cal_provide_jitsi_meeting_url": "Nous générerons un lien de réunion Jitsi Meet pour vous.",
|
||||
"cal_provide_huddle01_meeting_url": "{{appName}} fournira un lien de rendez-vous vidéo Huddle01 web3.",
|
||||
"cal_provide_huddle01_meeting_url": "{{appName}} fournira un lien de rendez-vous vidéo Huddle01.",
|
||||
"cal_provide_teams_meeting_url": "{{appName}} fournira un lien de rendez-vous MS Teams. NOTE : IL FAUT AVOIR UN COMPTE PROFESSIONNEL OU SCOLAIRE",
|
||||
"require_payment": "Exiger un paiement",
|
||||
"you_need_to_add_a_name": "Vous devez ajouter un nom",
|
||||
|
@ -904,7 +909,6 @@
|
|||
"no_category_apps_description_analytics": "Ajoutez une application d'analyse pour vos pages de réservation.",
|
||||
"no_category_apps_description_automation": "Ajoutez une application d'automatisation.",
|
||||
"no_category_apps_description_other": "Ajoutez n'importe quel autre type d'application pour faire toutes sortes de choses.",
|
||||
"no_category_apps_description_web3": "Ajoutez une application Web3 pour vos pages de réservation.",
|
||||
"no_category_apps_description_messaging": "Ajoutez une application de messagerie pour configurer des notifications et des rappels personnalisés.",
|
||||
"no_category_apps_description_crm": "Ajoutez une application de CRM pour garder une trace des personnes que vous avez rencontrées.",
|
||||
"installed_app_calendar_description": "Définissez les calendriers pour vérifier les conflits afin d'éviter les doubles réservations.",
|
||||
|
@ -913,7 +917,6 @@
|
|||
"installed_app_other_description": "Toutes vos applications installées à partir d'autres catégories.",
|
||||
"installed_app_conferencing_description": "Configurez les applications de conférence à utiliser.",
|
||||
"installed_app_automation_description": "Configurez les applications d'automatisation à utiliser.",
|
||||
"installed_app_web3_description": "Configurez les applications Web3 à utiliser pour vos pages de réservation.",
|
||||
"installed_app_messaging_description": "Configurez les applications de messagerie à utiliser pour configurer des notifications et des rappels personnalisés.",
|
||||
"installed_app_crm_description": "Configurez les applications de CRM à utiliser pour garder une trace des personnes que vous avez rencontrées.",
|
||||
"analytics": "Analytiques",
|
||||
|
@ -1036,6 +1039,7 @@
|
|||
"user_impersonation_heading": "Emprunt d'identité",
|
||||
"user_impersonation_description": "Autorisez notre équipe d'assistance à se connecter temporairement à votre place pour nous aider à résoudre les problèmes que vous pourriez nous signaler.",
|
||||
"team_impersonation_description": "Autorisez les propriétaires/administrateurs de votre équipe à se connecter temporairement à votre place.",
|
||||
"cal_signup_description": "Gratuit pour les particuliers. Plans Équipes pour les fonctionnalités collaboratives.",
|
||||
"make_team_private": "Rendre l'équipe privée",
|
||||
"make_team_private_description": "Les membres de votre équipe ne pourront pas voir les autres membres de l'équipe si cette option est activée.",
|
||||
"you_cannot_see_team_members": "Vous ne pouvez pas voir tous les membres d'une équipe privée.",
|
||||
|
@ -1303,7 +1307,6 @@
|
|||
"profile_picture": "Photo de profil",
|
||||
"upload": "Télécharger",
|
||||
"add_profile_photo": "Ajouter une photo de profil",
|
||||
"web3": "Web3",
|
||||
"token_address": "Adresse du token",
|
||||
"blockchain": "Blockchain",
|
||||
"old_password": "Ancien mot de passe",
|
||||
|
@ -1345,7 +1348,6 @@
|
|||
"connect_automation_apps": "Connecter des apps d'automatisation",
|
||||
"connect_analytics_apps": "Connecter des apps d'analytique",
|
||||
"connect_other_apps": "Connecter d'autres applications",
|
||||
"connect_web3_apps": "Connecter des apps Web3",
|
||||
"connect_messaging_apps": "Connecter des apps de messagerie",
|
||||
"connect_crm_apps": "Connecter des apps de CRM",
|
||||
"current_step_of_total": "Étape {{currentStep}} sur {{maxSteps}}",
|
||||
|
@ -1528,6 +1530,7 @@
|
|||
"your_org_disbanded_successfully": "Votre organisation a bien été dissoute",
|
||||
"error_creating_team": "Erreur lors de la création de l'équipe",
|
||||
"you": "Vous",
|
||||
"or_continue_with": "Ou continuez avec",
|
||||
"resend_email": "Renvoyer l’e-mail",
|
||||
"member_already_invited": "Le membre a déjà été invité",
|
||||
"already_in_use_error": "Nom d'utilisateur déjà utilisé",
|
||||
|
@ -1584,6 +1587,7 @@
|
|||
"enable_apps": "Activer les applications",
|
||||
"enable_apps_description": "Activer les applications que les utilisateurs peuvent intégrer à {{appName}}",
|
||||
"purchase_license": "Acheter une licence",
|
||||
"already_have_account": "J'ai déjà un compte",
|
||||
"already_have_key": "J'ai déjà une clé :",
|
||||
"already_have_key_suggestion": "Veuillez copier votre variable d'environnement CALCOM_LICENSE_KEY existante ici.",
|
||||
"app_is_enabled": "{{appName}} est activé",
|
||||
|
@ -2056,7 +2060,9 @@
|
|||
"include_calendar_event": "Inclure l'événement du calendrier",
|
||||
"recently_added": "Ajoutées récemment",
|
||||
"connect_all_calendars": "Connectez vos calendriers",
|
||||
"connect_all_calendars_description": "{{appName}} relève la disponibilité de tous vos calendriers existants.",
|
||||
"workflow_automation": "Automatisation de workflows",
|
||||
"workflow_automation_description": "Personnalisez votre expérience de planification avec les workflows",
|
||||
"scheduling_for_your_team": "Automatisation de workflows",
|
||||
"no_members_found": "Aucun membre trouvé",
|
||||
"event_setup_length_error": "Configuration de l'événement : la durée doit être d'au moins 1 minute.",
|
||||
|
|
|
@ -801,7 +801,7 @@
|
|||
"cal_provide_tandem_meeting_url": "{{appName}} יספק כתובת קישור לפגישת Tandem.",
|
||||
"cal_provide_video_meeting_url": "{{appName}} יספק כתובת קישור לפגישת וידאו.",
|
||||
"cal_provide_jitsi_meeting_url": "אנחנו ניצור עבורך כתובת URL לפגישת Jitsi Meet.",
|
||||
"cal_provide_huddle01_meeting_url": "{{appName}} יספק כתובת קישור לפגישת וידאו web3 ב- Huddle01.",
|
||||
"cal_provide_huddle01_meeting_url": "{{appName}} יספק כתובת קישור לפגישת וידאו ב- Huddle01.",
|
||||
"cal_provide_teams_meeting_url": "{{appName}} יספק כתובת קישור לפגישת MS Teams. הערה: חייב להיות חשבון של מקום עבודה או בית ספר",
|
||||
"require_payment": "דרישת תשלום",
|
||||
"you_need_to_add_a_name": "יש להוסיף שם",
|
||||
|
@ -904,7 +904,6 @@
|
|||
"no_category_apps_description_analytics": "להוסיף אפליקציה לניתוח נתונים עבור דפי ההזמנות שלך",
|
||||
"no_category_apps_description_automation": "להוסיף אפליקציית אוטומציה שברצונך להשתמש בה",
|
||||
"no_category_apps_description_other": "הוסף/הוסיפי אפליקציה מכל סוג אחר לביצוע פעולות שונות",
|
||||
"no_category_apps_description_web3": "הוסף אפליקצית web3 לעמודי תזמון הפגישות שלך",
|
||||
"no_category_apps_description_messaging": "הוסף/הוסיפי אפליקציית מסרים מידיים כדי להגדיר התראות ותזכורות בהתאמה אישית",
|
||||
"no_category_apps_description_crm": "הוסף/י אפליקציית CRM כדי לנהל מעקב אחר האנשים שנפגשת איתם",
|
||||
"installed_app_calendar_description": "הגדר/הגדירח את לוחות השנה כדי לבדוק אם יש התנגשויות על מנת למנוע כפל הזמנות.",
|
||||
|
@ -913,7 +912,6 @@
|
|||
"installed_app_other_description": "כל האפליקציות המותקנות שלך מקטגוריות אחרות.",
|
||||
"installed_app_conferencing_description": "הגדר/הגדירי את האפליקציות לשיחות ועידה שבהן ברצונך להשתמש",
|
||||
"installed_app_automation_description": "הגדרת אפליקציות האוטומציה שבהן ברצונך להשתמש",
|
||||
"installed_app_web3_description": "הגדר באיזה אפליקציות web3 להשתמש בעמודי תזמון הפגישות שלך",
|
||||
"installed_app_messaging_description": "הגדר/הגדירי את אפליקציות המסרים המידיים שבהן ברצונך להשתמש להגדרת עדכונים ותזכורות",
|
||||
"installed_app_crm_description": "הגדר/הגדירי את אפליקציות ה-CRM שבהן ברצונך להשתמש לניהול מעקב אחר האנשים שנפגשת איתם",
|
||||
"analytics": "ניתוח נתונים",
|
||||
|
@ -1304,7 +1302,6 @@
|
|||
"profile_picture": "תמונת פרופיל",
|
||||
"upload": "העלאה",
|
||||
"add_profile_photo": "הוספת תמונת פרופיל",
|
||||
"web3": "Web3",
|
||||
"token_address": "כתובת הטוקן",
|
||||
"blockchain": "בלוקצ'יין",
|
||||
"old_password": "סיסמה ישנה",
|
||||
|
@ -1346,7 +1343,6 @@
|
|||
"connect_automation_apps": "קישור אפליקציות אוטומציה",
|
||||
"connect_analytics_apps": "קישור אפליקציות ניתוח נתונים",
|
||||
"connect_other_apps": "חיבור אפליקציות אחרות",
|
||||
"connect_web3_apps": "חבר אפליקציות web3",
|
||||
"connect_messaging_apps": "קישור אפליקציות מסרים מידיים",
|
||||
"connect_crm_apps": "קישור אפליקציות CRM",
|
||||
"current_step_of_total": "שלב {{currentStep}} מתוך {{maxSteps}}",
|
||||
|
|
|
@ -801,7 +801,7 @@
|
|||
"cal_provide_tandem_meeting_url": "{{appName}} fornirà un URL di riunione Tandem.",
|
||||
"cal_provide_video_meeting_url": "{{appName}} fornirà un URL di riunione Daily video.",
|
||||
"cal_provide_jitsi_meeting_url": "{{appName}} fornirà un URL di riunione Jitsi Meet.",
|
||||
"cal_provide_huddle01_meeting_url": "{{appName}} fornirà un URL di riunione Huddle01 web3 video.",
|
||||
"cal_provide_huddle01_meeting_url": "{{appName}} fornirà un URL di riunione Huddle01 video.",
|
||||
"cal_provide_teams_meeting_url": "{{appName}} fornirà un URL per la riunione MS Teams. NOTA: È NECESSARIO POSSEDERE UN ACCOUNT LAVORATIVO O SCOLASTICO",
|
||||
"require_payment": "Richiedi Pagamento",
|
||||
"you_need_to_add_a_name": "Indica un nome",
|
||||
|
@ -904,7 +904,6 @@
|
|||
"no_category_apps_description_analytics": "Aggiungi un'app di analisi per le tue pagine di prenotazione",
|
||||
"no_category_apps_description_automation": "Aggiungi un'app di automazione da usare",
|
||||
"no_category_apps_description_other": "Aggiungi qualsiasi altra app per fare altre attività",
|
||||
"no_category_apps_description_web3": "Aggiungi un'app Web3 per le tue pagine di prenotazione",
|
||||
"no_category_apps_description_messaging": "Aggiungi un'app di messaggistica per impostare notifiche e promemoria personalizzati",
|
||||
"no_category_apps_description_crm": "Aggiungi un'app CRM per tenere traccia delle persone che hai incontrato",
|
||||
"installed_app_calendar_description": "Imposta uno o più calendari per controllare i conflitti ed evitare doppie prenotazioni.",
|
||||
|
@ -913,7 +912,6 @@
|
|||
"installed_app_other_description": "Tutte le app installate appartenenti ad altre categorie.",
|
||||
"installed_app_conferencing_description": "Scegli quali app di conferenza utilizzare",
|
||||
"installed_app_automation_description": "Imposta quali app di automazione usare",
|
||||
"installed_app_web3_description": "Imposta quali app Web3 usare per le tue pagine di prenotazione",
|
||||
"installed_app_messaging_description": "Scegli le app di messaggistica da usare per impostare notifiche e promemoria personalizzati",
|
||||
"installed_app_crm_description": "Scegli quali app CRM utilizzare per tenere traccia delle persone che hai incontrato",
|
||||
"analytics": "Analisi",
|
||||
|
@ -1304,7 +1302,6 @@
|
|||
"profile_picture": "Immagine del profilo",
|
||||
"upload": "Carica",
|
||||
"add_profile_photo": "Aggiungi foto del profilo",
|
||||
"web3": "Web3",
|
||||
"token_address": "Indirizzo token",
|
||||
"blockchain": "Blockchain",
|
||||
"old_password": "Vecchia password",
|
||||
|
@ -1346,7 +1343,6 @@
|
|||
"connect_automation_apps": "Connetti app di automazione",
|
||||
"connect_analytics_apps": "Connetti app di analisi",
|
||||
"connect_other_apps": "Connetti altre app",
|
||||
"connect_web3_apps": "Connetti app Web3",
|
||||
"connect_messaging_apps": "Connetti app di messaggistica",
|
||||
"connect_crm_apps": "Connetti app CRM",
|
||||
"current_step_of_total": "Passo {{currentStep}} di {{maxSteps}}",
|
||||
|
|
|
@ -801,7 +801,7 @@
|
|||
"cal_provide_tandem_meeting_url": "{{appName}} は Tandem ミーティングの URL を提供する。",
|
||||
"cal_provide_video_meeting_url": "{{appName}} はビデオミーティングの URL を提供する。",
|
||||
"cal_provide_jitsi_meeting_url": "Cal は Jitsi Meet の URL を提供する。",
|
||||
"cal_provide_huddle01_meeting_url": "{{appName}} は Huddle01 web3 ビデオミーティングの URL を提供する。",
|
||||
"cal_provide_huddle01_meeting_url": "{{appName}} は Huddle01 ビデオミーティングの URL を提供する。",
|
||||
"cal_provide_teams_meeting_url": "{{appName}} は、MS Teams のミーティングの URL を提供する。注: 職場や学校のアカウントが必要です。",
|
||||
"require_payment": "有料",
|
||||
"you_need_to_add_a_name": "名前を追加する必要があります",
|
||||
|
@ -904,7 +904,6 @@
|
|||
"no_category_apps_description_analytics": "予約ページに分析アプリを追加する",
|
||||
"no_category_apps_description_automation": "使用する自動化アプリを追加する",
|
||||
"no_category_apps_description_other": "その他のアプリを追加して、様々なことを実現しましょう",
|
||||
"no_category_apps_description_web3": "予約ページに Web3 アプリを追加",
|
||||
"no_category_apps_description_messaging": "カスタム通知とリマインダーを設定するには、メッセージングアプリを追加します",
|
||||
"no_category_apps_description_crm": "会った人を記録するには、CRM アプリを追加します",
|
||||
"installed_app_calendar_description": "ダブルブッキングを防ぐために、カレンダーの重複をチェックするように設定します。",
|
||||
|
@ -913,7 +912,6 @@
|
|||
"installed_app_other_description": "その他のカテゴリーからインストールしたすべてのアプリ。",
|
||||
"installed_app_conferencing_description": "どの会議アプリを使用するかを設定します",
|
||||
"installed_app_automation_description": "どの自動化アプリを使用するかを構成する",
|
||||
"installed_app_web3_description": "予約ページでどの Web3 アプリを使用するかを構成します",
|
||||
"installed_app_messaging_description": "カスタム通知とリマインダーの設定にどのメッセージングアプリを使用するかを設定します",
|
||||
"installed_app_crm_description": "会った人を記録するのにどの CRM アプリを使用するかを設定します",
|
||||
"analytics": "分析",
|
||||
|
@ -1304,7 +1302,6 @@
|
|||
"profile_picture": "プロフィール写真",
|
||||
"upload": "アップロード",
|
||||
"add_profile_photo": "プロフィール写真を追加",
|
||||
"web3": "Web3",
|
||||
"token_address": "トークンアドレス",
|
||||
"blockchain": "ブロックチェーン",
|
||||
"old_password": "古いパスワード",
|
||||
|
@ -1346,7 +1343,6 @@
|
|||
"connect_automation_apps": "自動化アプリを接続する",
|
||||
"connect_analytics_apps": "分析アプリを接続する",
|
||||
"connect_other_apps": "その他のアプリを接続",
|
||||
"connect_web3_apps": "Web3 アプリを接続",
|
||||
"connect_messaging_apps": "メッセージングアプリを接続する",
|
||||
"connect_crm_apps": "CRM アプリを接続する",
|
||||
"current_step_of_total": "ステップ {{currentStep}}/{{maxSteps}}",
|
||||
|
|
|
@ -904,7 +904,6 @@
|
|||
"no_category_apps_description_analytics": "예약 페이지에 대한 분석 앱 추가",
|
||||
"no_category_apps_description_automation": "사용할 자동화 앱 추가",
|
||||
"no_category_apps_description_other": "모든 종류의 작업을 수행하는 다른 유형의 앱을 추가합니다",
|
||||
"no_category_apps_description_web3": "예약 페이지에 web3 앱 추가",
|
||||
"no_category_apps_description_messaging": "사용자 정의 알림 및 미리 알림을 설정하려면 메시징 앱을 추가하세요",
|
||||
"no_category_apps_description_crm": "CRM 앱을 추가하여 만났던 사람을 추적하세요",
|
||||
"installed_app_calendar_description": "중복 예약을 방지하기 위해 충돌을 확인하도록 캘린더를 설정합니다.",
|
||||
|
@ -913,7 +912,6 @@
|
|||
"installed_app_other_description": "기타 카테고리에서 설치된 모든 앱.",
|
||||
"installed_app_conferencing_description": "사용할 회의 앱 구성",
|
||||
"installed_app_automation_description": "사용할 자동화 앱 구성",
|
||||
"installed_app_web3_description": "예약 페이지에 사용할 web3 앱 구성",
|
||||
"installed_app_messaging_description": "사용자 정의 알림 및 미리 알림 설정에 사용할 메시징 앱 구성",
|
||||
"installed_app_crm_description": "만났던 사람을 추적하는 데 사용할 CRM 앱 구성",
|
||||
"analytics": "분석",
|
||||
|
@ -1304,7 +1302,6 @@
|
|||
"profile_picture": "프로필 사진",
|
||||
"upload": "업로드",
|
||||
"add_profile_photo": "프로필 사진 추가",
|
||||
"web3": "Web3",
|
||||
"token_address": "토큰 주소",
|
||||
"blockchain": "블록체인",
|
||||
"old_password": "이전 비밀번호",
|
||||
|
@ -1346,7 +1343,6 @@
|
|||
"connect_automation_apps": "자동화 앱 연결",
|
||||
"connect_analytics_apps": "분석 앱 연결",
|
||||
"connect_other_apps": "기타 앱 연결",
|
||||
"connect_web3_apps": "web3 앱 연결",
|
||||
"connect_messaging_apps": "메시징 앱 연결",
|
||||
"connect_crm_apps": "CRM 앱 연결",
|
||||
"current_step_of_total": "{{maxSteps}} 중 {{currentStep}} 단계",
|
||||
|
|
|
@ -801,7 +801,7 @@
|
|||
"cal_provide_tandem_meeting_url": "{{appName}} zal een Tandem meeting-URL meegeven in de afspraak bevestiging.",
|
||||
"cal_provide_video_meeting_url": "{{appName}} zal een Daily meeting-URL meegeven in de afspraak bevestiging.",
|
||||
"cal_provide_jitsi_meeting_url": "{{appName}} zal een Jitsi Meet meeting-URL meegeven in de afspraak bevestiging.",
|
||||
"cal_provide_huddle01_meeting_url": "{{appName}} zal een Huddle01 web3 meeting-URL meegeven in de afspraak bevestiging.",
|
||||
"cal_provide_huddle01_meeting_url": "{{appName}} zal een Huddle01 meeting-URL meegeven in de afspraak bevestiging.",
|
||||
"cal_provide_teams_meeting_url": "{{appName}} geeft een vergaderings-URL voor MS Teams. OPMERKING: MOET EEN WERK- OF SCHOOLACCOUNT HEBBEN",
|
||||
"require_payment": "Betaling vereisen",
|
||||
"you_need_to_add_a_name": "U moet een naam toevoegen",
|
||||
|
@ -904,7 +904,6 @@
|
|||
"no_category_apps_description_analytics": "Voeg een analyse-app toe aan uw boekingspagina's",
|
||||
"no_category_apps_description_automation": "Voeg een automatiseringsapp toe om te gebruiken",
|
||||
"no_category_apps_description_other": "Voeg een ander type app toe om allerlei soorten dingen te doen",
|
||||
"no_category_apps_description_web3": "Voeg een web3-app toe aan uw boekingspagina's",
|
||||
"no_category_apps_description_messaging": "Voeg een berichtenapp toe om aangepaste meldingen en herinneringen in te stellen",
|
||||
"no_category_apps_description_crm": "Voeg een CRM-app toe om bij te houden met wie u heeft ontmoet",
|
||||
"installed_app_calendar_description": "Stel de agenda('s) in om te controleren op conflicten om dubbele boekingen te voorkomen.",
|
||||
|
@ -913,7 +912,6 @@
|
|||
"installed_app_other_description": "Alle geïnstalleerde apps uit andere categorieën.",
|
||||
"installed_app_conferencing_description": "Configureer welke conferentieapps moeten worden gebruikt",
|
||||
"installed_app_automation_description": "Configureer welke automatiseringsapps moeten worden gebruikt",
|
||||
"installed_app_web3_description": "Configureer welke web3-apps moeten worden gebruikt voor uw boekingspagina's",
|
||||
"installed_app_messaging_description": "Configureer welke berichtenapps moeten worden gebruikt voor het instellen van aangepaste meldingen en herinneringen",
|
||||
"installed_app_crm_description": "Configureer welke CRM-apps moeten worden gebruikt voor het bijhouden van wie u hebt ontmoet",
|
||||
"analytics": "Analyse",
|
||||
|
@ -1304,7 +1302,6 @@
|
|||
"profile_picture": "Profielafbeelding",
|
||||
"upload": "Uploaden",
|
||||
"add_profile_photo": "Profielfoto toevoegen",
|
||||
"web3": "Web3",
|
||||
"token_address": "Tokenadres",
|
||||
"blockchain": "Blockchain",
|
||||
"old_password": "Oude wachtwoord",
|
||||
|
@ -1346,7 +1343,6 @@
|
|||
"connect_automation_apps": "Koppel automatiseringsapps",
|
||||
"connect_analytics_apps": "Koppel analyse-apps",
|
||||
"connect_other_apps": "Andere apps koppelen",
|
||||
"connect_web3_apps": "Web3-apps koppelen",
|
||||
"connect_messaging_apps": "Berichtenapps koppelen",
|
||||
"connect_crm_apps": "CRM-apps koppelen",
|
||||
"current_step_of_total": "Stap {{currentStep}} van {{maxSteps}}",
|
||||
|
|
|
@ -670,7 +670,7 @@
|
|||
"cal_provide_tandem_meeting_url": "{{appName}} vil angi en URL for Tandem-møtet.",
|
||||
"cal_provide_video_meeting_url": "{{appName}} vil angi en videomøte-URL.",
|
||||
"cal_provide_jitsi_meeting_url": "Vi vil generere en Jitsi Meet URL for deg.",
|
||||
"cal_provide_huddle01_meeting_url": "{{appName}} vil angi en Huddle01 web3 videomøte-URL.",
|
||||
"cal_provide_huddle01_meeting_url": "{{appName}} vil angi en Huddle01 videomøte-URL.",
|
||||
"cal_provide_teams_meeting_url": "{{appName}} vil angi en URL for MS Teams møte. MERK: MÅ HA EN ARBEIDS- ELLER SKOLEKONTO",
|
||||
"require_payment": "Krev Betaling",
|
||||
"commission_per_transaction": "provisjon per transaksjon",
|
||||
|
@ -1112,7 +1112,6 @@
|
|||
"profile_picture": "Profilbilde",
|
||||
"upload": "Last opp",
|
||||
"add_profile_photo": "Legg til profilbilde",
|
||||
"web3": "Web3",
|
||||
"token_address": "Token Adresse",
|
||||
"blockchain": "Blockchain",
|
||||
"old_password": "Gammelt passord",
|
||||
|
|
|
@ -904,7 +904,6 @@
|
|||
"no_category_apps_description_analytics": "Dodaj aplikację analityczną do stron rezerwacji",
|
||||
"no_category_apps_description_automation": "Dodaj aplikację automatyzującą, która ma być używana",
|
||||
"no_category_apps_description_other": "Dodaj dowolny typ aplikacji, aby uzyskać dostęp do różnych innych funkcji",
|
||||
"no_category_apps_description_web3": "Dodaj aplikację web3 do stron rezerwacji",
|
||||
"no_category_apps_description_messaging": "Dodaj aplikację do wysyłania wiadomości, aby skonfigurować własne powiadomienia i przypomnienia",
|
||||
"no_category_apps_description_crm": "Dodaj aplikację CRM, aby monitorować to, z kim się spotykasz",
|
||||
"installed_app_calendar_description": "Ustaw kalendarze, aby wykrywać konflikty i unikać podwójnych rezerwacji.",
|
||||
|
@ -913,7 +912,6 @@
|
|||
"installed_app_other_description": "Wszystkie zainstalowane aplikacje z innych kategorii.",
|
||||
"installed_app_conferencing_description": "Skonfiguruj, z których aplikacji konferencyjnych chcesz korzystać",
|
||||
"installed_app_automation_description": "Skonfiguruj, które aplikacje automatyzujące mają być używane",
|
||||
"installed_app_web3_description": "Skonfiguruj aplikacje web3, które mają być używane na stronach rezerwacji",
|
||||
"installed_app_messaging_description": "Skonfiguruj aplikacje, które będą używane do ustawiania niestandardowych powiadomień i przypomnień",
|
||||
"installed_app_crm_description": "Skonfiguruj aplikacje CRM, za pomocą których chcesz monitorować to, z kim się spotykasz",
|
||||
"analytics": "Analityka",
|
||||
|
@ -1304,7 +1302,6 @@
|
|||
"profile_picture": "Zdjęcie profilowe",
|
||||
"upload": "Prześlij",
|
||||
"add_profile_photo": "Dodaj zdjęcie profilowe",
|
||||
"web3": "Web3",
|
||||
"token_address": "Adres tokena",
|
||||
"blockchain": "Blockchain",
|
||||
"old_password": "Stare hasło",
|
||||
|
@ -1346,7 +1343,6 @@
|
|||
"connect_automation_apps": "Połącz aplikacje automatyzujące",
|
||||
"connect_analytics_apps": "Połącz aplikacje analityczne",
|
||||
"connect_other_apps": "Połącz inne aplikacje",
|
||||
"connect_web3_apps": "Połącz aplikacje web3",
|
||||
"connect_messaging_apps": "Podłącz aplikacje do wysyłania wiadomości",
|
||||
"connect_crm_apps": "Podłącz aplikacje CRM",
|
||||
"current_step_of_total": "Krok {{currentStep}} z {{maxSteps}}",
|
||||
|
|
|
@ -904,7 +904,6 @@
|
|||
"no_category_apps_description_analytics": "Adicione um aplicativo de análise às suas páginas de reservas",
|
||||
"no_category_apps_description_automation": "Adicione um aplicativo de automação para usar",
|
||||
"no_category_apps_description_other": "Adicione qualquer outro tipo de aplicativo para fazer todos os tipos de coisas",
|
||||
"no_category_apps_description_web3": "Adicione um aplicativo web3 para suas páginas de reservas",
|
||||
"no_category_apps_description_messaging": "Adicione um aplicativo de mensagem para definir lembretes e notificações personalizados",
|
||||
"no_category_apps_description_crm": "Adicione um aplicativo CRM para acompanhar todos os integrantes das suas reuniões",
|
||||
"installed_app_calendar_description": "Defina o(s) calendário(s) para verificar se há conflitos e evitar reservas duplas.",
|
||||
|
@ -913,7 +912,6 @@
|
|||
"installed_app_other_description": "Todos os seus aplicativos instalados de outras categorias.",
|
||||
"installed_app_conferencing_description": "Configure quais aplicativos de conferência serão usados",
|
||||
"installed_app_automation_description": "Configure quais aplicativos de automação serão usados",
|
||||
"installed_app_web3_description": "Configure quais aplicativos web3 serão usados nas suas páginas de reservas",
|
||||
"installed_app_messaging_description": "Configure quais aplicativos de mensagem usar para definir lembretes e notificações",
|
||||
"installed_app_crm_description": "Configure quais aplicativos CRM usar para acompanhar os integrantes das suas reuniões",
|
||||
"analytics": "Análise",
|
||||
|
@ -1304,7 +1302,6 @@
|
|||
"profile_picture": "Imagem do perfil",
|
||||
"upload": "Enviar",
|
||||
"add_profile_photo": "Adicionar foto do perfil",
|
||||
"web3": "Web3",
|
||||
"token_address": "Endereço do Token",
|
||||
"blockchain": "Blockchain",
|
||||
"old_password": "Senha antiga",
|
||||
|
@ -1346,7 +1343,6 @@
|
|||
"connect_automation_apps": "Conecte aplicativos de automação",
|
||||
"connect_analytics_apps": "Conecte aplicativos de análise",
|
||||
"connect_other_apps": "Conectar outros aplicativos",
|
||||
"connect_web3_apps": "Conecte aplicativos web3",
|
||||
"connect_messaging_apps": "Conectar com aplicativos de mensagem",
|
||||
"connect_crm_apps": "Conecte aplicativos CRM",
|
||||
"current_step_of_total": "Passo {{currentStep}} de {{maxSteps}}",
|
||||
|
|
|
@ -904,7 +904,6 @@
|
|||
"no_category_apps_description_analytics": "Adicionar uma aplicação de análise às suas páginas de reservas",
|
||||
"no_category_apps_description_automation": "Adicionar uma aplicação de automatização a utilizar",
|
||||
"no_category_apps_description_other": "Adicione qualquer outro tipo de aplicações para fazer todos os tipos de coisas",
|
||||
"no_category_apps_description_web3": "Adicione uma aplicação web3 às suas páginas de reservas",
|
||||
"no_category_apps_description_messaging": "Adicione uma aplicação de mensagens para configurar notificações e lembretes personalizados",
|
||||
"no_category_apps_description_crm": "Adicione uma aplicação de CRM para manter um registo das pessoas com quem se reuniu",
|
||||
"installed_app_calendar_description": "Defina o(s) calendário(s) para verificar se existem conflitos e assim evitar marcações sobrepostas.",
|
||||
|
@ -913,7 +912,6 @@
|
|||
"installed_app_other_description": "Todas as aplicações instaladas de outras categorias.",
|
||||
"installed_app_conferencing_description": "Configurar as aplicações de conferência a utilizar",
|
||||
"installed_app_automation_description": "Configurar as aplicações de automatização a utilizar",
|
||||
"installed_app_web3_description": "Configure as aplicações web3 a utilizar nas suas páginas de reservas",
|
||||
"installed_app_messaging_description": "Configurar as aplicações de mensagens a utilizar para definir notificações e lembretes personalizados",
|
||||
"installed_app_crm_description": "Configurar as aplicações de CRM a utilizar para manter um registo das pessoas com quem se reuniu",
|
||||
"analytics": "Estatísticas",
|
||||
|
@ -1304,7 +1302,6 @@
|
|||
"profile_picture": "Imagem do perfil",
|
||||
"upload": "Carregar",
|
||||
"add_profile_photo": "Adicionar imagem de perfil",
|
||||
"web3": "Web3",
|
||||
"token_address": "Endereço do Token",
|
||||
"blockchain": "Blockchain",
|
||||
"old_password": "Palavra-passe antiga",
|
||||
|
@ -1346,7 +1343,6 @@
|
|||
"connect_automation_apps": "Associar aplicações de automatização",
|
||||
"connect_analytics_apps": "Associar aplicações de estatística",
|
||||
"connect_other_apps": "Associe outras aplicações",
|
||||
"connect_web3_apps": "Associe aplicações web3",
|
||||
"connect_messaging_apps": "Ligar aplicações de mensagens",
|
||||
"connect_crm_apps": "Ligar aplicações CRM",
|
||||
"current_step_of_total": "Passo {{currentStep}} de {{maxSteps}}",
|
||||
|
|
|
@ -904,7 +904,6 @@
|
|||
"no_category_apps_description_analytics": "Adăugați o aplicație de analiză pentru paginile dvs. de rezervări",
|
||||
"no_category_apps_description_automation": "Adăugați o aplicație de automatizare de utilizat",
|
||||
"no_category_apps_description_other": "Adăugați orice alt tip de aplicație pentru a întreprinde diverse acțiuni",
|
||||
"no_category_apps_description_web3": "Adăugați o aplicație Web3 pentru paginile dvs. de rezervări",
|
||||
"no_category_apps_description_messaging": "Adăugați o aplicație de mesagerie pentru a configura notificări și mementouri personalizate",
|
||||
"no_category_apps_description_crm": "Adăugați o aplicație CRM pentru a ține evidența persoanelor cu care v-ați întâlnit",
|
||||
"installed_app_calendar_description": "Pentru a evita rezervările suprapuse, configurează calendarele astfel încât să poată verifica existența conflictelor.",
|
||||
|
@ -913,7 +912,6 @@
|
|||
"installed_app_other_description": "Toate aplicațiile instalate din alte categorii.",
|
||||
"installed_app_conferencing_description": "Configurați ce aplicații de conferințe vor fi utilizate",
|
||||
"installed_app_automation_description": "Configurați care aplicații de automatizare vor fi utilizate",
|
||||
"installed_app_web3_description": "Configurați care aplicații Web3 vor fi utilizate pentru paginile dvs. de rezervări",
|
||||
"installed_app_messaging_description": "Definiți ce aplicații de mesagerie vor fi utilizate pentru configurarea de notificări și mementouri personalizate",
|
||||
"installed_app_crm_description": "Configurați ce aplicații CRM vor fi utilizate pentru a ține evidența persoanelor cu care v-ați întâlnit",
|
||||
"analytics": "Analiză",
|
||||
|
@ -1304,7 +1302,6 @@
|
|||
"profile_picture": "Fotografie de profil",
|
||||
"upload": "Încărcare",
|
||||
"add_profile_photo": "Adăugați poză de profil",
|
||||
"web3": "Web3",
|
||||
"token_address": "Adresă token",
|
||||
"blockchain": "Blockchain",
|
||||
"old_password": "Parola veche",
|
||||
|
@ -1346,7 +1343,6 @@
|
|||
"connect_automation_apps": "Conectați aplicații de automatizare",
|
||||
"connect_analytics_apps": "Conectați aplicații de analiză",
|
||||
"connect_other_apps": "Conectați alte aplicații",
|
||||
"connect_web3_apps": "Conectați aplicații Web3",
|
||||
"connect_messaging_apps": "Conectați aplicații de mesagerie",
|
||||
"connect_crm_apps": "Conectați aplicații CRM",
|
||||
"current_step_of_total": "Pasul {{currentStep}} din {{maxSteps}}",
|
||||
|
|
|
@ -904,7 +904,6 @@
|
|||
"no_category_apps_description_analytics": "Добавьте приложение аналитики для использования на страницах бронирования",
|
||||
"no_category_apps_description_automation": "Добавьте приложение для автоматизации",
|
||||
"no_category_apps_description_other": "Добавляйте всевозможные приложения для решения своих задач",
|
||||
"no_category_apps_description_web3": "Добавьте приложение web3 для использования на страницах бронирования",
|
||||
"no_category_apps_description_messaging": "Добавьте мессенджер, чтобы настроить пользовательские уведомления и напоминания",
|
||||
"no_category_apps_description_crm": "Добавьте приложение CRM, чтобы отслеживать, с кем у вас были встречи",
|
||||
"installed_app_calendar_description": "Настройте проверку календарей на предмет конфликтов для избежания двойного бронирования.",
|
||||
|
@ -913,7 +912,6 @@
|
|||
"installed_app_other_description": "Все установленные приложения из других категорий.",
|
||||
"installed_app_conferencing_description": "Выберите приложения для конференц-связи",
|
||||
"installed_app_automation_description": "Выберите приложения для автоматизации",
|
||||
"installed_app_web3_description": "Выберите приложения web3 для страниц бронирования",
|
||||
"installed_app_messaging_description": "Выберите мессенджеры, с помощью которых вы хотите отправлять пользовательские уведомления и напоминания",
|
||||
"installed_app_crm_description": "Выберите CRM-приложения, в которых вы хотите отслеживать, с кем у вас были встречи",
|
||||
"analytics": "Аналитика",
|
||||
|
@ -1304,7 +1302,6 @@
|
|||
"profile_picture": "Фото профиля",
|
||||
"upload": "Загрузить",
|
||||
"add_profile_photo": "Добавить фото профиля",
|
||||
"web3": "Web3",
|
||||
"token_address": "Адрес токена",
|
||||
"blockchain": "Блокчейн",
|
||||
"old_password": "Старый пароль",
|
||||
|
@ -1346,7 +1343,6 @@
|
|||
"connect_automation_apps": "Подключить приложения для автоматизации",
|
||||
"connect_analytics_apps": "Подключить приложения аналитики",
|
||||
"connect_other_apps": "Подключить другие приложения",
|
||||
"connect_web3_apps": "Подключить приложения web3",
|
||||
"connect_messaging_apps": "Подключить мессенджеры",
|
||||
"connect_crm_apps": "Подключить CRM-приложения",
|
||||
"current_step_of_total": "Шаг {{currentStep}} из {{maxSteps}}",
|
||||
|
|
|
@ -801,7 +801,7 @@
|
|||
"cal_provide_tandem_meeting_url": "{{appName}} će obezbediti URL Tandem sastanka.",
|
||||
"cal_provide_video_meeting_url": "{{appName}} će obezbediti Daily video meeting URL.",
|
||||
"cal_provide_jitsi_meeting_url": "Mi ćemo generisati Jitsi Meet URL za vas.",
|
||||
"cal_provide_huddle01_meeting_url": "{{appName}} će obezbediti Huddle01 web3 video meeting URL.",
|
||||
"cal_provide_huddle01_meeting_url": "{{appName}} će obezbediti Huddle01 video meeting URL.",
|
||||
"cal_provide_teams_meeting_url": "{{appName}} će dostaviti URL adresu MS Teams sastanka. NAPOMENA: NEOPHODAN JE POSLOVNI ILI ŠKOLSKI NALOG",
|
||||
"require_payment": "Obavezno plaćanje",
|
||||
"you_need_to_add_a_name": "Potrebno je da dodate ime",
|
||||
|
@ -904,7 +904,6 @@
|
|||
"no_category_apps_description_analytics": "Dodajte analitičku aplikaciju za vaše stranice za rezervacije",
|
||||
"no_category_apps_description_automation": "Dodajte aplikaciju za automatizaciju za korišćenje",
|
||||
"no_category_apps_description_other": "Dodajte bilo koju vrstu aplikacije da biste uradili svakakve stvari",
|
||||
"no_category_apps_description_web3": "Dodajte web3 aplikaciju na stranice za rezervacije",
|
||||
"no_category_apps_description_messaging": "Dodajte aplikaciju za poruke da biste podesili uobičajena obaveštenja i podsetnike",
|
||||
"no_category_apps_description_crm": "Dodajte aplikaciju za CRM da biste pratili sa kim ste se sreli",
|
||||
"installed_app_calendar_description": "Podesite kalendar(e) da biste proverili da li postoje konflikti i time sprečili dvostruka zakazivanja.",
|
||||
|
@ -913,7 +912,6 @@
|
|||
"installed_app_other_description": "Sve vaše instalirane aplikacije iz drugih kategorija.",
|
||||
"installed_app_conferencing_description": "Konfigurišite koje aplikacije ćete koristiti za konferencije",
|
||||
"installed_app_automation_description": "Konfigurišite koje ćete aplikacije za automatizaciju da koristite",
|
||||
"installed_app_web3_description": "Konfigurišite koje web3 aplikacije će se koristiti za stranice za rezervacije",
|
||||
"installed_app_messaging_description": "Konfigurišite koje aplikacije za poruke ćete koristiti da biste podesili uobičajena obaveštenja i podsetnike",
|
||||
"installed_app_crm_description": "Konfigurišite koje CRM aplikacije ćete koristiti za praćenje sa kim ste se sreli",
|
||||
"analytics": "Analitika",
|
||||
|
@ -1304,7 +1302,6 @@
|
|||
"profile_picture": "Profilna slika",
|
||||
"upload": "Otpremi",
|
||||
"add_profile_photo": "Dodajte profilnu fotografiju",
|
||||
"web3": "Web3",
|
||||
"token_address": "Adresa tokena",
|
||||
"blockchain": "Lanac blokova",
|
||||
"old_password": "Stara lozinka",
|
||||
|
@ -1346,7 +1343,6 @@
|
|||
"connect_automation_apps": "Povežite aplikacije za automatizaciju",
|
||||
"connect_analytics_apps": "Povežite analitičke aplikacije",
|
||||
"connect_other_apps": "Povežite druge aplikacije",
|
||||
"connect_web3_apps": "Povežite web3 aplikacije",
|
||||
"connect_messaging_apps": "Povežite aplikacije za razmenu poruka",
|
||||
"connect_crm_apps": "Povežite CRM aplikacije",
|
||||
"current_step_of_total": "Korak {{currentStep}} od {{maxSteps}}",
|
||||
|
|
|
@ -801,7 +801,7 @@
|
|||
"cal_provide_tandem_meeting_url": "{{appName}} kommer att generera en URL för Tandem-möte.",
|
||||
"cal_provide_video_meeting_url": "{{appName}} kommer att generera en URL för Daily video-möte.",
|
||||
"cal_provide_jitsi_meeting_url": "Vi kommer att generera en Jitsi Meet URL för dig.",
|
||||
"cal_provide_huddle01_meeting_url": "{{appName}} kommer att generera en URL för Huddle01 web3-möte.",
|
||||
"cal_provide_huddle01_meeting_url": "{{appName}} kommer att generera en URL för Huddle01-möte.",
|
||||
"cal_provide_teams_meeting_url": "{{appName}} kommer att tillhandahålla en mötes-URL för MS Teams. OBS! MÅSTE HA ETT ARBETS- ELLER SKOLKONTO",
|
||||
"require_payment": "Begär betalning",
|
||||
"you_need_to_add_a_name": "Du måste lägga till ett namn",
|
||||
|
@ -904,7 +904,6 @@
|
|||
"no_category_apps_description_analytics": "Lägg till en analysapp för dina bokningssidor",
|
||||
"no_category_apps_description_automation": "Lägg till en automationsapp att använda",
|
||||
"no_category_apps_description_other": "Lägg till en annan typ av app för att göra alla möjliga saker",
|
||||
"no_category_apps_description_web3": "Lägg till en web3-app för dina bokningssidor",
|
||||
"no_category_apps_description_messaging": "Lägg till en meddelandeapp för att skapa anpassade aviseringar och påminnelser",
|
||||
"no_category_apps_description_crm": "Lägg till en CRM-app för att hålla reda på vilka du har träffat",
|
||||
"installed_app_calendar_description": "Ställ in kalendrar att söka efter konflikter för att undvika dubbelbokningar.",
|
||||
|
@ -913,7 +912,6 @@
|
|||
"installed_app_other_description": "Alla dina installerade appar från andra kategorier.",
|
||||
"installed_app_conferencing_description": "Konfigurera vilka konferensappar som ska användas",
|
||||
"installed_app_automation_description": "Konfigurera vilka automationsappar som ska användas",
|
||||
"installed_app_web3_description": "Konfigurera vilka web3-appar som ska användas för dina bokningssidor",
|
||||
"installed_app_messaging_description": "Konfigurera vilka meddelandeappar som ska användas för att skapa anpassade aviseringar och påminnelser",
|
||||
"installed_app_crm_description": "Konfigurera vilka CRM-appar som ska användas för att hålla reda på vilka du har träffat",
|
||||
"analytics": "Analys",
|
||||
|
@ -1304,7 +1302,6 @@
|
|||
"profile_picture": "Profilbild",
|
||||
"upload": "Ladda upp",
|
||||
"add_profile_photo": "Lägg till profilfoto",
|
||||
"web3": "Web3",
|
||||
"token_address": "Tokenadress",
|
||||
"blockchain": "Blockkedja",
|
||||
"old_password": "Gammalt lösenord",
|
||||
|
@ -1346,7 +1343,6 @@
|
|||
"connect_automation_apps": "Anslut automationsappar",
|
||||
"connect_analytics_apps": "Anslut analysappar",
|
||||
"connect_other_apps": "Anslut andra appar",
|
||||
"connect_web3_apps": "Anslut web3-appar",
|
||||
"connect_messaging_apps": "Anslut meddelandeappar",
|
||||
"connect_crm_apps": "Anslut CRM-appar",
|
||||
"current_step_of_total": "Steg {{currentStep}} av {{maxSteps}}",
|
||||
|
|
|
@ -801,7 +801,7 @@
|
|||
"cal_provide_tandem_meeting_url": "{{appName}}, bir Tandem toplantı URL'si sağlayacaktır.",
|
||||
"cal_provide_video_meeting_url": "{{appName}}, bir görüntülü toplantı URL'si sağlayacaktır.",
|
||||
"cal_provide_jitsi_meeting_url": "Sizin için bir Jitsi Meet URL'si oluşturacağız.",
|
||||
"cal_provide_huddle01_meeting_url": "{{appName}}, bir Huddle01 web3 görüntülü toplantı URL'si sağlayacaktır.",
|
||||
"cal_provide_huddle01_meeting_url": "{{appName}}, bir Huddle01 görüntülü toplantı URL'si sağlayacaktır.",
|
||||
"cal_provide_teams_meeting_url": "{{appName}}, bir MS Teams toplantı URL'si sağlayacaktır. NOT: İŞ VEYA OKUL HESABINIZIN OLMASI GEREKİR",
|
||||
"require_payment": "Ödemeyi Gerekli Kılın",
|
||||
"you_need_to_add_a_name": "Ad eklemeniz gerekiyor",
|
||||
|
@ -904,7 +904,6 @@
|
|||
"no_category_apps_description_analytics": "Rezervasyon sayfalarınız için bir analiz uygulaması ekleyin",
|
||||
"no_category_apps_description_automation": "Kullanılacak otomasyon uygulamasını ekleyin",
|
||||
"no_category_apps_description_other": "Her türlü işlemi yapmak için farklı bir uygulama ekleyin",
|
||||
"no_category_apps_description_web3": "Rezervasyon sayfalarınız için bir web3 uygulaması ekleyin",
|
||||
"no_category_apps_description_messaging": "Özel bildirimler ve hatırlatıcılar ayarlamak için bir mesajlaşma uygulaması ekleyin",
|
||||
"no_category_apps_description_crm": "Tanıştığınız kullanıcıları takip etmek için bir CRM uygulaması ekleyin",
|
||||
"installed_app_calendar_description": "Çifte rezervasyonları önlemek amacıyla çakışmaları kontrol etmek için takvimleri ayarlayın.",
|
||||
|
@ -913,7 +912,6 @@
|
|||
"installed_app_other_description": "Diğer kategorilerdeki tüm yüklü uygulamalarınız.",
|
||||
"installed_app_conferencing_description": "Hangi konferans uygulamalarının kullanılacağını belirleyin",
|
||||
"installed_app_automation_description": "Kullanılacak otomasyon uygulamalarını yapılandırın",
|
||||
"installed_app_web3_description": "Rezervasyon sayfalarınız için hangi web3 uygulamalarının kullanılacağını yapılandırın",
|
||||
"installed_app_messaging_description": "Özel bildirimleri ve hatırlatıcıları ayarlamak için hangi mesajlaşma uygulamalarının kullanılacağını belirleyin",
|
||||
"installed_app_crm_description": "Tanıştığınız kullanıcıları takip etmek için hangi CRM uygulamalarının kullanılacağını belirleyin",
|
||||
"analytics": "Analizler",
|
||||
|
@ -1304,7 +1302,6 @@
|
|||
"profile_picture": "Profil resmi",
|
||||
"upload": "Yükle",
|
||||
"add_profile_photo": "Profil fotoğrafı ekleyin",
|
||||
"web3": "Web3",
|
||||
"token_address": "Token Adresi",
|
||||
"blockchain": "Blok zinciri",
|
||||
"old_password": "Eski şifre",
|
||||
|
@ -1346,7 +1343,6 @@
|
|||
"connect_automation_apps": "Otomasyon uygulamaları bağlayın",
|
||||
"connect_analytics_apps": "Analiz uygulamaları bağlayın",
|
||||
"connect_other_apps": "Diğer uygulamaları bağlayın",
|
||||
"connect_web3_apps": "Web3 uygulamalarını bağlayın",
|
||||
"connect_messaging_apps": "Mesajlaşma uygulamalarını bağlayın",
|
||||
"connect_crm_apps": "CRM uygulamalarını bağlayın",
|
||||
"current_step_of_total": "{{currentStep}} / {{maxSteps}}. Adım",
|
||||
|
|
|
@ -801,7 +801,7 @@
|
|||
"cal_provide_tandem_meeting_url": "{{appName}} надасть URL-адресу наради Tandem.",
|
||||
"cal_provide_video_meeting_url": "{{appName}} надасть URL-адресу наради Daily.",
|
||||
"cal_provide_jitsi_meeting_url": "Ми згенеруємо URL-адресу Jitsi Meet.",
|
||||
"cal_provide_huddle01_meeting_url": "{{appName}} надасть URL-адресу відеонаради Huddle01 web3.",
|
||||
"cal_provide_huddle01_meeting_url": "{{appName}} надасть URL-адресу відеонаради Huddle01.",
|
||||
"cal_provide_teams_meeting_url": "{{appName}} надасть URL-адресу наради в MS Teams. ПРИМІТКА: ПОТРІБЕН РОБОЧИЙ АБО НАВЧАЛЬНИЙ ОБЛІКОВИЙ ЗАПИС",
|
||||
"require_payment": "Вимагати оплату",
|
||||
"you_need_to_add_a_name": "Потрібно додати ім’я",
|
||||
|
@ -904,7 +904,6 @@
|
|||
"no_category_apps_description_analytics": "Вибрати аналітичний додаток для своїх сторінок бронювання",
|
||||
"no_category_apps_description_automation": "Вибрати додаток для автоматизації",
|
||||
"no_category_apps_description_other": "Додавайте інші додатки з різноманітними функціями",
|
||||
"no_category_apps_description_web3": "Вибрати додаток web3 для своїх сторінок бронювання",
|
||||
"no_category_apps_description_messaging": "Додайте застосунок для обміну повідомленнями, щоб налаштувати сповіщення й нагадування",
|
||||
"no_category_apps_description_crm": "Додайте застосунок для CRM, щоб вести облік користувачів, з якими ви зустрічалися",
|
||||
"installed_app_calendar_description": "Налаштуйте календарі, щоб перевіряти, чи немає конфліктів у розкладі, і уникати подвійних бронювань.",
|
||||
|
@ -913,7 +912,6 @@
|
|||
"installed_app_other_description": "Усі ваші встановлені додатки з інших категорій.",
|
||||
"installed_app_conferencing_description": "Укажіть, які застосунки для конференцій використовувати",
|
||||
"installed_app_automation_description": "Указати додатки для автоматизації",
|
||||
"installed_app_web3_description": "Виберіть додатки web3 для своїх сторінок бронювання",
|
||||
"installed_app_messaging_description": "Укажіть, які застосунки для обміну повідомленнями використовувати для налаштування сповіщень і нагадувань",
|
||||
"installed_app_crm_description": "Укажіть, які застосунки для CRM використовувати, щоб вести облік користувачів, з якими ви зустрічались",
|
||||
"analytics": "Аналітика",
|
||||
|
@ -1304,7 +1302,6 @@
|
|||
"profile_picture": "Зображення профілю",
|
||||
"upload": "Передати",
|
||||
"add_profile_photo": "Додати фото профілю",
|
||||
"web3": "Web3",
|
||||
"token_address": "Адреса токена",
|
||||
"blockchain": "Блокчейн",
|
||||
"old_password": "Старий пароль",
|
||||
|
@ -1346,7 +1343,6 @@
|
|||
"connect_automation_apps": "Підключити додатки для автоматизації",
|
||||
"connect_analytics_apps": "Підключити аналітичні додатки",
|
||||
"connect_other_apps": "Підключити інші додатки",
|
||||
"connect_web3_apps": "Підключити додатки web3",
|
||||
"connect_messaging_apps": "Підключити застосунки для повідомлень",
|
||||
"connect_crm_apps": "Підключити застосунки CRM",
|
||||
"current_step_of_total": "Крок {{currentStep}} із {{maxSteps}}",
|
||||
|
|
|
@ -801,7 +801,7 @@
|
|||
"cal_provide_tandem_meeting_url": "{{appName}} sẽ cung cấp URL cuộc họp Tandem.",
|
||||
"cal_provide_video_meeting_url": "{{appName}} sẽ cung cấp URL cuộc họp video.",
|
||||
"cal_provide_jitsi_meeting_url": "Chúng tôi sẽ tạo một URL Jitsi Meet cho bạn.",
|
||||
"cal_provide_huddle01_meeting_url": "{{appName}} sẽ cung cấp URL cuộc họp video Huddle01 web3.",
|
||||
"cal_provide_huddle01_meeting_url": "{{appName}} sẽ cung cấp URL cuộc họp video Huddle01.",
|
||||
"cal_provide_teams_meeting_url": "{{appName}} sẽ cung cấp URL cuộc họp MS Teams. LƯU Ý: PHẢI CÓ TÀI KHOẢN CÔNG VIỆC HOẶC TRƯỜNG HỌC",
|
||||
"require_payment": "Yêu cầu thanh toán",
|
||||
"you_need_to_add_a_name": "Bạn cần thêm vào một tên",
|
||||
|
@ -904,7 +904,6 @@
|
|||
"no_category_apps_description_analytics": "Thêm một ứng dụng phân tích cho những trang lịch hẹn của bạn",
|
||||
"no_category_apps_description_automation": "Thêm một ứng dụng tự động hoá để sử dụng",
|
||||
"no_category_apps_description_other": "Thêm loại ứng dụng khác để làm mọi loại công việc",
|
||||
"no_category_apps_description_web3": "Thêm một ứng dụng web3 cho những trang lịch hẹn của bạn",
|
||||
"no_category_apps_description_messaging": "Thêm một ứng dụng nhắn tin để thiết lập thông báo & lời nhắc tuỳ chỉnh",
|
||||
"no_category_apps_description_crm": "Thêm một ứng dụng CRM để theo dõi người mà bạn đã họp cùng",
|
||||
"installed_app_calendar_description": "Đặt (các) lịch làm nhiệm vụ kiểm tra xung đột nhằm ngăn tình trạng đặt lịch trùng.",
|
||||
|
@ -913,7 +912,6 @@
|
|||
"installed_app_other_description": "Tất cả những ứng dụng bạn đã cài từ những danh mục khác.",
|
||||
"installed_app_conferencing_description": "Cấu hình ứng dụng hội nghị nào nên dùng",
|
||||
"installed_app_automation_description": "Cấu hình ứng dụng tự động hoá nên dùng",
|
||||
"installed_app_web3_description": "Cấu hình ứng dụng web3 nào cần để sử dụng cho những trang lịch hẹn của bạn",
|
||||
"installed_app_messaging_description": "Cấu hình ứng dụng nhắn tin nào cần dùng để thiết lập thông báo & lời nhắc tuỳ chỉnh",
|
||||
"installed_app_crm_description": "Cấu hình ứng dụng CRM nào cần dùng để theo dõi những người mà bạn đã họp cùng",
|
||||
"analytics": "Phân tích",
|
||||
|
@ -1304,7 +1302,6 @@
|
|||
"profile_picture": "Ảnh hồ sơ",
|
||||
"upload": "Tải lên",
|
||||
"add_profile_photo": "Thêm ảnh hồ sơ",
|
||||
"web3": "Web3",
|
||||
"token_address": "Địa chỉ token",
|
||||
"blockchain": "Chuỗi khối",
|
||||
"old_password": "Mật khẩu cũ",
|
||||
|
@ -1346,7 +1343,6 @@
|
|||
"connect_automation_apps": "Kết nối các ứng dụng tự động hoá",
|
||||
"connect_analytics_apps": "Kết nối các ứng dụng phân tích",
|
||||
"connect_other_apps": "Kết nối các ứng dụng khác",
|
||||
"connect_web3_apps": "Kết nối các ứng dụng web3",
|
||||
"connect_messaging_apps": "Kết nối các ứng dụng nhắn tin",
|
||||
"connect_crm_apps": "Kết nối các ứng dụng CRM",
|
||||
"current_step_of_total": "Bước {{currentStep}}/{{maxSteps}}",
|
||||
|
|
|
@ -801,7 +801,7 @@
|
|||
"cal_provide_tandem_meeting_url": "{{appName}} 将提供 Tandem 会议链接",
|
||||
"cal_provide_video_meeting_url": "{{appName}}将提供 Daily 视频会议链接",
|
||||
"cal_provide_jitsi_meeting_url": "{{appName}} 将提供 Jitsi Meet 视频会议链接",
|
||||
"cal_provide_huddle01_meeting_url": "{{appName}} 将提供 Huddle01 web3 视频会议链接",
|
||||
"cal_provide_huddle01_meeting_url": "{{appName}} 将提供 Huddle01 视频会议链接",
|
||||
"cal_provide_teams_meeting_url": "{{appName}} 将提供 MS Teams 会议 URL。注意: 须拥有工作或学校帐户",
|
||||
"require_payment": "需要付款",
|
||||
"you_need_to_add_a_name": "您需要添加名称",
|
||||
|
@ -905,7 +905,6 @@
|
|||
"no_category_apps_description_analytics": "为您的预约页面添加分析应用",
|
||||
"no_category_apps_description_automation": "添加要使用的自动化应用",
|
||||
"no_category_apps_description_other": "添加任何其他类型的应用以执行各种操作",
|
||||
"no_category_apps_description_web3": "为您的预约页面添加 web3 应用",
|
||||
"no_category_apps_description_messaging": "添加一个消息应用,以设置自定义通知和提醒",
|
||||
"no_category_apps_description_crm": "添加一个 CRM 应用,以记录您见过的人",
|
||||
"installed_app_calendar_description": "设置日历以检查冲突,防止重复预约。",
|
||||
|
@ -914,7 +913,6 @@
|
|||
"installed_app_other_description": "所有属于其他类别的已安装应用。",
|
||||
"installed_app_conferencing_description": "配置要使用的会议应用",
|
||||
"installed_app_automation_description": "配置要使用的自动化应用",
|
||||
"installed_app_web3_description": "配置将用于您的预约页面的 web3 应用",
|
||||
"installed_app_messaging_description": "配置用于设置自定义通知和提醒的消息应用",
|
||||
"installed_app_crm_description": "配置用于记录您见过的人的 CRM 应用",
|
||||
"analytics": "分析",
|
||||
|
@ -1305,7 +1303,6 @@
|
|||
"profile_picture": "个人资料图片",
|
||||
"upload": "上传",
|
||||
"add_profile_photo": "添加个人资料照片",
|
||||
"web3": "Web3",
|
||||
"token_address": "代币地址",
|
||||
"blockchain": "区块链",
|
||||
"old_password": "旧密码",
|
||||
|
@ -1347,7 +1344,6 @@
|
|||
"connect_automation_apps": "连接自动化应用",
|
||||
"connect_analytics_apps": "连接分析应用",
|
||||
"connect_other_apps": "连接其他应用",
|
||||
"connect_web3_apps": "连接 web3 应用",
|
||||
"connect_messaging_apps": "连接消息应用",
|
||||
"connect_crm_apps": "连接 CRM 应用",
|
||||
"current_step_of_total": "第 {{currentStep}} 步,共 {{maxSteps}} 步",
|
||||
|
|
|
@ -904,7 +904,6 @@
|
|||
"no_category_apps_description_analytics": "為您的預約頁面加入分析應用程式",
|
||||
"no_category_apps_description_automation": "加入自動化應用程式來使用",
|
||||
"no_category_apps_description_other": "新增任何其他類型的應用程式以完成各種操作",
|
||||
"no_category_apps_description_web3": "為您的預約頁面加入 web3 應用程式",
|
||||
"no_category_apps_description_messaging": "新增傳訊應用程式,以設定自訂通知和提醒",
|
||||
"no_category_apps_description_crm": "新增 CRM 應用程式,追蹤您已見過面的人",
|
||||
"installed_app_calendar_description": "設定行事曆來檢查衝突,以避免重複預約。",
|
||||
|
@ -913,7 +912,6 @@
|
|||
"installed_app_other_description": "其他類別的所有已安裝應用程式。",
|
||||
"installed_app_conferencing_description": "設定要使用哪些會議應用程式",
|
||||
"installed_app_automation_description": "設定要使用哪些自動化應用程式",
|
||||
"installed_app_web3_description": "設定要為您的預約頁面使用哪些 web3 應用程式",
|
||||
"installed_app_messaging_description": "設定要使用哪些傳訊應用程式來設定自訂通知與提醒",
|
||||
"installed_app_crm_description": "設定要使用哪些 CRM 應用程式來追蹤您已見過面的人",
|
||||
"analytics": "分析",
|
||||
|
@ -1304,7 +1302,6 @@
|
|||
"profile_picture": "個人資料圖片",
|
||||
"upload": "上傳",
|
||||
"add_profile_photo": "新增個人資料相片",
|
||||
"web3": "Web3",
|
||||
"token_address": "代幣地址",
|
||||
"blockchain": "區塊鏈",
|
||||
"old_password": "舊密碼",
|
||||
|
@ -1346,7 +1343,6 @@
|
|||
"connect_automation_apps": "連至自動化應用程式",
|
||||
"connect_analytics_apps": "連至分析應用程式",
|
||||
"connect_other_apps": "連接其他應用程式",
|
||||
"connect_web3_apps": "連接 web3 應用程式",
|
||||
"connect_messaging_apps": "連接傳訊應用程式",
|
||||
"connect_crm_apps": "連接 CRM 應用程式",
|
||||
"current_step_of_total": "第 {{currentStep}} 步,共 {{maxSteps}} 步",
|
||||
|
|
|
@ -5,6 +5,7 @@ import type z from "zod";
|
|||
|
||||
import { ErrorCode } from "@calcom/lib/errorCodes";
|
||||
import logger from "@calcom/lib/logger";
|
||||
import { safeStringify } from "@calcom/lib/safeStringify";
|
||||
import prisma from "@calcom/prisma";
|
||||
import type { CalendarEvent } from "@calcom/types/Calendar";
|
||||
import type { IAbstractPaymentService } from "@calcom/types/PaymentService";
|
||||
|
@ -87,7 +88,7 @@ export class PaymentService implements IAbstractPaymentService {
|
|||
}
|
||||
return paymentData;
|
||||
} catch (error) {
|
||||
log.error("Alby: Payment could not be created", bookingId, JSON.stringify(error));
|
||||
log.error("Alby: Payment could not be created", bookingId, safeStringify(error));
|
||||
throw new Error(ErrorCode.PaymentCreationFailure);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -9,6 +9,7 @@ import { getFeatureFlagMap } from "@calcom/features/flags/server/utils";
|
|||
import { getLocation, getRichDescription } from "@calcom/lib/CalEventParser";
|
||||
import type CalendarService from "@calcom/lib/CalendarService";
|
||||
import logger from "@calcom/lib/logger";
|
||||
import { safeStringify } from "@calcom/lib/safeStringify";
|
||||
import prisma from "@calcom/prisma";
|
||||
import type {
|
||||
Calendar,
|
||||
|
@ -106,6 +107,7 @@ export default class GoogleCalendarService implements Calendar {
|
|||
});
|
||||
myGoogleAuth.setCredentials(googleCredentials);
|
||||
} catch (err) {
|
||||
this.log.error("Error Refreshing Google Token", safeStringify(err));
|
||||
let message;
|
||||
if (err instanceof Error) message = err.message;
|
||||
else message = String(err);
|
||||
|
@ -251,7 +253,10 @@ export default class GoogleCalendarService implements Calendar {
|
|||
iCalUID: event.data.iCalUID,
|
||||
};
|
||||
} catch (error) {
|
||||
console.error("There was an error contacting google calendar service: ", error);
|
||||
this.log.error(
|
||||
"There was an error creating event in google calendar: ",
|
||||
safeStringify({ error, selectedCalendar, credentialId })
|
||||
);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
@ -332,7 +337,10 @@ export default class GoogleCalendarService implements Calendar {
|
|||
}
|
||||
return evt?.data;
|
||||
} catch (error) {
|
||||
console.error("There was an error contacting google calendar service: ", error);
|
||||
this.log.error(
|
||||
"There was an error updating event in google calendar: ",
|
||||
safeStringify({ error, event, uid })
|
||||
);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
@ -354,6 +362,10 @@ export default class GoogleCalendarService implements Calendar {
|
|||
});
|
||||
return event?.data;
|
||||
} catch (error) {
|
||||
this.log.error(
|
||||
"There was an error deleting event from google calendar: ",
|
||||
safeStringify({ error, event, externalCalendarId })
|
||||
);
|
||||
const err = error as GoogleCalError;
|
||||
/**
|
||||
* 410 is when an event is already deleted on the Google cal before on cal.com
|
||||
|
@ -502,7 +514,10 @@ export default class GoogleCalendarService implements Calendar {
|
|||
return busyData;
|
||||
}
|
||||
} catch (error) {
|
||||
this.log.error("There was an error contacting google calendar service: ", error);
|
||||
this.log.error(
|
||||
"There was an error getting availability from google calendar: ",
|
||||
safeStringify({ error, selectedCalendars })
|
||||
);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
@ -524,7 +539,7 @@ export default class GoogleCalendarService implements Calendar {
|
|||
} satisfies IntegrationCalendar)
|
||||
);
|
||||
} catch (error) {
|
||||
this.log.error("There was an error contacting google calendar service: ", error);
|
||||
this.log.error("There was an error getting calendars: ", safeStringify(error));
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,6 +6,7 @@ import Paypal from "@calcom/app-store/paypal/lib/Paypal";
|
|||
import { WEBAPP_URL } from "@calcom/lib/constants";
|
||||
import { ErrorCode } from "@calcom/lib/errorCodes";
|
||||
import logger from "@calcom/lib/logger";
|
||||
import { safeStringify } from "@calcom/lib/safeStringify";
|
||||
import prisma from "@calcom/prisma";
|
||||
import type { CalendarEvent } from "@calcom/types/Calendar";
|
||||
import type { IAbstractPaymentService } from "@calcom/types/PaymentService";
|
||||
|
@ -91,7 +92,7 @@ export class PaymentService implements IAbstractPaymentService {
|
|||
}
|
||||
return paymentData;
|
||||
} catch (error) {
|
||||
log.error("Paypal: Payment could not be created for bookingId", bookingId);
|
||||
log.error("Paypal: Payment could not be created for bookingId", bookingId, safeStringify(error));
|
||||
throw new Error(ErrorCode.PaymentCreationFailure);
|
||||
}
|
||||
}
|
||||
|
@ -170,7 +171,11 @@ export class PaymentService implements IAbstractPaymentService {
|
|||
}
|
||||
return paymentData;
|
||||
} catch (error) {
|
||||
log.error("Paypal: Payment method could not be collected for bookingId", bookingId);
|
||||
log.error(
|
||||
"Paypal: Payment method could not be collected for bookingId",
|
||||
bookingId,
|
||||
safeStringify(error)
|
||||
);
|
||||
throw new Error("Paypal: Payment method could not be collected");
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,6 +7,7 @@ import { sendAwaitingPaymentEmail } from "@calcom/emails";
|
|||
import { ErrorCode } from "@calcom/lib/errorCodes";
|
||||
import { getErrorFromUnknown } from "@calcom/lib/errors";
|
||||
import logger from "@calcom/lib/logger";
|
||||
import { safeStringify } from "@calcom/lib/safeStringify";
|
||||
import prisma from "@calcom/prisma";
|
||||
import type { CalendarEvent } from "@calcom/types/Calendar";
|
||||
import type { IAbstractPaymentService } from "@calcom/types/PaymentService";
|
||||
|
@ -132,8 +133,7 @@ export class PaymentService implements IAbstractPaymentService {
|
|||
}
|
||||
return paymentData;
|
||||
} catch (error) {
|
||||
console.error(`Payment could not be created for bookingId ${bookingId}`, error);
|
||||
log.error("Stripe: Payment could not be created", bookingId, JSON.stringify(error));
|
||||
log.error("Stripe: Payment could not be created", bookingId, safeStringify(error));
|
||||
throw new Error("payment_not_created_error");
|
||||
}
|
||||
}
|
||||
|
@ -207,7 +207,7 @@ export class PaymentService implements IAbstractPaymentService {
|
|||
log.error(
|
||||
"Stripe: Payment method could not be collected for bookingId",
|
||||
bookingId,
|
||||
JSON.stringify(error)
|
||||
safeStringify(error)
|
||||
);
|
||||
throw new Error("Stripe: Payment method could not be collected");
|
||||
}
|
||||
|
@ -286,7 +286,7 @@ export class PaymentService implements IAbstractPaymentService {
|
|||
|
||||
return paymentData;
|
||||
} catch (error) {
|
||||
log.error("Stripe: Could not charge card for payment", _bookingId, JSON.stringify(error));
|
||||
log.error("Stripe: Could not charge card for payment", _bookingId, safeStringify(error));
|
||||
throw new Error(ErrorCode.ChargeCardFailure);
|
||||
}
|
||||
}
|
||||
|
@ -378,7 +378,7 @@ export class PaymentService implements IAbstractPaymentService {
|
|||
await this.stripe.paymentIntents.cancel(payment.externalId, { stripeAccount });
|
||||
return true;
|
||||
} catch (e) {
|
||||
log.error("Stripe: Unable to delete Payment in stripe of paymentId", paymentId, JSON.stringify(e));
|
||||
log.error("Stripe: Unable to delete Payment in stripe of paymentId", paymentId, safeStringify(e));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -144,7 +144,7 @@ const updateMeeting = async (
|
|||
if (!updatedMeeting) {
|
||||
log.error(
|
||||
"updateMeeting failed",
|
||||
JSON.stringify({ bookingRef, canCallUpdateMeeting, calEvent, credential })
|
||||
safeStringify({ bookingRef, canCallUpdateMeeting, calEvent, credential })
|
||||
);
|
||||
return {
|
||||
appName: credential.appId || "",
|
||||
|
|
|
@ -37,6 +37,7 @@ export default function DisconnectIntegration({
|
|||
},
|
||||
async onSettled() {
|
||||
await utils.viewer.connectedCalendars.invalidate();
|
||||
await utils.viewer.integrations.invalidate();
|
||||
},
|
||||
});
|
||||
|
||||
|
|
|
@ -0,0 +1,80 @@
|
|||
import { z } from "zod";
|
||||
|
||||
import {
|
||||
bookingCreateSchemaLegacyPropsForApi,
|
||||
bookingCreateBodySchemaForApi,
|
||||
extendedBookingCreateBody,
|
||||
} from "@calcom/prisma/zod-utils";
|
||||
|
||||
import getBookingResponsesSchema from "./getBookingResponsesSchema";
|
||||
import type { getEventTypesFromDB } from "./handleNewBooking";
|
||||
|
||||
const getBookingDataSchema = (
|
||||
rescheduleUid: string | undefined,
|
||||
isNotAnApiCall: boolean,
|
||||
eventType: Awaited<ReturnType<typeof getEventTypesFromDB>>
|
||||
) => {
|
||||
const responsesSchema = getBookingResponsesSchema({
|
||||
eventType: {
|
||||
bookingFields: eventType.bookingFields,
|
||||
},
|
||||
view: rescheduleUid ? "reschedule" : "booking",
|
||||
});
|
||||
const bookingDataSchema = isNotAnApiCall
|
||||
? extendedBookingCreateBody.merge(
|
||||
z.object({
|
||||
responses: responsesSchema,
|
||||
})
|
||||
)
|
||||
: bookingCreateBodySchemaForApi
|
||||
.merge(
|
||||
z.object({
|
||||
responses: responsesSchema.optional(),
|
||||
})
|
||||
)
|
||||
.superRefine((val, ctx) => {
|
||||
if (val.responses && val.customInputs) {
|
||||
ctx.addIssue({
|
||||
code: "custom",
|
||||
message:
|
||||
"Don't use both customInputs and responses. `customInputs` is only there for legacy support.",
|
||||
});
|
||||
return;
|
||||
}
|
||||
const legacyProps = Object.keys(bookingCreateSchemaLegacyPropsForApi.shape);
|
||||
|
||||
if (val.responses) {
|
||||
const unwantedProps: string[] = [];
|
||||
legacyProps.forEach((legacyProp) => {
|
||||
if (typeof val[legacyProp as keyof typeof val] !== "undefined") {
|
||||
console.error(
|
||||
`Deprecated: Unexpected falsy value for: ${unwantedProps.join(
|
||||
","
|
||||
)}. They can't be used with \`responses\`. This will become a 400 error in the future.`
|
||||
);
|
||||
}
|
||||
if (val[legacyProp as keyof typeof val]) {
|
||||
unwantedProps.push(legacyProp);
|
||||
}
|
||||
});
|
||||
if (unwantedProps.length) {
|
||||
ctx.addIssue({
|
||||
code: "custom",
|
||||
message: `Legacy Props: ${unwantedProps.join(",")}. They can't be used with \`responses\``,
|
||||
});
|
||||
return;
|
||||
}
|
||||
} else if (val.customInputs) {
|
||||
const { success } = bookingCreateSchemaLegacyPropsForApi.safeParse(val);
|
||||
if (!success) {
|
||||
ctx.addIssue({
|
||||
code: "custom",
|
||||
message: `With \`customInputs\` you must specify legacy props ${legacyProps.join(",")}`,
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
return bookingDataSchema;
|
||||
};
|
||||
|
||||
export default getBookingDataSchema;
|
|
@ -3,6 +3,7 @@ import { getWebhookPayloadForBooking } from "@calcom/features/bookings/lib/getWe
|
|||
import getWebhooks from "@calcom/features/webhooks/lib/getWebhooks";
|
||||
import sendPayload from "@calcom/features/webhooks/lib/sendPayload";
|
||||
import logger from "@calcom/lib/logger";
|
||||
import { safeStringify } from "@calcom/lib/safeStringify";
|
||||
import { WebhookTriggerEvents } from "@calcom/prisma/enums";
|
||||
import type { CalendarEvent } from "@calcom/types/Calendar";
|
||||
|
||||
|
@ -65,6 +66,6 @@ export async function handleBookingRequested(args: {
|
|||
await Promise.all(promises);
|
||||
} catch (error) {
|
||||
// Silently fail
|
||||
log.error(error);
|
||||
log.error("Error in handleBookingRequested", safeStringify(error));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -10,6 +10,7 @@ import type { EventTypeInfo } from "@calcom/features/webhooks/lib/sendPayload";
|
|||
import sendPayload from "@calcom/features/webhooks/lib/sendPayload";
|
||||
import { getTeamIdFromEventType } from "@calcom/lib/getTeamIdFromEventType";
|
||||
import logger from "@calcom/lib/logger";
|
||||
import { safeStringify } from "@calcom/lib/safeStringify";
|
||||
import type { PrismaClient } from "@calcom/prisma";
|
||||
import { BookingStatus, WebhookTriggerEvents } from "@calcom/prisma/enums";
|
||||
import { EventTypeMetaDataSchema } from "@calcom/prisma/zod-utils";
|
||||
|
@ -65,7 +66,7 @@ export async function handleConfirmation(args: {
|
|||
message: "Booking failed",
|
||||
};
|
||||
|
||||
log.error(`Booking ${user.username} failed`, JSON.stringify({ error, results }));
|
||||
log.error(`Booking ${user.username} failed`, safeStringify({ error, results }));
|
||||
} else {
|
||||
if (results.length) {
|
||||
// TODO: Handle created event metadata more elegantly
|
||||
|
|
|
@ -77,11 +77,9 @@ import type { BookingReference } from "@calcom/prisma/client";
|
|||
import { BookingStatus, SchedulingType, WebhookTriggerEvents } from "@calcom/prisma/enums";
|
||||
import { credentialForCalendarServiceSelect } from "@calcom/prisma/selects/credential";
|
||||
import {
|
||||
bookingCreateBodySchemaForApi,
|
||||
bookingCreateSchemaLegacyPropsForApi,
|
||||
customInputSchema,
|
||||
EventTypeMetaDataSchema,
|
||||
extendedBookingCreateBody,
|
||||
userMetadata as userMetadataSchema,
|
||||
} from "@calcom/prisma/zod-utils";
|
||||
import type { BufferedBusyTime } from "@calcom/types/BufferedBusyTime";
|
||||
|
@ -96,7 +94,7 @@ import type { CredentialPayload } from "@calcom/types/Credential";
|
|||
import type { EventResult, PartialReference } from "@calcom/types/EventManager";
|
||||
|
||||
import type { EventTypeInfo } from "../../webhooks/lib/sendPayload";
|
||||
import getBookingResponsesSchema from "./getBookingResponsesSchema";
|
||||
import getBookingDataSchema from "./getBookingDataSchema";
|
||||
|
||||
const translator = short();
|
||||
const log = logger.getSubLogger({ prefix: ["[api] book:user"] });
|
||||
|
@ -104,6 +102,14 @@ const log = logger.getSubLogger({ prefix: ["[api] book:user"] });
|
|||
type User = Prisma.UserGetPayload<typeof userSelect>;
|
||||
type BufferedBusyTimes = BufferedBusyTime[];
|
||||
type BookingType = Prisma.PromiseReturnType<typeof getOriginalRescheduledBooking>;
|
||||
type Booking = Prisma.PromiseReturnType<typeof createBooking>;
|
||||
export type NewBookingEventType =
|
||||
| Awaited<ReturnType<typeof getDefaultEvent>>
|
||||
| Awaited<ReturnType<typeof getEventTypesFromDB>>;
|
||||
|
||||
// Work with Typescript to require reqBody.end
|
||||
type ReqBodyWithoutEnd = z.infer<ReturnType<typeof getBookingDataSchema>>;
|
||||
type ReqBodyWithEnd = ReqBodyWithoutEnd & { end: string };
|
||||
|
||||
interface IEventTypePaymentCredentialType {
|
||||
appId: EventTypeAppsList;
|
||||
|
@ -244,7 +250,7 @@ function checkForConflicts(busyTimes: BufferedBusyTimes, time: dayjs.ConfigType,
|
|||
return false;
|
||||
}
|
||||
|
||||
const getEventTypesFromDB = async (eventTypeId: number) => {
|
||||
export const getEventTypesFromDB = async (eventTypeId: number) => {
|
||||
const eventType = await prisma.eventType.findUniqueOrThrow({
|
||||
where: {
|
||||
id: eventTypeId,
|
||||
|
@ -363,6 +369,53 @@ type IsFixedAwareUser = User & {
|
|||
organization: { slug: string };
|
||||
};
|
||||
|
||||
const loadUsers = async (
|
||||
eventType: NewBookingEventType,
|
||||
dynamicUserList: string[],
|
||||
reqHeadersHost: string | undefined
|
||||
) => {
|
||||
try {
|
||||
if (!eventType.id) {
|
||||
if (!Array.isArray(dynamicUserList) || dynamicUserList.length === 0) {
|
||||
throw new Error("dynamicUserList is not properly defined or empty.");
|
||||
}
|
||||
|
||||
const users = await prisma.user.findMany({
|
||||
where: {
|
||||
username: { in: dynamicUserList },
|
||||
organization: userOrgQuery(reqHeadersHost ? reqHeadersHost.replace(/^https?:\/\//, "") : ""),
|
||||
},
|
||||
select: {
|
||||
...userSelect.select,
|
||||
credentials: {
|
||||
select: credentialForCalendarServiceSelect,
|
||||
},
|
||||
metadata: true,
|
||||
},
|
||||
});
|
||||
|
||||
return users;
|
||||
}
|
||||
const hosts = eventType.hosts || [];
|
||||
|
||||
if (!Array.isArray(hosts)) {
|
||||
throw new Error("eventType.hosts is not properly defined.");
|
||||
}
|
||||
|
||||
const users = hosts.map(({ user, isFixed }) => ({
|
||||
...user,
|
||||
isFixed,
|
||||
}));
|
||||
|
||||
return users.length ? users : eventType.users;
|
||||
} catch (error) {
|
||||
if (error instanceof HttpError || error instanceof Prisma.PrismaClientKnownRequestError) {
|
||||
throw new HttpError({ statusCode: 400, message: error.message });
|
||||
}
|
||||
throw new HttpError({ statusCode: 500, message: "Unable to load users" });
|
||||
}
|
||||
};
|
||||
|
||||
async function ensureAvailableUsers(
|
||||
eventType: Awaited<ReturnType<typeof getEventTypesFromDB>> & {
|
||||
users: IsFixedAwareUser[];
|
||||
|
@ -506,73 +559,10 @@ async function getBookingData({
|
|||
isNotAnApiCall: boolean;
|
||||
eventType: Awaited<ReturnType<typeof getEventTypesFromDB>>;
|
||||
}) {
|
||||
const responsesSchema = getBookingResponsesSchema({
|
||||
eventType: {
|
||||
bookingFields: eventType.bookingFields,
|
||||
},
|
||||
view: req.body.rescheduleUid ? "reschedule" : "booking",
|
||||
});
|
||||
const bookingDataSchema = isNotAnApiCall
|
||||
? extendedBookingCreateBody.merge(
|
||||
z.object({
|
||||
responses: responsesSchema,
|
||||
})
|
||||
)
|
||||
: bookingCreateBodySchemaForApi
|
||||
.merge(
|
||||
z.object({
|
||||
responses: responsesSchema.optional(),
|
||||
})
|
||||
)
|
||||
.superRefine((val, ctx) => {
|
||||
if (val.responses && val.customInputs) {
|
||||
ctx.addIssue({
|
||||
code: "custom",
|
||||
message:
|
||||
"Don't use both customInputs and responses. `customInputs` is only there for legacy support.",
|
||||
});
|
||||
return;
|
||||
}
|
||||
const legacyProps = Object.keys(bookingCreateSchemaLegacyPropsForApi.shape);
|
||||
|
||||
if (val.responses) {
|
||||
const unwantedProps: string[] = [];
|
||||
legacyProps.forEach((legacyProp) => {
|
||||
if (typeof val[legacyProp as keyof typeof val] !== "undefined") {
|
||||
console.error(
|
||||
`Deprecated: Unexpected falsy value for: ${unwantedProps.join(
|
||||
","
|
||||
)}. They can't be used with \`responses\`. This will become a 400 error in the future.`
|
||||
);
|
||||
}
|
||||
if (val[legacyProp as keyof typeof val]) {
|
||||
unwantedProps.push(legacyProp);
|
||||
}
|
||||
});
|
||||
if (unwantedProps.length) {
|
||||
ctx.addIssue({
|
||||
code: "custom",
|
||||
message: `Legacy Props: ${unwantedProps.join(",")}. They can't be used with \`responses\``,
|
||||
});
|
||||
return;
|
||||
}
|
||||
} else if (val.customInputs) {
|
||||
const { success } = bookingCreateSchemaLegacyPropsForApi.safeParse(val);
|
||||
if (!success) {
|
||||
ctx.addIssue({
|
||||
code: "custom",
|
||||
message: `With \`customInputs\` you must specify legacy props ${legacyProps.join(",")}`,
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
const bookingDataSchema = getBookingDataSchema(req.body?.rescheduleUid, isNotAnApiCall, eventType);
|
||||
|
||||
const reqBody = await bookingDataSchema.parseAsync(req.body);
|
||||
|
||||
// Work with Typescript to require reqBody.end
|
||||
type ReqBodyWithoutEnd = z.infer<typeof bookingDataSchema>;
|
||||
type ReqBodyWithEnd = ReqBodyWithoutEnd & { end: string };
|
||||
|
||||
const reqBodyWithEnd = (reqBody: ReqBodyWithoutEnd): reqBody is ReqBodyWithEnd => {
|
||||
// Use the event length to auto-set the event end time.
|
||||
if (!Object.prototype.hasOwnProperty.call(reqBody, "end")) {
|
||||
|
@ -626,6 +616,181 @@ async function getBookingData({
|
|||
}
|
||||
}
|
||||
|
||||
async function createBooking({
|
||||
originalRescheduledBooking,
|
||||
evt,
|
||||
eventTypeId,
|
||||
eventTypeSlug,
|
||||
reqBodyUser,
|
||||
reqBodyMetadata,
|
||||
reqBodyRecurringEventId,
|
||||
uid,
|
||||
responses,
|
||||
isConfirmedByDefault,
|
||||
smsReminderNumber,
|
||||
organizerUser,
|
||||
rescheduleReason,
|
||||
eventType,
|
||||
bookerEmail,
|
||||
paymentAppData,
|
||||
changedOrganizer,
|
||||
}: {
|
||||
originalRescheduledBooking: Awaited<ReturnType<typeof getOriginalRescheduledBooking>>;
|
||||
evt: CalendarEvent;
|
||||
eventType: NewBookingEventType;
|
||||
eventTypeId: Awaited<ReturnType<typeof getBookingData>>["eventTypeId"];
|
||||
eventTypeSlug: Awaited<ReturnType<typeof getBookingData>>["eventTypeSlug"];
|
||||
reqBodyUser: ReqBodyWithEnd["user"];
|
||||
reqBodyMetadata: ReqBodyWithEnd["metadata"];
|
||||
reqBodyRecurringEventId: ReqBodyWithEnd["recurringEventId"];
|
||||
uid: short.SUUID;
|
||||
responses: ReqBodyWithEnd["responses"] | null;
|
||||
isConfirmedByDefault: ReturnType<typeof getRequiresConfirmationFlags>["isConfirmedByDefault"];
|
||||
smsReminderNumber: Awaited<ReturnType<typeof getBookingData>>["smsReminderNumber"];
|
||||
organizerUser: Awaited<ReturnType<typeof loadUsers>>[number] & {
|
||||
isFixed?: boolean;
|
||||
metadata?: Prisma.JsonValue;
|
||||
};
|
||||
rescheduleReason: Awaited<ReturnType<typeof getBookingData>>["rescheduleReason"];
|
||||
bookerEmail: Awaited<ReturnType<typeof getBookingData>>["email"];
|
||||
paymentAppData: ReturnType<typeof getPaymentAppData>;
|
||||
changedOrganizer: boolean;
|
||||
}) {
|
||||
if (originalRescheduledBooking) {
|
||||
evt.title = originalRescheduledBooking?.title || evt.title;
|
||||
evt.description = originalRescheduledBooking?.description || evt.description;
|
||||
evt.location = originalRescheduledBooking?.location || evt.location;
|
||||
evt.location = changedOrganizer ? evt.location : originalRescheduledBooking?.location || evt.location;
|
||||
}
|
||||
|
||||
const eventTypeRel = !eventTypeId
|
||||
? {}
|
||||
: {
|
||||
connect: {
|
||||
id: eventTypeId,
|
||||
},
|
||||
};
|
||||
|
||||
const dynamicEventSlugRef = !eventTypeId ? eventTypeSlug : null;
|
||||
const dynamicGroupSlugRef = !eventTypeId ? (reqBodyUser as string).toLowerCase() : null;
|
||||
|
||||
const attendeesData = evt.attendees.map((attendee) => {
|
||||
//if attendee is team member, it should fetch their locale not booker's locale
|
||||
//perhaps make email fetch request to see if his locale is stored, else
|
||||
return {
|
||||
name: attendee.name,
|
||||
email: attendee.email,
|
||||
timeZone: attendee.timeZone,
|
||||
locale: attendee.language.locale,
|
||||
};
|
||||
});
|
||||
|
||||
if (evt.team?.members) {
|
||||
attendeesData.push(
|
||||
...evt.team.members.map((member) => ({
|
||||
email: member.email,
|
||||
name: member.name,
|
||||
timeZone: member.timeZone,
|
||||
locale: member.language.locale,
|
||||
}))
|
||||
);
|
||||
}
|
||||
|
||||
const newBookingData: Prisma.BookingCreateInput = {
|
||||
uid,
|
||||
responses: responses === null ? Prisma.JsonNull : responses,
|
||||
title: evt.title,
|
||||
startTime: dayjs.utc(evt.startTime).toDate(),
|
||||
endTime: dayjs.utc(evt.endTime).toDate(),
|
||||
description: evt.additionalNotes,
|
||||
customInputs: isPrismaObjOrUndefined(evt.customInputs),
|
||||
status: isConfirmedByDefault ? BookingStatus.ACCEPTED : BookingStatus.PENDING,
|
||||
location: evt.location,
|
||||
eventType: eventTypeRel,
|
||||
smsReminderNumber,
|
||||
metadata: reqBodyMetadata,
|
||||
attendees: {
|
||||
createMany: {
|
||||
data: attendeesData,
|
||||
},
|
||||
},
|
||||
dynamicEventSlugRef,
|
||||
dynamicGroupSlugRef,
|
||||
user: {
|
||||
connect: {
|
||||
id: organizerUser.id,
|
||||
},
|
||||
},
|
||||
destinationCalendar:
|
||||
evt.destinationCalendar && evt.destinationCalendar.length > 0
|
||||
? {
|
||||
connect: { id: evt.destinationCalendar[0].id },
|
||||
}
|
||||
: undefined,
|
||||
};
|
||||
|
||||
if (reqBodyRecurringEventId) {
|
||||
newBookingData.recurringEventId = reqBodyRecurringEventId;
|
||||
}
|
||||
if (originalRescheduledBooking) {
|
||||
newBookingData.metadata = {
|
||||
...(typeof originalRescheduledBooking.metadata === "object" && originalRescheduledBooking.metadata),
|
||||
};
|
||||
newBookingData["paid"] = originalRescheduledBooking.paid;
|
||||
newBookingData["fromReschedule"] = originalRescheduledBooking.uid;
|
||||
if (originalRescheduledBooking.uid) {
|
||||
newBookingData.cancellationReason = rescheduleReason;
|
||||
}
|
||||
if (newBookingData.attendees?.createMany?.data) {
|
||||
// Reschedule logic with booking with seats
|
||||
if (eventType?.seatsPerTimeSlot && bookerEmail) {
|
||||
newBookingData.attendees.createMany.data = attendeesData.filter(
|
||||
(attendee) => attendee.email === bookerEmail
|
||||
);
|
||||
}
|
||||
}
|
||||
if (originalRescheduledBooking.recurringEventId) {
|
||||
newBookingData.recurringEventId = originalRescheduledBooking.recurringEventId;
|
||||
}
|
||||
}
|
||||
const createBookingObj = {
|
||||
include: {
|
||||
user: {
|
||||
select: { email: true, name: true, timeZone: true, username: true },
|
||||
},
|
||||
attendees: true,
|
||||
payment: true,
|
||||
references: true,
|
||||
},
|
||||
data: newBookingData,
|
||||
};
|
||||
|
||||
if (originalRescheduledBooking?.paid && originalRescheduledBooking?.payment) {
|
||||
const bookingPayment = originalRescheduledBooking?.payment?.find((payment) => payment.success);
|
||||
|
||||
if (bookingPayment) {
|
||||
createBookingObj.data.payment = {
|
||||
connect: { id: bookingPayment.id },
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
if (typeof paymentAppData.price === "number" && paymentAppData.price > 0) {
|
||||
/* Validate if there is any payment app credential for this user */
|
||||
await prisma.credential.findFirstOrThrow({
|
||||
where: {
|
||||
appId: paymentAppData.appId,
|
||||
...(paymentAppData.credentialId ? { id: paymentAppData.credentialId } : { userId: organizerUser.id }),
|
||||
},
|
||||
select: {
|
||||
id: true,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
return prisma.booking.create(createBookingObj);
|
||||
}
|
||||
|
||||
function getCustomInputsResponses(
|
||||
reqBody: {
|
||||
responses?: Record<string, object>;
|
||||
|
@ -781,54 +946,11 @@ async function handler(
|
|||
throw new HttpError({ statusCode: 400, message: error.message });
|
||||
}
|
||||
|
||||
const loadUsers = async () => {
|
||||
try {
|
||||
if (!eventTypeId) {
|
||||
if (!Array.isArray(dynamicUserList) || dynamicUserList.length === 0) {
|
||||
throw new Error("dynamicUserList is not properly defined or empty.");
|
||||
}
|
||||
|
||||
const users = await prisma.user.findMany({
|
||||
where: {
|
||||
username: { in: dynamicUserList },
|
||||
organization: userOrgQuery(req.headers.host ? req.headers.host.replace(/^https?:\/\//, "") : ""),
|
||||
},
|
||||
select: {
|
||||
...userSelect.select,
|
||||
credentials: {
|
||||
select: credentialForCalendarServiceSelect,
|
||||
},
|
||||
metadata: true,
|
||||
},
|
||||
});
|
||||
|
||||
return users;
|
||||
} else {
|
||||
const hosts = eventType.hosts || [];
|
||||
|
||||
if (!Array.isArray(hosts)) {
|
||||
throw new Error("eventType.hosts is not properly defined.");
|
||||
}
|
||||
|
||||
const users = hosts.map(({ user, isFixed }) => ({
|
||||
...user,
|
||||
isFixed,
|
||||
}));
|
||||
|
||||
return users.length ? users : eventType.users;
|
||||
}
|
||||
} catch (error) {
|
||||
if (error instanceof HttpError || error instanceof Prisma.PrismaClientKnownRequestError) {
|
||||
throw new HttpError({ statusCode: 400, message: error.message });
|
||||
}
|
||||
throw new HttpError({ statusCode: 500, message: "Unable to load users" });
|
||||
}
|
||||
};
|
||||
// loadUsers allows type inferring
|
||||
let users: (Awaited<ReturnType<typeof loadUsers>>[number] & {
|
||||
isFixed?: boolean;
|
||||
metadata?: Prisma.JsonValue;
|
||||
})[] = await loadUsers();
|
||||
})[] = await loadUsers(eventType, dynamicUserList, req.headers.host);
|
||||
|
||||
const isDynamicAllowed = !users.some((user) => !user.allowDynamicBooking);
|
||||
if (!isDynamicAllowed && !eventTypeId) {
|
||||
|
@ -1923,147 +2045,9 @@ async function handler(
|
|||
eventType.schedulingType === SchedulingType.ROUND_ROBIN &&
|
||||
originalRescheduledBooking.userId !== evt.organizer.id;
|
||||
|
||||
async function createBooking() {
|
||||
if (originalRescheduledBooking) {
|
||||
evt.title = originalRescheduledBooking?.title || evt.title;
|
||||
evt.description = originalRescheduledBooking?.description || evt.description;
|
||||
evt.location = changedOrganizer ? evt.location : originalRescheduledBooking?.location || evt.location;
|
||||
}
|
||||
|
||||
const eventTypeRel = !eventTypeId
|
||||
? {}
|
||||
: {
|
||||
connect: {
|
||||
id: eventTypeId,
|
||||
},
|
||||
};
|
||||
|
||||
const dynamicEventSlugRef = !eventTypeId ? eventTypeSlug : null;
|
||||
const dynamicGroupSlugRef = !eventTypeId ? (reqBody.user as string).toLowerCase() : null;
|
||||
|
||||
const attendeesData = evt.attendees.map((attendee) => {
|
||||
//if attendee is team member, it should fetch their locale not booker's locale
|
||||
//perhaps make email fetch request to see if his locale is stored, else
|
||||
return {
|
||||
name: attendee.name,
|
||||
email: attendee.email,
|
||||
timeZone: attendee.timeZone,
|
||||
locale: attendee.language.locale,
|
||||
};
|
||||
});
|
||||
|
||||
if (evt.team?.members) {
|
||||
attendeesData.push(
|
||||
...evt.team.members.map((member) => ({
|
||||
email: member.email,
|
||||
name: member.name,
|
||||
timeZone: member.timeZone,
|
||||
locale: member.language.locale,
|
||||
}))
|
||||
);
|
||||
}
|
||||
|
||||
const newBookingData: Prisma.BookingCreateInput = {
|
||||
uid,
|
||||
responses: responses === null ? Prisma.JsonNull : responses,
|
||||
title: evt.title,
|
||||
startTime: dayjs.utc(evt.startTime).toDate(),
|
||||
endTime: dayjs.utc(evt.endTime).toDate(),
|
||||
description: evt.additionalNotes,
|
||||
customInputs: isPrismaObjOrUndefined(evt.customInputs),
|
||||
status: isConfirmedByDefault ? BookingStatus.ACCEPTED : BookingStatus.PENDING,
|
||||
location: evt.location,
|
||||
eventType: eventTypeRel,
|
||||
smsReminderNumber,
|
||||
metadata: reqBody.metadata,
|
||||
attendees: {
|
||||
createMany: {
|
||||
data: attendeesData,
|
||||
},
|
||||
},
|
||||
dynamicEventSlugRef,
|
||||
dynamicGroupSlugRef,
|
||||
user: {
|
||||
connect: {
|
||||
id: organizerUser.id,
|
||||
},
|
||||
},
|
||||
destinationCalendar:
|
||||
evt.destinationCalendar && evt.destinationCalendar.length > 0
|
||||
? {
|
||||
connect: { id: evt.destinationCalendar[0].id },
|
||||
}
|
||||
: undefined,
|
||||
};
|
||||
|
||||
if (reqBody.recurringEventId) {
|
||||
newBookingData.recurringEventId = reqBody.recurringEventId;
|
||||
}
|
||||
if (originalRescheduledBooking) {
|
||||
newBookingData.metadata = {
|
||||
...(typeof originalRescheduledBooking.metadata === "object" && originalRescheduledBooking.metadata),
|
||||
};
|
||||
newBookingData["paid"] = originalRescheduledBooking.paid;
|
||||
newBookingData["fromReschedule"] = originalRescheduledBooking.uid;
|
||||
if (originalRescheduledBooking.uid) {
|
||||
newBookingData.cancellationReason = rescheduleReason;
|
||||
}
|
||||
if (newBookingData.attendees?.createMany?.data) {
|
||||
// Reschedule logic with booking with seats
|
||||
if (eventType?.seatsPerTimeSlot && bookerEmail) {
|
||||
newBookingData.attendees.createMany.data = attendeesData.filter(
|
||||
(attendee) => attendee.email === bookerEmail
|
||||
);
|
||||
}
|
||||
}
|
||||
if (originalRescheduledBooking.recurringEventId) {
|
||||
newBookingData.recurringEventId = originalRescheduledBooking.recurringEventId;
|
||||
}
|
||||
}
|
||||
const createBookingObj = {
|
||||
include: {
|
||||
user: {
|
||||
select: { email: true, name: true, timeZone: true, username: true },
|
||||
},
|
||||
attendees: true,
|
||||
payment: true,
|
||||
references: true,
|
||||
},
|
||||
data: newBookingData,
|
||||
};
|
||||
|
||||
if (originalRescheduledBooking?.paid && originalRescheduledBooking?.payment) {
|
||||
const bookingPayment = originalRescheduledBooking?.payment?.find((payment) => payment.success);
|
||||
|
||||
if (bookingPayment) {
|
||||
createBookingObj.data.payment = {
|
||||
connect: { id: bookingPayment.id },
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
if (typeof paymentAppData.price === "number" && paymentAppData.price > 0) {
|
||||
/* Validate if there is any payment app credential for this user */
|
||||
await prisma.credential.findFirstOrThrow({
|
||||
where: {
|
||||
appId: paymentAppData.appId,
|
||||
...(paymentAppData.credentialId
|
||||
? { id: paymentAppData.credentialId }
|
||||
: { userId: organizerUser.id }),
|
||||
},
|
||||
select: {
|
||||
id: true,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
return prisma.booking.create(createBookingObj);
|
||||
}
|
||||
|
||||
let results: EventResult<AdditionalInformation & { url?: string; iCalUID?: string }>[] = [];
|
||||
let referencesToCreate: PartialReference[] = [];
|
||||
|
||||
type Booking = Prisma.PromiseReturnType<typeof createBooking>;
|
||||
let booking: (Booking & { appsStatus?: AppsStatus[] }) | null = null;
|
||||
loggerWithEventDetails.debug(
|
||||
"Going to create booking in DB now",
|
||||
|
@ -2077,7 +2061,25 @@ async function handler(
|
|||
);
|
||||
|
||||
try {
|
||||
booking = await createBooking();
|
||||
booking = await createBooking({
|
||||
originalRescheduledBooking,
|
||||
evt,
|
||||
eventTypeId,
|
||||
eventTypeSlug,
|
||||
reqBodyUser: reqBody.user,
|
||||
reqBodyMetadata: reqBody.metadata,
|
||||
reqBodyRecurringEventId: reqBody.recurringEventId,
|
||||
uid,
|
||||
responses,
|
||||
isConfirmedByDefault,
|
||||
smsReminderNumber,
|
||||
organizerUser,
|
||||
rescheduleReason,
|
||||
eventType,
|
||||
bookerEmail,
|
||||
paymentAppData,
|
||||
changedOrganizer,
|
||||
});
|
||||
|
||||
// @NOTE: Add specific try catch for all subsequent async calls to avoid error
|
||||
// Sync Services
|
||||
|
|
|
@ -67,7 +67,7 @@ const CalendarSwitch = (props: ICalendarSwitchProps) => {
|
|||
},
|
||||
onError() {
|
||||
setCheckedInternal(false);
|
||||
showToast(`Something went wrong when toggling "${title}""`, "error");
|
||||
showToast(`Something went wrong when toggling "${title}"`, "error");
|
||||
},
|
||||
}
|
||||
);
|
||||
|
@ -77,9 +77,10 @@ const CalendarSwitch = (props: ICalendarSwitchProps) => {
|
|||
<Switch
|
||||
id={externalId}
|
||||
checked={checkedInternal}
|
||||
onCheckedChange={(isOn: boolean) => {
|
||||
disabled={mutation.isLoading}
|
||||
onCheckedChange={async (isOn: boolean) => {
|
||||
setCheckedInternal(isOn);
|
||||
mutation.mutate({ isOn });
|
||||
await mutation.mutate({ isOn });
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
|
|
|
@ -14,6 +14,7 @@ import { HttpError as HttpCode } from "@calcom/lib/http-error";
|
|||
import logger from "@calcom/lib/logger";
|
||||
import { getBooking } from "@calcom/lib/payment/getBooking";
|
||||
import { handlePaymentSuccess } from "@calcom/lib/payment/handlePaymentSuccess";
|
||||
import { safeStringify } from "@calcom/lib/safeStringify";
|
||||
import { prisma } from "@calcom/prisma";
|
||||
import { BookingStatus } from "@calcom/prisma/enums";
|
||||
|
||||
|
@ -38,7 +39,7 @@ export async function handleStripePaymentSuccess(event: Stripe.Event) {
|
|||
});
|
||||
|
||||
if (!payment?.bookingId) {
|
||||
log.error(JSON.stringify(paymentIntent), JSON.stringify(payment));
|
||||
log.error("Stripe: Payment Not Found", safeStringify(paymentIntent), safeStringify(payment));
|
||||
throw new HttpCode({ statusCode: 204, message: "Payment not found" });
|
||||
}
|
||||
if (!payment?.bookingId) throw new HttpCode({ statusCode: 204, message: "Payment not found" });
|
||||
|
|
|
@ -44,7 +44,7 @@ export function UpgradeTip({
|
|||
<picture className="absolute min-h-[295px] w-full rounded-lg object-cover">
|
||||
<source srcSet={`${background}-dark.jpg`} media="(prefers-color-scheme: dark)" />
|
||||
<img
|
||||
className="absolute min-h-[295px] w-full rounded-lg object-cover object-left md:object-center"
|
||||
className="absolute min-h-[295px] w-full rounded-lg object-cover object-left md:object-center select-none"
|
||||
src={`${background}.jpg`}
|
||||
loading="lazy"
|
||||
alt={title}
|
||||
|
|
|
@ -4,6 +4,7 @@ import { v4 } from "uuid";
|
|||
import { getHumanReadableLocationValue } from "@calcom/core/location";
|
||||
import { getCalEventResponses } from "@calcom/features/bookings/lib/getCalEventResponses";
|
||||
import logger from "@calcom/lib/logger";
|
||||
import { safeStringify } from "@calcom/lib/safeStringify";
|
||||
import { getTranslation } from "@calcom/lib/server";
|
||||
import prisma from "@calcom/prisma";
|
||||
import type { ApiKey } from "@calcom/prisma/client";
|
||||
|
@ -75,7 +76,10 @@ export async function addSubscription({
|
|||
const userId = appApiKey ? appApiKey.userId : account && !account.isTeam ? account.id : null;
|
||||
const teamId = appApiKey ? appApiKey.teamId : account && account.isTeam ? account.id : null;
|
||||
|
||||
log.error(`Error creating subscription for ${teamId ? `team ${teamId}` : `user ${userId}`}.`);
|
||||
log.error(
|
||||
`Error creating subscription for ${teamId ? `team ${teamId}` : `user ${userId}`}.`,
|
||||
safeStringify(error)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -157,7 +161,8 @@ export async function deleteSubscription({
|
|||
log.error(
|
||||
`Error deleting subscription for user ${
|
||||
teamId ? `team ${teamId}` : `userId ${userId}`
|
||||
}, webhookId ${webhookId}`
|
||||
}, webhookId ${webhookId}`,
|
||||
safeStringify(err)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -260,7 +265,10 @@ export async function listBookings(
|
|||
const userId = appApiKey ? appApiKey.userId : account && !account.isTeam ? account.id : null;
|
||||
const teamId = appApiKey ? appApiKey.teamId : account && account.isTeam ? account.id : null;
|
||||
|
||||
log.error(`Error retrieving list of bookings for ${teamId ? `team ${teamId}` : `user ${userId}`}.`);
|
||||
log.error(
|
||||
`Error retrieving list of bookings for ${teamId ? `team ${teamId}` : `user ${userId}`}.`,
|
||||
safeStringify(err)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -32,7 +32,7 @@ export function deriveAppDictKeyFromType(appType: string, dict: Record<string, u
|
|||
|
||||
return appType;
|
||||
|
||||
// const categories = ["video", "other", "calendar", "web3", "payment", "messaging"];
|
||||
// const categories = ["video", "other", "calendar", "payment", "messaging"];
|
||||
|
||||
// // Instead of doing a blind split at _ and using the first part, apply this hack only on strings that match legacy type.
|
||||
// // Transform zoomvideo to zoom
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
import { Prisma } from "@prisma/client";
|
||||
|
||||
import logger from "@calcom/lib/logger";
|
||||
import { safeStringify } from "@calcom/lib/safeStringify";
|
||||
|
||||
const log = logger.getSubLogger({ prefix: [`[[redactError]`] });
|
||||
|
||||
|
@ -19,7 +20,7 @@ export const redactError = <T extends Error | unknown>(error: T) => {
|
|||
}
|
||||
log.debug("Type of Error: ", error.constructor);
|
||||
if (shouldRedact(error)) {
|
||||
log.error("Error: ", JSON.stringify(error));
|
||||
log.error("Error: ", safeStringify(error));
|
||||
return new Error("An error occured while querying the database.");
|
||||
}
|
||||
return error;
|
||||
|
|
|
@ -217,46 +217,49 @@ export async function createNewUsersConnectToOrgIfExists({
|
|||
autoAcceptEmailDomain?: string;
|
||||
connectionInfoMap: Record<string, ReturnType<typeof getOrgConnectionInfo>>;
|
||||
}) {
|
||||
await prisma.$transaction(async (tx) => {
|
||||
for (let index = 0; index < usernamesOrEmails.length; index++) {
|
||||
const usernameOrEmail = usernamesOrEmails[index];
|
||||
const { orgId, autoAccept } = connectionInfoMap[usernameOrEmail];
|
||||
const [emailUser, emailDomain] = usernameOrEmail.split("@");
|
||||
const username =
|
||||
emailDomain === autoAcceptEmailDomain
|
||||
? slugify(emailUser)
|
||||
: slugify(`${emailUser}-${emailDomain.split(".")[0]}`);
|
||||
await prisma.$transaction(
|
||||
async (tx) => {
|
||||
for (let index = 0; index < usernamesOrEmails.length; index++) {
|
||||
const usernameOrEmail = usernamesOrEmails[index];
|
||||
const { orgId, autoAccept } = connectionInfoMap[usernameOrEmail];
|
||||
const [emailUser, emailDomain] = usernameOrEmail.split("@");
|
||||
const username =
|
||||
emailDomain === autoAcceptEmailDomain
|
||||
? slugify(emailUser)
|
||||
: slugify(`${emailUser}-${emailDomain.split(".")[0]}`);
|
||||
|
||||
const createdUser = await tx.user.create({
|
||||
data: {
|
||||
username,
|
||||
email: usernameOrEmail,
|
||||
verified: true,
|
||||
invitedTo: input.teamId,
|
||||
organizationId: orgId || null, // If the user is invited to a child team, they are automatically added to the parent org
|
||||
teams: {
|
||||
create: {
|
||||
teamId: input.teamId,
|
||||
role: input.role as MembershipRole,
|
||||
accepted: autoAccept, // If the user is invited to a child team, they are automatically accepted
|
||||
const createdUser = await tx.user.create({
|
||||
data: {
|
||||
username,
|
||||
email: usernameOrEmail,
|
||||
verified: true,
|
||||
invitedTo: input.teamId,
|
||||
organizationId: orgId || null, // If the user is invited to a child team, they are automatically added to the parent org
|
||||
teams: {
|
||||
create: {
|
||||
teamId: input.teamId,
|
||||
role: input.role as MembershipRole,
|
||||
accepted: autoAccept, // If the user is invited to a child team, they are automatically accepted
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
// We also need to create the membership in the parent org if it exists
|
||||
if (parentId) {
|
||||
await tx.membership.create({
|
||||
data: {
|
||||
teamId: parentId,
|
||||
userId: createdUser.id,
|
||||
role: input.role as MembershipRole,
|
||||
accepted: autoAccept,
|
||||
},
|
||||
});
|
||||
|
||||
// We also need to create the membership in the parent org if it exists
|
||||
if (parentId) {
|
||||
await tx.membership.create({
|
||||
data: {
|
||||
teamId: parentId,
|
||||
userId: createdUser.id,
|
||||
role: input.role as MembershipRole,
|
||||
accepted: autoAccept,
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
},
|
||||
{ timeout: 10000 }
|
||||
);
|
||||
}
|
||||
|
||||
export async function createProvisionalMemberships({
|
||||
|
|
|
@ -63,7 +63,6 @@ export interface App {
|
|||
| `${string}_messaging`
|
||||
| `${string}_payment`
|
||||
| `${string}_video`
|
||||
| `${string}_web3`
|
||||
| `${string}_other`
|
||||
| `${string}_automation`
|
||||
| `${string}_analytics`
|
||||
|
@ -80,15 +79,7 @@ export interface App {
|
|||
/** A brief description, usually found in the app's package.json */
|
||||
description: string;
|
||||
/** TODO determine if we should use this instead of category */
|
||||
variant:
|
||||
| "calendar"
|
||||
| "payment"
|
||||
| "conferencing"
|
||||
| "video"
|
||||
| "other"
|
||||
| "other_calendar"
|
||||
| "web3"
|
||||
| "automation";
|
||||
variant: "calendar" | "payment" | "conferencing" | "video" | "other" | "other_calendar" | "automation";
|
||||
/** The slug for the app store public page inside `/apps/[slug] */
|
||||
slug: string;
|
||||
|
||||
|
|
Loading…
Reference in New Issue
Block a user