Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
38d242add9 | ||
|
|
c272e281cf | ||
|
|
d4e19b0fa4 | ||
|
|
c12877a58f | ||
|
|
af83350d04 | ||
|
|
9d0cf6be0b | ||
|
|
2fe9c782d4 | ||
|
|
d0a3d8d144 | ||
|
|
cefcb1eaf8 | ||
|
|
83b60de640 | ||
|
|
a076418989 | ||
|
|
64ecce1ccb | ||
|
|
cd56a5d4f0 | ||
|
|
d5ca121ac6 | ||
|
|
1e20e80b65 | ||
|
|
75ac3fd40c | ||
|
|
3b91cc7f02 | ||
|
|
23450b61e0 | ||
|
|
dcc226976c | ||
|
|
196fde72f6 | ||
|
|
1e913cd406 | ||
|
|
02425702d1 | ||
|
|
2494655369 | ||
|
|
0e0a78c47e | ||
|
|
ed02c10f54 | ||
|
|
9c40f76184 | ||
|
|
8eda30d88c | ||
|
|
9de19d35a8 | ||
|
|
0770403ca5 | ||
|
|
1a45cb35c1 | ||
|
|
15cdff76d9 | ||
|
|
8c4eb4b5fe | ||
|
|
ae30aafafe | ||
|
|
3b74717591 | ||
|
|
7a6349b4c0 | ||
|
|
3b51fff88d | ||
|
+5 |
2a0b0be9d0 | ||
|
|
f373c9d818 | ||
|
|
540bf3a1cb | ||
|
|
2d9064e92f | ||
|
|
9487819ec1 | ||
|
|
49bf14b196 | ||
|
|
344f16d6cc | ||
|
|
ccbf3b1e54 | ||
|
|
dcf0fad35d | ||
|
|
a836800c69 | ||
|
|
b8c6ac43f7 | ||
|
|
f5e0c6b384 | ||
|
|
2a5dd9035f | ||
|
|
2cddad4336 | ||
|
|
4bcbff51b1 | ||
|
|
ae541e4c37 | ||
|
|
f254711d85 | ||
|
|
533e208643 | ||
|
|
795574ef88 | ||
|
|
48611d5c99 | ||
|
|
11a07961d0 | ||
|
|
6be0fd52e7 | ||
|
|
78da7ba338 | ||
|
|
9a72c648c5 | ||
|
|
3e42da7fc7 | ||
|
|
1d986cad04 | ||
|
|
f603e4eff2 | ||
|
|
1f4e6c1987 | ||
|
|
e57f734e79 | ||
|
|
7fad76ae23 | ||
|
|
7659a016b4 | ||
|
|
34fe1c4a95 | ||
|
|
205f73c4bc | ||
|
|
c4bd2167e1 | ||
|
|
49a7111b66 | ||
|
|
ca045a040b | ||
|
|
a8b4198bf7 | ||
|
|
2ab24e530b | ||
|
|
734b06dfdf | ||
|
|
467084993b | ||
|
|
1e2c8516d2 | ||
|
|
d57738f325 | ||
|
|
c39a7dba85 | ||
|
|
fd37397e5c | ||
|
|
df0a522656 | ||
|
|
916468b8cc | ||
|
|
b789e58624 | ||
|
|
4368536141 | ||
|
|
9eef9766ce | ||
|
|
68dbfbd7d0 | ||
|
|
692a84a86e | ||
|
|
1671095c94 | ||
|
|
3b896bee5c | ||
|
|
cc1985442e | ||
|
|
630f438b32 | ||
|
|
6fae01d45a | ||
|
|
7009373b11 | ||
|
|
c2f150dbab | ||
|
|
688541923b | ||
|
|
20402ac26c | ||
|
|
a54952b41a | ||
|
|
987756c4d4 | ||
|
|
3ee294ffc5 | ||
|
|
a638708871 | ||
|
|
3456cc5521 | ||
|
|
546f0c3881 | ||
|
|
7b18272d60 | ||
|
|
cf6efabdbb | ||
|
|
92d15a00f5 | ||
|
|
2f2b72dd54 | ||
|
|
8fd5d6b5b5 | ||
|
|
2078f12a85 | ||
|
|
77b8eb8a7f | ||
|
|
463787b607 | ||
|
|
1f4e7ca695 | ||
|
|
9eb52bbfb2 | ||
|
|
61e6f76bc6 | ||
|
|
2e6c3a6068 | ||
|
|
8f48ecafec | ||
|
|
8849d1148c | ||
|
|
98a4684a2b | ||
|
|
da0bdfacae | ||
|
|
68c7425922 | ||
|
|
c3418cbe1f | ||
|
|
3a641e0bc1 | ||
|
|
b7fcf6ade1 | ||
|
|
53d160e495 | ||
|
|
df4df6846b | ||
|
|
c1bbb9b139 | ||
|
|
56c07ec351 | ||
|
|
3080b47aec | ||
|
|
c1e23bfdc6 | ||
|
|
e7ff5508d7 | ||
|
|
5850d227ee | ||
|
|
ede987ba19 | ||
|
|
bc0d83164c | ||
|
|
30f0b080c5 | ||
|
|
ee39ea316f | ||
|
|
fbc2708259 | ||
|
|
9bb83aba7e | ||
|
|
3a67e5617e | ||
|
|
f401aa7669 | ||
|
|
a6e0678e59 | ||
|
|
e832015f26 | ||
|
|
5e86881e15 | ||
|
|
3b71f98460 | ||
|
|
144d57adb2 | ||
|
|
e1f1c15318 | ||
|
|
d88b1b2f8f | ||
|
|
2e61c15f2c | ||
|
|
df73473c7f | ||
|
|
7167973afd | ||
|
|
3c17bc2d1a | ||
|
|
a9a295dc54 | ||
|
+2 |
21dd1f4e95 |
+5
-3
@@ -7,14 +7,13 @@
|
||||
# - E-MAIL SETTINGS
|
||||
|
||||
# - LICENSE *************************************************************************************************
|
||||
# Set this value to 'agree' to accept our license:
|
||||
# LICENSE: https://github.com/calendso/calendso/blob/main/LICENSE
|
||||
# https://github.com/calendso/calendso/blob/main/LICENSE
|
||||
#
|
||||
# Summary of terms:
|
||||
# - The codebase has to stay open source, whether it was modified or not
|
||||
# - You can not repackage or sell the codebase
|
||||
# - Acquire a commercial license to remove these terms by visiting: cal.com/sales
|
||||
NEXT_PUBLIC_LICENSE_CONSENT=''
|
||||
#
|
||||
# To enable enterprise-only features, fill your license key in here.
|
||||
# @see https://console.cal.com
|
||||
CALCOM_LICENSE_KEY=
|
||||
@@ -86,6 +85,9 @@ SENDGRID_EMAIL=
|
||||
TWILIO_SID=
|
||||
TWILIO_TOKEN=
|
||||
TWILIO_MESSAGING_SID=
|
||||
TWILIO_PHONE_NUMBER=
|
||||
NEXT_PUBLIC_SENDER_ID=
|
||||
TWILIO_VERIFY_SID=
|
||||
|
||||
# This is used so we can bypass emails in auth flows for E2E testing
|
||||
# Set it to "1" if you need to run E2E tests locally
|
||||
|
||||
@@ -3,3 +3,10 @@
|
||||
|
||||
automerge:
|
||||
- apps/web/public/static/locales/**/*.json
|
||||
|
||||
"❗️ migrations":
|
||||
- packages/prisma/migrations/**/migration.sql
|
||||
|
||||
"❗️ .env changes":
|
||||
- .env.example
|
||||
- .env.appStore.example
|
||||
|
||||
@@ -12,8 +12,5 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/labeler@v4
|
||||
# Checking the actor will prevent your Action run failing on non-Dependabot
|
||||
# PRs but also ensures that it only does work for Dependabot PRs.
|
||||
if: ${{ github.actor == 'github-actions[bot]' }}
|
||||
with:
|
||||
repo-token: "${{ secrets.GITHUB_TOKEN }}"
|
||||
|
||||
@@ -292,7 +292,7 @@ You can deploy Cal on [Railway](https://railway.app/) using the button above. Th
|
||||
|
||||
Currently Vercel Pro Plan is required to be able to Deploy this application with Vercel, due to limitations on the number of serverless functions on the free plan.
|
||||
|
||||
[](https://vercel.com/new/clone?repository-url=https%3A%2F%2Fgithub.com%2Fcalcom%2Fcal.com&env=DATABASE_URL,NEXT_PUBLIC_WEBAPP_URL,NEXTAUTH_URL,NEXTAUTH_SECRET,CRON_API_KEY,CALENDSO_ENCRYPTION_KEY,NEXT_PUBLIC_LICENSE_CONSENT&envDescription=See%20all%20available%20env%20vars&envLink=https%3A%2F%2Fgithub.com%2Fcalcom%2Fcal.com%2Fblob%2Fmain%2F.env.example&project-name=cal&repo-name=cal.com&build-command=cd%20../..%20%26%26%20yarn%20build&root-directory=apps%2Fweb%2F)
|
||||
[](https://vercel.com/new/clone?repository-url=https%3A%2F%2Fgithub.com%2Fcalcom%2Fcal.com&env=DATABASE_URL,NEXT_PUBLIC_WEBAPP_URL,NEXTAUTH_URL,NEXTAUTH_SECRET,CRON_API_KEY,CALENDSO_ENCRYPTION_KEY&envDescription=See%20all%20available%20env%20vars&envLink=https%3A%2F%2Fgithub.com%2Fcalcom%2Fcal.com%2Fblob%2Fmain%2F.env.example&project-name=cal&repo-name=cal.com&build-command=cd%20../..%20%26%26%20yarn%20build&root-directory=apps%2Fweb%2F)
|
||||
|
||||
<!-- ROADMAP -->
|
||||
|
||||
@@ -419,14 +419,18 @@ following
|
||||
2. Click ‘Get a Twilio phone number’
|
||||
3. Copy Account SID to your .env file into the TWILIO_SID field
|
||||
4. Copy Auth Token to your .env file into the TWILIO_TOKEN field
|
||||
5. Create a messaging service (Develop -> Messaging -> Services)
|
||||
6. Choose any name for the messaging service
|
||||
7. Click 'Add Senders'
|
||||
8. Choose phone number as sender type
|
||||
9. Add the listed phone number
|
||||
10. Leave all other fields as they are
|
||||
11. Complete setup and click ‘View my new Messaging Service’
|
||||
12. Copy Messaging Service SID to your .env file into the TWILIO_MESSAGING_SID field
|
||||
5. Copy your Twilio phone number to your .env file into the TWILIO_PHONE_NUMBER field
|
||||
6. Add your own sender id to the .env file into the NEXT_PUBLIC_SENDER_ID field (fallback is Cal)
|
||||
7. Create a messaging service (Develop -> Messaging -> Services)
|
||||
8. Choose any name for the messaging service
|
||||
9. Click 'Add Senders'
|
||||
10. Choose phone number as sender type
|
||||
11. Add the listed phone number
|
||||
12. Leave all other fields as they are
|
||||
13. Complete setup and click ‘View my new Messaging Service’
|
||||
14. Copy Messaging Service SID to your .env file into the TWILIO_MESSAGING_SID field
|
||||
15. Create a verify service
|
||||
16. Copy Verify Service SID to your .env file into the TWILIO_VERIFY_SID field
|
||||
|
||||
<!-- LICENSE -->
|
||||
|
||||
|
||||
@@ -33,11 +33,6 @@
|
||||
"generator": "secret",
|
||||
"required": "true"
|
||||
},
|
||||
"NEXT_PUBLIC_LICENSE_CONSENT": {
|
||||
"description": "License consent",
|
||||
"value": "true",
|
||||
"required": "true"
|
||||
},
|
||||
"CRON_API_KEY": {
|
||||
"description": "ApiKey for cronjobs",
|
||||
"value": ""
|
||||
|
||||
+1
-1
Submodule apps/api updated: 41d22c8ccb...604d937661
+1
-1
Submodule apps/console updated: d2445da9f5...2d577dd9ed
@@ -4,6 +4,7 @@ module.exports = {
|
||||
stories: [
|
||||
"../intro.stories.mdx",
|
||||
"../../../packages/ui/components/**/*.stories.mdx",
|
||||
"../../../packages/features/**/*.stories.mdx",
|
||||
"../../../packages/ui/components/**/*.stories.@(js|jsx|ts|tsx)",
|
||||
],
|
||||
addons: [
|
||||
@@ -50,6 +51,21 @@ module.exports = {
|
||||
vm: false,
|
||||
zlib: false,
|
||||
};
|
||||
|
||||
config.module.rules.push({
|
||||
test: /\.css$/,
|
||||
use: [
|
||||
"style-loader",
|
||||
{
|
||||
loader: "css-loader",
|
||||
options: {
|
||||
modules: true, // Enable modules to help you using className
|
||||
},
|
||||
},
|
||||
],
|
||||
include: path.resolve(__dirname, "../src"),
|
||||
});
|
||||
|
||||
return config;
|
||||
},
|
||||
};
|
||||
|
||||
@@ -15,7 +15,11 @@ export const parameters = {
|
||||
},
|
||||
};
|
||||
|
||||
addDecorator((storyFn) => <I18nextProvider i18n={i18n}>{storyFn()}</I18nextProvider>);
|
||||
addDecorator((storyFn) => (
|
||||
<I18nextProvider i18n={i18n}>
|
||||
<div style={{ margin: "2rem" }}>{storyFn()}</div>
|
||||
</I18nextProvider>
|
||||
));
|
||||
|
||||
window.getEmbedNamespace = () => {
|
||||
const url = new URL(document.URL);
|
||||
|
||||
@@ -2,4 +2,4 @@
|
||||
@tailwind components;
|
||||
@tailwind utilities;
|
||||
|
||||
@import "../../../packages/ui/styles/shared-globals.css"
|
||||
@import "../../../packages/ui/styles/shared-globals.css"
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
@import url("../../../packages/features/calendars/weeklyview/styles/styles.css");
|
||||
|
||||
.sbdocs {
|
||||
font-family: 'Inter var' !important;
|
||||
padding: 0!important;
|
||||
@@ -36,7 +38,7 @@
|
||||
|
||||
/** Docs table **/
|
||||
.custom-args-wrapper{
|
||||
max-height: 600px;
|
||||
max-height: 400px;
|
||||
overflow-y: scroll;
|
||||
overflow-x: hidden;
|
||||
margin-bottom: 1rem;
|
||||
@@ -187,3 +189,7 @@
|
||||
padding: 24px !important;
|
||||
}
|
||||
}
|
||||
|
||||
.docs-story {
|
||||
padding: 24px !important;
|
||||
}
|
||||
|
||||
@@ -44,6 +44,7 @@ type PreviewState = {
|
||||
palette: {
|
||||
brandColor: string;
|
||||
};
|
||||
hideEventTypeDetails: boolean;
|
||||
};
|
||||
const queryParamsForDialog = ["embedType", "embedTabName", "embedUrl"];
|
||||
|
||||
@@ -125,10 +126,12 @@ const getEmbedUIInstructionString = ({
|
||||
apiName,
|
||||
theme,
|
||||
brandColor,
|
||||
hideEventTypeDetails,
|
||||
}: {
|
||||
apiName: string;
|
||||
theme?: string;
|
||||
brandColor: string;
|
||||
hideEventTypeDetails: boolean;
|
||||
}) => {
|
||||
theme = theme !== "auto" ? theme : undefined;
|
||||
return getInstructionString({
|
||||
@@ -141,6 +144,7 @@ const getEmbedUIInstructionString = ({
|
||||
brandColor,
|
||||
},
|
||||
},
|
||||
hideEventTypeDetails: hideEventTypeDetails,
|
||||
},
|
||||
});
|
||||
};
|
||||
@@ -253,18 +257,21 @@ const getEmbedTypeSpecificString = ({
|
||||
apiName: string;
|
||||
theme: PreviewState["theme"];
|
||||
brandColor: string;
|
||||
hideEventTypeDetails: boolean;
|
||||
};
|
||||
if (embedFramework === "react") {
|
||||
uiInstructionStringArg = {
|
||||
apiName: "cal",
|
||||
theme: previewState.theme,
|
||||
brandColor: previewState.palette.brandColor,
|
||||
hideEventTypeDetails: previewState.hideEventTypeDetails,
|
||||
};
|
||||
} else {
|
||||
uiInstructionStringArg = {
|
||||
apiName: "Cal",
|
||||
theme: previewState.theme,
|
||||
brandColor: previewState.palette.brandColor,
|
||||
hideEventTypeDetails: previewState.hideEventTypeDetails,
|
||||
};
|
||||
}
|
||||
if (!frameworkCodes[embedType]) {
|
||||
@@ -689,6 +696,7 @@ const EmbedTypeCodeAndPreviewDialogContent = ({
|
||||
theme: Theme.auto,
|
||||
floatingPopup: {},
|
||||
elementClick: {},
|
||||
hideEventTypeDetails: false,
|
||||
palette: {
|
||||
brandColor: "#000000",
|
||||
},
|
||||
@@ -753,6 +761,7 @@ const EmbedTypeCodeAndPreviewDialogContent = ({
|
||||
name: "ui",
|
||||
arg: {
|
||||
theme: previewState.theme,
|
||||
hideEventTypeDetails: previewState.hideEventTypeDetails,
|
||||
styles: {
|
||||
branding: {
|
||||
...previewState.palette,
|
||||
@@ -811,7 +820,7 @@ const EmbedTypeCodeAndPreviewDialogContent = ({
|
||||
{embed.title}
|
||||
</h3>
|
||||
<hr className={classNames("mt-4", embedType === "element-click" ? "hidden" : "")} />
|
||||
<div className="max-h-97 flex flex-col overflow-y-auto">
|
||||
<div className="flex flex-col overflow-y-auto">
|
||||
<div className={classNames("mt-4 font-medium", embedType === "element-click" ? "hidden" : "")}>
|
||||
<Collapsible
|
||||
open={isEmbedCustomizationOpen}
|
||||
@@ -838,7 +847,6 @@ const EmbedTypeCodeAndPreviewDialogContent = ({
|
||||
<div className="text-sm">Embed Window Sizing</div>
|
||||
<div className="justify-left flex items-center">
|
||||
<TextField
|
||||
name="width"
|
||||
labelProps={{ className: "hidden" }}
|
||||
required
|
||||
value={previewState.inline.width}
|
||||
@@ -860,7 +868,6 @@ const EmbedTypeCodeAndPreviewDialogContent = ({
|
||||
<span className="p-2">×</span>
|
||||
<TextField
|
||||
labelProps={{ className: "hidden" }}
|
||||
name="height"
|
||||
value={previewState.inline.height}
|
||||
required
|
||||
onChange={(e) => {
|
||||
@@ -888,7 +895,6 @@ const EmbedTypeCodeAndPreviewDialogContent = ({
|
||||
<div className="mb-2 text-sm">Button Text</div>
|
||||
{/* Default Values should come from preview iframe */}
|
||||
<TextField
|
||||
name="buttonText"
|
||||
labelProps={{ className: "hidden" }}
|
||||
onChange={(e) => {
|
||||
setPreviewState((previewState) => {
|
||||
@@ -1004,6 +1010,20 @@ const EmbedTypeCodeAndPreviewDialogContent = ({
|
||||
</CollapsibleTrigger>
|
||||
<CollapsibleContent>
|
||||
<div className="mt-6 text-sm">
|
||||
<div className="mb-4 flex items-center justify-start space-x-2">
|
||||
<Switch
|
||||
checked={previewState.hideEventTypeDetails}
|
||||
onCheckedChange={(checked) => {
|
||||
setPreviewState((previewState) => {
|
||||
return {
|
||||
...previewState,
|
||||
hideEventTypeDetails: checked,
|
||||
};
|
||||
});
|
||||
}}
|
||||
/>
|
||||
<div className="text-sm">{t("hide_eventtype_details")}</div>
|
||||
</div>
|
||||
<Label className="">
|
||||
<div className="mb-2">Theme</div>
|
||||
<Select
|
||||
|
||||
@@ -66,7 +66,9 @@ const Component = ({
|
||||
}
|
||||
);
|
||||
|
||||
const allowedMultipleInstalls = categories.indexOf("calendar") > -1;
|
||||
// variant not other allows, an app to be shown in calendar category without requiring an actual calendar connection e.g. vimcal
|
||||
// Such apps, can only be installed once.
|
||||
const allowedMultipleInstalls = categories.indexOf("calendar") > -1 && variant !== "other";
|
||||
|
||||
return (
|
||||
<div className="relative flex-1 flex-col items-start justify-start px-4 md:flex md:px-8 lg:flex-row lg:px-0">
|
||||
|
||||
@@ -159,6 +159,7 @@ function ConnectedCalendarsList(props: Props) {
|
||||
if (!data.connectedCalendars.length) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<List className="flex flex-col gap-6" noBorderTreatment>
|
||||
{data.connectedCalendars.map((item) => (
|
||||
@@ -168,7 +169,7 @@ function ConnectedCalendarsList(props: Props) {
|
||||
slug={item.integration.slug}
|
||||
title={item.integration.title}
|
||||
logo={item.integration.logo}
|
||||
description={item.primary?.externalId || "No external Id"}
|
||||
description={item.primary?.email ?? item.integration.description}
|
||||
separate={true}
|
||||
actions={
|
||||
<div className="flex w-32 justify-end">
|
||||
|
||||
@@ -44,7 +44,7 @@ function IntegrationListItem(props: {
|
||||
expanded={!!props.children}
|
||||
className={classNames(
|
||||
props.separate ? "rounded-md" : "first:rounded-t-md last:rounded-b-md",
|
||||
"my-0 flex-col border transition-colors duration-500 ",
|
||||
"my-0 flex-col border transition-colors duration-500",
|
||||
highlight ? "bg-yellow-100" : ""
|
||||
)}>
|
||||
<div className={classNames("flex w-full flex-1 items-center space-x-2 p-4 rtl:space-x-reverse")}>
|
||||
|
||||
@@ -57,7 +57,7 @@ const AvailableTimes: FC<AvailableTimesProps> = ({
|
||||
{nameOfDay(i18n.language, Number(date.format("d")), "short")}
|
||||
</span>
|
||||
<span className="text-bookinglight font-medium">
|
||||
, {date.toDate().toLocaleString(i18n.language, { month: "long" })} {date.format(" D ")}
|
||||
, {date.toDate().toLocaleString(i18n.language, { month: "short" })} {date.format(" D ")}
|
||||
</span>
|
||||
</div>
|
||||
<div className="ml-auto">
|
||||
@@ -101,7 +101,8 @@ const AvailableTimes: FC<AvailableTimesProps> = ({
|
||||
}
|
||||
|
||||
return (
|
||||
<div key={dayjs(slot.time).format()}>
|
||||
<div data-slot-owner={(slot.userIds || []).join(",")} key={`${dayjs(slot.time).format()}`}>
|
||||
{/* ^ data-slot-owner is helpful in debugging and used to identify the owners of the slot. Owners are the users which have the timeslot in their schedule. It doesn't consider if a user has that timeslot booked */}
|
||||
{/* Current there is no way to disable Next.js Links */}
|
||||
{seatsPerTimeSlot && slot.attendees && slot.attendees >= seatsPerTimeSlot ? (
|
||||
<div
|
||||
|
||||
@@ -44,18 +44,17 @@ const BookingDescription: FC<Props> = (props) => {
|
||||
const { profile, eventType, isBookingPage = false, children } = props;
|
||||
const { date: bookingDate } = useRouterQuery("date");
|
||||
const { t } = useLocale();
|
||||
const { duration, setQuery: setDuration } = useRouterQuery("duration");
|
||||
const { duration = eventType.length.toString(), setQuery: setDuration } = useRouterQuery("duration");
|
||||
|
||||
useEffect(() => {
|
||||
if (eventType.metadata?.multipleDuration !== undefined) {
|
||||
if (!duration) {
|
||||
setDuration(eventType.length);
|
||||
} else {
|
||||
if (!eventType.metadata?.multipleDuration.includes(Number(duration))) {
|
||||
setDuration(eventType.length);
|
||||
}
|
||||
}
|
||||
if (
|
||||
eventType.metadata?.multipleDuration &&
|
||||
!eventType.metadata?.multipleDuration?.includes(Number(duration))
|
||||
) {
|
||||
setDuration(eventType.length.toString());
|
||||
}
|
||||
}, []);
|
||||
}, [duration, setDuration, eventType.length, eventType.metadata?.multipleDuration]);
|
||||
|
||||
let requiresConfirmation = eventType?.requiresConfirmation;
|
||||
let requiresConfirmationText = t("requires_confirmation");
|
||||
const rcThreshold = eventType?.metadata?.requiresConfirmationThreshold;
|
||||
|
||||
@@ -23,14 +23,14 @@ import {
|
||||
TextArea,
|
||||
Tooltip,
|
||||
} from "@calcom/ui";
|
||||
import { ActionType, TableActions } from "@calcom/ui";
|
||||
|
||||
import useMeQuery from "@lib/hooks/useMeQuery";
|
||||
|
||||
import { EditLocationDialog } from "@components/dialog/EditLocationDialog";
|
||||
import { RescheduleDialog } from "@components/dialog/RescheduleDialog";
|
||||
import TableActions, { ActionType } from "@components/ui/TableActions";
|
||||
|
||||
type BookingListingStatus = RouterInputs["viewer"]["bookings"]["get"]["status"];
|
||||
type BookingListingStatus = RouterInputs["viewer"]["bookings"]["get"]["filters"]["status"];
|
||||
|
||||
type BookingItem = RouterOutputs["viewer"]["bookings"]["get"]["bookings"][number];
|
||||
|
||||
@@ -158,6 +158,10 @@ function BookingListItem(booking: BookingItemProps) {
|
||||
bookedActions = bookedActions.filter((action) => action.id !== "edit_booking");
|
||||
}
|
||||
|
||||
if (isPast && isPending && !isConfirmed) {
|
||||
bookedActions = bookedActions.filter((action) => action.id !== "cancel");
|
||||
}
|
||||
|
||||
const RequestSentMessage = () => {
|
||||
return (
|
||||
<div className="ml-1 mr-8 flex text-gray-500" data-testid="request_reschedule_sent">
|
||||
@@ -248,7 +252,7 @@ function BookingListItem(booking: BookingItemProps) {
|
||||
</DialogContent>
|
||||
</Dialog>
|
||||
|
||||
<tr className="flex flex-col hover:bg-neutral-50 sm:flex-row">
|
||||
<tr className="group flex flex-col hover:bg-neutral-50 sm:flex-row">
|
||||
<td
|
||||
className="hidden align-top ltr:pl-6 rtl:pr-6 sm:table-cell sm:min-w-[12rem]"
|
||||
onClick={onClickTableData}>
|
||||
@@ -275,11 +279,6 @@ function BookingListItem(booking: BookingItemProps) {
|
||||
{booking.eventType.team.name}
|
||||
</Badge>
|
||||
)}
|
||||
{!!booking?.eventType?.price && !booking.paid && (
|
||||
<Badge className="ltr:mr-2 rtl:ml-2" variant="orange">
|
||||
{t("pending_payment")}
|
||||
</Badge>
|
||||
)}
|
||||
{booking.paid && (
|
||||
<Badge className="ltr:mr-2 rtl:ml-2" variant="green">
|
||||
{t("paid")}
|
||||
@@ -343,12 +342,14 @@ function BookingListItem(booking: BookingItemProps) {
|
||||
<span> </span>
|
||||
|
||||
{!!booking?.eventType?.price && !booking.paid && (
|
||||
<Tag className="hidden ltr:ml-2 rtl:mr-2 sm:inline-flex">Pending payment</Tag>
|
||||
<Badge className="hidden ltr:ml-2 rtl:mr-2 sm:inline-flex" variant="orange">
|
||||
{t("pending_payment")}
|
||||
</Badge>
|
||||
)}
|
||||
</div>
|
||||
{booking.description && (
|
||||
<div
|
||||
className="max-w-10/12 sm:max-w-40 md:max-w-56 xl:max-w-80 lg:max-w-64 truncate text-sm text-gray-600"
|
||||
className="max-w-10/12 sm:max-w-32 md:max-w-52 xl:max-w-80 truncate text-sm text-gray-600"
|
||||
title={booking.description}>
|
||||
"{booking.description}"
|
||||
</div>
|
||||
@@ -531,13 +532,4 @@ const DisplayAttendees = ({
|
||||
);
|
||||
};
|
||||
|
||||
const Tag = ({ children, className = "" }: React.PropsWithChildren<{ className?: string }>) => {
|
||||
return (
|
||||
<span
|
||||
className={`inline-flex items-center rounded-sm bg-yellow-100 px-1.5 py-0.5 text-xs font-medium text-yellow-800 ${className}`}>
|
||||
{children}
|
||||
</span>
|
||||
);
|
||||
};
|
||||
|
||||
export default BookingListItem;
|
||||
|
||||
@@ -13,9 +13,11 @@ import dayjs, { Dayjs } from "@calcom/dayjs";
|
||||
import {
|
||||
useEmbedNonStylesConfig,
|
||||
useEmbedStyles,
|
||||
useEmbedUiConfig,
|
||||
useIsBackgroundTransparent,
|
||||
useIsEmbed,
|
||||
} from "@calcom/embed-core/embed-iframe";
|
||||
import DatePicker from "@calcom/features/calendars/DatePicker";
|
||||
import CustomBranding from "@calcom/lib/CustomBranding";
|
||||
import classNames from "@calcom/lib/classNames";
|
||||
import getStripeAppData from "@calcom/lib/getStripeAppData";
|
||||
@@ -26,13 +28,10 @@ import { getRecurringFreq } from "@calcom/lib/recurringStrings";
|
||||
import { collectPageParameters, telemetryEventTypes, useTelemetry } from "@calcom/lib/telemetry";
|
||||
import { detectBrowserTimeFormat, setIs24hClockInLocalStorage, TimeFormat } from "@calcom/lib/timeFormat";
|
||||
import { trpc } from "@calcom/trpc/react";
|
||||
import { Icon, DatePicker } from "@calcom/ui";
|
||||
import { Icon } from "@calcom/ui";
|
||||
|
||||
import { timeZone as localStorageTimeZone } from "@lib/clock";
|
||||
// import { timeZone } from "@lib/clock";
|
||||
import { useExposePlanGlobally } from "@lib/hooks/useExposePlanGlobally";
|
||||
import useRouterQuery from "@lib/hooks/useRouterQuery";
|
||||
import { isBrandingHidden } from "@lib/isBrandingHidden";
|
||||
|
||||
import Gates, { Gate, GateState } from "@components/Gates";
|
||||
import AvailableTimes from "@components/booking/AvailableTimes";
|
||||
@@ -153,7 +152,10 @@ const SlotPicker = ({
|
||||
eventTypeId: eventType.id,
|
||||
eventTypeSlug: eventType.slug,
|
||||
usernameList: users,
|
||||
startTime: browsingDate?.startOf("month"),
|
||||
startTime:
|
||||
browsingDate === undefined || browsingDate.get("month") === dayjs.tz(undefined, timeZone).get("month")
|
||||
? dayjs.tz(undefined, timeZone).subtract(2, "days").startOf("day")
|
||||
: browsingDate?.startOf("month"),
|
||||
endTime: browsingDate?.endOf("month"),
|
||||
timeZone,
|
||||
duration,
|
||||
@@ -256,6 +258,7 @@ const AvailabilityPage = ({ profile, eventType, ...restProps }: Props) => {
|
||||
useTheme(profile.theme);
|
||||
const { t } = useLocale();
|
||||
const availabilityDatePickerEmbedStyles = useEmbedStyles("availabilityDatePicker");
|
||||
//TODO: Plan to remove shouldAlignCentrallyInEmbed config
|
||||
const shouldAlignCentrallyInEmbed = useEmbedNonStylesConfig("align") !== "left";
|
||||
const shouldAlignCentrally = !isEmbed || shouldAlignCentrallyInEmbed;
|
||||
const isBackgroundTransparent = useIsBackgroundTransparent();
|
||||
@@ -280,9 +283,6 @@ const AvailabilityPage = ({ profile, eventType, ...restProps }: Props) => {
|
||||
setTimeZone(localStorageTimeZone() || dayjs.tz.guess());
|
||||
}, []);
|
||||
|
||||
// TODO: Improve this;
|
||||
useExposePlanGlobally(eventType.users.length === 1 ? eventType.users[0].plan : "PRO");
|
||||
|
||||
const [recurringEventCount, setRecurringEventCount] = useState(eventType.recurringEvent?.count);
|
||||
|
||||
const telemetry = useTelemetry();
|
||||
@@ -295,7 +295,7 @@ const AvailabilityPage = ({ profile, eventType, ...restProps }: Props) => {
|
||||
);
|
||||
}
|
||||
}, [telemetry]);
|
||||
|
||||
const embedUiConfig = useEmbedUiConfig();
|
||||
// get dynamic user list here
|
||||
const userList = eventType.users ? eventType.users.map((user) => user.username).filter(notEmpty) : [];
|
||||
|
||||
@@ -308,6 +308,8 @@ const AvailabilityPage = ({ profile, eventType, ...restProps }: Props) => {
|
||||
const rawSlug = profile.slug ? profile.slug.split("/") : [];
|
||||
if (rawSlug.length > 1) rawSlug.pop(); //team events have team name as slug, but user events have [user]/[type] as slug.
|
||||
|
||||
const showEventTypeDetails = (isEmbed && !embedUiConfig.hideEventTypeDetails) || !isEmbed;
|
||||
|
||||
// Define conditional gates here
|
||||
const gates = [
|
||||
// Rainbow gate is only added if the event has both a `blockchainId` and a `smartContractAddress`
|
||||
@@ -341,7 +343,7 @@ const AvailabilityPage = ({ profile, eventType, ...restProps }: Props) => {
|
||||
<div>
|
||||
<main
|
||||
className={classNames(
|
||||
"flex-col md:mx-4 lg:flex",
|
||||
"flex flex-col md:mx-4",
|
||||
shouldAlignCentrally ? "items-center" : "items-start",
|
||||
!isEmbed && classNames("mx-auto my-0 ease-in-out md:my-24")
|
||||
)}>
|
||||
@@ -356,54 +358,55 @@ const AvailabilityPage = ({ profile, eventType, ...restProps }: Props) => {
|
||||
isEmbed && "mx-auto"
|
||||
)}>
|
||||
<div className="overflow-hidden md:flex">
|
||||
<div
|
||||
className={classNames(
|
||||
"sm:dark:border-darkgray-200 flex flex-col border-gray-200 p-5 sm:border-r",
|
||||
"min-w-full md:w-[230px] md:min-w-[230px]",
|
||||
recurringEventCount && "xl:w-[380px] xl:min-w-[380px]"
|
||||
)}>
|
||||
<BookingDescription profile={profile} eventType={eventType} rescheduleUid={rescheduleUid}>
|
||||
{!rescheduleUid && eventType.recurringEvent && (
|
||||
<div className="flex items-start text-sm font-medium">
|
||||
<Icon.FiRefreshCcw className="float-left mr-[10px] mt-[7px] ml-[2px] inline-block h-4 w-4 " />
|
||||
<div>
|
||||
<p className="mb-1 -ml-2 inline px-2 py-1">
|
||||
{getRecurringFreq({ t, recurringEvent: eventType.recurringEvent })}
|
||||
</p>
|
||||
<input
|
||||
type="number"
|
||||
min="1"
|
||||
max={eventType.recurringEvent.count}
|
||||
className="w-15 dark:bg-darkgray-200 h-7 rounded-sm border-gray-300 bg-white text-sm font-medium [appearance:textfield] ltr:mr-2 rtl:ml-2 dark:border-gray-500"
|
||||
defaultValue={eventType.recurringEvent.count}
|
||||
onChange={(event) => {
|
||||
setRecurringEventCount(parseInt(event?.target.value));
|
||||
}}
|
||||
/>
|
||||
<p className="inline">
|
||||
{t("occurrence", {
|
||||
count: recurringEventCount,
|
||||
})}
|
||||
</p>
|
||||
{showEventTypeDetails && (
|
||||
<div
|
||||
className={classNames(
|
||||
"sm:dark:border-darkgray-200 flex flex-col border-gray-200 p-5 sm:border-r",
|
||||
"min-w-full md:w-[230px] md:min-w-[230px]",
|
||||
recurringEventCount && "xl:w-[380px] xl:min-w-[380px]"
|
||||
)}>
|
||||
<BookingDescription profile={profile} eventType={eventType} rescheduleUid={rescheduleUid}>
|
||||
{!rescheduleUid && eventType.recurringEvent && (
|
||||
<div className="flex items-start text-sm font-medium">
|
||||
<Icon.FiRefreshCcw className="float-left mr-[10px] mt-[7px] ml-[2px] inline-block h-4 w-4 " />
|
||||
<div>
|
||||
<p className="mb-1 -ml-2 inline px-2 py-1">
|
||||
{getRecurringFreq({ t, recurringEvent: eventType.recurringEvent })}
|
||||
</p>
|
||||
<input
|
||||
type="number"
|
||||
min="1"
|
||||
max={eventType.recurringEvent.count}
|
||||
className="w-15 dark:bg-darkgray-200 h-7 rounded-sm border-gray-300 bg-white text-sm font-medium [appearance:textfield] ltr:mr-2 rtl:ml-2 dark:border-gray-500"
|
||||
defaultValue={eventType.recurringEvent.count}
|
||||
onChange={(event) => {
|
||||
setRecurringEventCount(parseInt(event?.target.value));
|
||||
}}
|
||||
/>
|
||||
<p className="inline">
|
||||
{t("occurrence", {
|
||||
count: recurringEventCount,
|
||||
})}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
{stripeAppData.price > 0 && (
|
||||
<p className="-ml-2 px-2 text-sm font-medium">
|
||||
<Icon.FiCreditCard className="mr-[10px] ml-[2px] -mt-1 inline-block h-4 w-4" />
|
||||
<IntlProvider locale="en">
|
||||
<FormattedNumber
|
||||
value={stripeAppData.price / 100.0}
|
||||
style="currency"
|
||||
currency={stripeAppData.currency.toUpperCase()}
|
||||
/>
|
||||
</IntlProvider>
|
||||
</p>
|
||||
)}
|
||||
{timezoneDropdown}
|
||||
</BookingDescription>
|
||||
)}
|
||||
{stripeAppData.price > 0 && (
|
||||
<p className="-ml-2 px-2 text-sm font-medium">
|
||||
<Icon.FiCreditCard className="mr-[10px] ml-[2px] -mt-1 inline-block h-4 w-4" />
|
||||
<IntlProvider locale="en">
|
||||
<FormattedNumber
|
||||
value={stripeAppData.price / 100.0}
|
||||
style="currency"
|
||||
currency={stripeAppData.currency.toUpperCase()}
|
||||
/>
|
||||
</IntlProvider>
|
||||
</p>
|
||||
)}
|
||||
{timezoneDropdown}
|
||||
</BookingDescription>
|
||||
|
||||
{/* Temporarily disabled - booking?.startTime && rescheduleUid && (
|
||||
{/* Temporarily disabled - booking?.startTime && rescheduleUid && (
|
||||
<div>
|
||||
<p
|
||||
className="mt-4 mb-3 text-gray-600 dark:text-darkgray-600"
|
||||
@@ -416,7 +419,8 @@ const AvailabilityPage = ({ profile, eventType, ...restProps }: Props) => {
|
||||
</p>
|
||||
</div>
|
||||
)*/}
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
<SlotPicker
|
||||
weekStart={
|
||||
typeof profile.weekStart === "string"
|
||||
@@ -442,7 +446,8 @@ const AvailabilityPage = ({ profile, eventType, ...restProps }: Props) => {
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
{(!restProps.isBrandingHidden || isEmbed) && <PoweredByCal />}
|
||||
{/* FIXME: We don't show branding in Embed yet because we need to place branding on top of the main content. Keeping it outside the main content would have visibility issues because outside main content background is transparent */}
|
||||
{!restProps.isBrandingHidden && !isEmbed && <PoweredByCal />}
|
||||
</div>
|
||||
</main>
|
||||
</div>
|
||||
|
||||
@@ -26,6 +26,7 @@ import { LocationObject, LocationType } from "@calcom/core/location";
|
||||
import dayjs from "@calcom/dayjs";
|
||||
import {
|
||||
useEmbedNonStylesConfig,
|
||||
useEmbedUiConfig,
|
||||
useIsBackgroundTransparent,
|
||||
useIsEmbed,
|
||||
} from "@calcom/embed-core/embed-iframe";
|
||||
@@ -89,6 +90,7 @@ const BookingPage = ({
|
||||
const { t, i18n } = useLocale();
|
||||
const { duration: queryDuration } = useRouterQuery("duration");
|
||||
const isEmbed = useIsEmbed(restProps.isEmbed);
|
||||
const embedUiConfig = useEmbedUiConfig();
|
||||
const shouldAlignCentrallyInEmbed = useEmbedNonStylesConfig("align") !== "left";
|
||||
const shouldAlignCentrally = !isEmbed || shouldAlignCentrallyInEmbed;
|
||||
const router = useRouter();
|
||||
@@ -141,6 +143,7 @@ const BookingPage = ({
|
||||
isSuccessBookingPage: true,
|
||||
email: bookingForm.getValues("email"),
|
||||
eventTypeSlug: eventType.slug,
|
||||
formerTime: booking?.startTime.toString(),
|
||||
},
|
||||
});
|
||||
},
|
||||
@@ -156,6 +159,7 @@ const BookingPage = ({
|
||||
allRemainingBookings: true,
|
||||
email: bookingForm.getValues("email"),
|
||||
eventTypeSlug: eventType.slug,
|
||||
formerTime: booking?.startTime.toString(),
|
||||
},
|
||||
});
|
||||
},
|
||||
@@ -297,6 +301,39 @@ const BookingPage = ({
|
||||
}
|
||||
|
||||
const bookEvent = (booking: BookingFormValues) => {
|
||||
const bookingCustomInputs = Object.keys(booking.customInputs || {}).map((inputId) => ({
|
||||
label: eventType.customInputs.find((input) => input.id === parseInt(inputId))?.label || "",
|
||||
value: booking.customInputs && booking.customInputs[inputId] ? booking.customInputs[inputId] : "",
|
||||
}));
|
||||
|
||||
// Checking if custom inputs of type Phone number are valid to display error message on UI
|
||||
if (eventType.customInputs.length) {
|
||||
let isErrorFound = false;
|
||||
eventType.customInputs.forEach((customInput) => {
|
||||
if (customInput.required && customInput.type === EventTypeCustomInputType.PHONE) {
|
||||
const input = bookingCustomInputs.find((i) => i.label === customInput.label);
|
||||
try {
|
||||
z.string({
|
||||
errorMap: () => ({
|
||||
message: `Missing ${customInput.type} customInput: '${customInput.label}'`,
|
||||
}),
|
||||
})
|
||||
.refine((val) => isValidPhoneNumber(val), {
|
||||
message: "Phone number is invalid",
|
||||
})
|
||||
.parse(input?.value);
|
||||
} catch (err) {
|
||||
isErrorFound = true;
|
||||
bookingForm.setError(`customInputs.${customInput.id}`, {
|
||||
type: "custom",
|
||||
message: "Invalid Phone number",
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
if (isErrorFound) return;
|
||||
}
|
||||
|
||||
telemetry.event(
|
||||
top !== window ? telemetryEventTypes.embedBookingConfirmed : telemetryEventTypes.bookingConfirmed,
|
||||
{ isTeamBooking: document.URL.includes("team/") }
|
||||
@@ -315,6 +352,22 @@ const BookingPage = ({
|
||||
{}
|
||||
);
|
||||
|
||||
if (eventType.customInputs.length > 0) {
|
||||
// find all required custom inputs and ensure they are filled out in the booking form
|
||||
const requiredCustomInputs = eventType.customInputs.filter((input) => input.required);
|
||||
const missingRequiredCustomInputs = requiredCustomInputs.filter(
|
||||
(input) => !booking?.customInputs?.[input.id]
|
||||
);
|
||||
if (missingRequiredCustomInputs.length > 0) {
|
||||
missingRequiredCustomInputs.forEach((input) => {
|
||||
bookingForm.setError(`customInputs.${input.id}`, {
|
||||
type: "required",
|
||||
});
|
||||
});
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (recurringDates.length) {
|
||||
// Identify set of bookings to one intance of recurring event to support batch changes
|
||||
const recurringEventId = uuidv4();
|
||||
@@ -337,10 +390,7 @@ const BookingPage = ({
|
||||
attendeeAddress: booking.attendeeAddress,
|
||||
}),
|
||||
metadata,
|
||||
customInputs: Object.keys(booking.customInputs || {}).map((inputId) => ({
|
||||
label: eventType.customInputs.find((input) => input.id === parseInt(inputId))?.label || "",
|
||||
value: booking.customInputs && inputId in booking.customInputs ? booking.customInputs[inputId] : "",
|
||||
})),
|
||||
customInputs: bookingCustomInputs,
|
||||
hasHashedBookingLink,
|
||||
hashedLink,
|
||||
smsReminderNumber:
|
||||
@@ -368,10 +418,7 @@ const BookingPage = ({
|
||||
attendeeAddress: booking.attendeeAddress,
|
||||
}),
|
||||
metadata,
|
||||
customInputs: Object.keys(booking.customInputs || {}).map((inputId) => ({
|
||||
label: eventType.customInputs.find((input) => input.id === parseInt(inputId))?.label || "",
|
||||
value: booking.customInputs && inputId in booking.customInputs ? booking.customInputs[inputId] : "",
|
||||
})),
|
||||
customInputs: bookingCustomInputs,
|
||||
hasHashedBookingLink,
|
||||
hashedLink,
|
||||
smsReminderNumber:
|
||||
@@ -406,6 +453,7 @@ const BookingPage = ({
|
||||
}
|
||||
});
|
||||
}
|
||||
const showEventTypeDetails = (isEmbed && !embedUiConfig.hideEventTypeDetails) || !isEmbed;
|
||||
const rainbowAppData = getEventTypeAppData(eventType, "rainbow") || {};
|
||||
|
||||
// Define conditional gates here
|
||||
@@ -439,7 +487,7 @@ const BookingPage = ({
|
||||
className={classNames(
|
||||
shouldAlignCentrally ? "mx-auto" : "",
|
||||
isEmbed ? "" : "sm:my-24",
|
||||
"my-0 max-w-3xl "
|
||||
"my-0 max-w-3xl"
|
||||
)}>
|
||||
<div
|
||||
className={classNames(
|
||||
@@ -448,95 +496,97 @@ const BookingPage = ({
|
||||
"dark:border-darkgray-300 rounded-md sm:border"
|
||||
)}>
|
||||
<div className="sm:flex">
|
||||
<div className="sm:dark:border-darkgray-300 dark:text-darkgray-600 flex flex-col px-6 pt-6 pb-0 text-gray-600 sm:w-1/2 sm:border-r sm:pb-6">
|
||||
<BookingDescription isBookingPage profile={profile} eventType={eventType}>
|
||||
{stripeAppData.price > 0 && (
|
||||
<p className="text-bookinglight -ml-2 px-2 text-sm ">
|
||||
<Icon.FiCreditCard className="mr-[10px] ml-[2px] -mt-1 inline-block h-4 w-4" />
|
||||
<IntlProvider locale="en">
|
||||
<FormattedNumber
|
||||
value={stripeAppData.price / 100.0}
|
||||
style="currency"
|
||||
currency={stripeAppData.currency.toUpperCase()}
|
||||
/>
|
||||
</IntlProvider>
|
||||
</p>
|
||||
)}
|
||||
{!rescheduleUid && eventType.recurringEvent?.freq && recurringEventCount && (
|
||||
<div className="items-start text-sm font-medium text-gray-600 dark:text-white">
|
||||
<Icon.FiRefreshCw className="mr-[10px] ml-[2px] inline-block h-4 w-4" />
|
||||
<p className="-ml-2 inline-block items-center px-2">
|
||||
{getEveryFreqFor({
|
||||
t,
|
||||
recurringEvent: eventType.recurringEvent,
|
||||
recurringCount: recurringEventCount,
|
||||
})}
|
||||
{showEventTypeDetails && (
|
||||
<div className="sm:dark:border-darkgray-300 dark:text-darkgray-600 flex flex-col px-6 pt-6 pb-0 text-gray-600 sm:w-1/2 sm:border-r sm:pb-6">
|
||||
<BookingDescription isBookingPage profile={profile} eventType={eventType}>
|
||||
{stripeAppData.price > 0 && (
|
||||
<p className="text-bookinglight -ml-2 px-2 text-sm ">
|
||||
<Icon.FiCreditCard className="mr-[10px] ml-[2px] -mt-1 inline-block h-4 w-4" />
|
||||
<IntlProvider locale="en">
|
||||
<FormattedNumber
|
||||
value={stripeAppData.price / 100.0}
|
||||
style="currency"
|
||||
currency={stripeAppData.currency.toUpperCase()}
|
||||
/>
|
||||
</IntlProvider>
|
||||
</p>
|
||||
</div>
|
||||
)}
|
||||
<div className="text-bookinghighlight flex items-start text-sm">
|
||||
<Icon.FiCalendar className="mr-[10px] ml-[2px] mt-[2px] inline-block h-4 w-4" />
|
||||
<div className="text-sm font-medium">
|
||||
{(rescheduleUid || !eventType.recurringEvent?.freq) && `${parseDate(date, i18n)}`}
|
||||
{!rescheduleUid &&
|
||||
eventType.recurringEvent?.freq &&
|
||||
recurringStrings.slice(0, 5).map((timeFormatted, key) => {
|
||||
return <p key={key}>{timeFormatted}</p>;
|
||||
})}
|
||||
{!rescheduleUid && eventType.recurringEvent?.freq && recurringStrings.length > 5 && (
|
||||
<div className="flex">
|
||||
<Tooltip
|
||||
content={recurringStrings.slice(5).map((timeFormatted, key) => (
|
||||
<p key={key}>{timeFormatted}</p>
|
||||
))}>
|
||||
<p className="dark:text-darkgray-600 text-sm">
|
||||
+ {t("plus_more", { count: recurringStrings.length - 5 })}
|
||||
</p>
|
||||
</Tooltip>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
{booking?.startTime && rescheduleUid && (
|
||||
<div>
|
||||
<p className="mt-8 mb-2 text-sm " data-testid="former_time_p">
|
||||
{t("former_time")}
|
||||
</p>
|
||||
<p className="line-through ">
|
||||
<Icon.FiCalendar className="mr-[10px] ml-[2px] -mt-1 inline-block h-4 w-4" />
|
||||
{typeof booking.startTime === "string" && parseDate(dayjs(booking.startTime), i18n)}
|
||||
</p>
|
||||
</div>
|
||||
)}
|
||||
{!!eventType.seatsPerTimeSlot && (
|
||||
)}
|
||||
{!rescheduleUid && eventType.recurringEvent?.freq && recurringEventCount && (
|
||||
<div className="items-start text-sm font-medium text-gray-600 dark:text-white">
|
||||
<Icon.FiRefreshCw className="mr-[10px] ml-[2px] inline-block h-4 w-4" />
|
||||
<p className="-ml-2 inline-block items-center px-2">
|
||||
{getEveryFreqFor({
|
||||
t,
|
||||
recurringEvent: eventType.recurringEvent,
|
||||
recurringCount: recurringEventCount,
|
||||
})}
|
||||
</p>
|
||||
</div>
|
||||
)}
|
||||
<div className="text-bookinghighlight flex items-start text-sm">
|
||||
<Icon.FiUser
|
||||
className={`mr-[10px] ml-[2px] mt-[2px] inline-block h-4 w-4 ${
|
||||
booking && booking.attendees.length / eventType.seatsPerTimeSlot >= 0.5
|
||||
? "text-rose-600"
|
||||
: booking && booking.attendees.length / eventType.seatsPerTimeSlot >= 0.33
|
||||
? "text-yellow-500"
|
||||
: "text-bookinghighlight"
|
||||
}`}
|
||||
/>
|
||||
<p
|
||||
className={`${
|
||||
booking && booking.attendees.length / eventType.seatsPerTimeSlot >= 0.5
|
||||
? "text-rose-600"
|
||||
: booking && booking.attendees.length / eventType.seatsPerTimeSlot >= 0.33
|
||||
? "text-yellow-500"
|
||||
: "text-bookinghighlight"
|
||||
} mb-2 font-medium`}>
|
||||
{booking
|
||||
? eventType.seatsPerTimeSlot - booking.attendees.length
|
||||
: eventType.seatsPerTimeSlot}{" "}
|
||||
/ {eventType.seatsPerTimeSlot} {t("seats_available")}
|
||||
</p>
|
||||
<Icon.FiCalendar className="mr-[10px] ml-[2px] mt-[2px] inline-block h-4 w-4" />
|
||||
<div className="text-sm font-medium">
|
||||
{(rescheduleUid || !eventType.recurringEvent?.freq) && `${parseDate(date, i18n)}`}
|
||||
{!rescheduleUid &&
|
||||
eventType.recurringEvent?.freq &&
|
||||
recurringStrings.slice(0, 5).map((timeFormatted, key) => {
|
||||
return <p key={key}>{timeFormatted}</p>;
|
||||
})}
|
||||
{!rescheduleUid && eventType.recurringEvent?.freq && recurringStrings.length > 5 && (
|
||||
<div className="flex">
|
||||
<Tooltip
|
||||
content={recurringStrings.slice(5).map((timeFormatted, key) => (
|
||||
<p key={key}>{timeFormatted}</p>
|
||||
))}>
|
||||
<p className="dark:text-darkgray-600 text-sm">
|
||||
+ {t("plus_more", { count: recurringStrings.length - 5 })}
|
||||
</p>
|
||||
</Tooltip>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</BookingDescription>
|
||||
</div>
|
||||
<div className="p-6 sm:w-1/2">
|
||||
{booking?.startTime && rescheduleUid && (
|
||||
<div>
|
||||
<p className="mt-8 mb-2 text-sm " data-testid="former_time_p">
|
||||
{t("former_time")}
|
||||
</p>
|
||||
<p className="line-through ">
|
||||
<Icon.FiCalendar className="mr-[10px] ml-[2px] -mt-1 inline-block h-4 w-4" />
|
||||
{typeof booking.startTime === "string" && parseDate(dayjs(booking.startTime), i18n)}
|
||||
</p>
|
||||
</div>
|
||||
)}
|
||||
{!!eventType.seatsPerTimeSlot && (
|
||||
<div className="text-bookinghighlight flex items-start text-sm">
|
||||
<Icon.FiUser
|
||||
className={`mr-[10px] ml-[2px] mt-[2px] inline-block h-4 w-4 ${
|
||||
booking && booking.attendees.length / eventType.seatsPerTimeSlot >= 0.5
|
||||
? "text-rose-600"
|
||||
: booking && booking.attendees.length / eventType.seatsPerTimeSlot >= 0.33
|
||||
? "text-yellow-500"
|
||||
: "text-bookinghighlight"
|
||||
}`}
|
||||
/>
|
||||
<p
|
||||
className={`${
|
||||
booking && booking.attendees.length / eventType.seatsPerTimeSlot >= 0.5
|
||||
? "text-rose-600"
|
||||
: booking && booking.attendees.length / eventType.seatsPerTimeSlot >= 0.33
|
||||
? "text-yellow-500"
|
||||
: "text-bookinghighlight"
|
||||
} mb-2 font-medium`}>
|
||||
{booking
|
||||
? eventType.seatsPerTimeSlot - booking.attendees.length
|
||||
: eventType.seatsPerTimeSlot}{" "}
|
||||
/ {eventType.seatsPerTimeSlot} {t("seats_available")}
|
||||
</p>
|
||||
</div>
|
||||
)}
|
||||
</BookingDescription>
|
||||
</div>
|
||||
)}
|
||||
<div className={classNames("p-6", showEventTypeDetails ? "sm:w-1/2" : "w-full")}>
|
||||
<Form form={bookingForm} handleSubmit={bookEvent}>
|
||||
<div className="mb-4">
|
||||
<label htmlFor="name" className="block text-sm font-medium text-gray-700 dark:text-white">
|
||||
@@ -679,8 +729,11 @@ const BookingPage = ({
|
||||
{input.type !== EventTypeCustomInputType.BOOL && (
|
||||
<label
|
||||
htmlFor={"custom_" + input.id}
|
||||
className="mb-1 block text-sm font-medium text-gray-700 dark:text-white">
|
||||
{input.label}
|
||||
className={classNames(
|
||||
"mb-1 block text-sm font-medium text-gray-700 transition-colors dark:text-white",
|
||||
bookingForm.formState.errors.customInputs?.[input.id] && "!text-red-700"
|
||||
)}>
|
||||
{input.label} {input.required && <span className="text-red-700">*</span>}
|
||||
</label>
|
||||
)}
|
||||
{input.type === EventTypeCustomInputType.TEXTLONG && (
|
||||
@@ -745,24 +798,45 @@ const BookingPage = ({
|
||||
</div>
|
||||
)}
|
||||
{input.options && input.type === EventTypeCustomInputType.RADIO && (
|
||||
<div className="">
|
||||
<div className="flex">
|
||||
<Group
|
||||
onValueChange={(e) => {
|
||||
bookingForm.setValue(`customInputs.${input.id}`, e);
|
||||
}}>
|
||||
<>
|
||||
{input.options.map((option, i) => (
|
||||
<RadioField
|
||||
label={option.label}
|
||||
key={`option.${i}.radio`}
|
||||
value={option.label}
|
||||
id={`option.${i}.radio`}
|
||||
/>
|
||||
))}
|
||||
</>
|
||||
</Group>
|
||||
</div>
|
||||
<div className="flex">
|
||||
<Group
|
||||
required={input.required}
|
||||
onValueChange={(e) => {
|
||||
bookingForm.setValue(`customInputs.${input.id}`, e);
|
||||
}}>
|
||||
<>
|
||||
{input.options.map((option, i) => (
|
||||
<RadioField
|
||||
label={option.label}
|
||||
key={`option.${i}.radio`}
|
||||
value={option.label}
|
||||
id={`option.${i}.radio`}
|
||||
/>
|
||||
))}
|
||||
</>
|
||||
{bookingForm.formState.errors.customInputs?.[input.id] && (
|
||||
<div className="mt-px flex items-center text-xs text-red-700 ">
|
||||
<p>{t("required")}</p>
|
||||
</div>
|
||||
)}
|
||||
</Group>
|
||||
</div>
|
||||
)}
|
||||
{input.type === EventTypeCustomInputType.PHONE && (
|
||||
<div>
|
||||
<PhoneInput<BookingFormValues>
|
||||
name={`customInputs.${input.id}`}
|
||||
control={bookingForm.control}
|
||||
placeholder={t("enter_phone_number")}
|
||||
id={`customInputs.${input.id}`}
|
||||
required={input.required}
|
||||
/>
|
||||
{bookingForm.formState.errors?.customInputs?.[input.id] && (
|
||||
<div className="mt-2 flex items-center text-sm text-red-700 ">
|
||||
<Icon.FiInfo className="mr-2 h-3 w-3" />
|
||||
<p>{t("invalid_number")}</p>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
@@ -40,6 +40,7 @@ const CustomInputTypeForm: FC<Props> = (props) => {
|
||||
value: EventTypeCustomInputType.RADIO,
|
||||
label: t("radio"),
|
||||
},
|
||||
{ value: EventTypeCustomInputType.PHONE, label: t("phone_number") },
|
||||
];
|
||||
|
||||
const { selectedCustomInput } = props;
|
||||
|
||||
@@ -6,13 +6,13 @@ import short from "short-uuid";
|
||||
import { v5 as uuidv5 } from "uuid";
|
||||
|
||||
import DestinationCalendarSelector from "@calcom/features/calendars/DestinationCalendarSelector";
|
||||
import CustomInputItem from "@calcom/features/eventtypes/components/CustomInputItem";
|
||||
import { APP_NAME, CAL_URL } from "@calcom/lib/constants";
|
||||
import { useLocale } from "@calcom/lib/hooks/useLocale";
|
||||
import { trpc } from "@calcom/trpc/react";
|
||||
import {
|
||||
Button,
|
||||
Checkbox,
|
||||
CustomInputItem,
|
||||
Dialog,
|
||||
DialogClose,
|
||||
DialogContent,
|
||||
|
||||
@@ -250,23 +250,26 @@ export const EventSetupTab = (
|
||||
isSearchable={false}
|
||||
className="h-auto !min-h-[36px] text-sm"
|
||||
options={multipleDurationOptions}
|
||||
value={selectedMultipleDuration}
|
||||
onChange={(options) => {
|
||||
const values = options
|
||||
.map((opt) => opt.value)
|
||||
.sort(function (a, b) {
|
||||
return a - b;
|
||||
});
|
||||
let newOptions = [...options];
|
||||
newOptions = newOptions.sort((a, b) => {
|
||||
return a?.value - b?.value;
|
||||
});
|
||||
const values = newOptions.map((opt) => opt.value);
|
||||
setMultipleDuration(values);
|
||||
setSelectedMultipleDuration(options);
|
||||
if (!options.find((opt) => opt.value === defaultDuration?.value)) {
|
||||
if (options.length > 0) {
|
||||
setDefaultDuration(options[0]);
|
||||
setSelectedMultipleDuration(newOptions);
|
||||
if (!newOptions.find((opt) => opt.value === defaultDuration?.value)) {
|
||||
if (newOptions.length > 0) {
|
||||
setDefaultDuration(newOptions[0]);
|
||||
formMethods.setValue("length", newOptions[0].value);
|
||||
} else {
|
||||
setDefaultDuration(null);
|
||||
}
|
||||
}
|
||||
if (options.length === 1 && defaultDuration === null) {
|
||||
setDefaultDuration(options[0]);
|
||||
if (newOptions.length === 1 && defaultDuration === null) {
|
||||
setDefaultDuration(newOptions[0]);
|
||||
formMethods.setValue("length", newOptions[0].value);
|
||||
}
|
||||
formMethods.setValue("metadata.multipleDuration", values);
|
||||
}}
|
||||
@@ -287,7 +290,7 @@ export const EventSetupTab = (
|
||||
setDefaultDuration(
|
||||
selectedMultipleDuration.find((opt) => opt.value === option?.value) ?? null
|
||||
);
|
||||
formMethods.setValue("length", Number(option?.value));
|
||||
if (option) formMethods.setValue("length", option.value);
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
@@ -295,14 +298,11 @@ export const EventSetupTab = (
|
||||
) : (
|
||||
<TextField
|
||||
required
|
||||
name="length"
|
||||
type="number"
|
||||
label={t("duration")}
|
||||
addOnSuffix={<>{t("minutes")}</>}
|
||||
defaultValue={eventType.length ?? 15}
|
||||
onChange={(e) => {
|
||||
formMethods.setValue("length", Number(e.target.value));
|
||||
}}
|
||||
{...formMethods.register("length")}
|
||||
addOnSuffix={<>{t("minutes")}</>}
|
||||
/>
|
||||
)}
|
||||
<div className="!mt-4 [&_label]:my-1 [&_label]:font-normal">
|
||||
|
||||
@@ -3,9 +3,10 @@ import { EventTypeSetupInfered, FormValues } from "pages/event-types/[type]";
|
||||
import { useMemo } from "react";
|
||||
import { Controller, useFormContext } from "react-hook-form";
|
||||
|
||||
import CheckedTeamSelect from "@calcom/features/eventtypes/components/CheckedTeamSelect";
|
||||
import { WEBAPP_URL } from "@calcom/lib/constants";
|
||||
import { useLocale } from "@calcom/lib/hooks/useLocale";
|
||||
import { Avatar, Button, CheckedTeamSelect, Icon, Label, Select } from "@calcom/ui";
|
||||
import { Avatar, Button, Icon, Label, Select } from "@calcom/ui";
|
||||
|
||||
interface IMemberToValue {
|
||||
id: number | null;
|
||||
|
||||
@@ -0,0 +1,179 @@
|
||||
import { EventTypeSetupInfered, FormValues } from "pages/event-types/[type]";
|
||||
import { useState } from "react";
|
||||
import { TbWebhook } from "react-icons/tb";
|
||||
|
||||
import { WebhookForm } from "@calcom/features/webhooks/components";
|
||||
import { WebhookFormSubmitData } from "@calcom/features/webhooks/components/WebhookForm";
|
||||
import WebhookListItem from "@calcom/features/webhooks/components/WebhookListItem";
|
||||
import { APP_NAME } from "@calcom/lib/constants";
|
||||
import { useLocale } from "@calcom/lib/hooks/useLocale";
|
||||
import { Webhook } from "@calcom/prisma/client";
|
||||
import { trpc } from "@calcom/trpc/react";
|
||||
import { Button, Dialog, DialogContent, EmptyScreen, Icon, showToast } from "@calcom/ui";
|
||||
|
||||
export const EventTeamWebhooksTab = ({
|
||||
eventType,
|
||||
team,
|
||||
}: Pick<EventTypeSetupInfered, "eventType" | "team">) => {
|
||||
const { t } = useLocale();
|
||||
|
||||
const utils = trpc.useContext();
|
||||
|
||||
const { data: webhooks } = trpc.viewer.webhook.list.useQuery({ eventTypeId: eventType.id });
|
||||
|
||||
const { data: installedApps, isLoading } = trpc.viewer.integrations.useQuery({
|
||||
variant: "other",
|
||||
onlyInstalled: true,
|
||||
});
|
||||
|
||||
const [createModalOpen, setCreateModalOpen] = useState(false);
|
||||
const [editModalOpen, setEditModalOpen] = useState(false);
|
||||
const [webhookToEdit, setWebhookToEdit] = useState<Webhook>();
|
||||
|
||||
const subscriberUrlReserved = (subscriberUrl: string, id?: string): boolean => {
|
||||
return !!webhooks?.find(
|
||||
(webhook) => webhook.subscriberUrl === subscriberUrl && (!id || webhook.id !== id)
|
||||
);
|
||||
};
|
||||
|
||||
const editWebhookMutation = trpc.viewer.webhook.edit.useMutation({
|
||||
async onSuccess() {
|
||||
setEditModalOpen(false);
|
||||
await utils.viewer.webhook.list.invalidate();
|
||||
showToast(t("webhook_updated_successfully"), "success");
|
||||
},
|
||||
onError(error) {
|
||||
showToast(`${error.message}`, "error");
|
||||
},
|
||||
});
|
||||
|
||||
const createWebhookMutation = trpc.viewer.webhook.create.useMutation({
|
||||
async onSuccess() {
|
||||
showToast(t("webhook_created_successfully"), "success");
|
||||
await utils.viewer.webhook.list.invalidate();
|
||||
setCreateModalOpen(false);
|
||||
},
|
||||
onError(error) {
|
||||
showToast(`${error.message}`, "error");
|
||||
},
|
||||
});
|
||||
|
||||
const onCreateWebhook = async (values: WebhookFormSubmitData) => {
|
||||
if (subscriberUrlReserved(values.subscriberUrl, values.id)) {
|
||||
showToast(t("webhook_subscriber_url_reserved"), "error");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!values.payloadTemplate) {
|
||||
values.payloadTemplate = null;
|
||||
}
|
||||
|
||||
createWebhookMutation.mutate({
|
||||
subscriberUrl: values.subscriberUrl,
|
||||
eventTriggers: values.eventTriggers,
|
||||
active: values.active,
|
||||
payloadTemplate: values.payloadTemplate,
|
||||
secret: values.secret,
|
||||
eventTypeId: eventType.id,
|
||||
});
|
||||
};
|
||||
|
||||
const NewWebhookButton = () => {
|
||||
const { t } = useLocale();
|
||||
return (
|
||||
<Button
|
||||
color="secondary"
|
||||
data-testid="new_webhook"
|
||||
StartIcon={Icon.FiPlus}
|
||||
onClick={() => setCreateModalOpen(true)}>
|
||||
{t("new_webhook")}
|
||||
</Button>
|
||||
);
|
||||
};
|
||||
return (
|
||||
<div>
|
||||
{team && webhooks && !isLoading && (
|
||||
<>
|
||||
<div>
|
||||
<div>
|
||||
<>
|
||||
{webhooks.length ? (
|
||||
<>
|
||||
<div className="mt-4 mb-8 rounded-md border">
|
||||
{webhooks.map((webhook, index) => {
|
||||
return (
|
||||
<WebhookListItem
|
||||
key={webhook.id}
|
||||
webhook={webhook}
|
||||
lastItem={webhooks.length === index + 1}
|
||||
onEditWebhook={() => {
|
||||
setEditModalOpen(true);
|
||||
setWebhookToEdit(webhook);
|
||||
}}
|
||||
/>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
<NewWebhookButton />
|
||||
</>
|
||||
) : (
|
||||
<EmptyScreen
|
||||
Icon={TbWebhook}
|
||||
headline={t("create_your_first_webhook")}
|
||||
description={t("create_your_first_team_webhook_description", { appName: APP_NAME })}
|
||||
buttonRaw={<NewWebhookButton />}
|
||||
/>
|
||||
)}
|
||||
</>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* New webhook dialog */}
|
||||
<Dialog open={createModalOpen} onOpenChange={(isOpen) => !isOpen && setCreateModalOpen(false)}>
|
||||
<DialogContent title={t("create_webhook")} description={t("create_webhook_team_event_type")}>
|
||||
<WebhookForm
|
||||
onSubmit={onCreateWebhook}
|
||||
onCancel={() => setCreateModalOpen(false)}
|
||||
apps={installedApps?.items.map((app) => app.slug)}
|
||||
/>
|
||||
</DialogContent>
|
||||
</Dialog>
|
||||
{/* Edit webhook dialog */}
|
||||
<Dialog open={editModalOpen} onOpenChange={(isOpen) => !isOpen && setEditModalOpen(false)}>
|
||||
<DialogContent title={t("edit_webhook")}>
|
||||
<WebhookForm
|
||||
webhook={webhookToEdit}
|
||||
apps={installedApps?.items.map((app) => app.slug)}
|
||||
onCancel={() => setEditModalOpen(false)}
|
||||
onSubmit={(values: WebhookFormSubmitData) => {
|
||||
if (subscriberUrlReserved(values.subscriberUrl, webhookToEdit?.id || "")) {
|
||||
showToast(t("webhook_subscriber_url_reserved"), "error");
|
||||
return;
|
||||
}
|
||||
|
||||
if (values.changeSecret) {
|
||||
values.secret = values.newSecret.length ? values.newSecret : null;
|
||||
}
|
||||
|
||||
if (!values.payloadTemplate) {
|
||||
values.payloadTemplate = null;
|
||||
}
|
||||
|
||||
editWebhookMutation.mutate({
|
||||
id: webhookToEdit?.id || "",
|
||||
subscriberUrl: values.subscriberUrl,
|
||||
eventTriggers: values.eventTriggers,
|
||||
active: values.active,
|
||||
payloadTemplate: values.payloadTemplate,
|
||||
secret: values.secret,
|
||||
eventTypeId: webhookToEdit?.eventTypeId || undefined,
|
||||
});
|
||||
}}
|
||||
/>
|
||||
</DialogContent>
|
||||
</Dialog>
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
@@ -2,8 +2,8 @@ import { TFunction } from "next-i18next";
|
||||
import { useRouter } from "next/router";
|
||||
import { EventTypeSetupInfered, FormValues } from "pages/event-types/[type]";
|
||||
import { useMemo, useState } from "react";
|
||||
import { Loader } from "react-feather";
|
||||
import { UseFormReturn } from "react-hook-form";
|
||||
import { TbWebhook } from "react-icons/tb";
|
||||
|
||||
import { classNames } from "@calcom/lib";
|
||||
import { CAL_URL } from "@calcom/lib/constants";
|
||||
@@ -150,13 +150,20 @@ function EventTypeSingleLayout({
|
||||
enabledWorkflowsNumber,
|
||||
});
|
||||
// If there is a team put this navigation item within the tabs
|
||||
if (team)
|
||||
if (team) {
|
||||
navigation.splice(2, 0, {
|
||||
name: "scheduling_type",
|
||||
href: `/event-types/${eventType.id}?tabName=team`,
|
||||
icon: Icon.FiUsers,
|
||||
info: eventType.schedulingType === "COLLECTIVE" ? "collective" : "round_robin",
|
||||
});
|
||||
navigation.push({
|
||||
name: "webhooks",
|
||||
href: `/event-types/${eventType.id}?tabName=webhooks`,
|
||||
icon: TbWebhook,
|
||||
info: `${eventType.webhooks.filter((webhook) => webhook.active).length} ${t("active")}`,
|
||||
});
|
||||
}
|
||||
return navigation;
|
||||
}, [t, eventType, installedAppsNumber, enabledAppsNumber, enabledWorkflowsNumber, team]);
|
||||
|
||||
@@ -294,7 +301,7 @@ function EventTypeSingleLayout({
|
||||
</Button>
|
||||
</div>
|
||||
}>
|
||||
<ClientSuspense fallback={<Loader />}>
|
||||
<ClientSuspense fallback={<Icon.FiLoader />}>
|
||||
<div className="-mt-2 flex flex-col xl:flex-row xl:space-x-8">
|
||||
<div className="hidden xl:block">
|
||||
<VerticalTabs
|
||||
|
||||
@@ -35,23 +35,7 @@ interface ICustomUsernameProps {
|
||||
setInputUsernameValue: (value: string) => void;
|
||||
onSuccessMutation?: () => void;
|
||||
onErrorMutation?: (error: TRPCClientErrorLike<AppRouter>) => void;
|
||||
user: Pick<
|
||||
User,
|
||||
| "username"
|
||||
| "name"
|
||||
| "email"
|
||||
| "bio"
|
||||
| "avatar"
|
||||
| "timeZone"
|
||||
| "weekStart"
|
||||
| "hideBranding"
|
||||
| "theme"
|
||||
| "plan"
|
||||
| "brandColor"
|
||||
| "darkBrandColor"
|
||||
| "timeFormat"
|
||||
| "metadata"
|
||||
>;
|
||||
user: Pick<User, "username" | "metadata">;
|
||||
readonly?: boolean;
|
||||
}
|
||||
|
||||
|
||||
@@ -14,23 +14,7 @@ export const UsernameAvailability = IS_SELF_HOSTED ? UsernameTextfield : Premium
|
||||
interface UsernameAvailabilityFieldProps {
|
||||
onSuccessMutation?: () => void;
|
||||
onErrorMutation?: (error: TRPCClientErrorLike<AppRouter>) => void;
|
||||
user: Pick<
|
||||
User,
|
||||
| "username"
|
||||
| "name"
|
||||
| "email"
|
||||
| "bio"
|
||||
| "avatar"
|
||||
| "timeZone"
|
||||
| "weekStart"
|
||||
| "hideBranding"
|
||||
| "theme"
|
||||
| "plan"
|
||||
| "brandColor"
|
||||
| "darkBrandColor"
|
||||
| "timeFormat"
|
||||
| "metadata"
|
||||
>;
|
||||
user: Pick<User, "username" | "metadata">;
|
||||
}
|
||||
export const UsernameAvailabilityField = ({
|
||||
onSuccessMutation,
|
||||
|
||||
@@ -1,12 +0,0 @@
|
||||
import { UserPlan } from "@prisma/client";
|
||||
|
||||
/**
|
||||
* TODO: It should be exposed at a single place.
|
||||
*/
|
||||
export function useExposePlanGlobally(plan: UserPlan) {
|
||||
// Don't wait for component to mount. Do it ASAP. Delaying it would delay UI Configuration.
|
||||
if (typeof window !== "undefined") {
|
||||
// This variable is used by embed-iframe to determine if we should allow UI configuration
|
||||
window.CalComPlan = plan;
|
||||
}
|
||||
}
|
||||
@@ -227,6 +227,11 @@ const nextConfig = {
|
||||
destination: "/404",
|
||||
permanent: false,
|
||||
},
|
||||
{
|
||||
source: "/booking/direct/:action/:email/:bookingUid/:oldToken",
|
||||
destination: "/api/link?action=:action&email=:email&bookingUid=:bookingUid&oldToken=:oldToken",
|
||||
permanent: true,
|
||||
},
|
||||
];
|
||||
|
||||
if (process.env.NEXT_PUBLIC_WEBAPP_URL === "https://app.cal.com") {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@calcom/web",
|
||||
"version": "2.3.6",
|
||||
"version": "2.4.2",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"analyze": "ANALYZE=true next build",
|
||||
@@ -61,7 +61,7 @@
|
||||
"@stripe/stripe-js": "^1.35.0",
|
||||
"@tanstack/react-query": "^4.3.9",
|
||||
"@vercel/edge-functions-ui": "^0.2.1",
|
||||
"@vercel/og": "^0.0.19",
|
||||
"@vercel/og": "^0.0.21",
|
||||
"accept-language-parser": "^1.5.0",
|
||||
"async": "^3.2.4",
|
||||
"bcryptjs": "^2.4.3",
|
||||
@@ -121,7 +121,7 @@
|
||||
"tailwindcss-radix": "^2.6.0",
|
||||
"uuid": "^8.3.2",
|
||||
"web3": "^1.7.5",
|
||||
"zod": "^3.19.1"
|
||||
"zod": "^3.20.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@babel/core": "^7.19.6",
|
||||
|
||||
+29
-13
@@ -1,32 +1,48 @@
|
||||
import Head from "next/head";
|
||||
import { useRouter } from "next/router";
|
||||
|
||||
import { APP_NAME, WEBSITE_URL } from "@calcom/lib/constants";
|
||||
import { useLocale } from "@calcom/lib/hooks/useLocale";
|
||||
import { Button } from "@calcom/ui";
|
||||
import { Button, Icon, showToast } from "@calcom/ui";
|
||||
|
||||
export default function Error500() {
|
||||
const { t } = useLocale();
|
||||
const router = useRouter();
|
||||
|
||||
return (
|
||||
<div className="flex h-screen">
|
||||
<div className="flex h-screen bg-gray-100">
|
||||
<Head>
|
||||
<title>Something unexpected occurred | {APP_NAME}</title>
|
||||
<link rel="icon" href="/favicon.ico" />
|
||||
</Head>
|
||||
<div className="m-auto text-center">
|
||||
<h1 className="font-cal text-[250px] text-gray-900">
|
||||
5
|
||||
{
|
||||
// eslint-disable-next-line @next/next/no-img-element
|
||||
<img src="/error.svg" className="-mt-10 inline w-60" alt="0" />
|
||||
}
|
||||
0
|
||||
</h1>
|
||||
<h2 className="mb-2 -mt-16 text-3xl text-gray-600">It's not you, it's us.</h2>
|
||||
<p className="mb-4 max-w-2xl text-gray-500">
|
||||
<div className="rtl: m-auto rounded-md bg-white p-10 text-right ltr:text-left">
|
||||
<h1 className="font-cal text-6xl text-black">500</h1>
|
||||
<h2 className="mt-6 text-2xl font-medium text-black">It's not you, it's us.</h2>
|
||||
<p className="mt-4 mb-6 max-w-2xl text-sm text-gray-600">
|
||||
Something went wrong on our end. Get in touch with our support team, and we’ll get it fixed right
|
||||
away for you.
|
||||
</p>
|
||||
{router.query.error && (
|
||||
<div className="mb-8 flex flex-col">
|
||||
<p className="mb-4 max-w-2xl text-sm text-gray-600">
|
||||
Please provide the following text when contacting support to better help you:
|
||||
</p>
|
||||
<pre className="w-full max-w-2xl whitespace-normal break-words rounded-md bg-gray-200 p-4 text-gray-900">
|
||||
{router.query.error}
|
||||
<br />
|
||||
<Button
|
||||
color="secondary"
|
||||
className="mt-2 border-0 font-sans font-normal hover:bg-gray-300"
|
||||
StartIcon={Icon.FiCopy}
|
||||
onClick={() => {
|
||||
navigator.clipboard.writeText(router.query.error as string);
|
||||
showToast("Link copied!", "success");
|
||||
}}>
|
||||
{t("copy")}
|
||||
</Button>
|
||||
</pre>
|
||||
</div>
|
||||
)}
|
||||
<Button href={`${WEBSITE_URL}/support`}>{t("contact_support")}</Button>
|
||||
<Button color="secondary" href="javascript:history.back()" className="ml-2">
|
||||
Go back
|
||||
|
||||
@@ -12,6 +12,7 @@ import {
|
||||
useEmbedStyles,
|
||||
useIsEmbed,
|
||||
} from "@calcom/embed-core/embed-iframe";
|
||||
import { EventTypeDescriptionLazy as EventTypeDescription } from "@calcom/features/eventtypes/components";
|
||||
import EmptyPage from "@calcom/features/eventtypes/components/EmptyPage";
|
||||
import CustomBranding from "@calcom/lib/CustomBranding";
|
||||
import defaultEvents, {
|
||||
@@ -26,9 +27,8 @@ import { collectPageParameters, telemetryEventTypes, useTelemetry } from "@calco
|
||||
import prisma from "@calcom/prisma";
|
||||
import { baseEventTypeSelect } from "@calcom/prisma/selects";
|
||||
import { EventTypeMetaDataSchema } from "@calcom/prisma/zod-utils";
|
||||
import { BadgeCheckIcon, EventTypeDescriptionLazy as EventTypeDescription, Icon } from "@calcom/ui";
|
||||
import { BadgeCheckIcon, Icon } from "@calcom/ui";
|
||||
|
||||
import { useExposePlanGlobally } from "@lib/hooks/useExposePlanGlobally";
|
||||
import { inferSSRProps } from "@lib/types/inferSSRProps";
|
||||
import { EmbedProps } from "@lib/withEmbedSsr";
|
||||
|
||||
@@ -59,7 +59,7 @@ export default function User(props: inferSSRProps<typeof getServerSideProps> & E
|
||||
{eventTypes.map((type, index) => (
|
||||
<li
|
||||
key={index}
|
||||
className="dark:bg-darkgray-100 dark:border-darkgray-200 group relative rounded-sm border border-neutral-200 bg-white dark:hover:border-neutral-600">
|
||||
className="dark:bg-darkgray-100 group relative border-b border-neutral-200 bg-white first:rounded-t-md last:rounded-b-md last:border-b-0 hover:bg-gray-50 dark:border-neutral-700 dark:hover:border-neutral-600">
|
||||
<Icon.FiArrowRight className="absolute right-3 top-3 h-4 w-4 text-black opacity-0 transition-opacity group-hover:opacity-100 dark:text-white" />
|
||||
<Link href={getUsernameSlugLink({ users: props.users, slug: type.slug })}>
|
||||
<a className="flex justify-between px-6 py-4" data-testid="event-type-link">
|
||||
@@ -69,7 +69,7 @@ export default function User(props: inferSSRProps<typeof getServerSideProps> & E
|
||||
</div>
|
||||
<div className="mt-1 self-center">
|
||||
<AvatarGroup
|
||||
border="border-2 border-white"
|
||||
border="border-2 border-white dark:border-darkgray-100"
|
||||
truncateAfter={4}
|
||||
className="flex flex-shrink-0"
|
||||
size={10}
|
||||
@@ -92,7 +92,6 @@ export default function User(props: inferSSRProps<typeof getServerSideProps> & E
|
||||
const shouldAlignCentrally = !isEmbed || shouldAlignCentrallyInEmbed;
|
||||
const query = { ...router.query };
|
||||
delete query.user; // So it doesn't display in the Link (and make tests fail)
|
||||
useExposePlanGlobally("PRO");
|
||||
const nameOrUsername = user.name || user.username || "";
|
||||
const telemetry = useTelemetry();
|
||||
|
||||
@@ -272,7 +271,6 @@ export const getServerSideProps = async (context: GetServerSidePropsContext) =>
|
||||
darkBrandColor: true,
|
||||
avatar: true,
|
||||
theme: true,
|
||||
plan: true,
|
||||
away: true,
|
||||
verified: true,
|
||||
allowDynamicBooking: true,
|
||||
|
||||
@@ -4,7 +4,7 @@ import { JSONObject } from "superjson/dist/types";
|
||||
import { z } from "zod";
|
||||
|
||||
import { privacyFilteredLocations, LocationObject } from "@calcom/app-store/locations";
|
||||
import { WEBAPP_URL } from "@calcom/lib/constants";
|
||||
import { IS_TEAM_BILLING_ENABLED, WEBAPP_URL } from "@calcom/lib/constants";
|
||||
import { getDefaultEvent, getGroupName, getUsernameList } from "@calcom/lib/defaultEvents";
|
||||
import { useLocale } from "@calcom/lib/hooks/useLocale";
|
||||
import { parseRecurringEvent } from "@calcom/lib/isRecurringEvent";
|
||||
@@ -72,7 +72,6 @@ async function getUserPageProps(context: GetStaticPropsContext) {
|
||||
id: true,
|
||||
username: true,
|
||||
away: true,
|
||||
plan: true,
|
||||
name: true,
|
||||
hideBranding: true,
|
||||
timeZone: true,
|
||||
@@ -130,7 +129,7 @@ async function getUserPageProps(context: GetStaticPropsContext) {
|
||||
if (!user || !user.eventTypes.length) return { notFound: true };
|
||||
|
||||
const [eventType]: (typeof user.eventTypes[number] & {
|
||||
users: Pick<User, "name" | "username" | "hideBranding" | "plan" | "timeZone">[];
|
||||
users: Pick<User, "name" | "username" | "hideBranding" | "timeZone">[];
|
||||
})[] = [
|
||||
{
|
||||
...user.eventTypes[0],
|
||||
@@ -139,7 +138,6 @@ async function getUserPageProps(context: GetStaticPropsContext) {
|
||||
name: user.name,
|
||||
username: user.username,
|
||||
hideBranding: user.hideBranding,
|
||||
plan: user.plan,
|
||||
timeZone: user.timeZone,
|
||||
},
|
||||
],
|
||||
@@ -159,9 +157,10 @@ async function getUserPageProps(context: GetStaticPropsContext) {
|
||||
// Check if the user you are logging into has any active teams
|
||||
const hasActiveTeam =
|
||||
user.teams.filter((m) => {
|
||||
if (!IS_TEAM_BILLING_ENABLED) return true;
|
||||
const metadata = teamMetadataSchema.safeParse(m.team.metadata);
|
||||
if (metadata.success && metadata.data?.subscriptionId) return false;
|
||||
return true;
|
||||
if (metadata.success && metadata.data?.subscriptionId) return true;
|
||||
return false;
|
||||
}).length > 0;
|
||||
|
||||
return {
|
||||
@@ -226,7 +225,6 @@ async function getDynamicGroupPageProps(context: GetStaticPropsContext) {
|
||||
},
|
||||
},
|
||||
theme: true,
|
||||
plan: true,
|
||||
},
|
||||
});
|
||||
|
||||
@@ -246,7 +244,6 @@ async function getDynamicGroupPageProps(context: GetStaticPropsContext) {
|
||||
name: user.name,
|
||||
username: user.username,
|
||||
hideBranding: user.hideBranding,
|
||||
plan: user.plan,
|
||||
timeZone: user.timeZone,
|
||||
};
|
||||
}),
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { DefaultSeo } from "next-seo";
|
||||
import Head from "next/head";
|
||||
import Script from "next/script";
|
||||
import superjson from "superjson";
|
||||
|
||||
import "@calcom/embed-core/src/embed-iframe";
|
||||
@@ -36,8 +37,11 @@ function MyApp(props: AppProps) {
|
||||
<AppProviders {...props}>
|
||||
<DefaultSeo {...seoConfig.defaultNextSeo} />
|
||||
<I18nLanguageHandler />
|
||||
<Script
|
||||
id="page-status"
|
||||
dangerouslySetInnerHTML={{ __html: `window.CalComPageStatus = '${pageStatus}'` }}
|
||||
/>
|
||||
<Head>
|
||||
<script dangerouslySetInnerHTML={{ __html: `window.CalComPageStatus = '${pageStatus}'` }} />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1" />
|
||||
</Head>
|
||||
{getLayout(
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import Document, { DocumentContext, Head, Html, Main, NextScript, DocumentProps } from "next/document";
|
||||
import Script from "next/script";
|
||||
|
||||
type Props = Record<string, unknown> & DocumentProps;
|
||||
|
||||
@@ -69,7 +70,9 @@ class MyDocument extends Document<Props> {
|
||||
{/* Define isEmbed here so that it can be shared with App(embed-iframe) as well as the following code to change background and hide body
|
||||
Persist the embed mode in sessionStorage because query param might get lost during browsing.
|
||||
*/}
|
||||
<script
|
||||
<Script
|
||||
id="run-before-client"
|
||||
strategy="beforeInteractive"
|
||||
dangerouslySetInnerHTML={{
|
||||
__html: `(${toRunBeforeReactOnClient.toString()})()`,
|
||||
}}
|
||||
|
||||
@@ -14,7 +14,7 @@ import checkLicense from "@calcom/features/ee/common/server/checkLicense";
|
||||
import ImpersonationProvider from "@calcom/features/ee/impersonation/lib/ImpersonationProvider";
|
||||
import { hostedCal, isSAMLLoginEnabled } from "@calcom/features/ee/sso/lib/saml";
|
||||
import { ErrorCode, isPasswordValid, verifyPassword } from "@calcom/lib/auth";
|
||||
import { APP_NAME, WEBAPP_URL } from "@calcom/lib/constants";
|
||||
import { APP_NAME, IS_TEAM_BILLING_ENABLED, WEBAPP_URL } from "@calcom/lib/constants";
|
||||
import { symmetricDecrypt } from "@calcom/lib/crypto";
|
||||
import { defaultCookies } from "@calcom/lib/default-cookies";
|
||||
import rateLimit from "@calcom/lib/rateLimit";
|
||||
@@ -125,9 +125,10 @@ const providers: Provider[] = [
|
||||
// Check if the user you are logging into has any active teams
|
||||
const hasActiveTeams =
|
||||
user.teams.filter((m) => {
|
||||
if (!IS_TEAM_BILLING_ENABLED) return true;
|
||||
const metadata = teamMetadataSchema.safeParse(m.team.metadata);
|
||||
if (metadata.success && metadata.data?.subscriptionId) return false;
|
||||
return true;
|
||||
if (metadata.success && metadata.data?.subscriptionId) return true;
|
||||
return false;
|
||||
}).length > 0;
|
||||
|
||||
// authentication success- but does it meet the minimum password requirements?
|
||||
|
||||
@@ -46,7 +46,6 @@ async function handler(req: NextApiRequest) {
|
||||
name: parsedQuery.data.full_name,
|
||||
emailVerified: new Date(),
|
||||
locale: "en", // TODO: We should revisit this
|
||||
plan: "PRO",
|
||||
identityProvider: IdentityProvider.CAL,
|
||||
},
|
||||
});
|
||||
|
||||
@@ -1,10 +1,5 @@
|
||||
import type { NextApiRequest, NextApiResponse } from "next";
|
||||
|
||||
import dayjs from "@calcom/dayjs";
|
||||
import prisma from "@calcom/prisma";
|
||||
|
||||
import { TRIAL_LIMIT_DAYS } from "@lib/config/constants";
|
||||
|
||||
export default async function handler(req: NextApiRequest, res: NextApiResponse) {
|
||||
const apiKey = req.headers.authorization || req.query.apiKey;
|
||||
if (process.env.CRON_API_KEY !== apiKey) {
|
||||
@@ -18,35 +13,8 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse)
|
||||
|
||||
/**
|
||||
* TODO:
|
||||
* We should add and extra check for non-paying customers in Stripe so we can
|
||||
* downgrade them here.
|
||||
* Remove this endpoint
|
||||
*/
|
||||
|
||||
await prisma.user.updateMany({
|
||||
data: {
|
||||
plan: "FREE",
|
||||
},
|
||||
where: {
|
||||
plan: "TRIAL",
|
||||
OR: [
|
||||
/**
|
||||
* If the user doesn't have a trial end date,
|
||||
* use the default 14 day trial from creation.
|
||||
*/
|
||||
{
|
||||
createdDate: {
|
||||
lt: dayjs().subtract(TRIAL_LIMIT_DAYS, "day").toDate(),
|
||||
},
|
||||
trialEndsAt: null,
|
||||
},
|
||||
/** If it does, then honor the trial end date. */
|
||||
{
|
||||
trialEndsAt: {
|
||||
lt: dayjs().toDate(),
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
});
|
||||
res.json({ ok: true });
|
||||
}
|
||||
|
||||
@@ -13,10 +13,6 @@ const handler = async (req: NextApiRequest, res: NextApiResponse) => {
|
||||
title: "30min between Pro Example and pro@example.com",
|
||||
description: null,
|
||||
additionalNotes: "asdasdas",
|
||||
customInputs: {
|
||||
"Custom input 01": "sadasdasdsadasd",
|
||||
"Custom input 02": "asdasdasd",
|
||||
},
|
||||
startTime: "2022-06-03T09:00:00-06:00",
|
||||
endTime: "2022-06-03T09:30:00-06:00",
|
||||
organizer: {
|
||||
@@ -32,26 +28,12 @@ const handler = async (req: NextApiRequest, res: NextApiResponse) => {
|
||||
timeZone: "America/Chihuahua",
|
||||
language,
|
||||
},
|
||||
{
|
||||
email: "pro@example.com",
|
||||
name: "pro@example.com",
|
||||
timeZone: "America/Chihuahua",
|
||||
language,
|
||||
},
|
||||
{
|
||||
email: "pro@example.com",
|
||||
name: "pro@example.com",
|
||||
timeZone: "America/Chihuahua",
|
||||
language,
|
||||
},
|
||||
],
|
||||
location: "Zoom video",
|
||||
destinationCalendar: null,
|
||||
hideCalendarNotes: false,
|
||||
uid: "bwPWLpjYrx4rZf6MCZdKgE",
|
||||
uid: "xxyPr4cg2xx4XoS2KeMEQy",
|
||||
metadata: {},
|
||||
cancellationReason: "It got late",
|
||||
paymentInfo: { id: "pi_12312", link: "https://cal.com", reason: "no reason" },
|
||||
recurringEvent: null,
|
||||
};
|
||||
|
||||
@@ -60,7 +42,7 @@ const handler = async (req: NextApiRequest, res: NextApiResponse) => {
|
||||
res.setHeader("Content-Type", "text/html");
|
||||
res.setHeader("Cache-Control", "no-cache, no-store, private, must-revalidate");
|
||||
res.write(
|
||||
renderEmail("AttendeeScheduledEmail", {
|
||||
renderEmail("OrganizerRequestEmail", {
|
||||
attendee: evt.attendees[0],
|
||||
calEvent: evt,
|
||||
})
|
||||
|
||||
@@ -0,0 +1,71 @@
|
||||
import { UserPermissionRole } from "@prisma/client";
|
||||
import type { NextApiRequest, NextApiResponse } from "next";
|
||||
import { z } from "zod";
|
||||
|
||||
import { symmetricDecrypt } from "@calcom/lib/crypto";
|
||||
import { defaultResponder } from "@calcom/lib/server";
|
||||
import prisma from "@calcom/prisma";
|
||||
import { TRPCError } from "@calcom/trpc/server";
|
||||
import { createContext } from "@calcom/trpc/server/createContext";
|
||||
import { viewerRouter } from "@calcom/trpc/server/routers/viewer";
|
||||
|
||||
enum DirectAction {
|
||||
ACCEPT = "accept",
|
||||
REJECT = "reject",
|
||||
}
|
||||
|
||||
const querySchema = z.object({
|
||||
action: z.nativeEnum(DirectAction),
|
||||
token: z.string(),
|
||||
reason: z.string().optional(),
|
||||
});
|
||||
|
||||
const decryptedSchema = z.object({
|
||||
bookingUid: z.string(),
|
||||
userId: z.number().int(),
|
||||
});
|
||||
|
||||
async function handler(req: NextApiRequest, res: NextApiResponse<Response>) {
|
||||
const { action, token, reason } = querySchema.parse(req.query);
|
||||
const { bookingUid, userId } = decryptedSchema.parse(
|
||||
JSON.parse(symmetricDecrypt(decodeURIComponent(token), process.env.CALENDSO_ENCRYPTION_KEY || ""))
|
||||
);
|
||||
|
||||
/** We shape the session as required by tRPC router */
|
||||
async function sessionGetter() {
|
||||
return {
|
||||
user: {
|
||||
id: userId,
|
||||
username: "" /* Not used in this context */,
|
||||
role: UserPermissionRole.USER,
|
||||
},
|
||||
hasValidLicense: true,
|
||||
expires: "" /* Not used in this context */,
|
||||
};
|
||||
}
|
||||
|
||||
const booking = await prisma.booking.findUniqueOrThrow({
|
||||
where: { uid: bookingUid },
|
||||
});
|
||||
|
||||
try {
|
||||
/** @see https://trpc.io/docs/server-side-calls */
|
||||
const ctx = await createContext({ req, res }, sessionGetter);
|
||||
const caller = viewerRouter.createCaller(ctx);
|
||||
await caller.bookings.confirm({
|
||||
bookingId: booking.id,
|
||||
recurringEventId: booking.recurringEventId || undefined,
|
||||
confirmed: action === DirectAction.ACCEPT,
|
||||
reason,
|
||||
});
|
||||
} catch (e) {
|
||||
let message = "Error confirming booking";
|
||||
if (e instanceof TRPCError) message = e.message;
|
||||
res.redirect(`/booking/${bookingUid}?error=${encodeURIComponent(message)}`);
|
||||
return;
|
||||
}
|
||||
|
||||
res.redirect(`/booking/${bookingUid}`);
|
||||
}
|
||||
|
||||
export default defaultResponder(handler);
|
||||
@@ -53,6 +53,8 @@ export default async function handler(req: NextApiRequest) {
|
||||
interFontMedium,
|
||||
]);
|
||||
const ogConfig = {
|
||||
width: 1200,
|
||||
height: 630,
|
||||
fonts: [
|
||||
{ name: "inter", data: interFontData, weight: 400 },
|
||||
{ name: "inter", data: interFontMediumData, weight: 500 },
|
||||
@@ -71,7 +73,7 @@ export default async function handler(req: NextApiRequest) {
|
||||
meetingImage: searchParams.get("meetingImage"),
|
||||
imageType,
|
||||
});
|
||||
return new ImageResponse(
|
||||
const img = new ImageResponse(
|
||||
(
|
||||
<Meeting
|
||||
title={title}
|
||||
@@ -80,7 +82,9 @@ export default async function handler(req: NextApiRequest) {
|
||||
/>
|
||||
),
|
||||
ogConfig
|
||||
);
|
||||
) as { body: Buffer };
|
||||
|
||||
return new Response(img.body, { status: 200 });
|
||||
}
|
||||
case "app": {
|
||||
const { name, description, slug } = appSchema.parse({
|
||||
@@ -89,7 +93,11 @@ export default async function handler(req: NextApiRequest) {
|
||||
slug: searchParams.get("slug"),
|
||||
imageType,
|
||||
});
|
||||
return new ImageResponse(<App name={name} description={description} slug={slug} />, ogConfig);
|
||||
const img = new ImageResponse(<App name={name} description={description} slug={slug} />, ogConfig) as {
|
||||
body: Buffer;
|
||||
};
|
||||
|
||||
return new Response(img.body, { status: 200 });
|
||||
}
|
||||
|
||||
case "generic": {
|
||||
@@ -99,7 +107,11 @@ export default async function handler(req: NextApiRequest) {
|
||||
imageType,
|
||||
});
|
||||
|
||||
return new ImageResponse(<Generic title={title} description={description} />, ogConfig);
|
||||
const img = new ImageResponse(<Generic title={title} description={description} />, ogConfig) as {
|
||||
body: Buffer;
|
||||
};
|
||||
|
||||
return new Response(img.body, { status: 200 });
|
||||
}
|
||||
|
||||
default:
|
||||
|
||||
@@ -47,7 +47,6 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse)
|
||||
select: {
|
||||
username: true,
|
||||
id: true,
|
||||
plan: true,
|
||||
createdDate: true,
|
||||
},
|
||||
});
|
||||
@@ -81,7 +80,6 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse)
|
||||
? new Date(lastBooking.booking.createdAt).toLocaleDateString("en-US")
|
||||
: "No info"
|
||||
}</li>
|
||||
<li><b>Plan:</b> ${user.plan}</li>
|
||||
<li><b>Account created:</b> ${new Date(user.createdDate).toLocaleDateString("en-US")}</li>
|
||||
</ul>
|
||||
`,
|
||||
|
||||
@@ -1,86 +1,72 @@
|
||||
import crypto from "crypto";
|
||||
import type { NextApiRequest, NextApiResponse } from "next";
|
||||
import { z } from "zod";
|
||||
|
||||
import { CAL_URL, WEBAPP_URL } from "@calcom/lib/constants";
|
||||
import { getPlaceholderAvatar } from "@calcom/lib/getPlaceholderAvatar";
|
||||
import prisma from "@calcom/prisma";
|
||||
|
||||
import { defaultAvatarSrc } from "@lib/profile";
|
||||
|
||||
export default async function handler(req: NextApiRequest, res: NextApiResponse) {
|
||||
// const username = req.url?.substring(1, req.url.lastIndexOf("/"));
|
||||
const username = req.query.username as string;
|
||||
const teamname = req.query.teamname as string;
|
||||
let identity;
|
||||
let linksToThisRoute = false;
|
||||
const querySchema = z
|
||||
.object({
|
||||
username: z.string(),
|
||||
teamname: z.string(),
|
||||
})
|
||||
.partial();
|
||||
|
||||
async function getIdentityData(req: NextApiRequest) {
|
||||
const { username, teamname } = querySchema.parse(req.query);
|
||||
|
||||
if (username) {
|
||||
const user = await prisma.user.findUnique({
|
||||
where: {
|
||||
username: username,
|
||||
},
|
||||
select: {
|
||||
avatar: true,
|
||||
email: true,
|
||||
},
|
||||
where: { username },
|
||||
select: { avatar: true, email: true },
|
||||
});
|
||||
identity = {
|
||||
return {
|
||||
name: username,
|
||||
email: user?.email,
|
||||
avatar: user?.avatar,
|
||||
};
|
||||
linksToThisRoute =
|
||||
identity.avatar === `${CAL_URL}/${username}/avatar.png` ||
|
||||
identity.avatar === `${WEBAPP_URL}/${username}/avatar.png`;
|
||||
} else if (teamname) {
|
||||
const team = await prisma.team.findUnique({
|
||||
where: {
|
||||
slug: teamname,
|
||||
},
|
||||
select: {
|
||||
logo: true,
|
||||
},
|
||||
});
|
||||
identity = {
|
||||
name: teamname,
|
||||
shouldDefaultBeNameBased: true,
|
||||
avatar: team?.logo,
|
||||
};
|
||||
linksToThisRoute =
|
||||
identity.avatar === `${CAL_URL}/team/${teamname}/avatar.png` ||
|
||||
identity.avatar === `${WEBAPP_URL}/team/${teamname}/avatar.png`;
|
||||
}
|
||||
|
||||
const emailMd5 = crypto
|
||||
.createHash("md5")
|
||||
.update((identity?.email as string) || "guest@example.com")
|
||||
.digest("hex");
|
||||
const img = identity?.avatar;
|
||||
// If image isn't set or links to this route itself, use default avatar
|
||||
if (!img || linksToThisRoute) {
|
||||
let defaultSrc = defaultAvatarSrc({ md5: emailMd5 });
|
||||
if (identity?.shouldDefaultBeNameBased) {
|
||||
defaultSrc = getPlaceholderAvatar(null, identity.name);
|
||||
}
|
||||
res.writeHead(302, {
|
||||
Location: defaultSrc,
|
||||
if (teamname) {
|
||||
const team = await prisma.team.findUnique({
|
||||
where: { slug: teamname },
|
||||
select: { logo: true },
|
||||
});
|
||||
|
||||
res.end();
|
||||
} else if (!img.includes("data:image")) {
|
||||
res.writeHead(302, {
|
||||
Location: img,
|
||||
});
|
||||
res.end();
|
||||
} else {
|
||||
const decoded = img
|
||||
.toString()
|
||||
.replace("data:image/png;base64,", "")
|
||||
.replace("data:image/jpeg;base64,", "");
|
||||
const imageResp = Buffer.from(decoded, "base64");
|
||||
res.writeHead(200, {
|
||||
"Content-Type": "image/png",
|
||||
"Content-Length": imageResp.length,
|
||||
});
|
||||
res.end(imageResp);
|
||||
return {
|
||||
name: teamname,
|
||||
email: null,
|
||||
avatar: team?.logo || getPlaceholderAvatar(null, teamname),
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
export default async function handler(req: NextApiRequest, res: NextApiResponse) {
|
||||
const identity = await getIdentityData(req);
|
||||
const img = identity?.avatar;
|
||||
// If image isn't set or links to this route itself, use default avatar
|
||||
if (!img) {
|
||||
res.writeHead(302, {
|
||||
Location: defaultAvatarSrc({
|
||||
md5: crypto
|
||||
.createHash("md5")
|
||||
.update(identity?.email || "guest@example.com")
|
||||
.digest("hex"),
|
||||
}),
|
||||
});
|
||||
return res.end();
|
||||
}
|
||||
|
||||
if (!img.includes("data:image")) {
|
||||
res.writeHead(302, { Location: img });
|
||||
return res.end();
|
||||
}
|
||||
|
||||
const decoded = img.toString().replace("data:image/png;base64,", "").replace("data:image/jpeg;base64,", "");
|
||||
const imageResp = Buffer.from(decoded, "base64");
|
||||
res.writeHead(200, {
|
||||
"Content-Type": "image/png",
|
||||
"Content-Length": imageResp.length,
|
||||
});
|
||||
res.end(imageResp);
|
||||
}
|
||||
|
||||
@@ -47,13 +47,7 @@ export default function Apps({ apps }: InferGetStaticPropsType<typeof getStaticP
|
||||
}
|
||||
|
||||
export const getStaticPaths = async () => {
|
||||
const appStore = await getAppRegistry();
|
||||
const paths = appStore.reduce((categories, app) => {
|
||||
if (!categories.includes(app.category)) {
|
||||
categories.push(app.category);
|
||||
}
|
||||
return categories;
|
||||
}, [] as string[]);
|
||||
const paths = Object.keys(AppCategories);
|
||||
|
||||
return {
|
||||
paths: paths.map((category) => ({ params: { category } })),
|
||||
|
||||
@@ -44,7 +44,9 @@ export default function Apps({ categories }: InferGetStaticPropsType<typeof getS
|
||||
export const getStaticProps = async () => {
|
||||
const appStore = await getAppRegistry();
|
||||
const categories = appStore.reduce((c, app) => {
|
||||
c[app.category] = c[app.category] ? c[app.category] + 1 : 1;
|
||||
for (const category of app.categories) {
|
||||
c[category] = c[category] ? c[category] + 1 : 1;
|
||||
}
|
||||
return c;
|
||||
}, {} as Record<string, number>);
|
||||
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
import { useAutoAnimate } from "@formkit/auto-animate/react";
|
||||
import { InferGetStaticPropsType, NextPageContext } from "next";
|
||||
import { GetServerSidePropsContext } from "next";
|
||||
import { ChangeEventHandler, useState } from "react";
|
||||
|
||||
import { getAppRegistry, getAppRegistryWithCredentials } from "@calcom/app-store/_appRegistry";
|
||||
@@ -7,6 +6,7 @@ import { classNames } from "@calcom/lib";
|
||||
import { getSession } from "@calcom/lib/auth";
|
||||
import { useLocale } from "@calcom/lib/hooks/useLocale";
|
||||
import type { AppCategories } from "@calcom/prisma/client";
|
||||
import { inferSSRProps } from "@calcom/types/inferSSRProps";
|
||||
import { AllApps, AppsLayout, AppStoreCategories, Icon, TextField, TrendingAppsSlider } from "@calcom/ui";
|
||||
|
||||
import { ssgInit } from "@server/lib/ssg";
|
||||
@@ -31,7 +31,7 @@ function AppsSearch({
|
||||
);
|
||||
}
|
||||
|
||||
export default function Apps({ appStore, categories }: InferGetStaticPropsType<typeof getServerSideProps>) {
|
||||
export default function Apps({ categories, appStore }: inferSSRProps<typeof getServerSideProps>) {
|
||||
const { t } = useLocale();
|
||||
const [searchText, setSearchText] = useState<string | undefined>(undefined);
|
||||
|
||||
@@ -42,19 +42,24 @@ export default function Apps({ appStore, categories }: InferGetStaticPropsType<t
|
||||
subtitle={t("app_store_description")}
|
||||
actions={(className) => (
|
||||
<AppsSearch className={className} onChange={(e) => setSearchText(e.target.value)} />
|
||||
)}>
|
||||
)}
|
||||
emptyStore={!appStore.length}>
|
||||
{!searchText && (
|
||||
<>
|
||||
<AppStoreCategories categories={categories} />
|
||||
<TrendingAppsSlider items={appStore} />
|
||||
</>
|
||||
)}
|
||||
<AllApps apps={appStore} searchText={searchText} />
|
||||
<AllApps
|
||||
apps={appStore}
|
||||
searchText={searchText}
|
||||
categories={categories.map((category) => category.name)}
|
||||
/>
|
||||
</AppsLayout>
|
||||
);
|
||||
}
|
||||
|
||||
export const getServerSideProps = async (context: NextPageContext) => {
|
||||
export const getServerSideProps = async (context: GetServerSidePropsContext) => {
|
||||
const ssg = await ssgInit(context);
|
||||
|
||||
const session = await getSession(context);
|
||||
@@ -77,7 +82,6 @@ export const getServerSideProps = async (context: NextPageContext) => {
|
||||
}, {} as Record<string, number>);
|
||||
return {
|
||||
props: {
|
||||
trpcState: ssg.dehydrate(),
|
||||
categories: Object.entries(categories)
|
||||
.map(([name, count]): { name: AppCategories; count: number } => ({
|
||||
name: name as AppCategories,
|
||||
@@ -87,6 +91,7 @@ export const getServerSideProps = async (context: NextPageContext) => {
|
||||
return b.count - a.count;
|
||||
}),
|
||||
appStore,
|
||||
trpcState: ssg.dehydrate(),
|
||||
},
|
||||
};
|
||||
};
|
||||
|
||||
@@ -7,12 +7,13 @@ import { useState } from "react";
|
||||
import { FormProvider, useForm } from "react-hook-form";
|
||||
import { FaGoogle } from "react-icons/fa";
|
||||
|
||||
import { SAMLLogin } from "@calcom/features/auth/SAMLLogin";
|
||||
import { isSAMLLoginEnabled, samlProductID, samlTenantID } from "@calcom/features/ee/sso/lib/saml";
|
||||
import { getSafeRedirectUrl } from "@calcom/lib/getSafeRedirectUrl";
|
||||
import { useLocale } from "@calcom/lib/hooks/useLocale";
|
||||
import { collectPageParameters, telemetryEventTypes, useTelemetry } from "@calcom/lib/telemetry";
|
||||
import prisma from "@calcom/prisma";
|
||||
import { Alert, Button, EmailField, Icon, PasswordField, SAMLLogin } from "@calcom/ui";
|
||||
import { Alert, Button, EmailField, Icon, PasswordField } from "@calcom/ui";
|
||||
|
||||
import { ErrorCode, getSession } from "@lib/auth";
|
||||
import { WEBAPP_URL, WEBSITE_URL } from "@lib/config/constants";
|
||||
|
||||
@@ -0,0 +1,70 @@
|
||||
import { UserPermissionRole } from "@prisma/client";
|
||||
import { GetServerSidePropsContext } from "next";
|
||||
import { useState } from "react";
|
||||
|
||||
import AdminAppsList from "@calcom/features/apps/AdminAppsList";
|
||||
import { getSession } from "@calcom/lib/auth";
|
||||
import { useLocale } from "@calcom/lib/hooks/useLocale";
|
||||
import prisma from "@calcom/prisma";
|
||||
import { inferSSRProps } from "@calcom/types/inferSSRProps";
|
||||
import { WizardForm } from "@calcom/ui";
|
||||
|
||||
import SetupFormStep1 from "./steps/SetupFormStep1";
|
||||
import StepDone from "./steps/StepDone";
|
||||
|
||||
export default function Setup(props: inferSSRProps<typeof getServerSideProps>) {
|
||||
const { t } = useLocale();
|
||||
const [isLoadingStep1, setIsLoadingStep1] = useState(false);
|
||||
const shouldDisable = props.userCount !== 0;
|
||||
|
||||
const steps = [
|
||||
{
|
||||
title: t("administrator_user"),
|
||||
description: t("lets_create_first_administrator_user"),
|
||||
content: shouldDisable ? <StepDone /> : <SetupFormStep1 setIsLoading={setIsLoadingStep1} />,
|
||||
isLoading: isLoadingStep1,
|
||||
},
|
||||
{
|
||||
title: t("enable_apps"),
|
||||
description: t("enable_apps_description"),
|
||||
content: <AdminAppsList baseURL="/auth/setup?step=2" />,
|
||||
isLoading: false,
|
||||
},
|
||||
];
|
||||
|
||||
return (
|
||||
<>
|
||||
<main className="flex items-center bg-gray-100 print:h-full">
|
||||
<WizardForm
|
||||
href="/auth/setup"
|
||||
steps={steps}
|
||||
nextLabel={t("next_step_text")}
|
||||
finishLabel={t("finish")}
|
||||
prevLabel={t("prev_step")}
|
||||
stepLabel={(currentStep, maxSteps) => t("current_step_of_total", { currentStep, maxSteps })}
|
||||
/>
|
||||
</main>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
export const getServerSideProps = async (context: GetServerSidePropsContext) => {
|
||||
const userCount = await prisma.user.count();
|
||||
const { req } = context;
|
||||
const session = await getSession({ req });
|
||||
|
||||
if (session?.user.role && session?.user.role !== UserPermissionRole.ADMIN) {
|
||||
return {
|
||||
redirect: {
|
||||
destination: `/404`,
|
||||
permanent: false,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
props: {
|
||||
userCount,
|
||||
},
|
||||
};
|
||||
};
|
||||
+12
-59
@@ -1,34 +1,14 @@
|
||||
import { CheckIcon } from "@heroicons/react/solid";
|
||||
import { zodResolver } from "@hookform/resolvers/zod";
|
||||
import classNames from "classnames";
|
||||
import { GetServerSidePropsContext } from "next";
|
||||
import { signIn } from "next-auth/react";
|
||||
import { useRouter } from "next/router";
|
||||
import { useState } from "react";
|
||||
import { Controller, FormProvider, useForm } from "react-hook-form";
|
||||
import * as z from "zod";
|
||||
|
||||
import { isPasswordValid } from "@calcom/lib/auth";
|
||||
import { WEBSITE_URL } from "@calcom/lib/constants";
|
||||
import { useLocale } from "@calcom/lib/hooks/useLocale";
|
||||
import prisma from "@calcom/prisma";
|
||||
import { inferSSRProps } from "@calcom/types/inferSSRProps";
|
||||
import { EmailField, Label, PasswordField, TextField, WizardForm } from "@calcom/ui";
|
||||
|
||||
import { ssrInit } from "@server/lib/ssr";
|
||||
|
||||
const StepDone = () => {
|
||||
const { t } = useLocale();
|
||||
|
||||
return (
|
||||
<div className="min-h-36 my-6 flex flex-col items-center justify-center">
|
||||
<div className="flex h-[72px] w-[72px] items-center justify-center rounded-full bg-gray-600 dark:bg-white">
|
||||
<CheckIcon className="inline-block h-10 w-10 text-white dark:bg-white dark:text-gray-600" />
|
||||
</div>
|
||||
<div className="max-w-[420px] text-center">
|
||||
<h2 className="mt-6 mb-1 text-lg font-medium dark:text-gray-300">{t("all_done")}</h2>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
import { EmailField, Label, PasswordField, TextField } from "@calcom/ui";
|
||||
|
||||
const SetupFormStep1 = (props: { setIsLoading: (val: boolean) => void }) => {
|
||||
const router = useRouter();
|
||||
@@ -83,13 +63,19 @@ const SetupFormStep1 = (props: { setIsLoading: (val: boolean) => void }) => {
|
||||
},
|
||||
});
|
||||
if (response.status === 200) {
|
||||
router.replace(`/auth/login?email=${data.email_address.toLowerCase()}`);
|
||||
await signIn("credentials", {
|
||||
redirect: false,
|
||||
callbackUrl: "/",
|
||||
email: data.email_address.toLowerCase(),
|
||||
password: data.password,
|
||||
});
|
||||
router.replace(`/auth/setup?step=2&category=calendar`);
|
||||
} else {
|
||||
router.replace("/auth/setup");
|
||||
}
|
||||
}, onError);
|
||||
|
||||
const longWebsiteUrl = process.env.NEXT_PUBLIC_WEBSITE_URL.length > 30;
|
||||
const longWebsiteUrl = WEBSITE_URL.length > 30;
|
||||
|
||||
return (
|
||||
<FormProvider {...formMethods}>
|
||||
@@ -201,37 +187,4 @@ const SetupFormStep1 = (props: { setIsLoading: (val: boolean) => void }) => {
|
||||
);
|
||||
};
|
||||
|
||||
export default function Setup(props: inferSSRProps<typeof getServerSideProps>) {
|
||||
const { t } = useLocale();
|
||||
const [isLoadingStep1, setIsLoadingStep1] = useState(false);
|
||||
|
||||
const steps = [
|
||||
{
|
||||
title: t("administrator_user"),
|
||||
description: t("lets_create_first_administrator_user"),
|
||||
content: props.userCount !== 0 ? <StepDone /> : <SetupFormStep1 setIsLoading={setIsLoadingStep1} />,
|
||||
enabled: props.userCount === 0, // to check if the wizard should show buttons to navigate through more steps
|
||||
isLoading: isLoadingStep1,
|
||||
},
|
||||
];
|
||||
|
||||
return (
|
||||
<>
|
||||
<main className="flex h-screen items-center bg-gray-100 print:h-full">
|
||||
<WizardForm href="/auth/setup" steps={steps} containerClassname="max-w-sm" />
|
||||
</main>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
export const getServerSideProps = async (context: GetServerSidePropsContext) => {
|
||||
const ssr = await ssrInit(context);
|
||||
const userCount = await prisma.user.count();
|
||||
|
||||
return {
|
||||
props: {
|
||||
trpcState: ssr.dehydrate(),
|
||||
userCount,
|
||||
},
|
||||
};
|
||||
};
|
||||
export default SetupFormStep1;
|
||||
@@ -0,0 +1,31 @@
|
||||
import { useRouter } from "next/router";
|
||||
|
||||
import { useLocale } from "@calcom/lib/hooks/useLocale";
|
||||
import { Icon } from "@calcom/ui";
|
||||
|
||||
const StepDone = () => {
|
||||
const router = useRouter();
|
||||
const { t } = useLocale();
|
||||
|
||||
return (
|
||||
<form
|
||||
id="wizard-step-1"
|
||||
name="wizard-step-1"
|
||||
className="space-y-4"
|
||||
onSubmit={(e) => {
|
||||
e.preventDefault();
|
||||
router.replace(`/auth/setup?step=2&category=calendar`);
|
||||
}}>
|
||||
<div className="min-h-36 my-6 flex flex-col items-center justify-center">
|
||||
<div className="flex h-[72px] w-[72px] items-center justify-center rounded-full bg-gray-600 dark:bg-white">
|
||||
<Icon.FiCheck className="inline-block h-10 w-10 text-white dark:bg-white dark:text-gray-600" />
|
||||
</div>
|
||||
<div className="max-w-[420px] text-center">
|
||||
<h2 className="mt-6 mb-1 text-lg font-medium dark:text-gray-300">{t("all_done")}</h2>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
);
|
||||
};
|
||||
|
||||
export default StepDone;
|
||||
@@ -1,15 +1,16 @@
|
||||
import { GetStaticPaths, GetStaticProps } from "next";
|
||||
import { useEffect } from "react";
|
||||
import { Controller, useForm } from "react-hook-form";
|
||||
import { GetServerSidePropsContext } from "next";
|
||||
import { Controller, useFieldArray, useForm } from "react-hook-form";
|
||||
import { z } from "zod";
|
||||
|
||||
import { DateOverrideInputDialog, DateOverrideList } from "@calcom/features/schedules";
|
||||
import Schedule from "@calcom/features/schedules/components/Schedule";
|
||||
import { availabilityAsString } from "@calcom/lib/availability";
|
||||
import { yyyymmdd } from "@calcom/lib/date-fns";
|
||||
import { useLocale } from "@calcom/lib/hooks/useLocale";
|
||||
import { stringOrNumber } from "@calcom/prisma/zod-utils";
|
||||
import { trpc } from "@calcom/trpc/react";
|
||||
import useMeQuery from "@calcom/trpc/react/hooks/useMeQuery";
|
||||
import type { Schedule as ScheduleType } from "@calcom/types/schedule";
|
||||
import type { Schedule as ScheduleType, TimeRange, WorkingHours } from "@calcom/types/schedule";
|
||||
import {
|
||||
Button,
|
||||
Form,
|
||||
@@ -21,6 +22,7 @@ import {
|
||||
SkeletonText,
|
||||
Switch,
|
||||
TimezoneSelect,
|
||||
Tooltip,
|
||||
VerticalDivider,
|
||||
} from "@calcom/ui";
|
||||
|
||||
@@ -29,7 +31,7 @@ import { HttpError } from "@lib/core/http/error";
|
||||
import { SelectSkeletonLoader } from "@components/availability/SkeletonLoader";
|
||||
import EditableHeading from "@components/ui/EditableHeading";
|
||||
|
||||
import { ssgInit } from "@server/lib/ssg";
|
||||
import { ssrInit } from "@server/lib/ssr";
|
||||
|
||||
const querySchema = z.object({
|
||||
schedule: stringOrNumber,
|
||||
@@ -38,31 +40,59 @@ const querySchema = z.object({
|
||||
type AvailabilityFormValues = {
|
||||
name: string;
|
||||
schedule: ScheduleType;
|
||||
dateOverrides: { ranges: TimeRange[] }[];
|
||||
timeZone: string;
|
||||
isDefault: boolean;
|
||||
};
|
||||
|
||||
const DateOverride = ({ workingHours }: { workingHours: WorkingHours[] }) => {
|
||||
const { remove, append, update, fields } = useFieldArray<AvailabilityFormValues, "dateOverrides">({
|
||||
name: "dateOverrides",
|
||||
});
|
||||
const { t } = useLocale();
|
||||
return (
|
||||
<div className="px-4 py-5 sm:p-6">
|
||||
<h3 className="font-medium leading-6 text-gray-900">
|
||||
{t("date_overrides")}{" "}
|
||||
<Tooltip content={t("date_overrides_info")}>
|
||||
<span className="inline-block">
|
||||
<Icon.FiInfo />
|
||||
</span>
|
||||
</Tooltip>
|
||||
</h3>
|
||||
<p className="mb-4 text-sm text-neutral-500 ltr:mr-4 rtl:ml-4">{t("date_overrides_subtitle")}</p>
|
||||
<div className="mt-1 space-y-2">
|
||||
<DateOverrideList
|
||||
excludedDates={fields.map((field) => yyyymmdd(field.ranges[0].start))}
|
||||
remove={remove}
|
||||
update={update}
|
||||
items={fields}
|
||||
workingHours={workingHours}
|
||||
/>
|
||||
<DateOverrideInputDialog
|
||||
workingHours={workingHours}
|
||||
excludedDates={fields.map((field) => yyyymmdd(field.ranges[0].start))}
|
||||
onChange={(ranges) => append({ ranges })}
|
||||
Trigger={
|
||||
<Button color="secondary" StartIcon={Icon.FiPlus} data-testid="add-override">
|
||||
Add an override
|
||||
</Button>
|
||||
}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default function Availability({ schedule }: { schedule: number }) {
|
||||
const { t, i18n } = useLocale();
|
||||
const utils = trpc.useContext();
|
||||
const me = useMeQuery();
|
||||
const { timeFormat } = me.data || { timeFormat: null };
|
||||
const { data, isLoading } = trpc.viewer.availability.schedule.get.useQuery({ scheduleId: schedule });
|
||||
|
||||
const form = useForm<AvailabilityFormValues>();
|
||||
const { control, reset } = form;
|
||||
|
||||
useEffect(() => {
|
||||
if (!isLoading && data) {
|
||||
reset({
|
||||
name: data?.schedule?.name,
|
||||
schedule: data.availability,
|
||||
timeZone: data.timeZone,
|
||||
isDefault: data.isDefault,
|
||||
});
|
||||
}
|
||||
}, [data, isLoading, reset]);
|
||||
|
||||
const { data: defaultValues } = trpc.viewer.availability.defaultValues.useQuery({ scheduleId: schedule });
|
||||
const form = useForm<AvailabilityFormValues>({ defaultValues });
|
||||
const { control } = form;
|
||||
const updateMutation = trpc.viewer.availability.schedule.update.useMutation({
|
||||
onSuccess: async ({ prevDefaultId, currentDefaultId, ...data }) => {
|
||||
if (prevDefaultId && currentDefaultId) {
|
||||
@@ -73,7 +103,7 @@ export default function Availability({ schedule }: { schedule: number }) {
|
||||
utils.viewer.availability.schedule.get.refetch({ scheduleId: prevDefaultId });
|
||||
}
|
||||
}
|
||||
utils.viewer.availability.schedule.get.setData({ scheduleId: data.schedule.id }, data);
|
||||
utils.viewer.availability.schedule.get.invalidate({ scheduleId: data.schedule.id });
|
||||
utils.viewer.availability.list.invalidate();
|
||||
showToast(
|
||||
t("availability_updated_successfully", {
|
||||
@@ -98,17 +128,21 @@ export default function Availability({ schedule }: { schedule: number }) {
|
||||
<Controller
|
||||
control={form.control}
|
||||
name="name"
|
||||
render={({ field }) => <EditableHeading isReady={!isLoading} {...field} />}
|
||||
render={({ field }) => (
|
||||
<EditableHeading isReady={!isLoading} {...field} data-testid="availablity-title" />
|
||||
)}
|
||||
/>
|
||||
}
|
||||
subtitle={
|
||||
data ? (
|
||||
data.schedule.availability.map((availability) => (
|
||||
<span key={availability.id}>
|
||||
{availabilityAsString(availability, { locale: i18n.language, hour12: timeFormat === 12 })}
|
||||
<br />
|
||||
</span>
|
||||
))
|
||||
data.schedule.availability
|
||||
.filter((availability) => !!availability.days.length)
|
||||
.map((availability) => (
|
||||
<span key={availability.id}>
|
||||
{availabilityAsString(availability, { locale: i18n.language, hour12: timeFormat === 12 })}
|
||||
<br />
|
||||
</span>
|
||||
))
|
||||
) : (
|
||||
<SkeletonText className="h-4 w-48" />
|
||||
)
|
||||
@@ -140,95 +174,88 @@ export default function Availability({ schedule }: { schedule: number }) {
|
||||
</Button>
|
||||
</div>
|
||||
}>
|
||||
<div className="flex items-baseline sm:mt-0">
|
||||
{/* TODO: Find a better way to guarantee alignment, but for now this'll do. */}
|
||||
<Icon.FiArrowLeft className=" mr-3 text-transparent hover:cursor-pointer" />
|
||||
<div className="w-full">
|
||||
<Form
|
||||
form={form}
|
||||
id="availability-form"
|
||||
handleSubmit={async (values) => {
|
||||
updateMutation.mutate({
|
||||
scheduleId: schedule,
|
||||
...values,
|
||||
});
|
||||
}}
|
||||
className="-mx-4 flex flex-col pb-16 sm:mx-0 xl:flex-row xl:space-x-6">
|
||||
<div className="flex-1">
|
||||
<div className="rounded-md border-gray-200 bg-white py-5 pr-4 sm:border sm:p-6">
|
||||
<h3 className="mb-5 text-base font-medium leading-6 text-gray-900">
|
||||
{t("change_start_end")}
|
||||
</h3>
|
||||
{typeof me.data?.weekStart === "string" && (
|
||||
<Schedule
|
||||
control={control}
|
||||
name="schedule"
|
||||
weekStart={
|
||||
["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"].indexOf(
|
||||
me.data?.weekStart
|
||||
) as 0 | 1 | 2 | 3 | 4 | 5 | 6
|
||||
}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
<div className="w-full">
|
||||
<Form
|
||||
form={form}
|
||||
id="availability-form"
|
||||
handleSubmit={async ({ dateOverrides, ...values }) => {
|
||||
updateMutation.mutate({
|
||||
scheduleId: schedule,
|
||||
dateOverrides: dateOverrides.flatMap((override) => override.ranges),
|
||||
...values,
|
||||
});
|
||||
}}
|
||||
className="flex flex-col pb-16 sm:mx-0 xl:flex-row xl:space-x-6">
|
||||
<div className="flex-1 divide-y divide-neutral-200 rounded-md border">
|
||||
<div className=" py-5 sm:p-6">
|
||||
<h3 className="mb-2 px-5 text-base font-medium leading-6 text-gray-900 sm:pl-0">
|
||||
{t("change_start_end")}
|
||||
</h3>
|
||||
{typeof me.data?.weekStart === "string" && (
|
||||
<Schedule
|
||||
control={control}
|
||||
name="schedule"
|
||||
weekStart={
|
||||
["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"].indexOf(
|
||||
me.data?.weekStart
|
||||
) as 0 | 1 | 2 | 3 | 4 | 5 | 6
|
||||
}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
<div className="min-w-40 col-span-3 space-y-2 lg:col-span-1">
|
||||
<div className="xl:max-w-80 mt-4 w-full pr-4 sm:p-0">
|
||||
<div>
|
||||
<label htmlFor="timeZone" className="block text-sm font-medium text-gray-700">
|
||||
{t("timezone")}
|
||||
</label>
|
||||
<Controller
|
||||
name="timeZone"
|
||||
render={({ field: { onChange, value } }) =>
|
||||
value ? (
|
||||
<TimezoneSelect
|
||||
value={value}
|
||||
className="focus:border-brand mt-1 block w-72 rounded-md border-gray-300 text-sm"
|
||||
onChange={(timezone) => onChange(timezone.value)}
|
||||
/>
|
||||
) : (
|
||||
<SelectSkeletonLoader className="w-72" />
|
||||
)
|
||||
}
|
||||
/>
|
||||
</div>
|
||||
<hr className="my-8" />
|
||||
<div className="rounded-md">
|
||||
<h3 className="text-sm font-medium text-gray-900">{t("something_doesnt_look_right")}</h3>
|
||||
<div className="mt-3 flex">
|
||||
<Button href="/availability/troubleshoot" color="secondary">
|
||||
{t("launch_troubleshooter")}
|
||||
</Button>
|
||||
</div>
|
||||
{data?.workingHours && <DateOverride workingHours={data.workingHours} />}
|
||||
</div>
|
||||
<div className="min-w-40 col-span-3 space-y-2 lg:col-span-1">
|
||||
<div className="xl:max-w-80 mt-4 w-full pr-4 sm:p-0">
|
||||
<div>
|
||||
<label htmlFor="timeZone" className="block text-sm font-medium text-gray-700">
|
||||
{t("timezone")}
|
||||
</label>
|
||||
<Controller
|
||||
name="timeZone"
|
||||
render={({ field: { onChange, value } }) =>
|
||||
value ? (
|
||||
<TimezoneSelect
|
||||
value={value}
|
||||
className="focus:border-brand mt-1 block w-72 rounded-md border-gray-300 text-sm"
|
||||
onChange={(timezone) => onChange(timezone.value)}
|
||||
/>
|
||||
) : (
|
||||
<SelectSkeletonLoader className="w-72" />
|
||||
)
|
||||
}
|
||||
/>
|
||||
</div>
|
||||
<hr className="my-8" />
|
||||
<div className="rounded-md">
|
||||
<h3 className="text-sm font-medium text-gray-900">{t("something_doesnt_look_right")}</h3>
|
||||
<div className="mt-3 flex">
|
||||
<Button href="/availability/troubleshoot" color="secondary">
|
||||
{t("launch_troubleshooter")}
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</Form>
|
||||
</div>
|
||||
</div>
|
||||
</Form>
|
||||
</div>
|
||||
</Shell>
|
||||
);
|
||||
}
|
||||
|
||||
export const getStaticProps: GetStaticProps = async (ctx) => {
|
||||
export const getServerSideProps = async (ctx: GetServerSidePropsContext) => {
|
||||
const params = querySchema.safeParse(ctx.params);
|
||||
const ssg = await ssgInit(ctx);
|
||||
const ssr = await ssrInit(ctx);
|
||||
|
||||
if (!params.success) return { notFound: true };
|
||||
|
||||
const scheduleId = params.data.schedule;
|
||||
await ssr.viewer.availability.schedule.get.fetch({ scheduleId });
|
||||
await ssr.viewer.availability.defaultValues.fetch({ scheduleId });
|
||||
return {
|
||||
props: {
|
||||
schedule: params.data.schedule,
|
||||
trpcState: ssg.dehydrate(),
|
||||
schedule: scheduleId,
|
||||
trpcState: ssr.dehydrate(),
|
||||
},
|
||||
revalidate: 10, // seconds
|
||||
};
|
||||
};
|
||||
|
||||
export const getStaticPaths: GetStaticPaths = () => {
|
||||
return {
|
||||
paths: [],
|
||||
fallback: "blocking",
|
||||
};
|
||||
};
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
import { useState } from "react";
|
||||
|
||||
import dayjs from "@calcom/dayjs";
|
||||
import { useLocale } from "@calcom/lib/hooks/useLocale";
|
||||
import { RouterOutputs, trpc } from "@calcom/trpc/react";
|
||||
import { Shell, SkeletonText } from "@calcom/ui";
|
||||
|
||||
import useRouterQuery from "@lib/hooks/useRouterQuery";
|
||||
|
||||
type User = RouterOutputs["viewer"]["me"];
|
||||
|
||||
export interface IBusySlot {
|
||||
@@ -16,7 +16,9 @@ export interface IBusySlot {
|
||||
|
||||
const AvailabilityView = ({ user }: { user: User }) => {
|
||||
const { t } = useLocale();
|
||||
const [selectedDate, setSelectedDate] = useState(dayjs());
|
||||
const { date, setQuery: setSelectedDate } = useRouterQuery("date");
|
||||
const selectedDate = dayjs(date);
|
||||
const formattedSelectedDate = selectedDate.format("YYYY-MM-DD");
|
||||
|
||||
const { data, isLoading } = trpc.viewer.availability.user.useQuery(
|
||||
{
|
||||
@@ -30,6 +32,17 @@ const AvailabilityView = ({ user }: { user: User }) => {
|
||||
}
|
||||
);
|
||||
|
||||
const overrides =
|
||||
data?.dateOverrides.reduce((acc, override) => {
|
||||
if (
|
||||
formattedSelectedDate !== dayjs(override.start).format("YYYY-MM-DD") &&
|
||||
formattedSelectedDate !== dayjs(override.end).format("YYYY-MM-DD")
|
||||
)
|
||||
return acc;
|
||||
acc.push({ ...override, source: "Date override" });
|
||||
return acc;
|
||||
}, [] as IBusySlot[]) || [];
|
||||
|
||||
return (
|
||||
<div className="max-w-xl overflow-hidden rounded-md bg-white shadow">
|
||||
<div className="px-4 py-5 sm:p-6">
|
||||
@@ -37,9 +50,9 @@ const AvailabilityView = ({ user }: { user: User }) => {
|
||||
<input
|
||||
type="date"
|
||||
className="inline h-8 border-none p-0"
|
||||
defaultValue={selectedDate.format("YYYY-MM-DD")}
|
||||
defaultValue={formattedSelectedDate}
|
||||
onChange={(e) => {
|
||||
if (e.target.value) setSelectedDate(dayjs(e.target.value));
|
||||
if (e.target.value) setSelectedDate(e.target.value);
|
||||
}}
|
||||
/>
|
||||
<small className="block text-neutral-400">{t("hover_over_bold_times_tip")}</small>
|
||||
@@ -49,39 +62,47 @@ const AvailabilityView = ({ user }: { user: User }) => {
|
||||
{t("your_day_starts_at")} {convertMinsToHrsMins(user.startTime)}
|
||||
</div>
|
||||
</div>
|
||||
{isLoading ? (
|
||||
<>
|
||||
<SkeletonText className="block h-16 w-full" />
|
||||
<SkeletonText className="block h-16 w-full" />
|
||||
</>
|
||||
) : data && data.busy.length > 0 ? (
|
||||
data.busy
|
||||
.sort((a: IBusySlot, b: IBusySlot) => (a.start > b.start ? -1 : 1))
|
||||
.map((slot: IBusySlot) => (
|
||||
<div
|
||||
key={dayjs(slot.start).format("HH:mm")}
|
||||
className="overflow-hidden rounded-md bg-neutral-100">
|
||||
<div className="px-4 py-5 text-black sm:p-6">
|
||||
{t("calendar_shows_busy_between")}{" "}
|
||||
<span className="font-medium text-neutral-800" title={dayjs(slot.start).format("HH:mm")}>
|
||||
{dayjs(slot.start).format("HH:mm")}
|
||||
</span>{" "}
|
||||
{t("and")}{" "}
|
||||
<span className="font-medium text-neutral-800" title={dayjs(slot.end).format("HH:mm")}>
|
||||
{dayjs(slot.end).format("HH:mm")}
|
||||
</span>{" "}
|
||||
{t("on")} {dayjs(slot.start).format("D")}{" "}
|
||||
{t(dayjs(slot.start).format("MMMM").toLowerCase())} {dayjs(slot.start).format("YYYY")}
|
||||
{slot.title && ` - (${slot.title})`}
|
||||
{slot.source && <small>{` - (source: ${slot.source})`}</small>}
|
||||
{(() => {
|
||||
if (isLoading)
|
||||
return (
|
||||
<>
|
||||
<SkeletonText className="block h-16 w-full" />
|
||||
<SkeletonText className="block h-16 w-full" />
|
||||
</>
|
||||
);
|
||||
|
||||
if (data && (data.busy.length > 0 || overrides.length > 0))
|
||||
return [...data.busy, ...overrides]
|
||||
.sort((a: IBusySlot, b: IBusySlot) => (a.start > b.start ? -1 : 1))
|
||||
.map((slot: IBusySlot) => (
|
||||
<div
|
||||
key={dayjs(slot.start).format("HH:mm")}
|
||||
className="overflow-hidden rounded-md bg-neutral-100"
|
||||
data-testid="troubleshooter-busy-time">
|
||||
<div className="px-4 py-5 text-black sm:p-6">
|
||||
{t("calendar_shows_busy_between")}{" "}
|
||||
<span
|
||||
className="font-medium text-neutral-800"
|
||||
title={dayjs(slot.start).format("HH:mm")}>
|
||||
{dayjs(slot.start).format("HH:mm")}
|
||||
</span>{" "}
|
||||
{t("and")}{" "}
|
||||
<span className="font-medium text-neutral-800" title={dayjs(slot.end).format("HH:mm")}>
|
||||
{dayjs(slot.end).format("HH:mm")}
|
||||
</span>{" "}
|
||||
{t("on")} {dayjs(slot.start).format("D")}{" "}
|
||||
{t(dayjs(slot.start).format("MMMM").toLowerCase())} {dayjs(slot.start).format("YYYY")}
|
||||
{slot.title && ` - (${slot.title})`}
|
||||
{slot.source && <small>{` - (source: ${slot.source})`}</small>}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
))
|
||||
) : (
|
||||
<div className="overflow-hidden rounded-md bg-neutral-100">
|
||||
<div className="px-4 py-5 text-black sm:p-6">{t("calendar_no_busy_slots")}</div>
|
||||
</div>
|
||||
)}
|
||||
));
|
||||
return (
|
||||
<div className="overflow-hidden rounded-md bg-neutral-100">
|
||||
<div className="px-4 py-5 text-black sm:p-6">{t("calendar_no_busy_slots")}</div>
|
||||
</div>
|
||||
);
|
||||
})()}
|
||||
|
||||
<div className="bg-brand dark:bg-darkmodebrand overflow-hidden rounded-md">
|
||||
<div className="text-brandcontrast dark:text-darkmodebrandcontrast px-4 py-2 sm:px-6">
|
||||
|
||||
@@ -57,26 +57,41 @@ function redirectToExternalUrl(url: string) {
|
||||
function RedirectionToast({ url }: { url: string }) {
|
||||
const [timeRemaining, setTimeRemaining] = useState(10);
|
||||
const [isToastVisible, setIsToastVisible] = useState(true);
|
||||
const parsedSuccessUrl = new URL(document.URL);
|
||||
const parsedExternalUrl = new URL(url);
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
||||
/* @ts-ignore */ //https://stackoverflow.com/questions/49218765/typescript-and-iterator-type-iterableiteratort-is-not-an-array-type
|
||||
for (const [name, value] of parsedExternalUrl.searchParams.entries()) {
|
||||
parsedSuccessUrl.searchParams.set(name, value);
|
||||
}
|
||||
|
||||
const urlWithSuccessParams =
|
||||
parsedExternalUrl.origin +
|
||||
parsedExternalUrl.pathname +
|
||||
"?" +
|
||||
parsedSuccessUrl.searchParams.toString() +
|
||||
parsedExternalUrl.hash;
|
||||
|
||||
const { t } = useLocale();
|
||||
const timerRef = useRef<number | null>(null);
|
||||
const router = useRouter();
|
||||
const { cancel: isCancellationMode } = querySchema.parse(router.query);
|
||||
const urlWithSuccessParamsRef = useRef<string | null>();
|
||||
if (isCancellationMode && timerRef.current) {
|
||||
setIsToastVisible(false);
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
if (!isToastVisible && timerRef.current) {
|
||||
window.clearInterval(timerRef.current);
|
||||
}
|
||||
}, [isToastVisible]);
|
||||
|
||||
useEffect(() => {
|
||||
const parsedExternalUrl = new URL(url);
|
||||
|
||||
const parsedSuccessUrl = new URL(document.URL);
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
||||
/* @ts-ignore */ //https://stackoverflow.com/questions/49218765/typescript-and-iterator-type-iterableiteratort-is-not-an-array-type
|
||||
for (const [name, value] of parsedExternalUrl.searchParams.entries()) {
|
||||
parsedSuccessUrl.searchParams.set(name, value);
|
||||
}
|
||||
|
||||
const urlWithSuccessParams =
|
||||
parsedExternalUrl.origin +
|
||||
parsedExternalUrl.pathname +
|
||||
"?" +
|
||||
parsedSuccessUrl.searchParams.toString() +
|
||||
parsedExternalUrl.hash;
|
||||
urlWithSuccessParamsRef.current = urlWithSuccessParams;
|
||||
|
||||
timerRef.current = window.setInterval(() => {
|
||||
if (timeRemaining > 0) {
|
||||
setTimeRemaining((timeRemaining) => {
|
||||
@@ -90,7 +105,7 @@ function RedirectionToast({ url }: { url: string }) {
|
||||
return () => {
|
||||
window.clearInterval(timerRef.current as number);
|
||||
};
|
||||
}, [timeRemaining, urlWithSuccessParams]);
|
||||
}, [timeRemaining, url]);
|
||||
|
||||
if (!isToastVisible) {
|
||||
return null;
|
||||
@@ -113,7 +128,9 @@ function RedirectionToast({ url }: { url: string }) {
|
||||
<div className="order-3 mt-2 w-full flex-shrink-0 sm:order-2 sm:mt-0 sm:w-auto">
|
||||
<button
|
||||
onClick={() => {
|
||||
redirectToExternalUrl(urlWithSuccessParams);
|
||||
if (urlWithSuccessParamsRef.current) {
|
||||
redirectToExternalUrl(urlWithSuccessParamsRef.current);
|
||||
}
|
||||
}}
|
||||
className="flex w-full items-center justify-center rounded-sm border border-transparent bg-white px-4 py-2 text-sm font-medium text-green-600 hover:bg-green-50">
|
||||
{t("continue")}
|
||||
@@ -124,7 +141,6 @@ function RedirectionToast({ url }: { url: string }) {
|
||||
type="button"
|
||||
onClick={() => {
|
||||
setIsToastVisible(false);
|
||||
window.clearInterval(timerRef.current as number);
|
||||
}}
|
||||
className="-mr-1 flex rounded-md p-2 hover:bg-green-600 focus:outline-none focus:ring-2 focus:ring-white">
|
||||
<Icon.FiX className="h-6 w-6 text-white" />
|
||||
@@ -152,6 +168,7 @@ const querySchema = z.object({
|
||||
changes: stringToBoolean,
|
||||
reschedule: stringToBoolean,
|
||||
isSuccessBookingPage: z.string().optional(),
|
||||
formerTime: z.string().optional(),
|
||||
});
|
||||
|
||||
export default function Success(props: SuccessProps) {
|
||||
@@ -163,6 +180,7 @@ export default function Success(props: SuccessProps) {
|
||||
isSuccessBookingPage,
|
||||
cancel: isCancellationMode,
|
||||
changes,
|
||||
formerTime,
|
||||
} = querySchema.parse(router.query);
|
||||
|
||||
if ((isCancellationMode || changes) && typeof window !== "undefined") {
|
||||
@@ -349,7 +367,9 @@ export default function Success(props: SuccessProps) {
|
||||
<CustomBranding lightVal={props.profile.brandColor} darkVal={props.profile.darkBrandColor} />
|
||||
<main className={classNames(shouldAlignCentrally ? "mx-auto" : "", isEmbed ? "" : "max-w-3xl")}>
|
||||
<div className={classNames("overflow-y-auto", isEmbed ? "" : "z-50 ")}>
|
||||
{eventType.successRedirectUrl ? <RedirectionToast url={eventType.successRedirectUrl} /> : null}{" "}
|
||||
{isSuccessBookingPage && !isCancellationMode && eventType.successRedirectUrl ? (
|
||||
<RedirectionToast url={eventType.successRedirectUrl} />
|
||||
) : null}{" "}
|
||||
<div
|
||||
className={classNames(
|
||||
shouldAlignCentrally ? "text-center" : "",
|
||||
@@ -407,9 +427,11 @@ export default function Success(props: SuccessProps) {
|
||||
<p className="text-neutral-600 dark:text-gray-300">{getTitle()}</p>
|
||||
</div>
|
||||
<div className="border-bookinglightest text-bookingdark dark:border-darkgray-300 mt-8 grid grid-cols-3 border-t pt-8 text-left dark:text-gray-300">
|
||||
{isCancelled && cancellationReason && (
|
||||
{(isCancelled || reschedule) && cancellationReason && (
|
||||
<>
|
||||
<div className="font-medium">{t("reason")}</div>
|
||||
<div className="font-medium">
|
||||
{isCancelled ? t("reason") : t("reschedule_reason_success_page")}
|
||||
</div>
|
||||
<div className="col-span-2 mb-6 last:mb-0">{cancellationReason}</div>
|
||||
</>
|
||||
)}
|
||||
@@ -417,6 +439,19 @@ export default function Success(props: SuccessProps) {
|
||||
<div className="col-span-2 mb-6 last:mb-0">{eventName}</div>
|
||||
<div className="font-medium">{t("when")}</div>
|
||||
<div className="col-span-2 mb-6 last:mb-0">
|
||||
{reschedule && !!formerTime && (
|
||||
<p className="line-through">
|
||||
<RecurringBookings
|
||||
eventType={props.eventType}
|
||||
duration={calculatedDuration}
|
||||
recurringBookings={props.recurringBookings}
|
||||
allRemainingBookings={allRemainingBookings}
|
||||
date={dayjs(formerTime)}
|
||||
is24h={is24h}
|
||||
isCancelled={isCancelled}
|
||||
/>
|
||||
</p>
|
||||
)}
|
||||
<RecurringBookings
|
||||
eventType={props.eventType}
|
||||
duration={calculatedDuration}
|
||||
@@ -772,10 +807,10 @@ export function RecurringBookings({
|
||||
{eventType.recurringEvent?.count &&
|
||||
recurringBookingsSorted.slice(0, 4).map((dateStr: string, idx: number) => (
|
||||
<div key={idx} className={classNames("mb-2", isCancelled ? "line-through" : "")}>
|
||||
{dayjs.tz(dateStr, timeZone()).format("MMMM DD, YYYY")}
|
||||
{dayjs.tz(dateStr, timeZone()).format("dddd, DD MMMM YYYY")}
|
||||
<br />
|
||||
{formatTime(dateStr, is24h ? 24 : 12, timeZone())} -{" "}
|
||||
{formatTime(dayjs(dateStr).add(duration, "m"), is24h ? 24 : 12, timeZone())}{" "}
|
||||
{formatTime(dateStr, is24h ? 24 : 12, timeZone().toLowerCase())} -{" "}
|
||||
{formatTime(dayjs(dateStr).add(duration, "m"), is24h ? 24 : 12, timeZone().toLowerCase())}{" "}
|
||||
<span className="text-bookinglight">({timeZone()})</span>
|
||||
</div>
|
||||
))}
|
||||
@@ -790,10 +825,10 @@ export function RecurringBookings({
|
||||
{eventType.recurringEvent?.count &&
|
||||
recurringBookingsSorted.slice(4).map((dateStr: string, idx: number) => (
|
||||
<div key={idx} className={classNames("mb-2", isCancelled ? "line-through" : "")}>
|
||||
{dayjs.tz(dateStr, timeZone()).format("MMMM DD, YYYY")}
|
||||
{dayjs.tz(dateStr, timeZone()).format("dddd, DD MMMM YYYY")}
|
||||
<br />
|
||||
{formatTime(dateStr, is24h ? 24 : 12, timeZone())} -{" "}
|
||||
{formatTime(dayjs(dateStr).add(duration, "m"), is24h ? 24 : 12, timeZone())}{" "}
|
||||
{formatTime(dateStr, is24h ? 24 : 12, timeZone().toLowerCase())} -{" "}
|
||||
{formatTime(dayjs(dateStr).add(duration, "m"), is24h ? 24 : 12, timeZone().toLowerCase())}{" "}
|
||||
<span className="text-bookinglight">({timeZone()})</span>
|
||||
</div>
|
||||
))}
|
||||
@@ -806,10 +841,10 @@ export function RecurringBookings({
|
||||
|
||||
return (
|
||||
<div className={classNames(isCancelled ? "line-through" : "")}>
|
||||
{dayjs.tz(date, timeZone()).format("MMMM DD, YYYY")}
|
||||
{dayjs.tz(date, timeZone()).format("dddd, DD MMMM YYYY")}
|
||||
<br />
|
||||
{formatTime(date, is24h ? 24 : 12, timeZone())} -{" "}
|
||||
{formatTime(dayjs(date).add(duration, "m"), is24h ? 24 : 12, timeZone())}{" "}
|
||||
{formatTime(date, is24h ? 24 : 12, timeZone().toLowerCase())} -{" "}
|
||||
{formatTime(dayjs(date).add(duration, "m"), is24h ? 24 : 12, timeZone().toLowerCase())}{" "}
|
||||
<span className="text-bookinglight">({timeZone()})</span>
|
||||
</div>
|
||||
);
|
||||
@@ -840,7 +875,6 @@ const getEventTypesFromDB = async (id: number) => {
|
||||
name: true,
|
||||
username: true,
|
||||
hideBranding: true,
|
||||
plan: true,
|
||||
theme: true,
|
||||
brandColor: true,
|
||||
darkBrandColor: true,
|
||||
|
||||
@@ -5,9 +5,11 @@ import { Fragment } from "react";
|
||||
import { z } from "zod";
|
||||
|
||||
import { WipeMyCalActionButton } from "@calcom/app-store/wipemycalother/components";
|
||||
import BookingLayout from "@calcom/features/bookings/layout/BookingLayout";
|
||||
import { filterQuerySchema, useFilterQuery } from "@calcom/features/bookings/lib/useFilterQuery";
|
||||
import { useLocale } from "@calcom/lib/hooks/useLocale";
|
||||
import { RouterInputs, RouterOutputs, trpc } from "@calcom/trpc/react";
|
||||
import { Alert, BookingLayout, Button, EmptyScreen, Icon } from "@calcom/ui";
|
||||
import { RouterOutputs, trpc } from "@calcom/trpc/react";
|
||||
import { Alert, Button, EmptyScreen, Icon } from "@calcom/ui";
|
||||
|
||||
import { useInViewObserver } from "@lib/hooks/useInViewObserver";
|
||||
|
||||
@@ -16,7 +18,7 @@ import SkeletonLoader from "@components/booking/SkeletonLoader";
|
||||
|
||||
import { ssgInit } from "@server/lib/ssg";
|
||||
|
||||
type BookingListingStatus = RouterInputs["viewer"]["bookings"]["get"]["status"];
|
||||
type BookingListingStatus = z.infer<typeof filterQuerySchema>["status"];
|
||||
type BookingOutput = RouterOutputs["viewer"]["bookings"]["get"]["bookings"][0];
|
||||
|
||||
type RecurringInfo = {
|
||||
@@ -41,12 +43,19 @@ const querySchema = z.object({
|
||||
});
|
||||
|
||||
export default function Bookings() {
|
||||
const { data: filterQuery } = useFilterQuery();
|
||||
const router = useRouter();
|
||||
const { status } = router.isReady ? querySchema.parse(router.query) : { status: "upcoming" as const };
|
||||
const { t } = useLocale();
|
||||
|
||||
const query = trpc.viewer.bookings.get.useInfiniteQuery(
|
||||
{ status, limit: 10 },
|
||||
{
|
||||
limit: 10,
|
||||
filters: {
|
||||
...filterQuery,
|
||||
status: filterQuery.status ?? status,
|
||||
},
|
||||
},
|
||||
{
|
||||
// first render has status `undefined`
|
||||
enabled: router.isReady,
|
||||
@@ -165,7 +174,7 @@ export default function Bookings() {
|
||||
</>
|
||||
)}
|
||||
{query.status === "success" && isEmpty && (
|
||||
<div className="flex items-center justify-center pt-2 xl:mx-6 xl:pt-0">
|
||||
<div className="flex items-center justify-center pt-2 xl:pt-0">
|
||||
<EmptyScreen
|
||||
Icon={Icon.FiCalendar}
|
||||
headline={t("no_status_bookings_yet", { status: t(status).toLowerCase() })}
|
||||
|
||||
@@ -90,7 +90,6 @@ export const getServerSideProps = async (context: GetServerSidePropsContext) =>
|
||||
},
|
||||
},
|
||||
theme: true,
|
||||
plan: true,
|
||||
},
|
||||
});
|
||||
|
||||
@@ -117,7 +116,6 @@ export const getServerSideProps = async (context: GetServerSidePropsContext) =>
|
||||
name: u.name,
|
||||
username: u.username,
|
||||
hideBranding: u.hideBranding,
|
||||
plan: u.plan,
|
||||
timeZone: u.timeZone,
|
||||
})),
|
||||
});
|
||||
@@ -158,7 +156,6 @@ export const getServerSideProps = async (context: GetServerSidePropsContext) =>
|
||||
away: user.away,
|
||||
isDynamicGroup: false,
|
||||
profile,
|
||||
plan: user.plan,
|
||||
date,
|
||||
eventType: eventTypeObject,
|
||||
workingHours,
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
/* eslint-disable @typescript-eslint/no-empty-function */
|
||||
import { useAutoAnimate } from "@formkit/auto-animate/react";
|
||||
import { zodResolver } from "@hookform/resolvers/zod";
|
||||
import { PeriodType, Prisma, SchedulingType } from "@prisma/client";
|
||||
import { GetServerSidePropsContext } from "next";
|
||||
import { useRouter } from "next/router";
|
||||
@@ -8,9 +9,10 @@ import { useForm } from "react-hook-form";
|
||||
import { z } from "zod";
|
||||
|
||||
import { StripeData } from "@calcom/app-store/stripepayment/lib/server";
|
||||
import getApps, { getEventTypeAppData, getLocationOptions } from "@calcom/app-store/utils";
|
||||
import { getEventTypeAppData, getLocationOptions } from "@calcom/app-store/utils";
|
||||
import { EventLocationType, LocationObject } from "@calcom/core/location";
|
||||
import { parseBookingLimit, parseRecurringEvent, validateBookingLimitOrder } from "@calcom/lib";
|
||||
import getEnabledApps from "@calcom/lib/apps/getEnabledApps";
|
||||
import { CAL_URL } from "@calcom/lib/constants";
|
||||
import convertToNewDurationType from "@calcom/lib/convertToNewDurationType";
|
||||
import findDurationType from "@calcom/lib/findDurationType";
|
||||
@@ -35,6 +37,7 @@ import { EventLimitsTab } from "@components/eventtype/EventLimitsTab";
|
||||
import { EventRecurringTab } from "@components/eventtype/EventRecurringTab";
|
||||
import { EventSetupTab } from "@components/eventtype/EventSetupTab";
|
||||
import { EventTeamTab } from "@components/eventtype/EventTeamTab";
|
||||
import { EventTeamWebhooksTab } from "@components/eventtype/EventTeamWebhooksTab";
|
||||
import { EventTypeSingleLayout } from "@components/eventtype/EventTypeSingleLayout";
|
||||
import EventWorkflowsTab from "@components/eventtype/EventWorkfowsTab";
|
||||
|
||||
@@ -92,7 +95,17 @@ export type CustomInputParsed = typeof customInputSchema._output;
|
||||
|
||||
const querySchema = z.object({
|
||||
tabName: z
|
||||
.enum(["setup", "availability", "apps", "limits", "recurring", "team", "advanced", "workflows"])
|
||||
.enum([
|
||||
"setup",
|
||||
"availability",
|
||||
"apps",
|
||||
"limits",
|
||||
"recurring",
|
||||
"team",
|
||||
"advanced",
|
||||
"workflows",
|
||||
"webhooks",
|
||||
])
|
||||
.optional()
|
||||
.default("setup"),
|
||||
});
|
||||
@@ -192,6 +205,16 @@ const EventTypePage = (props: inferSSRProps<typeof getServerSideProps>) => {
|
||||
),
|
||||
metadata,
|
||||
},
|
||||
resolver: zodResolver(
|
||||
z
|
||||
.object({
|
||||
// Length if string, is converted to a number or it can be a number
|
||||
// Make it optional because it's not submitted from all tabs of the page
|
||||
length: z.union([z.string().transform((val) => +val), z.number()]).optional(),
|
||||
})
|
||||
// TODO: Add schema for other fields later.
|
||||
.passthrough()
|
||||
),
|
||||
});
|
||||
|
||||
const appsMetadata = formMethods.getValues("metadata")?.apps;
|
||||
@@ -236,6 +259,7 @@ const EventTypePage = (props: inferSSRProps<typeof getServerSideProps>) => {
|
||||
workflows={eventType.workflows.map((workflowOnEventType) => workflowOnEventType.workflow)}
|
||||
/>
|
||||
),
|
||||
webhooks: <EventTeamWebhooksTab eventType={eventType} team={team} />,
|
||||
} as const;
|
||||
|
||||
return (
|
||||
@@ -247,7 +271,7 @@ const EventTypePage = (props: inferSSRProps<typeof getServerSideProps>) => {
|
||||
team={team}
|
||||
isUpdateMutationLoading={updateMutation.isLoading}
|
||||
formMethods={formMethods}
|
||||
disableBorder={tabName === "apps" || tabName === "workflows"}
|
||||
disableBorder={tabName === "apps" || tabName === "workflows" || tabName === "webhooks"}
|
||||
currentUserMembership={props.currentUserMembership}>
|
||||
<Form
|
||||
form={formMethods}
|
||||
@@ -282,7 +306,7 @@ const EventTypePage = (props: inferSSRProps<typeof getServerSideProps>) => {
|
||||
if (metadata?.multipleDuration.length < 1) {
|
||||
throw new Error(t("event_setup_multiple_duration_error"));
|
||||
} else {
|
||||
if (!metadata?.multipleDuration?.includes(input.length)) {
|
||||
if (!input.length && !metadata?.multipleDuration?.includes(input.length)) {
|
||||
throw new Error(t("event_setup_multiple_duration_default_error"));
|
||||
}
|
||||
}
|
||||
@@ -340,7 +364,6 @@ export const getServerSideProps = async (context: GetServerSidePropsContext) =>
|
||||
id: true,
|
||||
avatar: true,
|
||||
email: true,
|
||||
plan: true,
|
||||
locale: true,
|
||||
defaultScheduleId: true,
|
||||
});
|
||||
@@ -436,6 +459,17 @@ export const getServerSideProps = async (context: GetServerSidePropsContext) =>
|
||||
destinationCalendar: true,
|
||||
seatsPerTimeSlot: true,
|
||||
seatsShowAttendees: true,
|
||||
webhooks: {
|
||||
select: {
|
||||
id: true,
|
||||
subscriberUrl: true,
|
||||
payloadTemplate: true,
|
||||
active: true,
|
||||
eventTriggers: true,
|
||||
secret: true,
|
||||
eventTypeId: true,
|
||||
},
|
||||
},
|
||||
workflows: {
|
||||
include: {
|
||||
workflow: {
|
||||
@@ -467,6 +501,9 @@ export const getServerSideProps = async (context: GetServerSidePropsContext) =>
|
||||
const credentials = await prisma.credential.findMany({
|
||||
where: {
|
||||
userId: session.user.id,
|
||||
app: {
|
||||
enabled: true,
|
||||
},
|
||||
},
|
||||
select: {
|
||||
id: true,
|
||||
@@ -474,6 +511,7 @@ export const getServerSideProps = async (context: GetServerSidePropsContext) =>
|
||||
key: true,
|
||||
userId: true,
|
||||
appId: true,
|
||||
invalid: true,
|
||||
},
|
||||
});
|
||||
|
||||
@@ -526,7 +564,7 @@ export const getServerSideProps = async (context: GetServerSidePropsContext) =>
|
||||
}
|
||||
const currentUser = eventType.users.find((u) => u.id === session.user.id);
|
||||
const t = await getTranslation(currentUser?.locale ?? "en", "common");
|
||||
const integrations = getApps(credentials);
|
||||
const integrations = await getEnabledApps(credentials);
|
||||
const locationOptions = getLocationOptions(integrations, t);
|
||||
|
||||
const eventTypeObject = Object.assign({}, eventType, {
|
||||
|
||||
@@ -4,7 +4,10 @@ import Link from "next/link";
|
||||
import { useRouter } from "next/router";
|
||||
import React, { Fragment, useEffect, useState } from "react";
|
||||
|
||||
import CreateEventTypeButton from "@calcom/features/eventtypes/components/CreateEventTypeButton";
|
||||
import {
|
||||
CreateEventTypeButton,
|
||||
EventTypeDescriptionLazy as EventTypeDescription,
|
||||
} from "@calcom/features/eventtypes/components";
|
||||
import { APP_NAME, CAL_URL, WEBAPP_URL } from "@calcom/lib/constants";
|
||||
import { useLocale } from "@calcom/lib/hooks/useLocale";
|
||||
import { RouterOutputs, trpc, TRPCClientError } from "@calcom/trpc/react";
|
||||
@@ -22,7 +25,6 @@ import {
|
||||
DropdownMenuSeparator,
|
||||
DropdownMenuTrigger,
|
||||
EmptyScreen,
|
||||
EventTypeDescription,
|
||||
Icon,
|
||||
Shell,
|
||||
showToast,
|
||||
@@ -177,22 +179,17 @@ export const EventTypeList = ({ group, groupIndex, readOnly, types }: EventTypeL
|
||||
}
|
||||
|
||||
// inject selection data into url for correct router history
|
||||
const openModal = (group: EventTypeGroup, type: EventType) => {
|
||||
const openDuplicateModal = (eventType: EventType) => {
|
||||
const query = {
|
||||
...router.query,
|
||||
dialog: "new-eventtype",
|
||||
eventPage: group.profile.slug,
|
||||
title: type.title,
|
||||
slug: type.slug,
|
||||
description: type.description,
|
||||
length: type.length,
|
||||
type: type.schedulingType,
|
||||
teamId: group.teamId,
|
||||
locations: encodeURIComponent(JSON.stringify(type.locations)),
|
||||
dialog: "duplicate-event-type",
|
||||
title: eventType.title,
|
||||
description: eventType.description,
|
||||
slug: eventType.slug,
|
||||
id: eventType.id,
|
||||
length: eventType.length,
|
||||
};
|
||||
if (!group.teamId) {
|
||||
delete query.teamId;
|
||||
}
|
||||
|
||||
router.push(
|
||||
{
|
||||
pathname: router.pathname,
|
||||
@@ -261,7 +258,7 @@ export const EventTypeList = ({ group, groupIndex, readOnly, types }: EventTypeL
|
||||
const calLink = `${CAL_URL}/${embedLink}`;
|
||||
return (
|
||||
<li key={type.id}>
|
||||
<div className="flex w-full items-center justify-between hover:bg-neutral-50">
|
||||
<div className="flex w-full items-center justify-between hover:bg-gray-50">
|
||||
<div className="group flex w-full max-w-full items-center justify-between overflow-hidden px-4 py-4 sm:px-6">
|
||||
{!(firstItem && firstItem.id === type.id) && (
|
||||
<button
|
||||
@@ -361,7 +358,7 @@ export const EventTypeList = ({ group, groupIndex, readOnly, types }: EventTypeL
|
||||
type="button"
|
||||
data-testid={"event-type-duplicate-" + type.id}
|
||||
StartIcon={Icon.FiCopy}
|
||||
onClick={() => openModal(group, type)}>
|
||||
onClick={() => openDuplicateModal(type)}>
|
||||
{t("duplicate") as string}
|
||||
</DropdownItem>
|
||||
</DropdownMenuItem>
|
||||
@@ -469,7 +466,7 @@ export const EventTypeList = ({ group, groupIndex, readOnly, types }: EventTypeL
|
||||
className="w-full rounded-none"
|
||||
data-testid={"event-type-duplicate-" + type.id}
|
||||
StartIcon={Icon.FiCopy}
|
||||
onClick={() => openModal(group, type)}>
|
||||
onClick={() => openDuplicateModal(type)}>
|
||||
{t("duplicate") as string}
|
||||
</Button>
|
||||
</DropdownMenuItem>
|
||||
|
||||
@@ -164,7 +164,6 @@ export const getServerSideProps = async (context: GetServerSidePropsContext) =>
|
||||
weekStart: true,
|
||||
hideBranding: true,
|
||||
theme: true,
|
||||
plan: true,
|
||||
brandColor: true,
|
||||
darkBrandColor: true,
|
||||
metadata: true,
|
||||
|
||||
+3
-2
@@ -1,5 +1,6 @@
|
||||
import { GetServerSidePropsContext } from "next";
|
||||
|
||||
import AdminAppsList from "@calcom/features/apps/AdminAppsList";
|
||||
import { useLocale } from "@calcom/lib/hooks/useLocale";
|
||||
import { getAdminLayout as getLayout, Meta } from "@calcom/ui";
|
||||
|
||||
@@ -9,8 +10,8 @@ function AdminAppsView() {
|
||||
const { t } = useLocale();
|
||||
return (
|
||||
<>
|
||||
<Meta title={t("apps")} description={t("apps_description")} />
|
||||
<h1>{t("apps_listing")}</h1>
|
||||
<Meta title={t("apps")} description={t("admin_apps_description")} />
|
||||
<AdminAppsList baseURL="/settings/admin/apps" className="w-0" />
|
||||
</>
|
||||
);
|
||||
}
|
||||
@@ -36,7 +36,6 @@ const CtaRow = ({ title, description, className, children }: CtaRowProps) => {
|
||||
const BillingView = () => {
|
||||
const { t } = useLocale();
|
||||
const { data: user } = trpc.viewer.me.useQuery();
|
||||
const isPro = user?.plan === "PRO";
|
||||
const [, loadChat] = useChat();
|
||||
const [showChat, setShowChat] = useState(false);
|
||||
const router = useRouter();
|
||||
@@ -53,14 +52,9 @@ const BillingView = () => {
|
||||
<Meta title={t("billing")} description={t("manage_billing_description")} />
|
||||
<div className="space-y-6 text-sm sm:space-y-8">
|
||||
<CtaRow
|
||||
className={classNames(!isPro && "pointer-events-none opacity-30")}
|
||||
title={t("billing_manage_details_title")}
|
||||
description={t("billing_manage_details_description")}>
|
||||
<Button
|
||||
color={isPro ? "primary" : "secondary"}
|
||||
href={billingHref}
|
||||
target="_blank"
|
||||
EndIcon={Icon.FiExternalLink}>
|
||||
<Button color="primary" href={billingHref} target="_blank" EndIcon={Icon.FiExternalLink}>
|
||||
{t("billing_portal")}
|
||||
</Button>
|
||||
</CtaRow>
|
||||
|
||||
@@ -189,7 +189,7 @@ const AppearanceView = () => {
|
||||
onCheckedChange={(checked) =>
|
||||
formMethods.setValue("hideBranding", checked, { shouldDirty: true })
|
||||
}
|
||||
checked={value}
|
||||
checked={!session.data?.user.belongsToActiveTeam ? false : value}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -70,6 +70,7 @@ const GeneralView = ({ localeProp, user }: GeneralViewProps) => {
|
||||
|
||||
const mutation = trpc.viewer.updateProfile.useMutation({
|
||||
onSuccess: () => {
|
||||
reset(getValues());
|
||||
showToast(t("settings_updated_successfully"), "success");
|
||||
},
|
||||
onError: () => {
|
||||
@@ -119,7 +120,12 @@ const GeneralView = ({ localeProp, user }: GeneralViewProps) => {
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
const {
|
||||
formState: { isDirty, isSubmitting },
|
||||
reset,
|
||||
getValues,
|
||||
} = formMethods;
|
||||
const isDisabled = isSubmitting || !isDirty;
|
||||
return (
|
||||
<Form
|
||||
form={formMethods}
|
||||
@@ -160,7 +166,7 @@ const GeneralView = ({ localeProp, user }: GeneralViewProps) => {
|
||||
id="timezone"
|
||||
value={value}
|
||||
onChange={(event) => {
|
||||
if (event) formMethods.setValue("timeZone", event.value);
|
||||
if (event) formMethods.setValue("timeZone", event.value, { shouldDirty: true });
|
||||
}}
|
||||
/>
|
||||
</>
|
||||
@@ -178,7 +184,7 @@ const GeneralView = ({ localeProp, user }: GeneralViewProps) => {
|
||||
value={value}
|
||||
options={timeFormatOptions}
|
||||
onChange={(event) => {
|
||||
if (event) formMethods.setValue("timeFormat", { ...event });
|
||||
if (event) formMethods.setValue("timeFormat", { ...event }, { shouldDirty: true });
|
||||
}}
|
||||
/>
|
||||
</>
|
||||
@@ -199,13 +205,13 @@ const GeneralView = ({ localeProp, user }: GeneralViewProps) => {
|
||||
value={value}
|
||||
options={weekStartOptions}
|
||||
onChange={(event) => {
|
||||
if (event) formMethods.setValue("weekStart", { ...event });
|
||||
if (event) formMethods.setValue("weekStart", { ...event }, { shouldDirty: true });
|
||||
}}
|
||||
/>
|
||||
</>
|
||||
)}
|
||||
/>
|
||||
<Button color="primary" type="submit" className="mt-8">
|
||||
<Button disabled={isDisabled} color="primary" type="submit" className="mt-8">
|
||||
<>{t("update")}</>
|
||||
</Button>
|
||||
</Form>
|
||||
|
||||
@@ -2,7 +2,7 @@ import { IdentityProvider } from "@prisma/client";
|
||||
import crypto from "crypto";
|
||||
import { GetServerSidePropsContext } from "next";
|
||||
import { signOut } from "next-auth/react";
|
||||
import { BaseSyntheticEvent, useEffect, useRef, useState } from "react";
|
||||
import { BaseSyntheticEvent, useRef, useState } from "react";
|
||||
import { Controller, useForm } from "react-hook-form";
|
||||
|
||||
import { ErrorCode } from "@calcom/lib/auth";
|
||||
@@ -63,14 +63,25 @@ interface DeleteAccountValues {
|
||||
totpCode: string;
|
||||
}
|
||||
|
||||
type FormValues = {
|
||||
username: string;
|
||||
avatar: string;
|
||||
name: string;
|
||||
email: string;
|
||||
bio: string;
|
||||
};
|
||||
|
||||
const ProfileView = () => {
|
||||
const { t } = useLocale();
|
||||
const utils = trpc.useContext();
|
||||
|
||||
const { data: user, isLoading } = trpc.viewer.me.useQuery();
|
||||
const { data: avatar, isLoading: isLoadingAvatar } = trpc.viewer.avatar.useQuery();
|
||||
const mutation = trpc.viewer.updateProfile.useMutation({
|
||||
onSuccess: () => {
|
||||
showToast(t("settings_updated_successfully"), "success");
|
||||
utils.viewer.me.invalidate();
|
||||
utils.viewer.avatar.invalidate();
|
||||
setTempFormValues(null);
|
||||
},
|
||||
onError: () => {
|
||||
showToast(t("error_updating_settings"), "error");
|
||||
@@ -78,18 +89,14 @@ const ProfileView = () => {
|
||||
});
|
||||
|
||||
const [confirmPasswordOpen, setConfirmPasswordOpen] = useState(false);
|
||||
const [tempFormValues, setTempFormValues] = useState<FormValues | null>(null);
|
||||
const [confirmPasswordErrorMessage, setConfirmPasswordDeleteErrorMessage] = useState("");
|
||||
|
||||
const [deleteAccountOpen, setDeleteAccountOpen] = useState(false);
|
||||
const [hasDeleteErrors, setHasDeleteErrors] = useState(false);
|
||||
const [deleteErrorMessage, setDeleteErrorMessage] = useState("");
|
||||
|
||||
const form = useForm<DeleteAccountValues>();
|
||||
|
||||
const emailMd5 = crypto
|
||||
.createHash("md5")
|
||||
.update(user?.email || "example@example.com")
|
||||
.digest("hex");
|
||||
|
||||
const onDeleteMeSuccessMutation = async () => {
|
||||
await utils.viewer.me.invalidate();
|
||||
showToast(t("Your account was deleted"), "success");
|
||||
@@ -104,7 +111,7 @@ const ProfileView = () => {
|
||||
|
||||
const confirmPasswordMutation = trpc.viewer.auth.verifyPassword.useMutation({
|
||||
onSuccess() {
|
||||
mutation.mutate(formMethods.getValues());
|
||||
if (tempFormValues) mutation.mutate(tempFormValues);
|
||||
setConfirmPasswordOpen(false);
|
||||
},
|
||||
onError() {
|
||||
@@ -150,6 +157,7 @@ const ProfileView = () => {
|
||||
deleteMeWithoutPasswordMutation.mutate();
|
||||
}
|
||||
};
|
||||
|
||||
const onConfirm = ({ totpCode }: DeleteAccountValues, e: BaseSyntheticEvent | undefined) => {
|
||||
e?.preventDefault();
|
||||
if (isCALIdentityProviver) {
|
||||
@@ -160,38 +168,6 @@ const ProfileView = () => {
|
||||
}
|
||||
};
|
||||
|
||||
const formMethods = useForm({
|
||||
defaultValues: {
|
||||
username: "",
|
||||
avatar: "",
|
||||
name: "",
|
||||
email: "",
|
||||
bio: "",
|
||||
},
|
||||
});
|
||||
|
||||
const {
|
||||
reset,
|
||||
formState: { isSubmitting, isDirty },
|
||||
} = formMethods;
|
||||
|
||||
useEffect(() => {
|
||||
if (user) {
|
||||
reset(
|
||||
{
|
||||
avatar: user?.avatar || "",
|
||||
username: user?.username || "",
|
||||
name: user?.name || "",
|
||||
email: user?.email || "",
|
||||
bio: user?.bio || "",
|
||||
},
|
||||
{
|
||||
keepDirtyValues: true,
|
||||
}
|
||||
);
|
||||
}
|
||||
}, [reset, user]);
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
||||
const passwordRef = useRef<HTMLInputElement>(null!);
|
||||
|
||||
@@ -203,133 +179,100 @@ const ProfileView = () => {
|
||||
[ErrorCode.InternalServerError]: `${t("something_went_wrong")} ${t("please_try_again_and_contact_us")}`,
|
||||
[ErrorCode.ThirdPartyIdentityProviderEnabled]: t("account_created_with_identity_provider"),
|
||||
};
|
||||
const onSuccessfulUsernameUpdate = async () => {
|
||||
showToast(t("settings_updated_successfully"), "success");
|
||||
await utils.viewer.me.invalidate();
|
||||
};
|
||||
|
||||
const onErrorInUsernameUpdate = () => {
|
||||
showToast(t("error_updating_settings"), "error");
|
||||
};
|
||||
|
||||
if (isLoading || !user)
|
||||
if (isLoading || !user || isLoadingAvatar || !avatar)
|
||||
return <SkeletonLoader title={t("profile")} description={t("profile_description")} />;
|
||||
|
||||
const isDisabled = isSubmitting || !isDirty;
|
||||
const defaultValues = {
|
||||
username: user.username || "",
|
||||
avatar: avatar.avatar || "",
|
||||
name: user.name || "",
|
||||
email: user.email || "",
|
||||
bio: user.bio || "",
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<Meta title={t("profile")} description={t("profile_description", { appName: APP_NAME })} />
|
||||
<Form
|
||||
form={formMethods}
|
||||
handleSubmit={(values) => {
|
||||
if (values.email !== user?.email && isCALIdentityProviver) {
|
||||
<ProfileForm
|
||||
key={JSON.stringify(defaultValues)}
|
||||
defaultValues={defaultValues}
|
||||
onSubmit={(values) => {
|
||||
if (values.email !== user.email && isCALIdentityProviver) {
|
||||
setTempFormValues(values);
|
||||
setConfirmPasswordOpen(true);
|
||||
} else {
|
||||
mutation.mutate(values);
|
||||
}
|
||||
}}>
|
||||
<div className="flex items-center">
|
||||
<Controller
|
||||
control={formMethods.control}
|
||||
name="avatar"
|
||||
render={({ field: { value } }) => (
|
||||
<>
|
||||
<Avatar alt="" imageSrc={value} gravatarFallbackMd5={emailMd5} size="lg" />
|
||||
<div className="ml-4">
|
||||
<ImageUploader
|
||||
target="avatar"
|
||||
id="avatar-upload"
|
||||
buttonMsg={t("change_avatar")}
|
||||
handleAvatarChange={(newAvatar) => {
|
||||
formMethods.setValue("avatar", newAvatar, { shouldDirty: true });
|
||||
}}
|
||||
imageSrc={value}
|
||||
/>
|
||||
</div>
|
||||
</>
|
||||
}}
|
||||
extraField={
|
||||
<div className="mt-8">
|
||||
<UsernameAvailabilityField
|
||||
user={user}
|
||||
onSuccessMutation={async () => {
|
||||
showToast(t("settings_updated_successfully"), "success");
|
||||
await utils.viewer.me.invalidate();
|
||||
}}
|
||||
onErrorMutation={() => {
|
||||
showToast(t("error_updating_settings"), "error");
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
}
|
||||
/>
|
||||
|
||||
<hr className="my-6 border-neutral-200" />
|
||||
|
||||
<Label>{t("danger_zone")}</Label>
|
||||
{/* Delete account Dialog */}
|
||||
<Dialog open={deleteAccountOpen} onOpenChange={setDeleteAccountOpen}>
|
||||
<DialogTrigger asChild>
|
||||
<Button
|
||||
data-testid="delete-account"
|
||||
color="destructive"
|
||||
className="mt-1 border-2"
|
||||
StartIcon={Icon.FiTrash2}>
|
||||
{t("delete_account")}
|
||||
</Button>
|
||||
</DialogTrigger>
|
||||
<DialogContent
|
||||
title={t("delete_account_modal_title")}
|
||||
description={t("confirm_delete_account_modal", { appName: APP_NAME })}
|
||||
type="creation"
|
||||
Icon={Icon.FiAlertTriangle}>
|
||||
<>
|
||||
<p className="mb-7">{t("delete_account_confirmation_message", { appName: APP_NAME })}</p>
|
||||
{isCALIdentityProviver && (
|
||||
<PasswordField
|
||||
data-testid="password"
|
||||
name="password"
|
||||
id="password"
|
||||
autoComplete="current-password"
|
||||
required
|
||||
label="Password"
|
||||
ref={passwordRef}
|
||||
/>
|
||||
)}
|
||||
/>
|
||||
</div>
|
||||
<div className="mt-8">
|
||||
<UsernameAvailabilityField
|
||||
user={user}
|
||||
onSuccessMutation={onSuccessfulUsernameUpdate}
|
||||
onErrorMutation={onErrorInUsernameUpdate}
|
||||
/>
|
||||
</div>
|
||||
<div className="mt-8">
|
||||
<TextField label={t("full_name")} {...formMethods.register("name")} />
|
||||
</div>
|
||||
<div className="mt-8">
|
||||
<TextField label={t("email")} hint={t("change_email_hint")} {...formMethods.register("email")} />
|
||||
</div>
|
||||
<div className="mt-8">
|
||||
<TextField label={t("about")} hint={t("bio_hint")} {...formMethods.register("bio")} />
|
||||
</div>
|
||||
|
||||
<Button
|
||||
disabled={isDisabled}
|
||||
color="primary"
|
||||
className="mt-8"
|
||||
type="submit"
|
||||
loading={mutation.isLoading}>
|
||||
{t("update")}
|
||||
</Button>
|
||||
{user?.twoFactorEnabled && isCALIdentityProviver && (
|
||||
<Form handleSubmit={onConfirm} className="pb-4" form={form}>
|
||||
<TwoFactor center={false} />
|
||||
</Form>
|
||||
)}
|
||||
|
||||
<hr className="my-6 border-neutral-200" />
|
||||
|
||||
<Label>{t("danger_zone")}</Label>
|
||||
{/* Delete account Dialog */}
|
||||
<Dialog open={deleteAccountOpen} onOpenChange={setDeleteAccountOpen}>
|
||||
<DialogTrigger asChild>
|
||||
<Button
|
||||
data-testid="delete-account"
|
||||
color="destructive"
|
||||
className="mt-1 border-2"
|
||||
StartIcon={Icon.FiTrash2}>
|
||||
{t("delete_account")}
|
||||
</Button>
|
||||
</DialogTrigger>
|
||||
<DialogContent
|
||||
title={t("delete_account_modal_title")}
|
||||
description={t("confirm_delete_account_modal", { appName: APP_NAME })}
|
||||
type="creation"
|
||||
Icon={Icon.FiAlertTriangle}>
|
||||
<>
|
||||
<p className="mb-7">{t("delete_account_confirmation_message", { appName: APP_NAME })}</p>
|
||||
{isCALIdentityProviver && (
|
||||
<PasswordField
|
||||
data-testid="password"
|
||||
name="password"
|
||||
id="password"
|
||||
autoComplete="current-password"
|
||||
required
|
||||
label="Password"
|
||||
ref={passwordRef}
|
||||
/>
|
||||
)}
|
||||
|
||||
{user?.twoFactorEnabled && isCALIdentityProviver && (
|
||||
<Form handleSubmit={onConfirm} className="pb-4" form={form}>
|
||||
<TwoFactor center={false} />
|
||||
</Form>
|
||||
)}
|
||||
|
||||
{hasDeleteErrors && <Alert severity="error" title={deleteErrorMessage} />}
|
||||
<DialogFooter>
|
||||
<Button
|
||||
color="primary"
|
||||
data-testid="delete-account-confirm"
|
||||
onClick={(e) => onConfirmButton(e)}>
|
||||
{t("delete_my_account")}
|
||||
</Button>
|
||||
<DialogClose />
|
||||
</DialogFooter>
|
||||
</>
|
||||
</DialogContent>
|
||||
</Dialog>
|
||||
</Form>
|
||||
{hasDeleteErrors && <Alert severity="error" title={deleteErrorMessage} />}
|
||||
<DialogFooter>
|
||||
<Button
|
||||
color="primary"
|
||||
data-testid="delete-account-confirm"
|
||||
onClick={(e) => onConfirmButton(e)}>
|
||||
{t("delete_my_account")}
|
||||
</Button>
|
||||
<DialogClose />
|
||||
</DialogFooter>
|
||||
</>
|
||||
</DialogContent>
|
||||
</Dialog>
|
||||
|
||||
{/* If changing email, confirm password */}
|
||||
<Dialog open={confirmPasswordOpen} onOpenChange={setConfirmPasswordOpen}>
|
||||
@@ -363,6 +306,73 @@ const ProfileView = () => {
|
||||
);
|
||||
};
|
||||
|
||||
const ProfileForm = ({
|
||||
defaultValues,
|
||||
onSubmit,
|
||||
extraField,
|
||||
}: {
|
||||
defaultValues: FormValues;
|
||||
onSubmit: (values: FormValues) => void;
|
||||
extraField?: React.ReactNode;
|
||||
}) => {
|
||||
const { t } = useLocale();
|
||||
const emailMd5 = crypto
|
||||
.createHash("md5")
|
||||
.update(defaultValues.email || "example@example.com")
|
||||
.digest("hex");
|
||||
|
||||
const formMethods = useForm<FormValues>({
|
||||
defaultValues,
|
||||
});
|
||||
|
||||
const {
|
||||
formState: { isSubmitting, isDirty },
|
||||
} = formMethods;
|
||||
|
||||
const isDisabled = isSubmitting || !isDirty;
|
||||
|
||||
return (
|
||||
<Form form={formMethods} handleSubmit={onSubmit}>
|
||||
<div className="flex items-center">
|
||||
<Controller
|
||||
control={formMethods.control}
|
||||
name="avatar"
|
||||
render={({ field: { value } }) => (
|
||||
<>
|
||||
<Avatar alt="" imageSrc={value} gravatarFallbackMd5={emailMd5} size="lg" />
|
||||
<div className="ml-4">
|
||||
<ImageUploader
|
||||
target="avatar"
|
||||
id="avatar-upload"
|
||||
buttonMsg={t("change_avatar")}
|
||||
handleAvatarChange={(newAvatar) => {
|
||||
formMethods.setValue("avatar", newAvatar, { shouldDirty: true });
|
||||
}}
|
||||
imageSrc={value || undefined}
|
||||
/>
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
/>
|
||||
</div>
|
||||
{extraField}
|
||||
<div className="mt-8">
|
||||
<TextField label={t("full_name")} {...formMethods.register("name")} />
|
||||
</div>
|
||||
<div className="mt-8">
|
||||
<TextField label={t("email")} hint={t("change_email_hint")} {...formMethods.register("email")} />
|
||||
</div>
|
||||
<div className="mt-8">
|
||||
<TextField label={t("about")} hint={t("bio_hint")} {...formMethods.register("bio")} />
|
||||
</div>
|
||||
|
||||
<Button disabled={isDisabled} color="primary" className="mt-8" type="submit">
|
||||
{t("update")}
|
||||
</Button>
|
||||
</Form>
|
||||
);
|
||||
};
|
||||
|
||||
ProfileView.getLayout = getLayout;
|
||||
|
||||
export const getServerSideProps = async (context: GetServerSidePropsContext) => {
|
||||
|
||||
@@ -23,8 +23,24 @@ const ProfileImpersonationView = () => {
|
||||
const mutation = trpc.viewer.updateProfile.useMutation({
|
||||
onSuccess: () => {
|
||||
showToast(t("profile_updated_successfully"), "success");
|
||||
reset(getValues());
|
||||
},
|
||||
onError: (error) => {
|
||||
onSettled: () => {
|
||||
utils.viewer.me.invalidate();
|
||||
},
|
||||
onMutate: async ({ disableImpersonation }) => {
|
||||
await utils.viewer.me.cancel();
|
||||
const previousValue = utils.viewer.me.getData();
|
||||
|
||||
if (previousValue && disableImpersonation) {
|
||||
utils.viewer.me.setData(undefined, { ...previousValue, disableImpersonation });
|
||||
}
|
||||
return { previousValue };
|
||||
},
|
||||
onError: (error, variables, context) => {
|
||||
if (context?.previousValue) {
|
||||
utils.viewer.me.setData(undefined, context.previousValue);
|
||||
}
|
||||
showToast(`${t("error")}, ${error.message}`, "error");
|
||||
},
|
||||
});
|
||||
@@ -36,10 +52,13 @@ const ProfileImpersonationView = () => {
|
||||
});
|
||||
|
||||
const {
|
||||
formState: { isSubmitting },
|
||||
formState: { isSubmitting, isDirty },
|
||||
setValue,
|
||||
reset,
|
||||
getValues,
|
||||
} = formMethods;
|
||||
|
||||
const isDisabled = isSubmitting || !isDirty;
|
||||
return (
|
||||
<>
|
||||
<Meta title={t("impersonation")} description={t("impersonation_description")} />
|
||||
@@ -47,14 +66,12 @@ const ProfileImpersonationView = () => {
|
||||
form={formMethods}
|
||||
handleSubmit={({ disableImpersonation }) => {
|
||||
mutation.mutate({ disableImpersonation });
|
||||
utils.viewer.me.invalidate();
|
||||
}}>
|
||||
<div className="flex space-x-3">
|
||||
<Switch
|
||||
{...formMethods.register("disableImpersonation")}
|
||||
defaultChecked={!user?.disableImpersonation}
|
||||
onCheckedChange={(e) => {
|
||||
setValue("disableImpersonation", !e);
|
||||
setValue("disableImpersonation", !e, { shouldDirty: true });
|
||||
}}
|
||||
fitToHeight={true}
|
||||
/>
|
||||
@@ -67,7 +84,7 @@ const ProfileImpersonationView = () => {
|
||||
</Skeleton>
|
||||
</div>
|
||||
</div>
|
||||
<Button color="primary" className="mt-8" type="submit" disabled={isSubmitting || mutation.isLoading}>
|
||||
<Button color="primary" className="mt-8" type="submit" disabled={isDisabled}>
|
||||
{t("update")}
|
||||
</Button>
|
||||
</Form>
|
||||
@@ -79,7 +96,7 @@ ProfileImpersonationView.getLayout = getLayout;
|
||||
|
||||
export const getServerSideProps = async (context: GetServerSidePropsContext) => {
|
||||
const ssr = await ssrInit(context);
|
||||
|
||||
await ssr.viewer.me.prefetch();
|
||||
return {
|
||||
props: {
|
||||
trpcState: ssr.dehydrate(),
|
||||
|
||||
@@ -18,10 +18,9 @@ import EnableTwoFactorModal from "@components/settings/EnableTwoFactorModal";
|
||||
|
||||
import { ssrInit } from "@server/lib/ssr";
|
||||
|
||||
const SkeletonLoader = ({ title, description }: { title: string; description: string }) => {
|
||||
const SkeletonLoader = () => {
|
||||
return (
|
||||
<SkeletonContainer>
|
||||
<Meta title={title} description={description} />
|
||||
<div className="mt-6 mb-8 space-y-6 divide-y">
|
||||
<div className="flex items-center">
|
||||
<SkeletonButton className="mr-6 h-8 w-20 rounded-md p-5" />
|
||||
@@ -41,7 +40,7 @@ const TwoFactorAuthView = () => {
|
||||
const [enableModalOpen, setEnableModalOpen] = useState(false);
|
||||
const [disableModalOpen, setDisableModalOpen] = useState(false);
|
||||
|
||||
if (isLoading) return <SkeletonLoader title={t("2fa")} description={t("2fa_description")} />;
|
||||
if (isLoading) return <SkeletonLoader />;
|
||||
|
||||
return (
|
||||
<>
|
||||
|
||||
@@ -6,6 +6,7 @@ import { FormProvider, SubmitHandler, useForm } from "react-hook-form";
|
||||
import LicenseRequired from "@calcom/features/ee/common/components/v2/LicenseRequired";
|
||||
import { isSAMLLoginEnabled } from "@calcom/features/ee/sso/lib/saml";
|
||||
import { useLocale } from "@calcom/lib/hooks/useLocale";
|
||||
import { collectPageParameters, telemetryEventTypes, useTelemetry } from "@calcom/lib/telemetry";
|
||||
import { inferSSRProps } from "@calcom/types/inferSSRProps";
|
||||
import { Alert, Button, EmailField, PasswordField, TextField } from "@calcom/ui";
|
||||
import { HeadSeo } from "@calcom/web/components/seo/head-seo";
|
||||
@@ -26,6 +27,8 @@ type FormValues = {
|
||||
export default function Signup({ prepopulateFormValues }: inferSSRProps<typeof getServerSideProps>) {
|
||||
const { t } = useLocale();
|
||||
const router = useRouter();
|
||||
const telemetry = useTelemetry();
|
||||
|
||||
const methods = useForm<FormValues>({
|
||||
defaultValues: prepopulateFormValues,
|
||||
});
|
||||
@@ -53,8 +56,12 @@ export default function Signup({ prepopulateFormValues }: inferSSRProps<typeof g
|
||||
})
|
||||
.then(handleErrors)
|
||||
.then(async () => {
|
||||
await signIn("Cal.com", {
|
||||
callbackUrl: router.query.callbackUrl ? `${WEBAPP_URL}/${router.query.callbackUrl}` : WEBAPP_URL,
|
||||
telemetry.event(telemetryEventTypes.login, collectPageParameters());
|
||||
await signIn<"credentials">("credentials", {
|
||||
...data,
|
||||
callbackUrl: router.query.callbackUrl
|
||||
? `${WEBAPP_URL}/${router.query.callbackUrl}`
|
||||
: `${WEBAPP_URL}/getting-started`,
|
||||
});
|
||||
})
|
||||
.catch((err) => {
|
||||
@@ -111,7 +118,9 @@ export default function Signup({ prepopulateFormValues }: inferSSRProps<typeof g
|
||||
className="w-5/12 justify-center"
|
||||
onClick={() =>
|
||||
signIn("Cal.com", {
|
||||
callbackUrl: (`${WEBAPP_URL}/${router.query.callbackUrl}` || "") as string,
|
||||
callbackUrl: router.query.callbackUrl
|
||||
? `${WEBAPP_URL}/${router.query.callbackUrl}`
|
||||
: `${WEBAPP_URL}/getting-started`,
|
||||
})
|
||||
}>
|
||||
{t("login_instead")}
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
import { UserPlan } from "@prisma/client";
|
||||
import classNames from "classnames";
|
||||
import { GetServerSidePropsContext } from "next";
|
||||
import Link from "next/link";
|
||||
@@ -6,15 +5,15 @@ import { useRouter } from "next/router";
|
||||
import { useEffect } from "react";
|
||||
|
||||
import { useIsEmbed } from "@calcom/embed-core/embed-iframe";
|
||||
import EventTypeDescription from "@calcom/features/eventtypes/components/EventTypeDescription";
|
||||
import { CAL_URL } from "@calcom/lib/constants";
|
||||
import { getPlaceholderAvatar } from "@calcom/lib/getPlaceholderAvatar";
|
||||
import { useLocale } from "@calcom/lib/hooks/useLocale";
|
||||
import useTheme from "@calcom/lib/hooks/useTheme";
|
||||
import { getTeamWithMembers } from "@calcom/lib/server/queries/teams";
|
||||
import { collectPageParameters, telemetryEventTypes, useTelemetry } from "@calcom/lib/telemetry";
|
||||
import { Avatar, Button, EventTypeDescription, Icon } from "@calcom/ui";
|
||||
import { Avatar, Button, Icon } from "@calcom/ui";
|
||||
|
||||
import { useExposePlanGlobally } from "@lib/hooks/useExposePlanGlobally";
|
||||
import { useToggleQuery } from "@lib/hooks/useToggleQuery";
|
||||
import { inferSSRProps } from "@lib/types/inferSSRProps";
|
||||
|
||||
@@ -27,7 +26,6 @@ function TeamPage({ team }: TeamPageProps) {
|
||||
useTheme();
|
||||
const showMembers = useToggleQuery("members");
|
||||
const { t } = useLocale();
|
||||
useExposePlanGlobally("PRO");
|
||||
const isEmbed = useIsEmbed();
|
||||
const telemetry = useTelemetry();
|
||||
const router = useRouter();
|
||||
@@ -40,12 +38,12 @@ function TeamPage({ team }: TeamPageProps) {
|
||||
}, [telemetry, router.asPath]);
|
||||
|
||||
const EventTypes = () => (
|
||||
<ul className="">
|
||||
<ul className="rounded-md border border-neutral-200 dark:border-neutral-700">
|
||||
{team.eventTypes.map((type, index) => (
|
||||
<li
|
||||
key={index}
|
||||
className={classNames(
|
||||
"dark:bg-darkgray-100 dark:border-darkgray-200 group relative rounded-sm border border-neutral-200 bg-white hover:bg-gray-50 dark:hover:border-neutral-600",
|
||||
"dark:bg-darkgray-100 group relative border-b border-neutral-200 bg-white first:rounded-t-md last:rounded-b-md last:border-b-0 hover:bg-gray-50 dark:border-neutral-700 dark:hover:border-neutral-600",
|
||||
!isEmbed && "bg-white"
|
||||
)}>
|
||||
<Link href={`/team/${team.slug}/${type.slug}`}>
|
||||
@@ -99,9 +97,7 @@ function TeamPage({ team }: TeamPageProps) {
|
||||
{(showMembers.isOn || !team.eventTypes.length) && <Team team={team} />}
|
||||
{!showMembers.isOn && team.eventTypes.length > 0 && (
|
||||
<div className="mx-auto max-w-3xl ">
|
||||
<div className="dark:border-darkgray-300 rounded-md border">
|
||||
<EventTypes />
|
||||
</div>
|
||||
<EventTypes />
|
||||
<div className="relative mt-12">
|
||||
<div className="absolute inset-0 flex items-center" aria-hidden="true">
|
||||
<div className="dark:border-darkgray-300 w-full border-t border-gray-200" />
|
||||
@@ -137,10 +133,6 @@ export const getServerSideProps = async (context: GetServerSidePropsContext) =>
|
||||
|
||||
if (!team) return { notFound: true } as { notFound: true };
|
||||
|
||||
const members = team.members.filter((member) => member.plan !== UserPlan.FREE);
|
||||
|
||||
team.members = members ?? [];
|
||||
|
||||
team.eventTypes = team.eventTypes.map((type) => ({
|
||||
...type,
|
||||
users: type.users.map((user) => ({
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
import { UserPlan } from "@prisma/client";
|
||||
import { GetServerSidePropsContext } from "next";
|
||||
|
||||
import { privacyFilteredLocations, LocationObject } from "@calcom/core/location";
|
||||
@@ -60,7 +59,6 @@ export const getServerSideProps = async (context: GetServerSidePropsContext) =>
|
||||
username: true,
|
||||
timeZone: true,
|
||||
hideBranding: true,
|
||||
plan: true,
|
||||
brandColor: true,
|
||||
darkBrandColor: true,
|
||||
},
|
||||
@@ -130,7 +128,6 @@ export const getServerSideProps = async (context: GetServerSidePropsContext) =>
|
||||
name: user.name,
|
||||
username: user.username,
|
||||
hideBranding: user.hideBranding,
|
||||
plan: user.plan,
|
||||
timeZone: user.timeZone,
|
||||
})),
|
||||
});
|
||||
@@ -144,8 +141,6 @@ export const getServerSideProps = async (context: GetServerSidePropsContext) =>
|
||||
|
||||
return {
|
||||
props: {
|
||||
// Team is always pro
|
||||
plan: "PRO" as UserPlan,
|
||||
profile: {
|
||||
name: team.name || team.slug,
|
||||
slug: team.slug,
|
||||
|
||||
@@ -14,7 +14,7 @@ function Teams() {
|
||||
heading={t("teams")}
|
||||
subtitle={t("create_manage_teams_collaborative")}
|
||||
CTA={
|
||||
<Button type="button" href={`${WEBAPP_URL}/settings/teams/new`}>
|
||||
<Button type="button" href={`${WEBAPP_URL}/settings/teams/new?returnTo=/teams`}>
|
||||
<Icon.FiPlus className="inline-block h-3.5 w-3.5 text-white group-hover:text-black ltr:mr-2 rtl:ml-2" />
|
||||
{t("new")}
|
||||
</Button>
|
||||
|
||||
@@ -0,0 +1,54 @@
|
||||
import { expect } from "@playwright/test";
|
||||
|
||||
import dayjs from "@calcom/dayjs";
|
||||
|
||||
import { test } from "./lib/fixtures";
|
||||
|
||||
test.describe.configure({ mode: "parallel" });
|
||||
|
||||
test.describe("Availablity tests", () => {
|
||||
test.beforeEach(async ({ page, users }) => {
|
||||
const user = await users.create();
|
||||
await user.login();
|
||||
await page.goto("/availability");
|
||||
// We wait until loading is finished
|
||||
await page.waitForSelector('[data-testid="schedules"]');
|
||||
});
|
||||
|
||||
test.afterEach(async ({ users }) => {
|
||||
await users.deleteAll();
|
||||
});
|
||||
|
||||
test("Date Overrides", async ({ page }) => {
|
||||
await test.step("Can add a date override", async () => {
|
||||
await page.locator('[data-testid="schedules"] > li a').click();
|
||||
await page.locator('[data-testid="add-override"]').click();
|
||||
await page.locator('[id="modal-title"]').waitFor();
|
||||
await page.locator('[data-testid="incrementMonth"]').click();
|
||||
await page.locator('[data-testid="day"][data-disabled="false"]').nth(0).click();
|
||||
await page.locator('[data-testid="date-override-mark-unavailable"]').click();
|
||||
await page.locator('[data-testid="add-override-submit-btn"]').click();
|
||||
await expect(page.locator('[data-testid="date-overrides-list"] > li')).toHaveCount(1);
|
||||
await page.locator('[form="availability-form"][type="submit"]').click();
|
||||
});
|
||||
|
||||
await test.step("Date override is displayed in troubleshooter", async () => {
|
||||
const response = await page.waitForResponse("**/api/trpc/viewer.availability.schedule.update?batch=1");
|
||||
const json = await response.json();
|
||||
// @ts-expect-error trust me bro
|
||||
const date = json[0].result.data.json.schedule.availability.find((a) => !!a.date);
|
||||
const troubleshooterURL = `/availability/troubleshoot?date=${dayjs(date.date).format("YYYY-MM-DD")}`;
|
||||
await page.goto(troubleshooterURL);
|
||||
await expect(page.locator('[data-testid="troubleshooter-busy-time"]')).toHaveCount(1);
|
||||
});
|
||||
});
|
||||
|
||||
test("Availablity pages", async ({ page }) => {
|
||||
await test.step("Can add a new schedule", async () => {
|
||||
await page.locator('[data-testid="new-schedule"]').click();
|
||||
await page.locator('[id="name"]').fill("More working hours");
|
||||
page.locator('[type="submit"]').click();
|
||||
await expect(page.locator("[data-testid=availablity-title]")).toHaveValue("More working hours");
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -13,7 +13,7 @@ test.describe.configure({ mode: "parallel" });
|
||||
|
||||
test.describe("free user", () => {
|
||||
test.beforeEach(async ({ page, users }) => {
|
||||
const free = await users.create({ plan: "FREE" });
|
||||
const free = await users.create();
|
||||
await page.goto(`/${free.username}`);
|
||||
});
|
||||
test.afterEach(async ({ users }) => {
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
import { expect } from "@playwright/test";
|
||||
import { UserPlan } from "@prisma/client";
|
||||
|
||||
import { getPremiumMonthlyPlanPriceId } from "@calcom/app-store/stripepayment/lib/utils";
|
||||
import stripe from "@calcom/features/ee/payments/server/stripe";
|
||||
import { WEBAPP_URL } from "@calcom/lib/constants";
|
||||
|
||||
|
||||
@@ -10,7 +10,7 @@ import {
|
||||
test("dynamic booking", async ({ page, users }) => {
|
||||
const pro = await users.create();
|
||||
await pro.login();
|
||||
const free = await users.create({ plan: "FREE" });
|
||||
const free = await users.create({ username: "free" });
|
||||
await page.goto(`/${pro.username}+${free.username}`);
|
||||
|
||||
await test.step("book an event first day in next month", async () => {
|
||||
|
||||
@@ -8,10 +8,10 @@ import { test } from "./lib/fixtures";
|
||||
test.describe.configure({ mode: "parallel" });
|
||||
|
||||
test.describe("Event Types tests", () => {
|
||||
test.describe("pro user", () => {
|
||||
test.describe("user", () => {
|
||||
test.beforeEach(async ({ page, users }) => {
|
||||
const proUser = await users.create();
|
||||
await proUser.login();
|
||||
const user = await users.create();
|
||||
await user.login();
|
||||
await page.goto("/event-types");
|
||||
// We wait until loading is finished
|
||||
await page.waitForSelector('[data-testid="event-types"]');
|
||||
@@ -101,13 +101,13 @@ test.describe("Event Types tests", () => {
|
||||
const params = new URLSearchParams(url);
|
||||
|
||||
expect(params.get("title")).toBe(firstTitle);
|
||||
expect(params.get("slug")).toBe(firstSlug);
|
||||
expect(params.get("slug")).toContain(firstSlug);
|
||||
|
||||
const formTitle = await page.inputValue("[name=title]");
|
||||
const formSlug = await page.inputValue("[name=slug]");
|
||||
|
||||
expect(formTitle).toBe(firstTitle);
|
||||
expect(formSlug).toBe(firstSlug);
|
||||
expect(formSlug).toContain(firstSlug);
|
||||
});
|
||||
test("edit first event", async ({ page }) => {
|
||||
const $eventTypes = page.locator("[data-testid=event-types] > li a");
|
||||
@@ -120,37 +120,7 @@ test.describe("Event Types tests", () => {
|
||||
});
|
||||
await page.locator("[data-testid=update-eventtype]").click();
|
||||
const toast = await page.waitForSelector("div[class*='data-testid-toast-success']");
|
||||
await expect(toast).toBeTruthy();
|
||||
});
|
||||
});
|
||||
|
||||
test.describe("free user", () => {
|
||||
test.beforeEach(async ({ page, users }) => {
|
||||
const free = await users.create({ plan: "FREE" });
|
||||
await free.login();
|
||||
await page.goto("/event-types");
|
||||
// We wait until loading is finished
|
||||
await page.waitForSelector('[data-testid="event-types"]');
|
||||
});
|
||||
|
||||
test("has at least 2 events where first is enabled", async ({ page }) => {
|
||||
const $eventTypes = page.locator("[data-testid=event-types] > li a");
|
||||
const count = await $eventTypes.count();
|
||||
expect(count).toBeGreaterThanOrEqual(2);
|
||||
});
|
||||
|
||||
test("edit first event", async ({ page }) => {
|
||||
const $eventTypes = page.locator("[data-testid=event-types] > li a");
|
||||
const firstEventTypeElement = $eventTypes.first();
|
||||
await firstEventTypeElement.click();
|
||||
await page.waitForNavigation({
|
||||
url: (url) => {
|
||||
return !!url.pathname.match(/\/event-types\/.+/);
|
||||
},
|
||||
});
|
||||
await page.locator("[data-testid=update-eventtype]").click();
|
||||
const toast = await page.waitForSelector("div[class*='data-testid-toast-success']");
|
||||
await expect(toast).toBeTruthy();
|
||||
expect(toast).toBeTruthy();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import type { Page, WorkerInfo } from "@playwright/test";
|
||||
import type Prisma from "@prisma/client";
|
||||
import { Prisma as PrismaType, UserPlan } from "@prisma/client";
|
||||
import { Prisma as PrismaType } from "@prisma/client";
|
||||
import { hash } from "bcryptjs";
|
||||
|
||||
import dayjs from "@calcom/dayjs";
|
||||
@@ -238,7 +238,7 @@ const createUserFixture = (user: UserWithIncludes, page: Page) => {
|
||||
};
|
||||
};
|
||||
|
||||
type CustomUserOptsKeys = "username" | "password" | "plan" | "completedOnboarding" | "locale" | "name";
|
||||
type CustomUserOptsKeys = "username" | "password" | "completedOnboarding" | "locale" | "name";
|
||||
type CustomUserOpts = Partial<Pick<Prisma.User, CustomUserOptsKeys>> & { timeZone?: TimeZoneEnum };
|
||||
|
||||
// creates the actual user in the db.
|
||||
@@ -247,13 +247,10 @@ const createUser = async (
|
||||
opts?: CustomUserOpts | null
|
||||
): Promise<PrismaType.UserCreateInput> => {
|
||||
// build a unique name for our user
|
||||
const uname = `${opts?.username ?? opts?.plan?.toLocaleLowerCase() ?? UserPlan.PRO.toLowerCase()}-${
|
||||
workerInfo.workerIndex
|
||||
}-${Date.now()}`;
|
||||
const uname = `${opts?.username || "user"}-${workerInfo.workerIndex}-${Date.now()}`;
|
||||
return {
|
||||
username: uname,
|
||||
name: opts?.name === undefined ? (opts?.plan ?? UserPlan.PRO).toUpperCase() : opts?.name,
|
||||
plan: opts?.plan ?? UserPlan.PRO,
|
||||
name: opts?.name,
|
||||
email: `${uname}@example.com`,
|
||||
password: await hashPassword(uname),
|
||||
emailVerified: new Date(),
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
import { expect } from "@playwright/test";
|
||||
import { UserPlan } from "@prisma/client";
|
||||
|
||||
import { login } from "./fixtures/users";
|
||||
import { test } from "./lib/fixtures";
|
||||
@@ -13,10 +12,10 @@ test.describe("user can login & logout succesfully", async () => {
|
||||
test.afterAll(async ({ users }) => {
|
||||
await users.deleteAll();
|
||||
});
|
||||
test("login flow TRAIL user & logout using dashboard", async ({ page, users }) => {
|
||||
test("login flow user & logout using dashboard", async ({ page, users }) => {
|
||||
// log in trail user
|
||||
await test.step("Log in", async () => {
|
||||
const user = await users.create({ plan: UserPlan.TRIAL });
|
||||
const user = await users.create();
|
||||
await user.login();
|
||||
|
||||
const shellLocator = page.locator(`[data-testid=dashboard-shell]`);
|
||||
@@ -24,11 +23,6 @@ test.describe("user can login & logout succesfully", async () => {
|
||||
// expects the home page for an authorized user
|
||||
await page.goto("/");
|
||||
await expect(shellLocator).toBeVisible();
|
||||
|
||||
// Asserts to read the tested plan
|
||||
const planLocator = shellLocator.locator(`[data-testid=plan-trial]`);
|
||||
await expect(planLocator).toBeVisible();
|
||||
await expect(planLocator).toHaveText("-TRIAL");
|
||||
});
|
||||
|
||||
//
|
||||
@@ -64,27 +58,6 @@ test.describe("Login and logout tests", () => {
|
||||
await expect(page.locator(`[data-testid=login-form]`)).toBeVisible();
|
||||
});
|
||||
|
||||
// Test login with all plans
|
||||
const plans = [UserPlan.PRO, UserPlan.FREE];
|
||||
plans.forEach((plan) => {
|
||||
test(`Should login with a ${plan} account`, async ({ page, users }) => {
|
||||
// Create user and login
|
||||
const user = await users.create({ plan });
|
||||
await user.login();
|
||||
|
||||
const shellLocator = page.locator(`[data-testid=dashboard-shell]`);
|
||||
|
||||
// expects the home page for an authorized user
|
||||
await page.goto("/");
|
||||
await expect(shellLocator).toBeVisible();
|
||||
|
||||
// Asserts to read the tested plan
|
||||
const planLocator = shellLocator.locator(`[data-testid=plan-${plan.toLowerCase()}]`);
|
||||
await expect(planLocator).toBeVisible();
|
||||
await expect(planLocator).toHaveText(`-${plan}`);
|
||||
});
|
||||
});
|
||||
|
||||
test.describe("Login flow validations", async () => {
|
||||
test("Should warn when user does not exist", async ({ page }) => {
|
||||
const alertMessage = (await localize("en"))("no_account_exists");
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
/* eslint-disable playwright/no-skipped-test */
|
||||
import { expect } from "@playwright/test";
|
||||
import { UserPlan } from "@prisma/client";
|
||||
|
||||
import { test } from "./lib/fixtures";
|
||||
|
||||
@@ -9,7 +8,7 @@ test.describe.configure({ mode: "serial" });
|
||||
test.describe("Onboarding", () => {
|
||||
test.describe("Onboarding v2", () => {
|
||||
test("Onboarding Flow", async ({ page, users }) => {
|
||||
const user = await users.create({ plan: UserPlan.TRIAL, completedOnboarding: false, name: null });
|
||||
const user = await users.create({ completedOnboarding: false, name: null });
|
||||
await user.login();
|
||||
|
||||
// tests whether the user makes it to /getting-started
|
||||
|
||||
@@ -57,6 +57,7 @@ test("add webhook & test that creating an event triggers a webhook call", async
|
||||
attendee.timeZone = dynamic;
|
||||
attendee.language = dynamic;
|
||||
}
|
||||
body.payload.organizer.id = dynamic;
|
||||
body.payload.organizer.email = dynamic;
|
||||
body.payload.organizer.timeZone = dynamic;
|
||||
body.payload.organizer.language = dynamic;
|
||||
@@ -67,6 +68,7 @@ test("add webhook & test that creating an event triggers a webhook call", async
|
||||
body.payload.eventTypeId = dynamic;
|
||||
body.payload.videoCallData = dynamic;
|
||||
body.payload.appsStatus = dynamic;
|
||||
body.payload.metadata.videoCallUrl = dynamic;
|
||||
|
||||
// if we change the shape of our webhooks, we can simply update this by clicking `u`
|
||||
// console.log("BODY", body);
|
||||
|
||||
@@ -1 +1 @@
|
||||
{"triggerEvent":"BOOKING_CREATED","createdAt":"[redacted/dynamic]","payload":{"type":"30 min","title":"30 min between PRO and Test Testson","description":"","additionalNotes":"","customInputs":{},"startTime":"[redacted/dynamic]","endTime":"[redacted/dynamic]","organizer":{"name":"PRO","email":"[redacted/dynamic]","timeZone":"[redacted/dynamic]","language":"[redacted/dynamic]"},"attendees":[{"email":"test@example.com","name":"Test Testson","timeZone":"[redacted/dynamic]","language":"[redacted/dynamic]"}],"location":"[redacted/dynamic]","destinationCalendar":null,"hideCalendarNotes":false,"requiresConfirmation":"[redacted/dynamic]","eventTypeId":"[redacted/dynamic]","seatsShowAttendees":false,"uid":"[redacted/dynamic]","videoCallData":"[redacted/dynamic]","appsStatus":"[redacted/dynamic]","eventTitle":"30 min","eventDescription":null,"price":0,"currency":"usd","length":30,"bookingId":"[redacted/dynamic]","metadata":{},"status":"ACCEPTED","additionalInformation":"[redacted/dynamic]"}}
|
||||
{"triggerEvent":"BOOKING_CREATED","createdAt":"[redacted/dynamic]","payload":{"type":"30 min","title":"30 min between Nameless and Test Testson","description":"","additionalNotes":"","customInputs":{},"startTime":"[redacted/dynamic]","endTime":"[redacted/dynamic]","organizer":{"id":"[redacted/dynamic]","name":"Nameless","email":"[redacted/dynamic]","timeZone":"[redacted/dynamic]","language":"[redacted/dynamic]"},"attendees":[{"email":"test@example.com","name":"Test Testson","timeZone":"[redacted/dynamic]","language":"[redacted/dynamic]"}],"location":"[redacted/dynamic]","destinationCalendar":null,"hideCalendarNotes":false,"requiresConfirmation":"[redacted/dynamic]","eventTypeId":"[redacted/dynamic]","seatsShowAttendees":false,"uid":"[redacted/dynamic]","videoCallData":"[redacted/dynamic]","appsStatus":"[redacted/dynamic]","eventTitle":"30 min","eventDescription":null,"price":0,"currency":"usd","length":30,"bookingId":"[redacted/dynamic]","metadata":{"videoCallUrl":"[redacted/dynamic]"},"status":"ACCEPTED","additionalInformation":"[redacted/dynamic]"}}
|
||||
@@ -0,0 +1,5 @@
|
||||
<svg stroke="#888888" fill="none" stroke-width="2.5" viewBox="0 0 24 24" stroke-linecap="round" stroke-linejoin="round" height="1em" width="1em" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>
|
||||
<polyline points="15 3 21 3 21 9"></polyline>
|
||||
<line x1="10" y1="14" x2="21" y2="3"></line>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 360 B |
Binary file not shown.
|
After Width: | Height: | Size: 2.4 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 197 KiB After Width: | Height: | Size: 53 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 166 KiB After Width: | Height: | Size: 35 KiB |
@@ -52,6 +52,7 @@
|
||||
"still_waiting_for_approval": "يوجد حدث لا يزال في انتظار الموافقة",
|
||||
"event_is_still_waiting": "لا يزال طلب الحدث في الانتظار: {{attendeeName}} - {{date}} - {{eventType}}",
|
||||
"no_more_results": "لا يوجد مزيد من النتائج",
|
||||
"no_results": "لا نتائج",
|
||||
"load_more_results": "تحميل المزيد من النتائج",
|
||||
"integration_meeting_id": "مُعرّف اجتماع {{integrationName}}: {{meetingId}}",
|
||||
"confirmed_event_type_subject": "تم التأكيد: {{eventType}} مع {{name}} في {{date}}",
|
||||
@@ -248,6 +249,7 @@
|
||||
"add_to_calendar": "إضافة إلى التقويم",
|
||||
"add_another_calendar": "إضافة تقويم آخر",
|
||||
"other": "آخر",
|
||||
"email_sign_in_subject": "رابط تسجيل الدخول بك لـ{{appName}}",
|
||||
"emailed_you_and_attendees": "لقد أرسلنا إليك وإلى الحضور الآخرين دعوة للتقويم عبر البريد الإلكتروني تتضمن كل التفاصيل.",
|
||||
"emailed_you_and_attendees_recurring": "لقد أرسلنا إليك وإلى الحضور الآخرين دعوة تقويم عبر البريد الإلكتروني لأول هذه الأحداث المتكررة.",
|
||||
"emailed_you_and_any_other_attendees": "تم إرسال هذه المعلومات إليك وإلى الحضور الآخرين عبر البريد الإلكتروني.",
|
||||
@@ -420,6 +422,7 @@
|
||||
"current_incorrect_password": "كلمة المرور الحالية غير صحيحة",
|
||||
"password_hint_caplow": "مزيج من الحروف الكبيرة والحروف الصغيرة",
|
||||
"password_hint_min": "8 أحرف كحد أدنى",
|
||||
"password_hint_admin_min": "15 محرفًا كحد أدنى",
|
||||
"password_hint_num": "يحتوي على رقم واحد على الأقل",
|
||||
"invalid_password_hint": "يجب أن تتألف كلمة المرور على الأقل من 7 أحرف، ورقم واحد على الأقل، ومزيج من الحروف الكبيرة والصغيرة",
|
||||
"incorrect_password": "كلمة المرور غير صحيحة.",
|
||||
@@ -463,11 +466,14 @@
|
||||
"booking_confirmation": "قم بتأكيد {{eventTypeTitle}} مع {{profileName}}",
|
||||
"booking_reschedule_confirmation": "أعد جدولة {{eventTypeTitle}} مع {{profileName}}",
|
||||
"in_person_meeting": "الرابط أو الاجتماع الشخصي",
|
||||
"attendeeInPerson": "شخصيًا (عنوان من سيحضر)",
|
||||
"inPerson": "شخصيًا (عنوان المنظم)",
|
||||
"link_meeting": "رابط الاجتماع",
|
||||
"phone_call": "رقم هاتف الحضور",
|
||||
"your_number": "رقم هاتفك",
|
||||
"phone_number": "رقم الهاتف",
|
||||
"attendee_phone_number": "رقم هاتف الحضور",
|
||||
"organizer_phone_number": "رقم هاتف المنظم",
|
||||
"host_phone_number": "رقم هاتفك",
|
||||
"enter_phone_number": "أدخل رقم الهاتف",
|
||||
"reschedule": "إعادة الجدولة",
|
||||
@@ -554,6 +560,10 @@
|
||||
"collective": "جماعي",
|
||||
"collective_description": "جدولة الاجتماعات عندما يكون جميع أعضاء الفريق المحددين متاحين.",
|
||||
"duration": "المدة",
|
||||
"available_durations": "المدد المتاحة",
|
||||
"default_duration": "المدة الافتراضية",
|
||||
"default_duration_no_options": "يرجى اختيار المدد المتاحة أولاً",
|
||||
"multiple_duration_mins": "{{count}} $t(minute_timeUnit)",
|
||||
"minutes": "الدقائق",
|
||||
"round_robin": "الترتيب الدوري",
|
||||
"round_robin_description": "نقل الاجتماعات بشكل دوري بين أعضاء الفريق المتعددين.",
|
||||
@@ -619,6 +629,7 @@
|
||||
"teams": "الفرق",
|
||||
"team": "فريق",
|
||||
"team_billing": "الفوترة الخاصة بالفريق",
|
||||
"team_billing_description": "إدارة الفواتير لفريقك",
|
||||
"upgrade_to_flexible_pro_title": "لقد قمنا بتغيير الفوترة الخاصة بالفرق",
|
||||
"upgrade_to_flexible_pro_message": "يوجد أعضاء في فريقك من دون مقاعد. قم بترقية خطة Pro خاصتك لتوفير المقاعد الناقصة.",
|
||||
"changed_team_billing_info": "بدءًا من يناير 2022، أصبحنا نفرض الرسوم على مقاعد أعضاء الفريق بشكل منفرد. حاليًا، أعضاء فريقك الذين كانت لديهم خطة Pro مجانية أصبحوا في فترة تجريبية مدتها 14 يومًا. وبمجرد انتهاء الفترة التجريبية الخاصة بهم، سيجري إخفاء هؤلاء الأعضاء من فريقك ما لم تقم بالترقية الآن.",
|
||||
@@ -694,6 +705,7 @@
|
||||
"hide_event_type": "إخفاء نوع الحدث",
|
||||
"edit_location": "تعديل الموقع",
|
||||
"into_the_future": "في المستقبل",
|
||||
"when_booked_with_less_than_notice": "عند الحجز بأقل من إشعار <time></time>",
|
||||
"within_date_range": "خلال فترة زمنية",
|
||||
"indefinitely_into_future": "إلى أجل غير مسمى في المستقبل",
|
||||
"add_new_custom_input_field": "إضافة خانة إدخال مخصص جديدة",
|
||||
@@ -713,6 +725,8 @@
|
||||
"delete_account_confirmation_message": "هل تريد بالتأكيد حذف حسابك على {{appName}}؟ أي شخص شاركت رابط حسابك معه لن يستطيع بعد الآن الحجز باستخدامه، وستفقد أي تفضيلات حفظتها.",
|
||||
"integrations": "التكاملات",
|
||||
"apps": "التطبيقات",
|
||||
"apps_description": "تمكين تطبيقات مثيل Cal الخاص بك",
|
||||
"apps_listing": "قائمة التطبيقات",
|
||||
"category_apps": "تطبيقات {{category}}",
|
||||
"app_store": "متجر التطبيقات",
|
||||
"app_store_description": "الربط بين الناس، والتكنولوجيا، ومكان العمل.",
|
||||
@@ -736,6 +750,7 @@
|
||||
"toggle_calendars_conflict": "قم بتبديل التقويمات التي تريد التحقق من وجود تضاربات فيها لمنع حدوث حجز مزدوج.",
|
||||
"select_destination_calendar": "إنشاء أحداث في",
|
||||
"connect_additional_calendar": "ربط رزنامة إضافية",
|
||||
"calendar_updated_successfully": "تم تحديث الرزنامة بنجاح",
|
||||
"conferencing": "المؤتمرات عبر الفيديو",
|
||||
"calendar": "التقويم",
|
||||
"payments": "المدفوعات",
|
||||
@@ -768,6 +783,7 @@
|
||||
"trending_apps": "التطبيقات الرائجة",
|
||||
"explore_apps": "تطبيقات {{category}}",
|
||||
"installed_apps": "التطبيقات المثبتة",
|
||||
"free_to_use_apps": "متاح",
|
||||
"no_category_apps": "لا توجد تطبيقات {{category}}",
|
||||
"no_category_apps_description_calendar": "إضافة تطبيق تقويم للتحقق من أي تضارب لمنع أي حجوزات مزدوجة",
|
||||
"no_category_apps_description_conferencing": "جرب إضافة تطبيق مؤتمرات لإنشاء مكالمات فيديو مع عملائك",
|
||||
@@ -806,6 +822,8 @@
|
||||
"verify_wallet": "تأكيد المحفظة",
|
||||
"connect_metamask": "توصيل Metamask",
|
||||
"create_events_on": "إنشاء أحداث في",
|
||||
"enterprise_license": "هذه هي ميزة للمؤسسات",
|
||||
"enterprise_license_description": "لتمكين هذه الميزة، احصل على مفتاح نشر في وحدة التحكم {{consoleUrl}} وأضفه إلى وحدة التحكم الخاصة بك. nv باسم CALCOM_LICENSE_KEY. إذا كان لدى فريقك بالفعل ترخيص، يرجى الاتصال بـ {{supportMail}} للحصول على المساعدة.",
|
||||
"missing_license": "الترخيص مفقود",
|
||||
"signup_requires": "يلزم ترخيص تجاري",
|
||||
"signup_requires_description": "لا تقدم شركة {{companyName}} حاليًا إصدارًا مجانيًا مفتوح المصدر لصفحة التسجيل. للحصول على حق الوصول الكامل إلى مكونات التسجيل، يجب أن تحصل على ترخيص تجاري. للاستخدام الشخصي، نوصي باستخدام منصة Prisma Data أو أي واجهة أخرى من واجهات Postgres لإنشاء الحسابات.",
|
||||
@@ -897,6 +915,7 @@
|
||||
"user_impersonation_heading": "انتحال شخصية مستخدم",
|
||||
"user_impersonation_description": "يسمح لفريق الدعم الخاص بنا بتسجيل الدخول مؤقتًا نيابة عنك لمساعدتنا على حل أي مشاكل تبلغ عنها بسرعة.",
|
||||
"team_impersonation_description": "يسمح لأعضاء فريقك بتسجيل الدخول نيابة عنك مؤقتًا.",
|
||||
"allow_booker_to_select_duration": "السماح لمن يقوم بالحجز بتحديد المدة",
|
||||
"impersonate_user_tip": "يتم مراجعة جميع استخدامات هذه الميزة.",
|
||||
"impersonating_user_warning": "انتحال اسم مستخدم \"{{user}}\".",
|
||||
"impersonating_stop_instructions": "<0>انقر هنا لإيقاف </0>.",
|
||||
@@ -1014,6 +1033,9 @@
|
||||
"error_removing_app": "خطأ في إزالة التطبيق",
|
||||
"web_conference": "مؤتمر عبر الإنترنت",
|
||||
"requires_confirmation": "يتطلب التأكيد",
|
||||
"always_requires_confirmation": "دائمًا",
|
||||
"requires_confirmation_threshold": "يتطلب تأكيد إذا تم حجزه مع إشعار $t({{unit}}_timeUnit){{time}}",
|
||||
"may_require_confirmation": "قد يتطلب التأكيد",
|
||||
"nr_event_type_one": "{{count}} نوع حدث",
|
||||
"nr_event_type_other": "{{count}} من أنواع الحدث",
|
||||
"add_action": "إضافة إجراء",
|
||||
@@ -1101,6 +1123,9 @@
|
||||
"event_limit_tab_description": "ما تواتر مرات الحجز",
|
||||
"event_advanced_tab_description": "إعدادات الرزنامة والمزيد...",
|
||||
"event_advanced_tab_title": "متقدم",
|
||||
"event_setup_multiple_duration_error": "إعداد الحدث: تستلزم فترات متعددة خيارًا واحدًا على الأقل.",
|
||||
"event_setup_multiple_duration_default_error": "إعداد الحدث: الرجاء تحديد مدة افتراضية صالحة.",
|
||||
"event_setup_booking_limits_error": "يجب أن تكون حدود الحجز بترتيب تصاعدي. [يوم،أسبوع،شهر،سنة]",
|
||||
"select_which_cal": "اختر أي رزنامة تريد إضافة الحجز إليها",
|
||||
"custom_event_name": "اسم حدث مخصص",
|
||||
"custom_event_name_description": "إنشاء أسماء أحداث مخصصة لعرضها في حدث الرزنامة",
|
||||
@@ -1154,8 +1179,11 @@
|
||||
"invoices": "الفواتير",
|
||||
"embeds": "التضمينات",
|
||||
"impersonation": "انتحال الشخصية",
|
||||
"impersonation_description": "إعدادات إدارة انتحال شخصية مستخدم",
|
||||
"users": "المستخدمون",
|
||||
"profile_description": "إدارة الإعدادات لملفك الشخصي على {{appName}}",
|
||||
"users_description": "يمكنك هنا العثور على قائمة بجميع المستخدمين",
|
||||
"users_listing": "قائمة المستخدمين",
|
||||
"general_description": "إدارة الإعدادات للغة والمنطقة الزمنية الخاصة بك",
|
||||
"calendars_description": "قم بتهيئة كيفية تفاعل أنواع الأحداث مع التقويمات الخاصة بك",
|
||||
"appearance_description": "إدارة إعدادات مظهر الحجز الخاص بك",
|
||||
@@ -1360,6 +1388,7 @@
|
||||
"number_sms_notifications": "رقم الهاتف (إشعارات الرسائل النصية)",
|
||||
"attendee_email_workflow": "اسم الحاضر",
|
||||
"attendee_email_info": "البريد الإلكتروني للشخص الحجز",
|
||||
"kbar_search_placeholder": "اكتب أمرًا أو بحثًا...",
|
||||
"invalid_credential": "لا! يبدو أن الصلاحية انتهت أو تم إلغاؤها. يرجى إعادة التثبيت مرة أخرى.",
|
||||
"choose_common_schedule_team_event": "اختر جدولاً زمنياً مشتركاً",
|
||||
"choose_common_schedule_team_event_description": "قم بتمكين هذا الخيار إذا كنت ترغب في استخدام جدول زمني مشترك بين المضيفين. عند تعطيل هذا الخيار، سيتم حجز كل مضيف على أساس جدوله الافتراضي.",
|
||||
@@ -1370,5 +1399,44 @@
|
||||
"test_preview": "اختبار المعاينة",
|
||||
"route_to": "التوجيه إلى",
|
||||
"test_preview_description": "اختبار نموذج التوجيه الخاص بك دون تقديم أي بيانات",
|
||||
"test_routing": "اختبار التوجيه"
|
||||
"test_routing": "اختبار التوجيه",
|
||||
"payment_app_disabled": "قام المشرف بتعطيل تطبيق دفع",
|
||||
"edit_event_type": "تعديل نوع الحدث",
|
||||
"collective_scheduling": "جدولة جماعية",
|
||||
"make_it_easy_to_book": "سهّل على فريقك الحجز عندما يكون الجميع متاحين.",
|
||||
"find_the_best_person": "ابحث عن أفضل شخص متوفر، وقم بالتدوير بين أعضاء فريقك.",
|
||||
"fixed_round_robin": "روبين دائري ثابت",
|
||||
"add_one_fixed_attendee": "أضف حاضرًا ثابتًا وروبين مستدير من خلال عدد من الحاضرين.",
|
||||
"calcom_is_better_with_team": "Cal.com أفضل مع الفرق",
|
||||
"add_your_team_members": "أضف أعضاء فريقك إلى أنواع الأحداث الخاصة بك. استخدم الجدولة الجماعية لإدراج الجميع أو العثور على أنسب شخص مع جدولة روبن الدائرية.",
|
||||
"booking_limit_reached": "تم الوصول إلى الحد الأقصى للحجز لهذا النوع من الأحداث",
|
||||
"admin_has_disabled": "قام المشرف بتعطيل {{appName}}",
|
||||
"disabled_app_affects_event_type": "قام المشرف بتعطيل {{appName}} مما يؤثر على نوع الحدث {{eventType}} لديك",
|
||||
"disable_payment_app": "قام المشرف بتعطيل {{appName}} الذي يؤثر على نوع الحدث {{title}} لديك. ولا يزال بإمكان الحاضرين حجز هذا النوع من الأحداث، ولكن لن يُطالبوا بالدفع. يمكنك إخفاء نوع الحدث لمنع حدوث هذا إلى أن يقوم المشرف بتغيير طريقة الدفع لك.",
|
||||
"payment_disabled_still_able_to_book": "لا يزال بإمكان الحاضرين حجز هذا النوع من الأحداث، ولكن لن يُطالبوا بالدفع. يمكنك إخفاء نوع الحدث لمنع حدوث هذا إلى أن يقوم المشرف بتغيير طريقة الدفع لك.",
|
||||
"app_disabled_with_event_type": "عطّل المشرف {{appName}} مما يؤثر على نوع الحدث {{title}} لديك.",
|
||||
"app_disabled_video": "عطّل المشرف {{appName}} الذي قد يؤثر على أنواع الأحداث لديك. إذا كان لديك أنواع من الأحداث مع {{appName}} كموقع، سيكون افتراضيًا من أجل فيديو Cal.",
|
||||
"app_disabled_subject": "تم تعطيل {{appName}}",
|
||||
"navigate_installed_apps": "الذهاب إلى التطبيقات المثبتة",
|
||||
"disabled_calendar": "إذا كان لديك تقويم آخر مثبت، ستُضاف الحجوزات الجديدة إليه. إذا لم يكن الأمر كذلك، قم إذن بتوصيل تقويم جديد لكيلا تفوت أي حجوزات جديدة.",
|
||||
"enable_apps": "تمكين التطبيقات",
|
||||
"enable_apps_description": "تمكين التطبيقات التي يمكن للمستخدمين دمجها مع Cal.com",
|
||||
"app_is_enabled": "تم تمكين {{appName}}",
|
||||
"app_is_disabled": "تم تعطيل {{appName}}",
|
||||
"keys_have_been_saved": "تم حفظ المفاتيح",
|
||||
"disable_app": "تعطيل التطبيق",
|
||||
"disable_app_description": "يمكن لتعطيل هذا التطبيق أن يسبب مشاكل مع كيفية تفاعل المستخدمين مع Cal",
|
||||
"edit_keys": "تحرير المفاتيح",
|
||||
"admin_apps_description": "تمكين تطبيقات مثيل Cal الخاص بك",
|
||||
"no_available_apps": "لا توجد تطبيقات متاحة",
|
||||
"no_available_apps_description": "الرجاء التأكد من وجود تطبيقات في نشرك تحت 'حزم/متجر تطبيقات'",
|
||||
"no_apps": "لا توجد تطبيقات مفعلة في هذا المظهر من Cal",
|
||||
"apps_settings": "إعدادات التطبيقات",
|
||||
"fill_this_field": "يرجى ملء هذا الحقل",
|
||||
"options": "خيارات",
|
||||
"enter_option": "أدخل خيار {{index}}",
|
||||
"add_an_option": "إضافة خيار",
|
||||
"radio": "الراديو",
|
||||
"event_type_duplicate_copy_text": "{{slug}}-نسخ",
|
||||
"set_as_default": "تعيين كافتراضي"
|
||||
}
|
||||
|
||||
@@ -52,6 +52,7 @@
|
||||
"still_waiting_for_approval": "Událost stále čeká na schválení",
|
||||
"event_is_still_waiting": "Požadavek na událost stále čeká: {{attendeeName}} - {{date}} - {{eventType}}",
|
||||
"no_more_results": "Žádné další výsledky",
|
||||
"no_results": "Žádné výsledky",
|
||||
"load_more_results": "Načíst další výsledky",
|
||||
"integration_meeting_id": "{{integrationName}} ID schůzky: {{meetingId}}",
|
||||
"confirmed_event_type_subject": "Potvrzeno: {{eventType}} s {{name}} během {{date}}",
|
||||
@@ -248,6 +249,7 @@
|
||||
"add_to_calendar": "Přidat do kalendáře",
|
||||
"add_another_calendar": "Přidat další kalendář",
|
||||
"other": "Ostatní",
|
||||
"email_sign_in_subject": "Váš přihlašovací odkaz pro {{appName}}",
|
||||
"emailed_you_and_attendees": "Poslali jsme vám a ostatním účastníkům e-mail s pozvánkou a podrobnostmi.",
|
||||
"emailed_you_and_attendees_recurring": "Na první z těchto opakovaných událostí jsme vám a ostatním účastníkům poslali e-mail s pozvánkou a podrobnostmi.",
|
||||
"emailed_you_and_any_other_attendees": "Poslali jsme vám a ostatním účastníkům e-mail s těmito informacemi.",
|
||||
@@ -420,6 +422,7 @@
|
||||
"current_incorrect_password": "Aktuální heslo není správné",
|
||||
"password_hint_caplow": "Kombinace velkých a malých písmen",
|
||||
"password_hint_min": "Minimální délka 7 znaků",
|
||||
"password_hint_admin_min": "Minimální délka 15 znaků",
|
||||
"password_hint_num": "Obsahuje alespoň 1 číslo",
|
||||
"invalid_password_hint": "Heslo musí být minimálně 7 znaků dlouhé, obsahovat alespoň jedno číslo a obsahovat kombinaci velkých a malých písmen",
|
||||
"incorrect_password": "Heslo není správné.",
|
||||
@@ -463,11 +466,14 @@
|
||||
"booking_confirmation": "Potvrďte {{eventTypeTitle}} skrz účet {{profileName}}",
|
||||
"booking_reschedule_confirmation": "Přesunout {{eventTypeTitle}} na jindy skrz účet {{profileName}}",
|
||||
"in_person_meeting": "Odkaz nebo osobní schůzka",
|
||||
"attendeeInPerson": "Osobně (adresa účastníka)",
|
||||
"inPerson": "Osobně (adresa organizátora)",
|
||||
"link_meeting": "Odkaz na schůzku",
|
||||
"phone_call": "Telefon",
|
||||
"your_number": "Vaše telefonní číslo",
|
||||
"phone_number": "Tel. číslo",
|
||||
"attendee_phone_number": "Telefonní číslo účastníka",
|
||||
"organizer_phone_number": "Telefonní číslo organizátora",
|
||||
"host_phone_number": "Vaše telefonní číslo",
|
||||
"enter_phone_number": "Zadejte telefonní číslo",
|
||||
"reschedule": "Přesunout na jindy",
|
||||
@@ -554,6 +560,10 @@
|
||||
"collective": "Souhrn",
|
||||
"collective_description": "Naplánovat schůzku na dobu, kdy jsou vybraní členové týmu dostupní.",
|
||||
"duration": "Doba trvání",
|
||||
"available_durations": "Dostupné doby trvání",
|
||||
"default_duration": "Výchozí doba trvání",
|
||||
"default_duration_no_options": "Nejprve vyberte dostupné doby trvání",
|
||||
"multiple_duration_mins": "{{count}} $t(minute_timeUnit)",
|
||||
"minutes": "min",
|
||||
"round_robin": "Plánování Round Robin",
|
||||
"round_robin_description": "Schůzky v řadě mezi několika členy týmu.",
|
||||
@@ -619,6 +629,7 @@
|
||||
"teams": "Týmy",
|
||||
"team": "Tým",
|
||||
"team_billing": "Fakturace týmů",
|
||||
"team_billing_description": "Správa účtování pro váš tým",
|
||||
"upgrade_to_flexible_pro_title": "Změnili jsme fakturaci pro týmy",
|
||||
"upgrade_to_flexible_pro_message": "Ve vašem týmu jsou členové bez místa. Upgradujte svůj Pro plán pro pokrytí chybějících míst.",
|
||||
"changed_team_billing_info": "Od ledna 2022 účtujeme členy vašeho týmu podle počtu míst. Členové vašeho týmu, kteří využívali tarif Pro zdarma, nyní mají 14 denní zkušební verzi. Jakmile zkušební verze skončí, nebudou tito členové v týmu vidět, pokud nepřejdete na vyšší tarif.",
|
||||
@@ -694,6 +705,7 @@
|
||||
"hide_event_type": "Skrýt typ události",
|
||||
"edit_location": "Upravit polohu",
|
||||
"into_the_future": "v budoucnu",
|
||||
"when_booked_with_less_than_notice": "Při rezervaci s předstihem méně než <time></time>",
|
||||
"within_date_range": "V časovém rozmezí",
|
||||
"indefinitely_into_future": "Neomezeně do budoucna",
|
||||
"add_new_custom_input_field": "Přidat nové vlastní pole",
|
||||
@@ -713,6 +725,7 @@
|
||||
"delete_account_confirmation_message": "Opravdu chcete odstranit svůj účet na {{appName}}? Všichni, se kterými jste sdíleli odkaz na účet, přijdou o možnost vytvářet rezervace a vy přijdete o uložené předvolby.",
|
||||
"integrations": "Integrace",
|
||||
"apps": "Aplikace",
|
||||
"apps_listing": "Výpis aplikace",
|
||||
"category_apps": "Aplikace v kategorii {{category}}",
|
||||
"app_store": "App Store",
|
||||
"app_store_description": "Propojování lidí, technologií a pracoviště.",
|
||||
@@ -769,6 +782,7 @@
|
||||
"trending_apps": "Populární aplikace",
|
||||
"explore_apps": "Aplikace v kategorii {{category}}",
|
||||
"installed_apps": "Nainstalované aplikace",
|
||||
"free_to_use_apps": "Zdarma",
|
||||
"no_category_apps": "Žádné aplikace v kategorii {{category}}",
|
||||
"no_category_apps_description_calendar": "Přidejte aplikaci kalendáře, ať máte přehled v zájmu prevence dvojích rezervací",
|
||||
"no_category_apps_description_conferencing": "Zkuste přidat aplikaci pro konference, která umožní propojit videohovory s vašimi klienty",
|
||||
@@ -807,6 +821,8 @@
|
||||
"verify_wallet": "Ověřit peněženku",
|
||||
"connect_metamask": "Připojit Metamask",
|
||||
"create_events_on": "Vytvořit události v:",
|
||||
"enterprise_license": "Jedná se o firemní funkci",
|
||||
"enterprise_license_description": "Pokud chcete povolit tuto funkci, získejte klíč pro nasazení v konzoli {{consoleUrl}} a přidejte ho do souboru .env jako CALCOM_LICENSE_KEY. Pokud váš tým již licenci má, kontaktujte prosím {{supportMail}} a požádejte o pomoc.",
|
||||
"missing_license": "Chybějící licence",
|
||||
"signup_requires": "Je vyžadována komerční licence",
|
||||
"signup_requires_description": "{{companyName}} v současné době nenabízí bezplatnou open source verzi stránky registrace. Chcete-li získat plný přístup ke komponentám registrace, musíte získat komerční licenci. Pro osobní použití doporučujeme Prisma Data Platform nebo jakékoli jiné Postgres rozhraní pro vytváření účtů.",
|
||||
@@ -898,6 +914,7 @@
|
||||
"user_impersonation_heading": "Přizpůsobení uživatele",
|
||||
"user_impersonation_description": "Náš tým podpory se bude moci dočasně přihlásit místo vás, aby nám pomohl rychle vyřešit jakékoli problémy, které nám nahlásíte.",
|
||||
"team_impersonation_description": "Členové vašeho týmu se mohou dočasně přihlásit jako vy.",
|
||||
"allow_booker_to_select_duration": "Umožnit rezervující osobě vybrat dobu trvání",
|
||||
"impersonate_user_tip": "Všechna použití této funkce jsou kontrolována.",
|
||||
"impersonating_user_warning": "Zosobnění uživatelského jména „{{user}}“.",
|
||||
"impersonating_stop_instructions": "<0>Kliknutím zde zastavte</0>.",
|
||||
@@ -1015,6 +1032,9 @@
|
||||
"error_removing_app": "Při odstraňování aplikace došlo k chybě",
|
||||
"web_conference": "Webová konference",
|
||||
"requires_confirmation": "Vyžaduje potvrzení",
|
||||
"always_requires_confirmation": "Vždy",
|
||||
"requires_confirmation_threshold": "Pokud je rezervace provedena s předstihem < {{time}} $t({{unit}}_timeUnit), je nutné potvrzení",
|
||||
"may_require_confirmation": "Může vyžadovat potvrzení",
|
||||
"nr_event_type_one": "Typ události: {{count}}",
|
||||
"nr_event_type_other": "Typy událostí: {{count}}",
|
||||
"add_action": "Přidat akci",
|
||||
@@ -1102,6 +1122,9 @@
|
||||
"event_limit_tab_description": "Jak často lze u vás provést rezervaci",
|
||||
"event_advanced_tab_description": "Nastavení kalendáře a další...",
|
||||
"event_advanced_tab_title": "Upřesnit",
|
||||
"event_setup_multiple_duration_error": "Nastavení události: více dob trvání vyžaduje alespoň 1 možnost.",
|
||||
"event_setup_multiple_duration_default_error": "Nastavení události: vyberte prosím platnou výchozí dobu trvání.",
|
||||
"event_setup_booking_limits_error": "Limity rezervací musí být seřazeny vzestupně. [den,týden,měsíc,rok]",
|
||||
"select_which_cal": "Vyberte kalendář, do kterého se mají přidávat rezervace",
|
||||
"custom_event_name": "Vlastní název události",
|
||||
"custom_event_name_description": "Vytvářejte vlastní názvy událostí, které se budou zobrazovat v kalendáři událostí",
|
||||
@@ -1155,8 +1178,11 @@
|
||||
"invoices": "Faktury",
|
||||
"embeds": "Vložené kalendáře",
|
||||
"impersonation": "Ztotožnění",
|
||||
"impersonation_description": "Nastavení správy ztotožnění uživatele",
|
||||
"users": "Uživatelé",
|
||||
"profile_description": "Správa nastavení profilu {{appName}}",
|
||||
"users_description": "Tady najdete seznam všech uživatelů",
|
||||
"users_listing": "Výpis uživatelů",
|
||||
"general_description": "Správa nastavení jazyka a časového pásma",
|
||||
"calendars_description": "Konfigurace způsobu interakce typů událostí s kalendáři",
|
||||
"appearance_description": "Správa nastavení vzhledu rezervace",
|
||||
@@ -1361,6 +1387,7 @@
|
||||
"number_sms_notifications": "Číslo telefonu (SMS oznámení)",
|
||||
"attendee_email_workflow": "E-mail účastníka",
|
||||
"attendee_email_info": "E-mail osoby provádějící rezervaci",
|
||||
"kbar_search_placeholder": "Zadejte příkaz nebo vyhledejte...",
|
||||
"invalid_credential": "Ale ne! Zdá se, že platnost oprávnění vypršela nebo byla zrušena. Proveďte novou instalaci.",
|
||||
"choose_common_schedule_team_event": "Vyberte společný plán",
|
||||
"choose_common_schedule_team_event_description": "Tuto možnost povolte, pokud chcete používat společný plán mezi hostiteli. Při zakázání této možnosti bude každý hostitel rezervován na základě svého výchozího plánu.",
|
||||
@@ -1371,5 +1398,43 @@
|
||||
"test_preview": "Testovací náhled",
|
||||
"route_to": "Směrovat na",
|
||||
"test_preview_description": "Otestujte svůj směrovací formulář bez odeslání jakýchkoli dat",
|
||||
"test_routing": "Test směrování"
|
||||
"test_routing": "Test směrování",
|
||||
"payment_app_disabled": "Správce zakázal platební aplikaci",
|
||||
"edit_event_type": "Upravit typ události",
|
||||
"collective_scheduling": "Kolektivní plánování",
|
||||
"make_it_easy_to_book": "Usnadněte si rezervaci týmu, pokud jsou všichni k dispozici.",
|
||||
"find_the_best_person": "Najděte nejlepšího dostupného člověka a procházejte tým.",
|
||||
"fixed_round_robin": "Pevný „round robin“",
|
||||
"add_one_fixed_attendee": "Přidejte jednoho pevně stanoveného účastníka a „round robin“ přes daný počet účastníků.",
|
||||
"calcom_is_better_with_team": "Cal.com je s týmy lepší",
|
||||
"add_your_team_members": "Přidejte členy týmu k typům událostí. Použijte kolektivní plánování, abyste zahrnuli všechny, případně vyhledejte tu nejvhodnější osobu s plánováním „round robin“.",
|
||||
"booking_limit_reached": "Byl dosažen limit rezervací pro tento typ události",
|
||||
"admin_has_disabled": "Administrátor zakázal {{appName}}",
|
||||
"disabled_app_affects_event_type": "Administrátor zakázal {{appName}}, což ovlivňuje váš typ události {{eventType}}",
|
||||
"disable_payment_app": "Administrátor zakázal {{appName}}, což ovlivňuje váš typ události {{title}}. Účastníci si stále mohou rezervovat tento typ události, ale nebudou vyzváni k platbě. Abyste tomu zabránili, můžete tento typ události skrýt, dokud správce tento způsob platby znovu nepovolí.",
|
||||
"payment_disabled_still_able_to_book": "Účastníci si stále mohou rezervovat tento typ události, ale nebudou vyzváni k platbě. Abyste tomu zabránili, můžete tento typ události skrýt, dokud správce tento způsob platby znovu nepovolí.",
|
||||
"app_disabled_with_event_type": "Administrátor zakázal {{appName}}, což ovlivňuje váš typ události {{title}}.",
|
||||
"app_disabled_video": "Administrátor zakázal {{appName}}, což může ovlivnit vaše typy událostí. Pokud máte typy událostí s {{appName}} jako umístění, bude výchozí nastavení Cal Video.",
|
||||
"app_disabled_subject": "Aplikace {{appName}} byla zakázána",
|
||||
"navigate_installed_apps": "Přejděte na nainstalované aplikace",
|
||||
"disabled_calendar": "Pokud máte nainstalovaný jiný kalendář, budou do něj přidány nové rezervace. Pokud ne, připojte nový kalendář, abyste nepřišli o žádné nové rezervace.",
|
||||
"enable_apps": "Povolit aplikace",
|
||||
"enable_apps_description": "Povolte aplikace, které mohou uživatelé integrovat s Cal.com.",
|
||||
"app_is_enabled": "Aplikace {{appName}} je povolena",
|
||||
"app_is_disabled": "Aplikace {{appName}} je zakázána",
|
||||
"keys_have_been_saved": "Klíče byly uloženy",
|
||||
"disable_app": "Zakázat aplikaci",
|
||||
"disable_app_description": "Zakázání této aplikace by mohlo způsobit problémy s interakcí uživatelů s aplikací Cal",
|
||||
"edit_keys": "Upravit klávesy",
|
||||
"no_available_apps": "Nejsou k dispozici žádné aplikace",
|
||||
"no_available_apps_description": "Zkontrolujte, zda máte ve svém nasazení v části „packages/app-store“ k dispozici aplikace",
|
||||
"no_apps": "V této instanci Cal nejsou povoleny žádné aplikace",
|
||||
"apps_settings": "Nastavení aplikací",
|
||||
"fill_this_field": "Vyplňte prosím toto pole",
|
||||
"options": "Možnosti",
|
||||
"enter_option": "Zadejte možnost {{index}}",
|
||||
"add_an_option": "Přidat možnost",
|
||||
"radio": "Přepínač",
|
||||
"event_type_duplicate_copy_text": "{{slug}} – kopírovat",
|
||||
"set_as_default": "Nastavit jako výchozí"
|
||||
}
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
"upgrade_now": "Jetzt upgraden",
|
||||
"accept_invitation": "Einladung annehmen",
|
||||
"have_any_questions": "Haben Sie Fragen? Wir sind hier um Ihnen zu helfen.",
|
||||
"reset_password_subject": "{{appName}}: Anleitung zum Zurücksetzen des Passworts",
|
||||
"event_declined_subject": "Abgelehnt: {{eventType}} mit {{name}} am {{date}}",
|
||||
"event_cancelled_subject": "Abgesagt: {{eventType}} mit {{name}} am {{date}}",
|
||||
"event_request_declined": "Ihre Event-Anfrage wurde abgelehnt",
|
||||
@@ -14,7 +15,7 @@
|
||||
"event_request_cancelled": "Ihr geplanter Termin wurde abgesagt",
|
||||
"organizer": "Organisator",
|
||||
"need_to_reschedule_or_cancel": "Möchten Sie einen neuen Termin finden oder absagen?",
|
||||
"cancellation_reason": "Grund für Ihre Absage",
|
||||
"cancellation_reason": "Grund für Ihre Absage (optional)",
|
||||
"cancellation_reason_placeholder": "Warum sagen Sie ab? (optional)",
|
||||
"rejection_reason": "Grund für die Ablehnung",
|
||||
"rejection_reason_title": "Die Buchungsanfrage ablehnen?",
|
||||
@@ -50,6 +51,7 @@
|
||||
"still_waiting_for_approval": "Ein Termin wartet noch auf Bestätigung",
|
||||
"event_is_still_waiting": "Termin-Anfrage wartet: {{attendeeName}} - {{date}} - {{eventType}}",
|
||||
"no_more_results": "Keine weiteren Ergebnisse",
|
||||
"no_results": "Keine Ergebnisse",
|
||||
"load_more_results": "Weitere Ergebnisse laden",
|
||||
"integration_meeting_id": "{{integrationName}} Termin-ID: {{meetingId}}",
|
||||
"confirmed_event_type_subject": "Bestätigt: {{eventType}} mit {{name}} am {{date}}",
|
||||
@@ -97,7 +99,9 @@
|
||||
"join_team": "Team beitreten",
|
||||
"manage_this_team": "Dieses Team verwalten",
|
||||
"team_info": "Informationen zum Team",
|
||||
"request_another_invitation_email": "Falls Sie {{toEmail}} lieber nicht als Ihre {{appName}}-E-Mail verwenden möchten oder bereits über ein {{appName}}-Konto verfügen, fordern Sie bitte eine weitere Einladung zu dieser E-Mail an.",
|
||||
"you_have_been_invited": "Sie wurden eingeladen, dem Team {{teamName}} beizutreten",
|
||||
"user_invited_you": "{{user}} hat Sie eingeladen, dem Team {{team}} auf {{appName}} beizutreten",
|
||||
"hidden_team_member_title": "Sie sind in diesem Team ausgeblendet",
|
||||
"hidden_team_member_message": "Ihre Teammitgliedschaft ist nicht bezahlt, entweder upgraden Sie Ihren Account auf Pro oder lassen den Team-Organisator wissen, dass er für Ihren Platz im Team bezahlen kann.",
|
||||
"hidden_team_owner_message": "Sie benötigen einen Pro-Account um die Teamfunktionen zu verweden. Sie werden dem Team nicht angezeigt, bis der Account upgegradet wurde.",
|
||||
@@ -109,6 +113,8 @@
|
||||
"team_upgraded_successfully": "Das Update für Ihr Team war erfolgreich!",
|
||||
"use_link_to_reset_password": "Benutzen Sie den Link, um Ihr Passwort zurückzusetzen",
|
||||
"hey_there": "Hallo,",
|
||||
"forgot_your_password_calcom": "Passwort vergessen? - {{appName}}",
|
||||
"delete_webhook_confirmation_message": "Sind Sie sicher, dass Sie diesen Webhook löschen möchten? Sie werden keine {{appName}} Meetingdaten mehr unter einer bestimmten URL, in Echtzeit erhalten, wenn ein Ereignis geplant oder abgesagt wird.",
|
||||
"confirm_delete_webhook": "Ja, Webhook löschen",
|
||||
"edit_webhook": "Webhook bearbeiten",
|
||||
"delete_webhook": "Webhook löschen",
|
||||
@@ -126,9 +132,9 @@
|
||||
"no_data_yet": "Noch keine Daten",
|
||||
"ping_test": "Pingtest",
|
||||
"add_to_homescreen": "Fügen Sie diese App Ihrem Startbildschirm für schnelleren Zugriff hinzu.",
|
||||
"upcoming": "Bevorstehend",
|
||||
"recurring": "Wiederkehrend",
|
||||
"past": "Vergangen",
|
||||
"upcoming": "Bevorstehende",
|
||||
"recurring": "Wiederkehrende",
|
||||
"past": "Vergangene",
|
||||
"choose_a_file": "Datei auswählen...",
|
||||
"upload_image": "Bild hochladen",
|
||||
"upload_target": "{{target}} hochladen",
|
||||
@@ -184,6 +190,7 @@
|
||||
"30min_meeting": "30 Minuten Termin",
|
||||
"secret": "Passwort",
|
||||
"leave_blank_to_remove_secret": "Leer lassen, um Passwort zu entfernen",
|
||||
"webhook_secret_key_description": "Stellen Sie sicher, dass Ihr Server aus Sicherheitsgründen nur die erwarteten {{appName}}-Anfragen empfängt",
|
||||
"secret_meeting": "Geheimer Termin",
|
||||
"login_instead": "Stattdessen einloggen",
|
||||
"already_have_an_account": "Haben Sie bereits ein Konto?",
|
||||
@@ -227,11 +234,13 @@
|
||||
"details": "Details",
|
||||
"welcome": "Willkommen",
|
||||
"welcome_back": "Willkommen zurück",
|
||||
"welcome_to_calcom": "Willkommen bei {{appName}}",
|
||||
"welcome_instructions": "Wie ist Ihr Name und in welcher Zeitzone sind Sie? Dies kann später bearbeitet werden.",
|
||||
"connect_caldav": "Mit CalDav-Server verbinden",
|
||||
"credentials_stored_and_encrypted": "Ihre Zugangsdaten werden verschlüsselt gespeichert.",
|
||||
"connect": "Verbinden",
|
||||
"try_for_free": "Kostenlos testen",
|
||||
"create_booking_link_with_calcom": "Erstellen Sie Ihren eigenen Buchungslink mit {{appName}}",
|
||||
"who": "Wer",
|
||||
"what": "Was",
|
||||
"when": "Wann",
|
||||
@@ -239,9 +248,10 @@
|
||||
"add_to_calendar": "Zum Kalender hinzufügen",
|
||||
"add_another_calendar": "Einen weiteren Kalender hinzufügen",
|
||||
"other": "Sonstige",
|
||||
"email_sign_in_subject": "Ihr Anmelde-Link für {{appName}}",
|
||||
"emailed_you_and_attendees": "Wir haben Ihnen und den anderen Teilnehmern eine Einladung zum Kalender mit allen Details zugeschickt.",
|
||||
"emailed_you_and_attendees_recurring": "Wir haben Ihnn und den anderen Teilnemern eine Kalendereinladung für den ersten Termin dieser wiederkehrenden Termins gesendet.",
|
||||
"emailed_you_and_any_other_attendees": "Wir haben Ihnen und allen anderen Teilnehmer diesen Informationen per E-Mail geschickt.",
|
||||
"emailed_you_and_attendees_recurring": "Wir haben Ihnen und den anderen Teilnemern eine Kalendereinladung für den ersten Termin dieser wiederkehrenden Termins gesendet.",
|
||||
"emailed_you_and_any_other_attendees": "Wir haben Ihnen und allen anderen Teilnehmern diese Informationen per E-Mail zugeschickt.",
|
||||
"needs_to_be_confirmed_or_rejected": "Ihre Buchung muss noch bestätigt oder abgelehnt werden.",
|
||||
"needs_to_be_confirmed_or_rejected_recurring": "Ihr wiederkehrender Termin muss noch bestätigt oder abgelehnt werden.",
|
||||
"user_needs_to_confirm_or_reject_booking": "{{user}} muss den Termin noch bestätigen oder ablehnen.",
|
||||
@@ -252,7 +262,7 @@
|
||||
"submitted_recurring": "Ihr wiederkehrender Termin wurde gebucht",
|
||||
"booking_submitted": "Ihre Buchung wurde versandt",
|
||||
"booking_submitted_recurring": "Ihre wiederkehrende Buchung wurde versandt",
|
||||
"booking_confirmed": "Ihre Termin wurde bestätigt",
|
||||
"booking_confirmed": "Ihr Termin wurde bestätigt",
|
||||
"booking_confirmed_recurring": "Ihr wiederkehrender Termin wurde bestätigt",
|
||||
"warning_recurring_event_payment": "Zahlungen werden bei wiederkehrenden Terminen noch nicht unterstützt",
|
||||
"warning_payment_recurring_event": "Zahlungen werden bei wiederkehrenden Terminen noch nicht unterstützt",
|
||||
@@ -282,7 +292,7 @@
|
||||
"error_end_time_next_day": "Die Endzeit darf nicht größer als 24 Stunden sein",
|
||||
"back_to_bookings": "Zurück zu den Buchungen",
|
||||
"free_to_pick_another_event_type": "Sie können jederzeit einen anderen Termin wählen.",
|
||||
"cancelled": "Abgesagt",
|
||||
"cancelled": "Abgesagte",
|
||||
"cancellation_successful": "Stornierung erfolgreich",
|
||||
"really_cancel_booking": "Möchten Sie wirklich stornieren?",
|
||||
"cannot_cancel_booking": "Sie können diese Buchung nicht stornieren",
|
||||
@@ -303,7 +313,7 @@
|
||||
"bookings": "Buchungen",
|
||||
"bookings_description": "Sehen Sie anstehende und vergangene Veranstaltungen, die über Ihre Events gebucht wurden.",
|
||||
"upcoming_bookings": "Sobald jemand eine Zeit bei Ihnen bucht können Sie das hier sehen.",
|
||||
"recurring_bookings": "Sobald jemand einen wiederkehrenden Termin mit Ihnen bucht er hier erscheinen.",
|
||||
"recurring_bookings": "Sobald jemand einen wiederkehrenden Termin mit Ihnen bucht wird er hier erscheinen.",
|
||||
"past_bookings": "Ihre früheren Buchungen werden hier angezeigt.",
|
||||
"cancelled_bookings": "Ihre stornierten Buchungen werden hier angezeigt.",
|
||||
"unconfirmed_bookings": "Ihre unbestätigten Buchungen werden hier angezeigt.",
|
||||
@@ -337,6 +347,7 @@
|
||||
"dark": "Dunkel",
|
||||
"automatically_adjust_theme": "Theme automatisch basierend auf den Einstellungen des Teilnehmers anpassen",
|
||||
"user_dynamic_booking_disabled": "Einige der Benutzer in der Gruppe haben derzeit dynamische Gruppenbuchungen deaktiviert",
|
||||
"allow_dynamic_booking_tooltip": "Gruppenbuchungslinks, die dynamisch durch Hinzufügen mehrerer Benutzernamen mit einem '+' erstellt werden können. Beispiel: '{{appName}}/bailey+peer'",
|
||||
"allow_dynamic_booking": "Ermöglichen Sie es den Teilnehmenden, Sie über dynamische Gruppenbuchungen zu buchen",
|
||||
"email": "E-Mail",
|
||||
"email_placeholder": "max@example.com",
|
||||
@@ -356,6 +367,8 @@
|
||||
"team_webhooks": "Team-Webhooks",
|
||||
"create_new_webhook_to_account": "Erstellen Sie einen neuen Webhook in Ihrem Account",
|
||||
"new_webhook": "Neuer Webhook",
|
||||
"receive_cal_meeting_data": "Erhalte {{appName}} Termindaten unter einer bestimmten URL in Echtzeit, wenn ein Termin geplant oder abgesagt wird.",
|
||||
"receive_cal_event_meeting_data": "Erhalte {{appName}} Termindaten unter einer bestimmten URL in Echtzeit, wenn dieser Termin geplant oder abgesagt wird.",
|
||||
"responsive_fullscreen_iframe": "Responsives Vollbild-iFrame",
|
||||
"loading": "Wird geladen...",
|
||||
"deleting": "Lösche...",
|
||||
@@ -363,6 +376,7 @@
|
||||
"developer": "Entwickler",
|
||||
"manage_developer_settings": "Verwalten Sie Ihre Entwicklereinstellungen.",
|
||||
"iframe_embed": "iFrame-Einbettung",
|
||||
"embed_calcom": "Der einfachste Weg, {{appName}} auf Ihrer Website einzubinden.",
|
||||
"integrate_using_embed_or_webhooks": "Integrieren Sie Cal.com in Ihre Website mit unseren Einbettungs-Optionen oder erhalten Sie Buchungsdaten mit Webhooks.",
|
||||
"schedule_a_meeting": "Termin planen",
|
||||
"view_and_manage_billing_details": "Ihre Rechnungsdetails ansehen und verwalten",
|
||||
@@ -406,7 +420,8 @@
|
||||
"forgotten_secret_description": "Wenn Sie dieses Passwort verloren oder vergessen haben, können Sie es ändern. Bitte beachten Sie, dass alle Integrationen, die dieses Geheimnis nutzen, aktualisiert werden müssen",
|
||||
"current_incorrect_password": "Aktuelles Passwort ist falsch",
|
||||
"password_hint_caplow": "Mischung aus Groß- und Kleinbuchstaben",
|
||||
"password_hint_min": "Mindestens 7 Zeichen lang",
|
||||
"password_hint_min": "Mindestens 8 Zeichen lang",
|
||||
"password_hint_admin_min": "Mindestens 15 Zeichen lang",
|
||||
"password_hint_num": "Enthält mindestens 1 Zahl",
|
||||
"invalid_password_hint": "Das Passwort muss mindestens 7 Zeichen lang sein und mindestens eine Nummer beinhalten, sowie eine Mischung aus Groß- und Kleinbuchstaben sein",
|
||||
"incorrect_password": "Passwort ist falsch",
|
||||
@@ -450,11 +465,14 @@
|
||||
"booking_confirmation": "Bestätigen Sie {{eventTypeTitle}} mit {{profileName}}",
|
||||
"booking_reschedule_confirmation": "Planen Sie Ihr {{eventTypeTitle}} mit {{profileName}} um",
|
||||
"in_person_meeting": "Vor-Ort-Termin",
|
||||
"attendeeInPerson": "Persönlich (Teilnehmeradresse)",
|
||||
"inPerson": "Persönlich (Organisator-Adresse)",
|
||||
"link_meeting": "Termin verknüpfen",
|
||||
"phone_call": "Telefonat",
|
||||
"your_number": "Ihre Telefonnummer",
|
||||
"phone_number": "Telefonnummer",
|
||||
"attendee_phone_number": "Telefonnummer des Teilnehmers",
|
||||
"organizer_phone_number": "Telefonnummer des Organisators",
|
||||
"host_phone_number": "Ihre Telefonnummer",
|
||||
"enter_phone_number": "Telefonnummer eingeben",
|
||||
"reschedule": "Neuplanen",
|
||||
@@ -494,6 +512,8 @@
|
||||
"invite_new_member_description": "Hinweis: Dies wird <1>einen zusätzlichen Platz(15 $/m)</1> in Ihrem Abonnement kosten.",
|
||||
"invite_new_team_member": "Laden Sie jemanden in Ihr Team ein.",
|
||||
"change_member_role": "Rolle des Teammitglieds ändern",
|
||||
"disable_cal_branding": "{{appName}}-Branding deaktivieren",
|
||||
"disable_cal_branding_description": "Blendet alle {{appName}}-Werbung auf Ihren öffentlichen Seiten aus.",
|
||||
"danger_zone": "Achtung",
|
||||
"back": "Zurück",
|
||||
"cancel": "Abbrechen",
|
||||
@@ -539,6 +559,10 @@
|
||||
"collective": "Kollektiv",
|
||||
"collective_description": "Planen Sie Meetings, bei denen alle ausgewählten Teammitglieder verfügbar sind.",
|
||||
"duration": "Dauer",
|
||||
"available_durations": "Verfügbare Laufzeiten",
|
||||
"default_duration": "Standardlaufzeit",
|
||||
"default_duration_no_options": "Bitte wählen Sie zuerst die verfügbaren Laufzeiten aus",
|
||||
"multiple_duration_mins": "{{count}} $t(minute_timeUnit)",
|
||||
"minutes": "Minuten",
|
||||
"round_robin": "Round Robin",
|
||||
"round_robin_description": "Treffen zwischen mehreren Teammitgliedern durchwechseln.",
|
||||
@@ -610,6 +634,7 @@
|
||||
"changed_team_billing_info": "Ab Januar 2022 berechnen wir pro Sitzplatz für Teammitglieder. Mitglieder deines Teams, die Pro kostenlos hatten, sind jetzt in einer 14 Tage Testphase. Sobald die Testversion abläuft, werden diese Mitglieder vor Ihrem Team verborgen, es sei denn, Sie upgraden jetzt.",
|
||||
"create_manage_teams_collaborative": "Erstellen und verwalten Sie Teams, um kollaborative Funktionen zu nutzen.",
|
||||
"only_available_on_pro_plan": "Diese Funktion ist nur im Pro Plan verfügbar",
|
||||
"remove_cal_branding_description": "Um das {{appName}}-Branding von Ihren Buchungsseiten zu entfernen, müssen Sie auf ein Pro-Konto upgraden.",
|
||||
"edit_profile_info_description": "Bearbeiten Sie Ihre Profilinformationen, welche bei Ihrem Cal-Link angezeigt werden.",
|
||||
"change_email_tip": "Möglicherweise müssen Sie sich aus- und einloggen, um die Änderung wirksam zu machen.",
|
||||
"little_something_about": "Ein wenig über sich selbst.",
|
||||
@@ -658,19 +683,28 @@
|
||||
"private_link_label": "Privater Link",
|
||||
"private_link_hint": "Ihr privater Link wird nach jeder Nutzung neu generiert",
|
||||
"copy_private_link": "Privaten Link kopieren",
|
||||
"private_link_description": "Erzeugen Sie einen privaten Link, den Sie teilen können, ohne Ihren {{appName}}-Benutzername preiszugeben",
|
||||
"invitees_can_schedule": "Teilnehmende können folgendes buchen",
|
||||
"date_range": "Datumszeitraum",
|
||||
"calendar_days": "Kalendertage",
|
||||
"business_days": "Werktage",
|
||||
"set_address_place": "Adresse oder Ort festlegen",
|
||||
"set_link_meeting": "Einen Link zum Termin setzen",
|
||||
"cal_invitee_phone_number_scheduling": "{{appName}} wird Ihren Teilnehmer bitten, vor der Planung eine Telefonnummer einzugeben.",
|
||||
"cal_provide_google_meet_location": "{{appName}} wird einen Google Meet Ort zur Verfügung stellen.",
|
||||
"cal_provide_zoom_meeting_url": "{{appName}} wird eine Zoom Meeting URL zur Verfügung stellen.",
|
||||
"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_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",
|
||||
"commission_per_transaction": "Provision pro Transaktion",
|
||||
"event_type_updated_successfully_description": "Ihr Termintyp wurde erfolgreich aktualisiert.",
|
||||
"hide_event_type": "Termintyp ausblenden",
|
||||
"edit_location": "Standort bearbeiten",
|
||||
"into_the_future": "in die Zukunft",
|
||||
"when_booked_with_less_than_notice": "Bei Buchung mit weniger als <time></time> Vorlauf",
|
||||
"within_date_range": "Innerhalb eines Zeitraums",
|
||||
"indefinitely_into_future": "Auf unbestimmte Zeit in die Zukunft",
|
||||
"add_new_custom_input_field": "Neues individuelles Eingabefeld hinzufügen",
|
||||
@@ -687,6 +721,7 @@
|
||||
"confirm_delete_event_type": "Ja, Termintyp löschen",
|
||||
"delete_account": "Account löschen",
|
||||
"confirm_delete_account": "Ja, Account löschen",
|
||||
"delete_account_confirmation_message": "Sind Sie sicher, dass Sie Ihr {{appName}}-Konto löschen möchten? Sie können dann nicht mehr über Ihre geteilten Links gebucht werden und alle Einstellungen werden gelöscht.",
|
||||
"integrations": "Integrationen",
|
||||
"apps": "Apps",
|
||||
"apps_description": "Hier findest du eine Auflistung deiner Apps",
|
||||
@@ -714,6 +749,7 @@
|
||||
"toggle_calendars_conflict": "Wechseln Sie die Kalender in denen nach Konflikten gesucht werden sollen, um Doppelbuchungen zu vermeiden.",
|
||||
"select_destination_calendar": "Erstelle Termine im",
|
||||
"connect_additional_calendar": "Zusätzlichen Kalender verbinden",
|
||||
"calendar_updated_successfully": "Kalender erfolgreich aktualisiert",
|
||||
"conferencing": "Videokonferenzen",
|
||||
"calendar": "Kalender",
|
||||
"payments": "Zahlungen",
|
||||
@@ -746,6 +782,7 @@
|
||||
"trending_apps": "Angesagte Apps",
|
||||
"explore_apps": "{{category}} Apps",
|
||||
"installed_apps": "Installierte Apps",
|
||||
"free_to_use_apps": "Kostenlos",
|
||||
"no_category_apps": "Keine {{category}} Apps",
|
||||
"no_category_apps_description_calendar": "Fügen Sie eine Kalender-App hinzu, in der nach Konflikten gesucht werden soll, um Doppelbuchungen zu vermeiden",
|
||||
"no_category_apps_description_conferencing": "Versuchen Sie, eine Konferenz-App hinzuzufügen, um Videoanrufe mit Ihren Kunden zu integrieren",
|
||||
@@ -762,7 +799,7 @@
|
||||
"analytics": "Analyse",
|
||||
"empty_installed_apps_headline": "Keine Apps installiert",
|
||||
"empty_installed_apps_description": "Apps erlauben es Ihnen, Ihren Arbeitsfluss zu verbessern und Ihre Planung viel besser zu gestalten.",
|
||||
"empty_installed_apps_button": "Entdecken Sie den App Store",
|
||||
"empty_installed_apps_button": "Durchsuchen Sie den App Store",
|
||||
"manage_your_connected_apps": "Verwalten Sie Ihre installierten Apps oder ändern Sie die Einstellungen",
|
||||
"browse_apps": "Apps durchsuchen",
|
||||
"features": "Funktionen",
|
||||
@@ -784,8 +821,11 @@
|
||||
"verify_wallet": "Wallet verifizieren",
|
||||
"connect_metamask": "Metamask verbinden",
|
||||
"create_events_on": "Erstelle Termine in:",
|
||||
"enterprise_license": "Das ist eine Enterprise-Funktion",
|
||||
"enterprise_license_description": "Um diese Funktion zu aktivieren, holen Sie sich einen Deployment-Schlüssel von der {{consoleUrl}}-Konsole und fügen Sie ihn als CALCOM_LICENSE_KEY zu Ihrer .env hinzu. Wenn Ihr Team bereits eine Lizenz hat, wenden Sie sich bitte an {{supportMail}} für Hilfe.",
|
||||
"missing_license": "Lizenz fehlt",
|
||||
"signup_requires": "Kommerzielle Lizenz erforderlich",
|
||||
"signup_requires_description": "{{companyName}} bietet zur Zeit keine kostenlose Open-Source-Version der Anmeldeseite an. Um vollen Zugriff auf die Registrierungskomponenten zu erhalten, müssen Sie eine kommerzielle Lizenz erwerben. Für den persönlichen Gebrauch empfehlen wir die Prisma Data Platform oder jede andere Postgres-Schnittstelle zur Erstellung von Accounts.",
|
||||
"next_steps": "Nächste Schritte",
|
||||
"acquire_commercial_license": "Eine kommerzielle Lizenz erwerben",
|
||||
"the_infrastructure_plan": "Der Infrastrukturplan ist nutzungsbasiert und bietet Startup-freundliche Discounts an.",
|
||||
@@ -874,6 +914,7 @@
|
||||
"user_impersonation_heading": "Benutzeridentitätswechsel",
|
||||
"user_impersonation_description": "Erlaubt es unserem Support-Team, sich vorübergehend mit Ihrem Konto anzumelden, um jegliche Probleme, die Sie gemeldet haben, schneller zu lösen.",
|
||||
"team_impersonation_description": "Ermöglicht den Team-Administratoren, sich vorübergehend als Sie einzuloggen.",
|
||||
"allow_booker_to_select_duration": "Bucher erlauben, die Länge zu wählen",
|
||||
"impersonate_user_tip": "Alle Verwendungen dieser Funktion werden geprüft.",
|
||||
"impersonating_user_warning": "Imitiere den Account {{user}}.",
|
||||
"impersonating_stop_instructions": "<0>Klicke hier um zu stoppen </0>.",
|
||||
@@ -887,17 +928,23 @@
|
||||
"update_location": "Ort aktualisieren",
|
||||
"location_updated": "Ort aktualisiert",
|
||||
"email_validation_error": "Das sieht nicht wie eine E-Mail-Adresse aus",
|
||||
"place_where_cal_widget_appear": "Kopieren Sie diesen Code an die Stelle in Ihrem HTML, an der Ihr {{appName}}-Widget erscheinen soll.",
|
||||
"create_update_react_component": "Erstellen oder Aktualisieren einer existierenden Reaktionskomponente wie unten gezeigt.",
|
||||
"copy_code": "Code kopieren",
|
||||
"code_copied": "Code kopiert!",
|
||||
"how_you_want_add_cal_site": "Wie möchten Sie {{appName}} zu Ihrer Website hinzufügen?",
|
||||
"choose_ways_put_cal_site": "Wählen Sie eine der folgenden Möglichkeiten, um {{appName}} in Ihre Website zu integrieren.",
|
||||
"setting_up_zapier": "Einrichtung Ihrer Zapier-Integration",
|
||||
"generate_api_key": "Api Key generieren",
|
||||
"generate_api_key_description": "Generieren Sie einen API-Schlüssel für {{appName}} unter",
|
||||
"your_unique_api_key": "Ihr eindeutiger API-Key",
|
||||
"copy_safe_api_key": "Kopieren Sie diesen API-Schlüssel und speichern Sie ihn an einem sicheren Ort. Wenn Sie diesen Schlüssel verlieren, müssen Sie einen neuen generieren.",
|
||||
"zapier_setup_instructions": "<0>Gehen Sie zu: <1>Zapier-Einladungs-Link</1></0><1>Logge Sie sich in Ihr Zapier-Konto ein und erstelle einen neuen Zap.</1><2>Wählen Sie Cal.com als ihre Trigger-App aus. Wählen Sie auch ein Auslöserereignis.</2><3>Wähle Sie ihr Konto aus und geben dann ihren eindeutigen API-Key ein.</3><4>Teste Sie den Trigger.</4><5>Alles fertig!</5>",
|
||||
"install_zapier_app": "Bitte installieren Sie zuerst die Zapier-App im App Store.",
|
||||
"connect_apple_server": "Mit Apple-Server verbinden",
|
||||
"connect_caldav_server": "Mit CalDav-Server verbinden",
|
||||
"calendar_url": "Kalender-URL",
|
||||
"apple_server_generate_password": "Generieren Sie ein App-spezifisches Passwort für {{appName}} unter",
|
||||
"credentials_stored_encrypted": "Ihre Zugangsdaten werden verschlüsselt gespeichert.",
|
||||
"it_stored_encrypted": "Er wird gespeichert und verschlüsselt.",
|
||||
"go_to_app_store": "Zum App Store",
|
||||
@@ -985,6 +1032,9 @@
|
||||
"error_removing_app": "Fehler beim Entfernen der App",
|
||||
"web_conference": "Webkonferenz",
|
||||
"requires_confirmation": "Erfordert Bestätigung",
|
||||
"always_requires_confirmation": "Immer",
|
||||
"requires_confirmation_threshold": "Erfordert eine Bestätigung bei Buchung mit < {{time}} $t({{unit}}_timeUnit) Vorlauf",
|
||||
"may_require_confirmation": "Kann Bestätigung erfordern",
|
||||
"nr_event_type_one": "{{count}} Ereignistyp",
|
||||
"nr_event_type_other": "{{count}} Ereignistypen",
|
||||
"add_action": "Aktion hinzufügen",
|
||||
@@ -1072,6 +1122,9 @@
|
||||
"event_limit_tab_description": "Wie oft können Sie gebucht werden",
|
||||
"event_advanced_tab_description": "Kalendereinstellungen & mehr...",
|
||||
"event_advanced_tab_title": "Erweitert",
|
||||
"event_setup_multiple_duration_error": "Terminkonfiguration: Mehrere Laufzeiten erfordern mindestens eine Option.",
|
||||
"event_setup_multiple_duration_default_error": "Termineinrichtung: Bitte wählen Sie eine gültige Standarddauer.",
|
||||
"event_setup_booking_limits_error": "Die Buchungslimits müssen in aufsteigender Reihenfolge sein. [Tag, Woche, Monat, Jahr]",
|
||||
"select_which_cal": "Wählen Sie den Kalender aus, zu dem Termine hinzugefügt werden sollen",
|
||||
"custom_event_name": "Eigener Terminname",
|
||||
"custom_event_name_description": "Erstellen Sie benutzerdefinierte Terminnamen, die im Kalendereintrag angezeigt werden sollen",
|
||||
@@ -1085,8 +1138,10 @@
|
||||
"turn_off": "Abschalten",
|
||||
"settings_updated_successfully": "Einstellungen erfolgreich aktualisiert",
|
||||
"error_updating_settings": "Fehler beim Aktualisieren der Einstellungen",
|
||||
"personal_cal_url": "Meine persönliche {{appName}}-URL",
|
||||
"bio_hint": "Schreiben Sie eine kurze Beschreibung, welche auf Ihrer persönlichen Profil-Seite erscheinen wird.",
|
||||
"delete_account_modal_title": "Account löschen",
|
||||
"confirm_delete_account_modal": "Sind Sie sicher, dass Sie Ihr {{appName}}-Konto löschen möchten?",
|
||||
"delete_my_account": "Meinen Account löschen",
|
||||
"start_of_week": "Wochenstart",
|
||||
"select_calendars": "Wählen Sie aus, in welchen Kalendern Sie nach Konflikten suchen wollen, um Doppelbuchungen zu vermeiden.",
|
||||
@@ -1096,6 +1151,7 @@
|
||||
"custom_brand_colors": "Eigene Marken-Farben",
|
||||
"customize_your_brand_colors": "Passen Sie Ihre eigene Markenfarbe auf Ihrer Buchungsseite an.",
|
||||
"pro": "Pro",
|
||||
"removes_cal_branding": "Entfernt alle {{appName}}-bezogenen Markenzeichen, z. B. „Powered by {{appName}}.“",
|
||||
"profile_picture": "Profilbild",
|
||||
"upload": "Upload",
|
||||
"add_profile_photo": "Profilbild hinzufügen",
|
||||
@@ -1164,6 +1220,7 @@
|
||||
"create_your_first_form": "Erstellen Sie Ihr erstes Formular",
|
||||
"create_your_first_form_description": "Mithilfe von Leitungsformularen können Sie qualifizierende Fragen stellen und zur richtigen Person oder zum richtigen Veranstaltungstyp weiterleiten.",
|
||||
"create_your_first_webhook": "Erstellen Sie Ihren ersten Webhook",
|
||||
"create_your_first_webhook_description": "Mit Webhooks können Sie Meetingdaten in Echtzeit erhalten, sobald etwas in {{appName}} passiert.",
|
||||
"for_a_maximum_of": "Für maximal",
|
||||
"event_one": "Ereignis",
|
||||
"event_other": "Ereignisse",
|
||||
@@ -1179,6 +1236,7 @@
|
||||
"workflow_example_4": "Eine Erinnerung per SMS an die Teilnehmer verschicken, 24 Stunden bevor das Event startet",
|
||||
"workflow_example_5": "Benutzerdefinierte E-Mail senden, wenn der Termin zum Moderieren neu geplant wird",
|
||||
"workflow_example_6": "Benutzerdefinierte SMS senden, wenn der Termin zum Moderieren gebucht wird",
|
||||
"welcome_to_cal_header": "Willkommen bei {{appName}}!",
|
||||
"edit_form_later_subtitle": "Sie können dies später bearbeiten.",
|
||||
"connect_calendar_later": "Ich verbinde meinen Kalender später",
|
||||
"set_my_availability_later": "Ich werde meine Verfügbarkeit später festlegen",
|
||||
@@ -1188,6 +1246,7 @@
|
||||
"booking_appearance": "Darstellung der Buchungsseite",
|
||||
"appearance_team_description": "Einstellungen für die Buchungsdarstellung Ihres Teams verwalten",
|
||||
"only_owner_change": "Nur der Besitzer dieses Teams kann Änderungen an den Buchungen des Teams vornehmen ",
|
||||
"team_disable_cal_branding_description": "Entfernt alle {{appName}}-bezogenen Markenzeichen, z. B. „Powered by {{appName}}“",
|
||||
"invited_by_team": "{{teamName}} hat Sie eingeladen, dem Team als {{role}} beizutreten",
|
||||
"token_invalid_expired": "Token ist entweder ungültig oder abgelaufen.",
|
||||
"exchange_add": "Mit Microsoft Exchange verbinden",
|
||||
@@ -1207,11 +1266,13 @@
|
||||
"theme_dark": "Dunkel",
|
||||
"theme_system": "Systemstandard",
|
||||
"add_a_team": "Team hinzufügen",
|
||||
"add_webhook_description": "Erhalten Sie Meetingdaten in Echtzeit, wenn etwas in {{appName}} passiert",
|
||||
"triggers_when": "Löst aus, wenn",
|
||||
"test_webhook": "Bitte führen Sie einen Pingtest vor der Erstellung durch.",
|
||||
"enable_webhook": "Webhook aktivieren",
|
||||
"add_webhook": "Webhook hinzufügen",
|
||||
"webhook_edited_successfully": "Webhook gespeichert",
|
||||
"webhooks_description": "Erhalten Sie Meetingdaten in Echtzeit, wenn etwas in {{appName}} passiert",
|
||||
"api_keys_description": "Generieren Sie API-Schlüssel für den Zugriff auf Ihren eigenen Account",
|
||||
"new_api_key": "Neuer API-Schlüssel",
|
||||
"active": "Aktiv",
|
||||
@@ -1220,6 +1281,7 @@
|
||||
"embeds_title": "HTML iframe-Einbettung",
|
||||
"embeds_description": "Alle Event-Typen auf Ihrer Website einbetten",
|
||||
"create_first_api_key": "Erstellen Sie Ihren ersten API-Schlüssel",
|
||||
"create_first_api_key_description": "API-Schlüssel erlauben es anderen Apps, mit {{appName}} zu kommunizieren",
|
||||
"back_to_signin": "Zurück zur Anmeldung",
|
||||
"reset_link_sent": "Zurücksetzungslink gesendet",
|
||||
"password_reset_email": "Eine E-Mail mit Anweisungen zum Zurücksetzen Ihres Passworts ist auf dem Weg zu {{email}}.",
|
||||
@@ -1227,12 +1289,14 @@
|
||||
"password_updated": "Passwort aktualisiert!",
|
||||
"pending_payment": "Zahlung ausstehend",
|
||||
"confirmation_page_rainbow": "Sperren Sie Ihr Ereignis hinter Tokens oder NFTs auf Ethereum, Polygon und mehr.",
|
||||
"not_on_cal": "Nicht auf {{appName}}",
|
||||
"no_calendar_installed": "Kein Kalender installiert",
|
||||
"no_calendar_installed_description": "Sie haben noch keinen Ihrer Kalender verbunden",
|
||||
"add_a_calendar": "Kalender hinzufügen",
|
||||
"change_email_hint": "Möglicherweise müssen Sie sich aus- und einloggen, um jegliche Änderung wirksam zu machen",
|
||||
"confirm_password_change_email": "Bitte bestätigen Sie Ihr Passwort, bevor Sie Ihre E-Mail-Adresse ändern",
|
||||
"seats": "Plätze",
|
||||
"every_app_published": "Jede App, die im {{appName}} App Store veröffentlicht wird, ist Open Source und gründlich durch Peer Reviews getestet. {{companyName}} unterstützt oder zertifiziert diese Apps jedoch nicht, es sei denn, sie werden von {{appName}} selbst veröffentlicht. Wenn Sie auf unangemessene Inhalte oder Verhaltensweisen stoßen, melden Sie diese bitte.",
|
||||
"report_app": "App melden",
|
||||
"limit_booking_frequency": "Buchungsfrequenz begrenzen",
|
||||
"limit_booking_frequency_description": "Begrenzen, wie oft dieses Ereignis gebucht werden kann",
|
||||
@@ -1300,10 +1364,6 @@
|
||||
"saml_sp_acs_url_copied": "ACS-URL kopiert!",
|
||||
"saml_sp_entity_id_copied": "SP-Entitäts-ID kopiert!",
|
||||
"saml_btn_configure": "Konfigurieren",
|
||||
"kbar_search_placeholder": "Geben Sie einen Befehl ein oder suchen Sie...",
|
||||
"free_to_use_apps": "Kostenlos",
|
||||
"enterprise_license": "Das ist eine Enterprise-Funktion",
|
||||
"enterprise_license_description": "Um diese Funktion zu aktivieren, holen Sie sich einen Deployment-Schlüssel von der {{consoleUrl}}-Konsole und fügen Sie ihn als CALCOM_LICENSE_KEY zu Ihrer .env hinzu. Wenn Ihr Team bereits eine Lizenz hat, wenden Sie sich bitte an {{supportMail}} für Hilfe.",
|
||||
"add_calendar": "Kalender hinzufügen",
|
||||
"limit_future_bookings": "Zukünftige Termine begrenzen",
|
||||
"limit_future_bookings_description": "Begrenzt, wie weit in die Zukunft dieser Termin gebucht werden kann",
|
||||
@@ -1327,7 +1387,8 @@
|
||||
"number_sms_notifications": "Telefonnummer (SMS-Benachrichtigungen)",
|
||||
"attendee_email_workflow": "Teilnehmer E-Mail",
|
||||
"attendee_email_info": "Die E-Mail-Adresse der buchenden Person",
|
||||
"invalid_credential": "Oh nein! Es sieht so aus, als ob die Berechtigung abgelaufen sind oder entzogen wurden. Bitte erneut installieren.",
|
||||
"kbar_search_placeholder": "Geben Sie einen Befehl ein oder suchen Sie...",
|
||||
"invalid_credential": "Oh nein! Es sieht so aus, als ob die Berechtigung abgelaufen ist oder entzogen wurden. Bitte erneut installieren.",
|
||||
"choose_common_schedule_team_event": "Gemeinsamen Zeitplan auswählen",
|
||||
"choose_common_schedule_team_event_description": "Aktivieren Sie dies, wenn Sie einen gemeinsamen Zeitplan zwischen Hosts verwenden möchten. Wenn deaktiviert, ist jeder Host basierend auf seinen Standardplan buchbar.",
|
||||
"reason": "Grund",
|
||||
@@ -1335,7 +1396,46 @@
|
||||
"sender_id_error_message": "Nur Buchstaben, Zahlen und Leerzeichen erlaubt (max. 11 Zeichen)",
|
||||
"test_routing_form": "Testweiterleitungsformular",
|
||||
"test_preview": "Vorschau testen",
|
||||
"route_to": "Route zu",
|
||||
"test_preview_description": "Testen Sie Ihr Leitungsformular, ohne Daten zu senden",
|
||||
"test_routing": "Testweiterleitung"
|
||||
"route_to": "Weiterleiten zu",
|
||||
"test_preview_description": "Testen Sie Ihr Weiterleitungsformular, ohne Daten zu senden",
|
||||
"test_routing": "Testweiterleitung",
|
||||
"payment_app_disabled": "Ein Administrator hat eine Zahlungs-App deaktiviert",
|
||||
"edit_event_type": "Termintyp bearbeiten",
|
||||
"collective_scheduling": "Kollektive Terminplanung",
|
||||
"make_it_easy_to_book": "Machen Sie es einfach, Ihr Team zu buchen, wenn jeder verfügbar ist.",
|
||||
"find_the_best_person": "Finden Sie die beste verfügbare Person und rotieren Sie durch Ihr Team.",
|
||||
"fixed_round_robin": "Festgelegter Round Robin",
|
||||
"add_one_fixed_attendee": "Fügen Sie einen festen Teilnehmer und einen Round Robin mit einer Reihe von Teilnehmern hinzu.",
|
||||
"calcom_is_better_with_team": "Cal.com ist mit Teams besser",
|
||||
"add_your_team_members": "Fügen Sie Ihre Teammitglieder zu Ihren Termintypen hinzu. Nutzen Sie kollektive Planung, um alle einzubinden oder finden Sie die geeignetste Person mit der Round Robin Planung.",
|
||||
"booking_limit_reached": "Das Buchungslimit für diesen Termintyp wurde erreicht",
|
||||
"admin_has_disabled": "Ein Admin hat {{appName}} deaktiviert",
|
||||
"disabled_app_affects_event_type": "Ein Admin hat {{appName}} deaktiviert, was Ihren Termintyp {{eventType}} betrifft",
|
||||
"disable_payment_app": "Der Admin hat {{appName}} deaktiviert, wodurch Ihr Termintyp {{title}} beeinflusst wurde. Die Teilnehmer können diesen Termintyp immer noch buchen, werden aber nicht zur Zahlung aufgefordert. Sie können den Termintyp ausblenden, um dies zu verhindern, bis Ihr Administrator Ihre Zahlungsmethode wieder aktiviert.",
|
||||
"payment_disabled_still_able_to_book": "Die Teilnehmer können diesen Termintyp immer noch buchen, werden aber nicht zur Zahlung aufgefordert. Sie können den Termintyp ausblenden, um dies zu verhindern, bis Ihr Administrator Ihre Zahlungsmethode wieder aktiviert.",
|
||||
"app_disabled_with_event_type": "Der Admin hat {{appName}} deaktiviert, was Ihren Termintyp {{title}} betrifft.",
|
||||
"app_disabled_video": "Der Administrator hat {{appName}} deaktiviert, was Ihre Termintypen beeinflussen kann. Wenn Sie Termintypen mit {{appName}} als Ort haben, wird es standardmäßig zu Cal Video geändert.\n",
|
||||
"app_disabled_subject": "{{appName}} wurde deaktiviert",
|
||||
"navigate_installed_apps": "Zu installierte Apps wechseln",
|
||||
"disabled_calendar": "Wenn Sie einen anderen Kalender installiert haben, werden neue Buchungen zu dem Kalender hinzugefügt. Verbinden Sie andernfalls einen neuen Kalender, damit Sie keine neuen Buchungen verpassen.",
|
||||
"enable_apps": "Apps aktivieren",
|
||||
"enable_apps_description": "Apps aktivieren, die Benutzer mit Cal.com integrieren können",
|
||||
"app_is_enabled": "{{appName}} ist aktiviert",
|
||||
"app_is_disabled": "{{appName}} ist deaktiviert",
|
||||
"keys_have_been_saved": "Schlüssel wurden gespeichert",
|
||||
"disable_app": "App deaktivieren",
|
||||
"disable_app_description": "Das Deaktivieren dieser App kann Probleme mit den Interaktionen Ihrer Nutzer mit Cal verursachen",
|
||||
"edit_keys": "Schlüssel bearbeiten",
|
||||
"admin_apps_description": "Hier findest du eine Auflistung deiner Apps",
|
||||
"no_available_apps": "Es gibt keine verfügbaren Apps",
|
||||
"no_available_apps_description": "Bitte stellen Sie sicher, dass sich unter „packages/app-store“ Apps in Ihrem Deployment befinden",
|
||||
"no_apps": "In dieser Instanz von Cal sind keine Apps aktiviert",
|
||||
"apps_settings": "Apps-Einstellungen",
|
||||
"fill_this_field": "Bitte füllen Sie dieses Feld aus",
|
||||
"options": "Optionen",
|
||||
"enter_option": "Option {{index}} eingeben",
|
||||
"add_an_option": "Option hinzufügen",
|
||||
"radio": "Radio",
|
||||
"event_type_duplicate_copy_text": "{{slug}}-Kopie",
|
||||
"set_as_default": "Als Standard festlegen"
|
||||
}
|
||||
|
||||
@@ -0,0 +1,111 @@
|
||||
{
|
||||
"day_one": "{{count}} ημέρα",
|
||||
"day_other": "{{count}} ημέρες",
|
||||
"second_one": "{{count}} δευτερόλεπτο",
|
||||
"second_other": "{{count}} δευτερόλεπτα",
|
||||
"upgrade_now": "Αναβαθμίστε τώρα",
|
||||
"accept_invitation": "Αποδοχή Πρόσκλησης",
|
||||
"have_any_questions": "Έχετε ερωτήσεις? Είμαστε εδώ για να βοηθήσουμε.",
|
||||
"reset_password_subject": "{{appName}}: Οδηγίες επαναφοράς κωδικού πρόσβασης",
|
||||
"event_declined_subject": "Απορρίφθηκε: {{eventType}} με {{name}} στις {{date}}",
|
||||
"event_cancelled_subject": "Ακύρωση: {{eventType}} με {{name}} στις {{date}}",
|
||||
"need_to_reschedule_or_cancel": "Χρειάζεται να επαναπρογραμματίσετε ή να ακυρώσετε;",
|
||||
"cancellation_reason": "Λόγος ακύρωσης (προαιρετικό)",
|
||||
"rejection_reason": "Λόγος απόρριψης",
|
||||
"rejection_reason_title": "Απόρριψη του αιτήματος κράτησης;",
|
||||
"rejection_confirmation": "Απόρριψη κράτησης",
|
||||
"error_message": "Το μήνυμα σφάλματος ήταν: '{{errorMessage}}'",
|
||||
"refund_failed_subject": "Η επιστροφή χρημάτων απέτυχε: {{name}} - {{date}} - {{eventType}}",
|
||||
"refund_failed": "Η επιστροφή χρημάτων για την εκδήλωση {{eventType}} με {{userName}} στις {{date}} απέτυχε.",
|
||||
"a_refund_failed": "Αποτυχία επιστροφής χρημάτων",
|
||||
"awaiting_payment_subject": "Σε αναμονή Πληρωμής: {{eventType}} με {{name}} στις {{date}}",
|
||||
"meeting_awaiting_payment": "Η πληρωμή της συνάντησής σας εκκρεμεί",
|
||||
"help": "Βοήθεια",
|
||||
"price": "Τιμή",
|
||||
"payment": "Πληρωμή",
|
||||
"missing_card_fields": "Λείπουν τα πεδία της κάρτας",
|
||||
"pay_now": "Πληρωμή τώρα",
|
||||
"terms_summary": "Περίληψη όρων",
|
||||
"open_env": "Ανοίξτε το .env και συμφωνήστε με την Άδεια χρήσης μας",
|
||||
"env_changed": "Έχω αλλάξει το .env μου",
|
||||
"accept_license": "Αποδοχή Άδειας",
|
||||
"no_more_results": "Δεν υπάρχουν άλλα αποτελέσματα",
|
||||
"no_results": "Δεν υπάρχουν αποτελέσματα",
|
||||
"load_more_results": "Φόρτωση περισσότερων αποτελεσμάτων",
|
||||
"integration_meeting_id": "ID συνάντησης {{integrationName}} : {{meetingId}}",
|
||||
"confirmed_event_type_subject": "Επιβεβαίωση: {{eventType}} με {{name}} στις {{date}}",
|
||||
"new_event_request": "Νέο αίτημα εκδήλωσης: {{attendeeName}} - {{date}} - {{eventType}}",
|
||||
"confirm_or_reject_request": "Επιβεβαιώστε ή απορρίψτε το αίτημα",
|
||||
"check_bookings_page_to_confirm_or_reject": "Ελέγξτε τη σελίδα κρατήσεων για να επιβεβαιώσετε ή να απορρίψετε την κράτηση.",
|
||||
"event_awaiting_approval": "Ένα γεγονός περιμένει την έγκρισή σας",
|
||||
"event_type": "Τύπος Συμβάντος",
|
||||
"meeting_password": "Συνθηματικό Συνάντησης",
|
||||
"meeting_url": "URL Συνάντησης",
|
||||
"meeting_request_rejected": "Το αίτημα συνάντησής σας απορρίφθηκε",
|
||||
"hi": "Γεια",
|
||||
"manage_this_team": "Διαχείριση αυτής της ομάδας",
|
||||
"team_info": "Πληροφορίες Ομάδας",
|
||||
"hidden_team_member_title": "Είστε κρυμμένοι σε αυτήν την ομάδα",
|
||||
"edit_webhook": "Επεξεργασία Webhook",
|
||||
"delete_webhook": "Διαγραφή Webhook",
|
||||
"webhook_enabled": "Ενεργοποιημένο Webhook",
|
||||
"webhook_disabled": "Απενεργοποιημένο Webhook",
|
||||
"webhook_response": "Απάντηση Webhook",
|
||||
"webhook_test": "Έλεγχος Webhook",
|
||||
"webhook_created_successfully": "Το Webhook δημιουργήθηκε επιτυχώς!",
|
||||
"webhook_updated_successfully": "Το Webhook ενημερώθηκε επιτυχώς!",
|
||||
"webhook_removed_successfully": "Το Webhook αφαιρέθηκε επιτυχώς!",
|
||||
"dismiss": "Παράβλεψη",
|
||||
"no_data_yet": "Δεν υπάρχουν δεδομένα ακόμη",
|
||||
"upcoming": "Επερχόμενα",
|
||||
"recurring": "Επαναλαμβανόμενα",
|
||||
"past": "Παρελθοντικά",
|
||||
"choose_a_file": "Επιλογή αρχείου...",
|
||||
"upload_image": "Μεταφόρτωση εικόνας",
|
||||
"username": "Όνομα χρήστη",
|
||||
"is_still_available": "είναι ακόμα διαθέσιμο.",
|
||||
"documentation": "Τεκμηρίωση",
|
||||
"blog": "Ιστολόγιο",
|
||||
"blog_description": "Διαβάστε τα τελευταία μας νέα και άρθρα",
|
||||
"popular_pages": "Δημοφιλείς σελίδες",
|
||||
"register_now": "Εγγραφή τώρα",
|
||||
"register": "Εγγραφή",
|
||||
"page_doesnt_exist": "Η σελίδα δεν υπάρχει.",
|
||||
"check_spelling_mistakes_or_go_back": "Έλεγχος για ορθογραφικά λάθη ή επιστροφή στην προηγούμενη σελίδα.",
|
||||
"404_page_not_found": "404: Η σελίδα δεν βρέθηκε.",
|
||||
"getting_started": "Ξεκινήστε",
|
||||
"already_have_an_account": "Έχετε ήδη λογαριασμό;",
|
||||
"create_account": "Δημιουργία Λογαριασμού",
|
||||
"confirm_password": "Επιβεβαίωση κωδικού πρόσβασης",
|
||||
"create_your_account": "Δημιουργία λογαριασμού",
|
||||
"sign_up": "Εγγραφή",
|
||||
"youve_been_logged_out": "Έχετε αποσυνδεθεί",
|
||||
"hope_to_see_you_soon": "Ελπίζουμε να σας ξαναδούμε σύντομα!",
|
||||
"please_try_again_and_contact_us": "Παρακαλούμε δοκιμάστε ξανά και επικοινωνήστε μαζί μας αν το πρόβλημα παραμένει.",
|
||||
"no_account_exists": "Δεν υπάρχει λογαριασμός που να ταιριάζει με τη διεύθυνση email.",
|
||||
"2fa_enter_six_digit_code": "Εισάγετε τον εξαψήφιο κωδικό από την εφαρμογή ελέγχου ταυτότητας παρακάτω.",
|
||||
"create_an_account": "Δημιουργία λογαριασμού",
|
||||
"dont_have_an_account": "Δεν έχετε λογαριασμό;",
|
||||
"sign_in_account": "Συνδεθείτε στο λογαριασμό σας",
|
||||
"sign_in": "Είσοδος",
|
||||
"connect": "Σύνδεση",
|
||||
"try_for_free": "Δοκιμάστε δωρεάν",
|
||||
"add_to_calendar": "Προσθήκη στο ημερολόγιο",
|
||||
"add_another_calendar": "Προσθήκη άλλου ημερολογίου",
|
||||
"meeting_is_scheduled": "Η συνάντηση έχει προγραμματιστεί",
|
||||
"submitted": "Η κράτησή σας έχει υποβληθεί",
|
||||
"reset_password": "Επαναφορά Κωδικού Πρόσβασης",
|
||||
"change_your_password": "Αλλαγή κωδικού πρόσβασης",
|
||||
"show_password": "Εμφάνιση κωδικού πρόσβασης",
|
||||
"hide_password": "Απόκρυψη κωδικού πρόσβασης",
|
||||
"try_again": "Δοκιμάστε ξανά",
|
||||
"sunday_time_error": "Μη έγκυρη ώρα την Κυριακή",
|
||||
"monday_time_error": "Μη έγκυρη ώρα τη Δευτέρα",
|
||||
"tuesday_time_error": "Μη έγκυρη ώρα την Τρίτη",
|
||||
"wednesday_time_error": "Μη έγκυρη ώρα την Τετάρτη",
|
||||
"thursday_time_error": "Μη έγκυρη ώρα την Πέμπτη",
|
||||
"friday_time_error": "Μη έγκυρη ώρα την Παρασκευή",
|
||||
"saturday_time_error": "Μη έγκυρη ώρα το Σάββατο",
|
||||
"no_meeting_found": "Δε βρέθηκε συνάντηση",
|
||||
"bookings": "Κρατήσεις"
|
||||
}
|
||||
@@ -6,7 +6,7 @@
|
||||
"second_other": "{{count}} seconds",
|
||||
"upgrade_now": "Upgrade now",
|
||||
"accept_invitation": "Accept Invitation",
|
||||
"calcom_explained": "{{appName}} is the open source Calendly alternative putting you in control of your own data, workflow and appearance.",
|
||||
"calcom_explained": "{{appName}} provides scheduling infrastructure for absolutely everyone.",
|
||||
"have_any_questions": "Have questions? We're here to help.",
|
||||
"reset_password_subject": "{{appName}}: Reset password instructions",
|
||||
"event_declined_subject": "Declined: {{eventType}} with {{name}} at {{date}}",
|
||||
@@ -303,6 +303,7 @@
|
||||
"cancelling_all_recurring": "These are all remaining instances in the recurring event.",
|
||||
"error_with_status_code_occured": "An error with status code {{status}} occurred.",
|
||||
"booking_already_cancelled": "This booking was already cancelled",
|
||||
"booking_already_accepted_rejected": "This booking was already accepted or rejected",
|
||||
"go_back_home": "Go back home",
|
||||
"or_go_back_home": "Or go back home",
|
||||
"no_availability": "Unavailable",
|
||||
@@ -385,7 +386,9 @@
|
||||
"go_to_billing_portal": "Go to the billing portal",
|
||||
"need_anything_else": "Need anything else?",
|
||||
"further_billing_help": "If you need any further help with billing, our support team are here to help.",
|
||||
"contact_our_support_team": "Contact our support team",
|
||||
"contact": "Contact",
|
||||
"our_support_team": "our support team",
|
||||
"contact_our_support_team":"Contact our support team",
|
||||
"uh_oh": "Uh oh!",
|
||||
"no_event_types_have_been_setup": "This user hasn't set up any event types yet.",
|
||||
"edit_logo": "Edit logo",
|
||||
@@ -750,7 +753,7 @@
|
||||
"toggle_calendars_conflict": "Toggle the calendars you want to check for conflicts to prevent double bookings.",
|
||||
"select_destination_calendar": "Create events on",
|
||||
"connect_additional_calendar": "Connect additional calendar",
|
||||
"calendar_updated_successfully":"Calendar updated successfully",
|
||||
"calendar_updated_successfully": "Calendar updated successfully",
|
||||
"conferencing": "Conferencing",
|
||||
"calendar": "Calendar",
|
||||
"payments": "Payments",
|
||||
@@ -791,7 +794,7 @@
|
||||
"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",
|
||||
"installed_app_calendar_description": "Set the calendar(s) to check for conflicts to prevent double bookings.",
|
||||
"installed_app_calendar_description": "Set the calendars to check for conflicts to prevent double bookings.",
|
||||
"installed_app_conferencing_description": "Add your favourite video conferencing apps for your meetings",
|
||||
"installed_app_payment_description": "Configure which payment processing services to use when charging your clients.",
|
||||
"installed_app_analytics_description": "Configure which analytics apps to use for your booking pages",
|
||||
@@ -918,7 +921,7 @@
|
||||
"allow_booker_to_select_duration": "Allow booker to select duration",
|
||||
"impersonate_user_tip": "All uses of this feature is audited.",
|
||||
"impersonating_user_warning": "Impersonating username \"{{user}}\".",
|
||||
"impersonating_stop_instructions": "<0>Click Here to stop</0>.",
|
||||
"impersonating_stop_instructions": "Click here to stop",
|
||||
"event_location_changed": "Updated - Your event changed the location",
|
||||
"location_changed_event_type_subject": "Location Changed: {{eventType}} with {{name}} at {{date}}",
|
||||
"current_location": "Current Location",
|
||||
@@ -940,7 +943,7 @@
|
||||
"generate_api_key_description": "Generate an API key to use with {{appName}} at",
|
||||
"your_unique_api_key": "Your unique API key",
|
||||
"copy_safe_api_key": "Copy this API key and save it somewhere safe. If you lose this key you have to generate a new one.",
|
||||
"zapier_setup_instructions": "<0>Log into your Zapier account and create a new Zap.</0><1>Select {{appName}} as your Trigger app. Also choose a Trigger event.</1><2>Choose your account and then enter your Unique API Key.</2><3>Test your Trigger.</3><4>You're set!</4>",
|
||||
"zapier_setup_instructions": "<0>Log into your Zapier account and create a new Zap.</0><1>Select Cal.com as your Trigger app. Also choose a Trigger event.</1><2>Choose your account and then enter your Unique API Key.</2><3>Test your Trigger.</3><4>You're set!</4>",
|
||||
"install_zapier_app": "Please first install the Zapier App in the app store.",
|
||||
"connect_apple_server": "Connect to Apple Server",
|
||||
"connect_caldav_server": "Connect to CalDav (Beta)",
|
||||
@@ -1213,7 +1216,7 @@
|
||||
"event_time_info": "The event start time",
|
||||
"location_info": "The event location",
|
||||
"organizer_name_info": "Your name",
|
||||
"additional_notes_info": "The Additional notes of booking",
|
||||
"additional_notes_info": "The additional notes of booking",
|
||||
"attendee_name_info": "The person booking's name",
|
||||
"to": "To",
|
||||
"workflow_turned_on_successfully": "{{workflowName}} workflow turned {{offOn}} successfully",
|
||||
@@ -1326,6 +1329,8 @@
|
||||
"booking_confirmation_success": "Booking confirmation succeeded",
|
||||
"booking_rejection_success": "Booking rejection succeeded",
|
||||
"booking_confirmation_fail": "Booking confirmation failed",
|
||||
"booking_tentative": "This booking is tentative",
|
||||
"booking_accept_intent": "Oops, I want to accept",
|
||||
"we_wont_show_again": "We won't show this again",
|
||||
"couldnt_update_timezone": "We couldn't update the timezone",
|
||||
"updated_timezone_to": "Updated timezone to {{formattedCurrentTz}}",
|
||||
@@ -1389,10 +1394,8 @@
|
||||
"attendee_email_workflow": "Attendee email",
|
||||
"attendee_email_info": "The person booking's email",
|
||||
"kbar_search_placeholder": "Type a command or search...",
|
||||
"free_to_use_apps": "Free",
|
||||
"enterprise_license": "This is an enterprise feature",
|
||||
"enterprise_license_description": "To enable this feature, get a deployment key at {{consoleUrl}} console and add it to your .env as CALCOM_LICENSE_KEY. If your team already has a license, please contact {{supportMail}} for help.",
|
||||
"invalid_credential": "Oh no! Looks like permission expired or was revoked. Please reinstall again.",
|
||||
"reschedule_reason_success_page": "Reschedule reason",
|
||||
"choose_common_schedule_team_event": "Choose a common schedule",
|
||||
"choose_common_schedule_team_event_description": "Enable this if you want to use a common schedule between hosts. When disabled, each host will be booked based on their default schedule.",
|
||||
"reason": "Reason",
|
||||
@@ -1403,8 +1406,8 @@
|
||||
"route_to": "Route to",
|
||||
"test_preview_description": "Test your routing form without submitting any data",
|
||||
"test_routing": "Test Routing",
|
||||
"booking_limit_reached": "Booking Limit for this event type has been reached",
|
||||
"fill_this_field": "Please fill in this field",
|
||||
"payment_app_disabled": "An admin has disabled a payment app",
|
||||
"edit_event_type": "Edit event type",
|
||||
"collective_scheduling": "Collective Scheduling",
|
||||
"make_it_easy_to_book": "Make it easy to book your team when everyone is available.",
|
||||
"find_the_best_person": "Find the best person available and cycle through your team.",
|
||||
@@ -1412,12 +1415,63 @@
|
||||
"add_one_fixed_attendee": "Add one fixed attendee and round robin through a number of attendees.",
|
||||
"calcom_is_better_with_team": "Cal.com is better with teams",
|
||||
"add_your_team_members": "Add your team members to your event types. Use collective scheduling to include everyone or find the most suitable person with round robin scheduling.",
|
||||
"booking_limit_reached":"Booking Limit for this event type has been reached",
|
||||
"booking_limit_reached": "Booking Limit for this event type has been reached",
|
||||
"admin_has_disabled": "An admin has disabled {{appName}}",
|
||||
"disabled_app_affects_event_type": "An admin has disabled {{appName}} which affects your event type {{eventType}}",
|
||||
"disable_payment_app": "The admin has disabled {{appName}} which affects your event type {{title}}. Attendees are still able to book this type of event but will not be prompted to pay. You may hide hide the event type to prevent this until your admin renables your payment method.",
|
||||
"payment_disabled_still_able_to_book": "Attendees are still able to book this type of event but will not be prompted to pay. You may hide hide the event type to prevent this until your admin reenables your payment method.",
|
||||
"app_disabled_with_event_type": "The admin has disabled {{appName}} which affects your event type {{title}}.",
|
||||
"app_disabled_video": "The admin has disabled {{appName}} which may affect your event types. If you have event types with {{appName}} as the location then it will default to Cal Video.",
|
||||
"app_disabled_subject": "{{appName}} has been disabled",
|
||||
"navigate_installed_apps": "Go to installed apps",
|
||||
"disabled_calendar": "If you have another calendar installed new bookings will be added to it. If not then connect a new calendar so you do not miss any new bookings.",
|
||||
"enable_apps": "Enable Apps",
|
||||
"enable_apps_description": "Enable apps that users can integrate with Cal.com",
|
||||
"app_is_enabled": "{{appName}} is enabled",
|
||||
"app_is_disabled": "{{appName}} is disabled",
|
||||
"keys_have_been_saved": "Keys have been saved",
|
||||
"disable_app": "Disable App",
|
||||
"disable_app_description": "Disabling this app could cause problems with how your users interact with Cal",
|
||||
"edit_keys": "Edit Keys",
|
||||
"admin_apps_description": "Enable apps for your instance of Cal",
|
||||
"no_available_apps": "There are no available apps",
|
||||
"no_available_apps_description": "Please ensure there are apps in your deployment under 'packages/app-store'",
|
||||
"no_apps": "There are no apps enabled in this instance of Cal",
|
||||
"apps_settings": "Apps settings",
|
||||
"fill_this_field": "Please fill in this field",
|
||||
"options": "Options",
|
||||
"enter_option": "Enter Option {{index}}",
|
||||
"add_an_option": "Add an option",
|
||||
"radio": "Radio",
|
||||
"kbar_search_placeholder" : "Start typing to search",
|
||||
"set_as_default": "Set as default"
|
||||
"individual":"Individual",
|
||||
"all_bookings_filter_label":"All Bookings",
|
||||
"all_users_filter_label":"All Users",
|
||||
"meeting_url_workflow": "Meeting url",
|
||||
"meeting_url_info": "The event meeting conference url",
|
||||
"date_overrides": "Date overrides",
|
||||
"date_overrides_subtitle": "Add dates when your availability changes from your daily hours.",
|
||||
"date_overrides_info": "Date overrides are archived automatically after the date has passed",
|
||||
"date_overrides_dialog_which_hours": "Which hours are you free?",
|
||||
"date_overrides_dialog_which_hours_unavailable": "Which hours are you busy?",
|
||||
"date_overrides_dialog_title": "Select the dates to override",
|
||||
"date_overrides_unavailable": "Unavailable all day",
|
||||
"date_overrides_mark_all_day_unavailable_one": "Mark unavailable (All day)",
|
||||
"date_overrides_mark_all_day_unavailable_other": "Mark unavailable on selected dates",
|
||||
"date_overrides_add_btn": "Add Override",
|
||||
"date_overrides_update_btn": "Update Override",
|
||||
"event_type_duplicate_copy_text": "{{slug}}-copy",
|
||||
"set_as_default": "Set as default",
|
||||
"hide_eventtype_details": "Hide EventType Details",
|
||||
"show_navigation": "Show navigation",
|
||||
"hide_navigation": "Hide navigation",
|
||||
"verification_code_sent": "Verification code sent",
|
||||
"verified_successfully": "Verified successfully",
|
||||
"wrong_code": "Wong verification code",
|
||||
"not_verified": "Not yet verified",
|
||||
"no_availability_in_month": "No availability in {{month}}",
|
||||
"view_next_month": "View next month",
|
||||
"send_code" : "Send code",
|
||||
"number_verified": "Number Verified",
|
||||
"create_your_first_team_webhook_description": "Create your first webhook for this team event type",
|
||||
"create_webhook_team_event_type": "Create a webhook for this team event type"
|
||||
}
|
||||
|
||||
@@ -16,8 +16,8 @@
|
||||
"event_request_cancelled": "Tu evento programado fue cancelado",
|
||||
"organizer": "Organizador",
|
||||
"need_to_reschedule_or_cancel": "¿Necesita reprogramar o cancelar?",
|
||||
"cancellation_reason": "Motivo de la cancelación",
|
||||
"cancellation_reason_placeholder": "¿Por qué razón estás cancelando? (opcional)",
|
||||
"cancellation_reason": "Motivo de la cancelación (opcional)",
|
||||
"cancellation_reason_placeholder": "¿Por qué razón está cancelando?",
|
||||
"rejection_reason": "Motivo del rechazo",
|
||||
"rejection_reason_title": "¿Rechazar la solicitud de reserva?",
|
||||
"rejection_reason_description": "¿Estás seguro de que deseas rechazar la reserva? Le haremos saber a la persona que ha intentado reservar. Puedes indicar una razón a continuación.",
|
||||
@@ -52,6 +52,7 @@
|
||||
"still_waiting_for_approval": "Un evento aún está esperando su aprobación",
|
||||
"event_is_still_waiting": "La solicitud del evento todavía está esperando: {{attendeeName}} - {{date}} - {{eventType}}",
|
||||
"no_more_results": "No hay más resultados",
|
||||
"no_results": "Sin resultados",
|
||||
"load_more_results": "Cargar más resultados",
|
||||
"integration_meeting_id": "ID de la reunión {{integrationName}}: {{meetingId}}",
|
||||
"confirmed_event_type_subject": "Confirma: {{eventType}} con {{name}} en {{date}}",
|
||||
@@ -248,6 +249,7 @@
|
||||
"add_to_calendar": "Añadir al Calendario",
|
||||
"add_another_calendar": "Añadir otro calendario",
|
||||
"other": "Otro",
|
||||
"email_sign_in_subject": "Su enlace de inicio de sesión para {{appName}}",
|
||||
"emailed_you_and_attendees": "Le enviamos a usted y a los demás asistentes una invitación al calendario con todos los detalles.",
|
||||
"emailed_you_and_attendees_recurring": "Le enviamos a usted y a los demás asistentes una invitación al calendario para el primero de estos eventos recurrentes.",
|
||||
"emailed_you_and_any_other_attendees": "Usted y cualquier otro asistente han recibido esta información.",
|
||||
@@ -420,6 +422,7 @@
|
||||
"current_incorrect_password": "La Contraseña Actual es Incorrecta",
|
||||
"password_hint_caplow": "Mezcla de letras mayúsculas y minúsculas",
|
||||
"password_hint_min": "Mínimo 7 caracteres",
|
||||
"password_hint_admin_min": "Longitud mínima de 15 caracteres",
|
||||
"password_hint_num": "Debe contener al menos 1 número",
|
||||
"invalid_password_hint": "La contraseña debe tener un mínimo de 7 caracteres que contengan al menos un número y una mezcla de letras mayúsculas y minúsculas",
|
||||
"incorrect_password": "La Contraseña es Incorrecta.",
|
||||
@@ -463,11 +466,14 @@
|
||||
"booking_confirmation": "Confirma tu {{eventTypeTitle}} con {{profileName}}",
|
||||
"booking_reschedule_confirmation": "Reprogramar tu {{eventTypeTitle}} con {{profileName}}",
|
||||
"in_person_meeting": "Reunión en Línea o en Persona",
|
||||
"attendeeInPerson": "En persona (dirección del asistente)",
|
||||
"inPerson": "En persona (dirección del organizador)",
|
||||
"link_meeting": "Enlazar reunión",
|
||||
"phone_call": "Número de teléfono del asistente",
|
||||
"your_number": "Su número de teléfono",
|
||||
"phone_number": "Nª de Telefono",
|
||||
"attendee_phone_number": "Número de teléfono del asistente",
|
||||
"organizer_phone_number": "Número de teléfono del organizador",
|
||||
"host_phone_number": "Su número de teléfono",
|
||||
"enter_phone_number": "Introducir Nº de Telefono",
|
||||
"reschedule": "Reprogramar",
|
||||
@@ -554,6 +560,10 @@
|
||||
"collective": "Colectivo",
|
||||
"collective_description": "Programe reuniones cuando todos los miembros del equipo seleccionados estén disponibles.",
|
||||
"duration": "Duración",
|
||||
"available_durations": "Duraciones disponibles",
|
||||
"default_duration": "Duración predeterminada",
|
||||
"default_duration_no_options": "Seleccione primero las duraciones disponibles",
|
||||
"multiple_duration_mins": "{{count}} $t(minute_timeUnit)",
|
||||
"minutes": "Minutos",
|
||||
"round_robin": "Petición Firmada por Turnos",
|
||||
"round_robin_description": "Ciclo de reuniones entre varios miembros del equipo.",
|
||||
@@ -619,6 +629,7 @@
|
||||
"teams": "Equipos",
|
||||
"team": "Equipo",
|
||||
"team_billing": "Facturación del equipo",
|
||||
"team_billing_description": "Gestione la facturación para su equipo",
|
||||
"upgrade_to_flexible_pro_title": "Hemos cambiado la facturación de los equipos",
|
||||
"upgrade_to_flexible_pro_message": "Hay miembros en tu equipo sin asiento. Actualiza al plan Pro para cubrir los asientos restantes.",
|
||||
"changed_team_billing_info": "A partir de enero de 2022 cobramos por asiento para los miembros del equipo. Los miembros de tu equipo que tenían el plan Pro de forma gratuita están ahora en una prueba de 14 días. Una vez que caduque su prueba, estos miembros estarán ocultos para tu equipo a menos que actualices ahora.",
|
||||
@@ -694,6 +705,7 @@
|
||||
"hide_event_type": "Ocultar Tipo de Evento",
|
||||
"edit_location": "Editar Localización",
|
||||
"into_the_future": "en el futuro",
|
||||
"when_booked_with_less_than_notice": "Cuando se reserve con menos de <time></time> de aviso",
|
||||
"within_date_range": "Dentro de un rango de fechas",
|
||||
"indefinitely_into_future": "Indefinidamente en el futuro",
|
||||
"add_new_custom_input_field": "Agregar nuevo campo de entrada personalizado",
|
||||
@@ -713,6 +725,7 @@
|
||||
"delete_account_confirmation_message": "¿Estás seguro de que quieres eliminar tu cuenta de {{appName}}? Cualquier persona con la que hayas compartido el enlace de tu cuenta ya no podrá reservar con ella y cualquier preferencia que hayas guardado se perderá.",
|
||||
"integrations": "Integraciones",
|
||||
"apps": "Aplicaciones",
|
||||
"apps_listing": "Lista de aplicaciones",
|
||||
"category_apps": "Aplicaciones {{category}}",
|
||||
"app_store": "App Store",
|
||||
"app_store_description": "Conectar personas, tecnología y lugar de trabajo.",
|
||||
@@ -736,6 +749,7 @@
|
||||
"toggle_calendars_conflict": "Activa/desactiva los calendarios en los que desees comprobar conflictos para evitar reservas dobles.",
|
||||
"select_destination_calendar": "Crear eventos en",
|
||||
"connect_additional_calendar": "Conectar calendario adicional",
|
||||
"calendar_updated_successfully": "Calendario actualizado correctamente",
|
||||
"conferencing": "Conferencias",
|
||||
"calendar": "Calendario",
|
||||
"payments": "Pagos",
|
||||
@@ -768,6 +782,7 @@
|
||||
"trending_apps": "Aplicaciones populares",
|
||||
"explore_apps": "Aplicaciones {{category}}",
|
||||
"installed_apps": "Aplicaciones instaladas",
|
||||
"free_to_use_apps": "Libre",
|
||||
"no_category_apps": "No hay aplicaciones de {{category}}",
|
||||
"no_category_apps_description_calendar": "Añade una aplicación de calendario para comprobar si hay conflictos y evitar reservas duplicadas",
|
||||
"no_category_apps_description_conferencing": "Intenta añadir una aplicación de conferencias para integrar las videollamadas con tus clientes",
|
||||
@@ -806,6 +821,8 @@
|
||||
"verify_wallet": "Verificar billetera",
|
||||
"connect_metamask": "Conectar Metamask",
|
||||
"create_events_on": "Crear eventos en",
|
||||
"enterprise_license": "Esta es una función empresarial",
|
||||
"enterprise_license_description": "Para habilitar esta función, obtenga una clave de despliegue en la consola {{consoleUrl}} y añádala a su .env como CALCOM_LICENSE_KEY. Si su equipo ya tiene una licencia, póngase en contacto con {{supportMail}} para obtener ayuda.",
|
||||
"missing_license": "Falta la licencia",
|
||||
"signup_requires": "Licencia comercial requerida",
|
||||
"signup_requires_description": "Actualmente, {{companyName}} no ofrece una versión gratuita de código abierto de la página de registro. Para recibir acceso completo a los componentes de registro es necesario adquirir una licencia comercial. Para uso personal, recomendamos la Plataforma de Datos Prisma o cualquier otra interfaz Postgres para crear cuentas.",
|
||||
@@ -897,6 +914,7 @@
|
||||
"user_impersonation_heading": "Suplantación de usuario",
|
||||
"user_impersonation_description": "Permite a nuestro equipo de soporte iniciar sesión temporalmente para ayudar a resolver rápidamente cualquier problema reportado.",
|
||||
"team_impersonation_description": "Permite a los administradores de tu equipo iniciar sesión temporalmente como tú.",
|
||||
"allow_booker_to_select_duration": "Permitir que el encargado de las reservas seleccione la duración",
|
||||
"impersonate_user_tip": "Todos los usos de esta función son revisados.",
|
||||
"impersonating_user_warning": "Suplantando nombre de usuario \"{{user}}\".",
|
||||
"impersonating_stop_instructions": "<0>Haga clic aquí para detener</0>.",
|
||||
@@ -1014,6 +1032,9 @@
|
||||
"error_removing_app": "Error al eliminar la aplicación",
|
||||
"web_conference": "Conferencia web",
|
||||
"requires_confirmation": "Requiere confirmación",
|
||||
"always_requires_confirmation": "Siempre",
|
||||
"requires_confirmation_threshold": "Requiere confirmación si se reservó con el aviso < {{time}} $t({{unit}}_timeUnit)",
|
||||
"may_require_confirmation": "Puede requerir confirmación",
|
||||
"nr_event_type_one": "{{count}} tipo de evento",
|
||||
"nr_event_type_other": "{{count}} tipos de eventos",
|
||||
"add_action": "Agregar acción",
|
||||
@@ -1101,6 +1122,9 @@
|
||||
"event_limit_tab_description": "Con qué frecuencia se puede reservar",
|
||||
"event_advanced_tab_description": "Ajustes del calendario y más...",
|
||||
"event_advanced_tab_title": "Avanzado",
|
||||
"event_setup_multiple_duration_error": "Configuración de eventos: varias duraciones requieren al menos una opción.",
|
||||
"event_setup_multiple_duration_default_error": "Configuración de eventos: seleccione una duración predeterminada válida.",
|
||||
"event_setup_booking_limits_error": "Los límites de las reservas deben estar en orden ascendente. [día, semana, mes, año]",
|
||||
"select_which_cal": "Seleccione a qué calendario añadir reservas",
|
||||
"custom_event_name": "Nombre de evento personalizado",
|
||||
"custom_event_name_description": "Cree nombres de eventos personalizados para que el evento aparezca en el calendario",
|
||||
@@ -1154,8 +1178,11 @@
|
||||
"invoices": "Facturas",
|
||||
"embeds": "Inserciones",
|
||||
"impersonation": "Suplantación",
|
||||
"impersonation_description": "Configuración para administrar la suplantación del usuario",
|
||||
"users": "Usuarios",
|
||||
"profile_description": "Administra los ajustes para tu perfil de {{appName}}",
|
||||
"users_description": "Aquí puede encontrar una lista de todos los usuarios",
|
||||
"users_listing": "Listado de usuarios",
|
||||
"general_description": "Administre los ajustes para tu idioma y zona horaria",
|
||||
"calendars_description": "Configura cómo interactúan tus tipos de eventos con tus calendarios",
|
||||
"appearance_description": "Administra los ajustes para el aspecto de tu reserva",
|
||||
@@ -1228,8 +1255,8 @@
|
||||
"exchange_authentication_ntlm": "Autenticación NTLM",
|
||||
"exchange_compression": "Compresión GZip",
|
||||
"routing_forms_description": "Aquí puedes ver todos los formularios y rutas que has creado.",
|
||||
"routing_forms_send_email_owner": "Enviar email al propietario",
|
||||
"routing_forms_send_email_owner_description": "Envía un correo electrónico al propietario cuando se envía el formulario",
|
||||
"routing_forms_send_email_owner": "Enviar correo electrónico al propietario",
|
||||
"routing_forms_send_email_owner_description": "Mande un correo electrónico al propietario cuando se envía el formulario",
|
||||
"add_new_form": "Añadir formulario nuevo",
|
||||
"form_description": "Crea tu formulario para dirigirlo a un agente de reservas",
|
||||
"copy_link_to_form": "Copiar enlace al formulario",
|
||||
@@ -1360,15 +1387,54 @@
|
||||
"number_sms_notifications": "Número de teléfono (notificaciones por SMS)",
|
||||
"attendee_email_workflow": "Correo electrónico del asistente",
|
||||
"attendee_email_info": "El correo electrónico de la persona que reserva",
|
||||
"kbar_search_placeholder": "Escriba un comando o búsqueda...",
|
||||
"invalid_credential": "¡Oh no! Parece que el permiso ha caducado o se ha revocado. Vuelva a instalarlo.",
|
||||
"choose_common_schedule_team_event": "Elija un horario común",
|
||||
"choose_common_schedule_team_event_description": "Habilite esto si desea utilizar un cronograma común entre anfitriones. Cuando esté desactivado, cada anfitrión se reservará con base en su horario predeterminado.",
|
||||
"choose_common_schedule_team_event": "Elige un horario común para todos",
|
||||
"choose_common_schedule_team_event_description": "Habilite esto si desea utilizar un cronograma común entre anfitriones. Cuando esté desactivado, cada anfitrión se reservará en relación a su horario predeterminado.",
|
||||
"reason": "Motivo",
|
||||
"sender_id": "ID del remitente",
|
||||
"sender_id_error_message": "Sólo se permiten letras, números y espacios (máx. 11 caracteres)",
|
||||
"test_routing_form": "Prueba de formulario de ruta",
|
||||
"test_preview": "Vista previa de prueba",
|
||||
"test_preview": "Vista previa de la prueba",
|
||||
"route_to": "Ruta hacia",
|
||||
"test_preview_description": "Pruebe su formulario de ruta sin enviar ningún dato",
|
||||
"test_routing": "Prueba de ruta"
|
||||
"test_routing": "Prueba de ruta",
|
||||
"payment_app_disabled": "Un administrador ha desactivado una aplicación de pago",
|
||||
"edit_event_type": "Editar tipo de evento",
|
||||
"collective_scheduling": "Programación colectiva",
|
||||
"make_it_easy_to_book": "Haga que sea fácil reservar su equipo cuando todos estén disponibles.",
|
||||
"find_the_best_person": "Encuentre a la mejor persona disponible y haga una rotación en su equipo.",
|
||||
"fixed_round_robin": "Rotación fija por turnos",
|
||||
"add_one_fixed_attendee": "Agregue un asistente fijo y la rotación por turnos a través de un número de asistentes.",
|
||||
"calcom_is_better_with_team": "Cal.com funciona mejor con equipos",
|
||||
"add_your_team_members": "Añada los miembros de su equipo a sus tipos de eventos. Utilice la programación colectiva para incluir a todos o encuentre a la persona más adecuada con programación de rotación por turnos.",
|
||||
"booking_limit_reached": "Se ha alcanzado el límite de reserva para este tipo de evento",
|
||||
"admin_has_disabled": "Un administrador ha desactivado {{appName}}",
|
||||
"disabled_app_affects_event_type": "Un administrador ha desactivado {{appName}}, lo que afecta a su tipo de evento {{eventType}}",
|
||||
"disable_payment_app": "El administrador ha deshabilitado {{appName}}, lo que afecta a su tipo de evento {{title}}. Los asistentes todavía pueden reservar este tipo de evento pero no se les pedirá que paguen. Puede ocultar el tipo de evento para evitar esto hasta que su administrador cambie su forma de pago.",
|
||||
"payment_disabled_still_able_to_book": "Los asistentes todavía pueden reservar este tipo de eventos, pero no se les pedirá que paguen. Puede ocultar el tipo de evento para evitar esto hasta que su administrador reactive su método de pago.",
|
||||
"app_disabled_with_event_type": "El administrador ha desactivado {{appName}}, lo que afecta a su tipo de evento {{title}}.",
|
||||
"app_disabled_video": "El administrador ha desactivado {{appName}}, lo que puede afectar a sus tipos de evento. Si tiene tipos de eventos con {{appName}} como localización, entonces el valor predeterminado será Cal Video.",
|
||||
"app_disabled_subject": "{{appName}} se ha desactivado",
|
||||
"navigate_installed_apps": "Ir a las aplicaciones instaladas",
|
||||
"disabled_calendar": "Si tiene otro calendario instalado se le añadirán nuevas reservas. De lo contrario, conecte un nuevo calendario para que no se pierda ninguna reserva nueva.",
|
||||
"enable_apps": "Activar aplicaciones",
|
||||
"enable_apps_description": "Active aplicaciones que los usuarios puedan integrar con Cal.com",
|
||||
"app_is_enabled": "{{appName}} está activada",
|
||||
"app_is_disabled": "{{appName}} está desactivada",
|
||||
"keys_have_been_saved": "Las llaves se han guardado",
|
||||
"disable_app": "Desactivar aplicación",
|
||||
"disable_app_description": "Desactivar esta aplicación puede causar problemas con la forma en que sus usuarios interactúan con Cal",
|
||||
"edit_keys": "Editar claves",
|
||||
"no_available_apps": "No hay aplicaciones disponibles",
|
||||
"no_available_apps_description": "Verifique que haya aplicaciones en su despliegue bajo 'packages/app-store'",
|
||||
"no_apps": "No hay aplicaciones activadas en esta instancia de Cal",
|
||||
"apps_settings": "Configuración de aplicaciones",
|
||||
"fill_this_field": "Complete este campo",
|
||||
"options": "Opciones",
|
||||
"enter_option": "Introduzca la opción {{index}}",
|
||||
"add_an_option": "Agregue una opción",
|
||||
"radio": "Radio",
|
||||
"event_type_duplicate_copy_text": "{{slug}}-copia",
|
||||
"set_as_default": "Establecer como predeterminado"
|
||||
}
|
||||
|
||||
@@ -16,8 +16,8 @@
|
||||
"event_request_cancelled": "Votre événement programmé a été annulé",
|
||||
"organizer": "Organisateur",
|
||||
"need_to_reschedule_or_cancel": "Besoin de reprogrammer ou d'annuler ?",
|
||||
"cancellation_reason": "Motif de l'annulation",
|
||||
"cancellation_reason_placeholder": "Pourquoi annulez-vous ? (facultatif)",
|
||||
"cancellation_reason": "Motif de l'annulation (facultatif)",
|
||||
"cancellation_reason_placeholder": "Pourquoi annulez-vous ?",
|
||||
"rejection_reason": "Motif de rejet",
|
||||
"rejection_reason_title": "Rejeter la demande de réservation ?",
|
||||
"rejection_reason_description": "Êtes-vous sûr de vouloir rejeter la réservation ? Nous informerons la personne qui a essayé de réserver. Vous pouvez fournir une raison ci-dessous.",
|
||||
@@ -52,6 +52,7 @@
|
||||
"still_waiting_for_approval": "Un événement est toujours en attente d'approbation",
|
||||
"event_is_still_waiting": "La demande d'événement est toujours en attente : {{attendeeName}} - {{date}} - {{eventType}}",
|
||||
"no_more_results": "Plus de résultats",
|
||||
"no_results": "Aucun résultat",
|
||||
"load_more_results": "Charger plus de résultats",
|
||||
"integration_meeting_id": "Identifiant de la réunion {{integrationName}} : {{meetingId}}",
|
||||
"confirmed_event_type_subject": "Confirmé : {{eventType}} avec {{name}} le {{date}}",
|
||||
@@ -248,6 +249,7 @@
|
||||
"add_to_calendar": "Ajouter au calendrier",
|
||||
"add_another_calendar": "Ajouter un autre calendrier",
|
||||
"other": "Autre",
|
||||
"email_sign_in_subject": "Votre lien de connexion pour {{appName}}",
|
||||
"emailed_you_and_attendees": "Nous vous avons envoyé, à vous et aux autres participants, une invitation par e-mail avec tous les détails.",
|
||||
"emailed_you_and_attendees_recurring": "Nous vous avons envoyé, à vous et aux autres participants, une invitation au calendrier pour le premier de ces événements récurrents.",
|
||||
"emailed_you_and_any_other_attendees": "Ces informations vous ont été envoyées par e-mail, ainsi qu'à tous les autres participants.",
|
||||
@@ -419,7 +421,8 @@
|
||||
"forgotten_secret_description": "Si vous avez perdu ou oublié ce code secret, vous pouvez le modifer, mais soyez conscient que toutes les intégrations l'utilisant devront être actualisées",
|
||||
"current_incorrect_password": "Le mot de passe actuel est incorrect",
|
||||
"password_hint_caplow": "Mélange de lettres majuscules et minuscules",
|
||||
"password_hint_min": "Minimum 7 caractères",
|
||||
"password_hint_min": "Minimum 8 caractères",
|
||||
"password_hint_admin_min": "Minimum 15 caractères",
|
||||
"password_hint_num": "Contient au moins 1 chiffre",
|
||||
"invalid_password_hint": "Le mot de passe doit comporter un minimum de 7 caractères, dont au moins un chiffre, et avoir un mélange de lettres majuscules et minuscules",
|
||||
"incorrect_password": "Le mot de passe est incorrect.",
|
||||
@@ -463,11 +466,14 @@
|
||||
"booking_confirmation": "Confirmez votre {{eventTypeTitle}} avec {{profileName}}",
|
||||
"booking_reschedule_confirmation": "Reporté votre {{eventTypeTitle}} avec {{profileName}}",
|
||||
"in_person_meeting": "Lien ou réunion en présentiel",
|
||||
"attendeeInPerson": "En personne (adresse du participant)",
|
||||
"inPerson": "En personne (adresse de l'organisateur)",
|
||||
"link_meeting": "Lier une réunion",
|
||||
"phone_call": "Appel téléphonique",
|
||||
"your_number": "Votre numéro de téléphone",
|
||||
"phone_number": "Numéro de téléphone",
|
||||
"attendee_phone_number": "Numéro de téléphone du participant",
|
||||
"organizer_phone_number": "Numéro de téléphone de l'organisateur",
|
||||
"host_phone_number": "Votre numéro de téléphone",
|
||||
"enter_phone_number": "Saisissez le numéro de téléphone",
|
||||
"reschedule": "Reporter",
|
||||
@@ -554,6 +560,10 @@
|
||||
"collective": "Collectif",
|
||||
"collective_description": "Planifiez des réunions lorsque tous les membres de l'équipe sélectionnés sont disponibles.",
|
||||
"duration": "Durée",
|
||||
"available_durations": "Durées disponibles",
|
||||
"default_duration": "Durée par défaut",
|
||||
"default_duration_no_options": "Veuillez d'abord choisir les durées disponibles",
|
||||
"multiple_duration_mins": "{{count}} $t(minute_timeUnit)",
|
||||
"minutes": "Minutes",
|
||||
"round_robin": "Round Robin",
|
||||
"round_robin_description": "Faites tourner les réunions entre plusieurs membres de l'équipe.",
|
||||
@@ -619,6 +629,7 @@
|
||||
"teams": "Équipes",
|
||||
"team": "Équipe",
|
||||
"team_billing": "Facturation d'équipe",
|
||||
"team_billing_description": "Gérer la facturation pour votre équipe",
|
||||
"upgrade_to_flexible_pro_title": "Nous avons modifié la facturation pour les équipes",
|
||||
"upgrade_to_flexible_pro_message": "Des membres dans votre équipe n'ont pas de place. Mettez à niveau votre offre pro pour couvrir les places manquantes.",
|
||||
"changed_team_billing_info": "Depuis janvier 2022, nous facturons chaque place aux membres de l'équipe. Les membres de votre équipe qui ont eu la version Pro gratuitement disposent maintenant d'un essai de 14 jours. Une fois leur période d'essai expirée, ces membres seront cachés pour votre équipe, sauf si vous mettez à niveau maintenant.",
|
||||
@@ -694,6 +705,7 @@
|
||||
"hide_event_type": "Masquer le type d'événement",
|
||||
"edit_location": "Modifier le lieu",
|
||||
"into_the_future": "dans le futur",
|
||||
"when_booked_with_less_than_notice": "Si réservé avec moins de <time></time> de préavis",
|
||||
"within_date_range": "Dans une plage de dates",
|
||||
"indefinitely_into_future": "Sans doute dans le futur",
|
||||
"add_new_custom_input_field": "Ajouter un nouveau champ de saisie personnalisé",
|
||||
@@ -713,6 +725,7 @@
|
||||
"delete_account_confirmation_message": "Êtes-vous sûr de vouloir supprimer votre compte {{appName}} ? Toute personne avec qui vous avez partagé le lien de votre compte ne pourra plus réserver en utilisant ce lien et toutes les préférences que vous avez enregistrées seront perdues.",
|
||||
"integrations": "Intégrations",
|
||||
"apps": "Applications",
|
||||
"apps_listing": "Liste des applications",
|
||||
"category_apps": "Applications {{category}}",
|
||||
"app_store": "App Store",
|
||||
"app_store_description": "Connecter les personnes, la technologie et l'espace de travail.",
|
||||
@@ -736,6 +749,7 @@
|
||||
"toggle_calendars_conflict": "Activer/désactiver les calendriers pour lesquels vous souhaiter vérifier les conflits afin d'éviter les doubles réservations.",
|
||||
"select_destination_calendar": "Créer des événements le",
|
||||
"connect_additional_calendar": "Connecter un calendrier supplémentaire",
|
||||
"calendar_updated_successfully": "Calendrier mis à jour avec succès",
|
||||
"conferencing": "Conférence",
|
||||
"calendar": "Calendrier",
|
||||
"payments": "Paiements",
|
||||
@@ -768,6 +782,7 @@
|
||||
"trending_apps": "Applications populaires",
|
||||
"explore_apps": "{{category}} applications",
|
||||
"installed_apps": "Applications installées",
|
||||
"free_to_use_apps": "Gratuit",
|
||||
"no_category_apps": "Aucune application {{category}}",
|
||||
"no_category_apps_description_calendar": "Ajouter une application de calendrier pour vérifier les conflits et éviter les doubles réservations",
|
||||
"no_category_apps_description_conferencing": "Essayez d'ajouter une application de conférence pour interconnecter les appels vidéo avec vos clients",
|
||||
@@ -806,6 +821,8 @@
|
||||
"verify_wallet": "Vérifier le portefeuille",
|
||||
"connect_metamask": "Connecter Metamask",
|
||||
"create_events_on": "Créer des événements le :",
|
||||
"enterprise_license": "Il s'agit d'une fonctionnalité d'entreprise",
|
||||
"enterprise_license_description": "Pour activer cette fonctionnalité, obtenez une clé de déploiement sur la console {{consoleUrl}} et ajoutez-la à votre .env en tant que CALCOM_LICENSE_KEY. Si votre équipe a déjà une licence, veuillez contacter {{supportMail}} pour obtenir de l'aide.",
|
||||
"missing_license": "Licence manquante",
|
||||
"signup_requires": "Licence commerciale requise",
|
||||
"signup_requires_description": "{{companyName}} ne propose pas actuellement de version open source gratuite de la page d'inscription. Pour obtenir un accès complet aux composants d'inscription, vous devez acquérir une licence commerciale. Pour une utilisation personnelle, nous recommandons la Plateforme de Données Prisma ou toute autre interface Postgres pour créer des comptes.",
|
||||
@@ -897,6 +914,7 @@
|
||||
"user_impersonation_heading": "Connexion en tant qu'autre utilisateur",
|
||||
"user_impersonation_description": "Permet à notre équipe d'assistance de se connecter temporairement lorsque vous nous aidez à résoudre rapidement tous les problèmes que vous nous signalez.",
|
||||
"team_impersonation_description": "Permet aux administrateurs de votre équipe de se connecter temporairement en tant que vous-même.",
|
||||
"allow_booker_to_select_duration": "Autoriser l'organisateur à sélectionner la durée",
|
||||
"impersonate_user_tip": "Toutes les utilisations de cette fonctionnalité sont vérifiées.",
|
||||
"impersonating_user_warning": "Identification du nom d'utilisateur \"{{user}}\".",
|
||||
"impersonating_stop_instructions": "<0>Cliquez ici pour arrêter</0>.",
|
||||
@@ -1014,6 +1032,9 @@
|
||||
"error_removing_app": "Erreur lors de la suppression de l'application",
|
||||
"web_conference": "Conférence en ligne",
|
||||
"requires_confirmation": "Nécessite une confirmation",
|
||||
"always_requires_confirmation": "Toujours",
|
||||
"requires_confirmation_threshold": "Nécessite une confirmation si réservé avec un préavis de < {{time}} $t({{unit}}_timeUnit)",
|
||||
"may_require_confirmation": "Peut nécessiter une confirmation",
|
||||
"nr_event_type_one": "{{count}} type d'événement",
|
||||
"nr_event_type_other": "{{count}} types d'événements",
|
||||
"add_action": "Ajouter une action",
|
||||
@@ -1101,6 +1122,9 @@
|
||||
"event_limit_tab_description": "Fréquence de réservation",
|
||||
"event_advanced_tab_description": "Paramètres du calendrier & plus...",
|
||||
"event_advanced_tab_title": "Avancé",
|
||||
"event_setup_multiple_duration_error": "Configuration de l'événement : plusieurs durées requièrent au moins une option.",
|
||||
"event_setup_multiple_duration_default_error": "Configuration de l'événement: veuillez sélectionner une durée par défaut valide.",
|
||||
"event_setup_booking_limits_error": "Les limites de réservation doivent être en ordre croissant. [jour,semaine,mois,année]",
|
||||
"select_which_cal": "Sélectionnez le calendrier auquel ajouter des réservations",
|
||||
"custom_event_name": "Nom de l'événement personnalisé",
|
||||
"custom_event_name_description": "Créer des noms d'événements personnalisés à afficher sur l'événement du calendrier",
|
||||
@@ -1154,8 +1178,11 @@
|
||||
"invoices": "Factures",
|
||||
"embeds": "Intègre",
|
||||
"impersonation": "Identification",
|
||||
"impersonation_description": "Paramètres de gestion de l'identité de l'utilisateur",
|
||||
"users": "Utilisateurs",
|
||||
"profile_description": "Gérer les paramètres de votre profil {{appName}}",
|
||||
"users_description": "Vous trouverez ici une liste de tous les utilisateurs",
|
||||
"users_listing": "Liste des utilisateurs",
|
||||
"general_description": "Gérer les paramètres pour votre langue et votre fuseau horaire",
|
||||
"calendars_description": "Configurez la manière dont vos types d'événements interagissent avec vos calendriers",
|
||||
"appearance_description": "Gérer les paramètres pour votre apparence de réservation",
|
||||
@@ -1228,8 +1255,8 @@
|
||||
"exchange_authentication_ntlm": "Authentification NTLM",
|
||||
"exchange_compression": "Compression GZip",
|
||||
"routing_forms_description": "Vous pouvez voir tous les formulaires et tous les parcours que vous avez créés ici.",
|
||||
"routing_forms_send_email_owner": "Envoyer un e-mail au responsable",
|
||||
"routing_forms_send_email_owner_description": "Envoie un e-mail au responsable lorsque le formulaire est soumis",
|
||||
"routing_forms_send_email_owner": "Envoyer un e-mail au propriétaire",
|
||||
"routing_forms_send_email_owner_description": "Envoie un e-mail au propriétaire lorsque le formulaire est envoyé",
|
||||
"add_new_form": "Ajouter un nouveau formulaire",
|
||||
"form_description": "Créez votre formulaire pour acheminer un organisateur",
|
||||
"copy_link_to_form": "Copier le lien vers le formulaire",
|
||||
@@ -1296,7 +1323,7 @@
|
||||
"fetching_calendars_error": "Un problème est survenu lors de la récupération de vos calendriers. Veuillez <1>réessayer</1> ou contacter le service client.",
|
||||
"calendar_connection_fail": "Échec de la connexion au calendrier",
|
||||
"booking_confirmation_success": "Confirmation de réservation réussie",
|
||||
"booking_rejection_success": "Rejet de réservation réussi",
|
||||
"booking_rejection_success": "Refus de réservation réussi",
|
||||
"booking_confirmation_fail": "Échec de la confirmation de la réservation",
|
||||
"we_wont_show_again": "Nous n'afficherons plus ceci",
|
||||
"couldnt_update_timezone": "Nous n'avons pas pu mettre à jour le fuseau horaire",
|
||||
@@ -1346,21 +1373,22 @@
|
||||
"monthly": "Mensuellement",
|
||||
"yearly": "Annuellement",
|
||||
"checkout": "Paiement",
|
||||
"your_team_disbanded_successfully": "Votre équipe a été dissoute avec succès",
|
||||
"your_team_disbanded_successfully": "Votre équipe a bien été dissoute",
|
||||
"error_creating_team": "Erreur lors de la création de l'équipe",
|
||||
"you": "Vous",
|
||||
"send_email": "Envoyer un e-mail",
|
||||
"member_already_invited": "Le membre a déjà été invité",
|
||||
"enter_email_or_username": "Saisissez une adresse e-mail ou un nom d'utilisateur",
|
||||
"team_name_taken": "Ce nom est déjà pris",
|
||||
"must_enter_team_name": "Vous devez entrer un nom d'équipe",
|
||||
"team_url_required": "Vous devez entrer une URL d'équipe",
|
||||
"must_enter_team_name": "Vous devez saisir un nom d'équipe",
|
||||
"team_url_required": "Vous devez saisir une URL d'équipe",
|
||||
"team_url_taken": "Cette URL est déjà prise",
|
||||
"team_publish": "Publier l'équipe",
|
||||
"number_sms_notifications": "Numéro de téléphone (notifications SMS)",
|
||||
"attendee_email_workflow": "E-mail du participant",
|
||||
"attendee_email_info": "E-mail de la personne ayant réservé",
|
||||
"invalid_credential": "Oh non ! Il semble que l’autorisation ait expiré ou a été révoquée. Veuillez la réinstaller.",
|
||||
"kbar_search_placeholder": "Saisissez une commande ou une recherche...",
|
||||
"invalid_credential": "Oh non ! L'autorisation semble avoir expiré ou avoir été révoquée. Veuillez la réinstaller.",
|
||||
"choose_common_schedule_team_event": "Choisissez un horaire commun",
|
||||
"choose_common_schedule_team_event_description": "Activez cette option si vous souhaitez utiliser un horaire commun entre les hôtes. Si désactivée, chaque hôte sera réservé en fonction de son planning par défaut.",
|
||||
"reason": "Raison",
|
||||
@@ -1370,5 +1398,44 @@
|
||||
"test_preview": "Tester l'aperçu",
|
||||
"route_to": "Router vers",
|
||||
"test_preview_description": "Tester votre formulaire de routage sans envoyer de données",
|
||||
"test_routing": "Tester le routage"
|
||||
"test_routing": "Tester le routage",
|
||||
"payment_app_disabled": "Un administrateur a désactivé une application de paiement",
|
||||
"edit_event_type": "Modifier le type d'événement",
|
||||
"collective_scheduling": "Programmation collective",
|
||||
"make_it_easy_to_book": "Il est facile de réserver votre équipe quand tout le monde sera disponible.",
|
||||
"find_the_best_person": "Trouvez la meilleure personne disponible et passez en revue votre équipe.",
|
||||
"fixed_round_robin": "Round robin établi",
|
||||
"add_one_fixed_attendee": "Ajoutez un participant fixe et un round robin via un certain nombre de participants.",
|
||||
"calcom_is_better_with_team": "Cal.com est meilleur avec des équipes",
|
||||
"add_your_team_members": "Ajoutez les membres de votre équipe à vos types d'événements. Utilisez la planification collective pour inclure tout le monde ou trouvez la personne la plus appropriée avec la planification de round robin.",
|
||||
"booking_limit_reached": "La limite de réservation pour ce type d'événement a été atteinte",
|
||||
"admin_has_disabled": "Un administrateur a désactivé {{appName}}",
|
||||
"disabled_app_affects_event_type": "Un administrateur a désactivé {{appName}} qui affecte votre type d'événement {{eventType}}",
|
||||
"disable_payment_app": "L'administrateur a désactivé {{appName}} qui affecte votre type d'événement {{title}}. Les participants sont toujours en mesure de réserver ce type d'événement, mais ne seront pas invités à payer. Vous pouvez masquer le type d'événement pour l'empêcher jusqu'à ce que votre administrateur réactive votre moyen de paiement.",
|
||||
"payment_disabled_still_able_to_book": "Les participants sont toujours en mesure de réserver ce type d'événement, mais ne seront pas invités à payer. Vous pouvez masquer le type d'événement pour l'empêcher jusqu'à ce que votre administrateur réactive votre mode de paiement.",
|
||||
"app_disabled_with_event_type": "L'administrateur a désactivé {{appName}} qui affecte votre type d'événement {{title}}.",
|
||||
"app_disabled_video": "L'administrateur a désactivé {{appName}}, ce qui peut affecter vos types d'événements. Si vous avez des types d'événements avec {{appName}} comme emplacement, Cal Video sera alors utilisé par défaut.",
|
||||
"app_disabled_subject": "{{appName}} a été désactivé",
|
||||
"navigate_installed_apps": "Accéder aux applications installées",
|
||||
"disabled_calendar": "Si un autre calendrier est installé, de nouvelles réservations y seront ajoutées. Si ce n'est pas le cas, connectez un nouveau calendrier pour ne pas manquer de nouvelles réservations.",
|
||||
"enable_apps": "Activer les applications",
|
||||
"enable_apps_description": "Activer les applications que les utilisateurs peuvent intégrer à Cal.com",
|
||||
"app_is_enabled": "{{appName}} est activé",
|
||||
"app_is_disabled": "{{appName}} est désactivé",
|
||||
"keys_have_been_saved": "Les clés ont été enregistrées",
|
||||
"disable_app": "Désactiver l'application",
|
||||
"disable_app_description": "Désactiver cette application peut causer des problèmes avec la façon dont vos utilisateurs interagissent avec Cal",
|
||||
"edit_keys": "Modifier les clés",
|
||||
"admin_apps_description": "Activer les applications pour votre instance de Cal",
|
||||
"no_available_apps": "Il n'y a aucune application disponible",
|
||||
"no_available_apps_description": "Veuillez vous assurer qu'il y a des applications dans votre déploiement sous 'packages/app-store'",
|
||||
"no_apps": "Aucune application n'est activée dans cette instance de Cal",
|
||||
"apps_settings": "Paramètres des applications",
|
||||
"fill_this_field": "Veuillez remplir ce champ",
|
||||
"options": "Options",
|
||||
"enter_option": "Entrer l'option {{index}}",
|
||||
"add_an_option": "Ajouter une option",
|
||||
"radio": "Radio",
|
||||
"event_type_duplicate_copy_text": "{{slug}}-copie",
|
||||
"set_as_default": "Définir par défaut"
|
||||
}
|
||||
|
||||
@@ -52,6 +52,7 @@
|
||||
"still_waiting_for_approval": "אירוע עדיין ממתין לאישור",
|
||||
"event_is_still_waiting": "בקשת האירוע עדיין בהמתנה: {{attendeeName}} - {{date}} - {{eventType}}",
|
||||
"no_more_results": "אין יותר תוצאות",
|
||||
"no_results": "אין תוצאות",
|
||||
"load_more_results": "לטעון תוצאות נוספות",
|
||||
"integration_meeting_id": "{{integrationName}} מזהה פגישה: {{meetingId}}",
|
||||
"confirmed_event_type_subject": "אושר: {{eventType}} עם {{name}} בתאריך {{date}}",
|
||||
@@ -248,6 +249,7 @@
|
||||
"add_to_calendar": "הוספה ללוח השנה",
|
||||
"add_another_calendar": "להוסיף לוח שנה אחר",
|
||||
"other": "אחר",
|
||||
"email_sign_in_subject": "קישור הכניסה שלך אל {{appName}}",
|
||||
"emailed_you_and_attendees": "שלחנו לך ולמשתתפים האחרים הודעת דוא\"ל עם הזמנה בלוח השנה הכוללת את כל הפרטים.",
|
||||
"emailed_you_and_attendees_recurring": "שלחנו לך ולמשתתפים האחרים הודעת דוא\"ל עם הזמנה בלוח השנה לאירוע הראשון מבין האירועים החוזרים האלה.",
|
||||
"emailed_you_and_any_other_attendees": "שלחנו לך ולמשתתפים האחרים, אם ישנם כאלה, הודעת דוא\"ל עם הפרטים האלה.",
|
||||
@@ -420,6 +422,7 @@
|
||||
"current_incorrect_password": "הסיסמה הנוכחית שגויה",
|
||||
"password_hint_caplow": "שילוב של אותיות רישיות וקטנות",
|
||||
"password_hint_min": "באורך 8 תווים לפחות",
|
||||
"password_hint_admin_min": "באורך של 15 תווים לפחות",
|
||||
"password_hint_num": "לכלול לפחות ספרה אחת",
|
||||
"invalid_password_hint": "הסיסמה חייבת להיות באורך של 7 תווים לפחות ולכלול לפחות ספרה אחת ושילוב של אותיות רישיות וקטנות",
|
||||
"incorrect_password": "הסיסמה שגויה.",
|
||||
@@ -463,11 +466,14 @@
|
||||
"booking_confirmation": "אשר את ה{{eventTypeTitle}} עם {{profileName}}",
|
||||
"booking_reschedule_confirmation": "שנה את המועד של ה{{eventTypeTitle}} עם {{profileName}}",
|
||||
"in_person_meeting": "פגישה אישית",
|
||||
"attendeeInPerson": "פנים-אל-פנים (הכתובת של המשתתף/ת)",
|
||||
"inPerson": "פנים-אל-פנים (הכתובת של המארגן/ת)",
|
||||
"link_meeting": "פגישה עם קישור",
|
||||
"phone_call": "מספר הטלפון של המשתתף/ת",
|
||||
"your_number": "מספר הטלפון שלך",
|
||||
"phone_number": "מספר טלפון",
|
||||
"attendee_phone_number": "מספר הטלפון של המשתתף/ת",
|
||||
"organizer_phone_number": "מספר הטלפון של המארגן/ת",
|
||||
"host_phone_number": "מספר הטלפון שלך",
|
||||
"enter_phone_number": "נא להזין מספר טלפון",
|
||||
"reschedule": "שינוי המועד שנקבע",
|
||||
@@ -554,6 +560,10 @@
|
||||
"collective": "קבוצתי",
|
||||
"collective_description": "קבע מועדים לפגישות כאשר כל חברי הצוות שנבחרו זמינים.",
|
||||
"duration": "משך זמן",
|
||||
"available_durations": "משכי זמן זמינים",
|
||||
"default_duration": "משך הזמן המוגדר כברירת מחדל",
|
||||
"default_duration_no_options": "יש לבחור תחילה משכי זמן זמינים",
|
||||
"multiple_duration_mins": "{{count}} $t(minute_timeUnit)",
|
||||
"minutes": "דקות",
|
||||
"round_robin": "לפי תורות",
|
||||
"round_robin_description": "פגישות מחזוריות בין חברי צוות מרובים.",
|
||||
@@ -619,6 +629,7 @@
|
||||
"teams": "צוותים",
|
||||
"team": "צוות",
|
||||
"team_billing": "חיוב צוותים",
|
||||
"team_billing_description": "ניהול החיוב עבור הצוות",
|
||||
"upgrade_to_flexible_pro_title": "שינינו את החיוב בעבור צוותים",
|
||||
"upgrade_to_flexible_pro_message": "יש בצוות שלך חברים שאין להם מקום. שדרג לחבילת Pro לדאוג למקומות החסרים.",
|
||||
"changed_team_billing_info": "החל מינואר 2022, התחלנו לגבות תשלום עבור כל חבר צוות שמשתתף בפגישה. חברי צוות שעבדו עם גרסת PRO בחינם, הועברו לגרסת ניסיון למשך 14 יום. ברגע שהתוקף של גרסת הניסיון יסתיים, חברי צוות אלה יוסתרו מהצוות, אלא אם תשדרג כעת.",
|
||||
@@ -694,6 +705,7 @@
|
||||
"hide_event_type": "הסתר את סוג האירוע",
|
||||
"edit_location": "ערוך מיקום",
|
||||
"into_the_future": "בעתיד",
|
||||
"when_booked_with_less_than_notice": "כאשר ההזמנה היא פחות מ-<time></time> מראש",
|
||||
"within_date_range": "בתוך טווח תאריכים",
|
||||
"indefinitely_into_future": "בעתיד, במועד לא ידוע",
|
||||
"add_new_custom_input_field": "הוספת שדה קלט מותאם אישית חדש",
|
||||
@@ -713,6 +725,7 @@
|
||||
"delete_account_confirmation_message": "בטוח שברצונך למחוק את חשבון {{appName}} שלך? כל מי ששיתפת איתו את הקישור לחשבון לא יוכל יותר להזמין באמצעותו, וכל ההעדפות ששמרת יאבדו.",
|
||||
"integrations": "שילובים",
|
||||
"apps": "אפליקציות",
|
||||
"apps_listing": "פירוט האפליקציות",
|
||||
"category_apps": "אפליקציות בקטגוריה {{category}}",
|
||||
"app_store": "App Store",
|
||||
"app_store_description": "מקשרים בין אנשים, טכנולוגיה ומקום העבודה.",
|
||||
@@ -736,6 +749,7 @@
|
||||
"toggle_calendars_conflict": "סמן/י את לוחות השנה שבהם ברצונך לבדוק אם יש התנגשויות כדי למנוע כפל הזמנות.",
|
||||
"select_destination_calendar": "יצירת אירועים ב",
|
||||
"connect_additional_calendar": "חיבור לוח שנה נוסף",
|
||||
"calendar_updated_successfully": "עדכון לוח השנה בוצע בהצלחה",
|
||||
"conferencing": "שיחות ועידה",
|
||||
"calendar": "לוח שנה",
|
||||
"payments": "תשלומים",
|
||||
@@ -768,6 +782,7 @@
|
||||
"trending_apps": "אפליקציות פופולריות",
|
||||
"explore_apps": "אפליקציות בקטגוריה {{category}}",
|
||||
"installed_apps": "אפליקציות מותקנות",
|
||||
"free_to_use_apps": "חינם",
|
||||
"no_category_apps": "אין אפליקציות בקטגוריה {{category}}",
|
||||
"no_category_apps_description_calendar": "הוסף/י אפליקציית לוח שנה כדי לבדוק אם יש התנגשויות על מנת למנוע כפל הזמנות",
|
||||
"no_category_apps_description_conferencing": "נסה/י להוסיף אפליקציית שיחות ועידה כדי לשלב שיחות וידאו עם הלקוחות",
|
||||
@@ -806,6 +821,8 @@
|
||||
"verify_wallet": "אימות הארנק",
|
||||
"connect_metamask": "קישור Metamask",
|
||||
"create_events_on": "ליצור אירועים ב-",
|
||||
"enterprise_license": "תכונה זו זמינה רק במינוי ארגוני",
|
||||
"enterprise_license_description": "כדי להפעיל תכונה זו, עליך לקבל מפתח פריסה בכתובת {{consoleUrl}} ולהוסיף אותו לסביבת .env שלך בתור CALCOM_LICENSE_KEY. אם כבר יש לצוות שלך רישיון, ניתן לפנות אל {{supportMail}} לקבלת עזרה.",
|
||||
"missing_license": "חסר רישיון",
|
||||
"signup_requires": "נדרש רישיון לשימוש מסחרי",
|
||||
"signup_requires_description": "בשלב זה, {{companyName}} אינה מציעה גרסת קוד פתוח חינמית של דף ההרשמה. לקבלת גישה מלאה לרכיבי ההרשמה, תצטרך לקנות רישיון לשימוש מסחרי. ליציר חשבונות המיועדים לשימוש אישי, אנחנו ממליצים על Prisma Data Platform או על כל ממשק אחר של Postgres ליצירת חשבונות.",
|
||||
@@ -897,6 +914,7 @@
|
||||
"user_impersonation_heading": "התחזות למשתמשים",
|
||||
"user_impersonation_description": "מצב זה מאפשר לצוות התמיכה שלנו להתחבר באופן זמני לחשבונך כדי שנוכל לפתור במהירות את הבעיות שתדווח/י לנו עליהם.",
|
||||
"team_impersonation_description": "מאפשר למנהלי הצוות להיכנס זמנית בשמך.",
|
||||
"allow_booker_to_select_duration": "אפשר/י למזמין/ה לבחור משך זמן",
|
||||
"impersonate_user_tip": "כל השימושים בתכונה זו נבדקים.",
|
||||
"impersonating_user_warning": "בהתחזות לשם המשתמש \"{{user}}\".",
|
||||
"impersonating_stop_instructions": "<0>לחץ כאן כדי להפסיק</0>.",
|
||||
@@ -1014,6 +1032,9 @@
|
||||
"error_removing_app": "שגיאה בהסרת האפליקציה",
|
||||
"web_conference": "שיחת ועידה מקוונת",
|
||||
"requires_confirmation": "נדרש אישור",
|
||||
"always_requires_confirmation": "תמיד",
|
||||
"requires_confirmation_threshold": "מחייב אישור אם ההזמנה בוצעה פחות מ-{{time}} $t({{unit}}_timeUnit) מראש",
|
||||
"may_require_confirmation": "עשוי לחייב אישור",
|
||||
"nr_event_type_one": "סוג אירוע {{count}}",
|
||||
"nr_event_type_other": "{{count}} סוגי אירועים",
|
||||
"add_action": "הוספת פעולה",
|
||||
@@ -1101,6 +1122,9 @@
|
||||
"event_limit_tab_description": "באיזו תדירות ניתן להזמין אותך",
|
||||
"event_advanced_tab_description": "הגדרות לוח שנה ועוד...",
|
||||
"event_advanced_tab_title": "מתקדם",
|
||||
"event_setup_multiple_duration_error": "הגדרת אירוע: משכי זמן מרובים מחייבים הגדרה של אפשרות אחת לפחות.",
|
||||
"event_setup_multiple_duration_default_error": "הגדרת אירוע: יש לבחור משך זמן חוקי המוגדר כברירת מחדל.",
|
||||
"event_setup_booking_limits_error": "הגבלות על הזמנות חייבות להיות מוגדרות בסדר עולה. [יום,שבוע,חודש,שנה]",
|
||||
"select_which_cal": "בחר/י את לוח השנה שאליו יש להוסיף הזמנות",
|
||||
"custom_event_name": "שם אירוע מותאם אישית",
|
||||
"custom_event_name_description": "ניתן ליצור שמות אירועים בהתאמה אישית שיוצגו באירוע בלוח השנה",
|
||||
@@ -1154,8 +1178,11 @@
|
||||
"invoices": "חשבוניות",
|
||||
"embeds": "הטמעות",
|
||||
"impersonation": "התחזות",
|
||||
"impersonation_description": "הגדרות לניהול התחזות למשתמשים",
|
||||
"users": "משתמשים",
|
||||
"profile_description": "ניהול הגדרות עבור פרופיל {{appName}} שלך",
|
||||
"users_description": "כאן אפשר למצוא רשימה של כל המשתמשים",
|
||||
"users_listing": "רישום משתמש",
|
||||
"general_description": "ניהול הגדרות השפה ואזור הזמן",
|
||||
"calendars_description": "הגדרת האינטראקציה בין סוגי האירועים שלך לבין לוחות השנה שלך",
|
||||
"appearance_description": "ניהול ההגדרות של מראה ההזמנות שלך",
|
||||
@@ -1360,6 +1387,7 @@
|
||||
"number_sms_notifications": "מספר טלפון (הודעות SMS)",
|
||||
"attendee_email_workflow": "כתובת הדוא\"ל של המשתתף/ת",
|
||||
"attendee_email_info": "כתובת הדוא\"ל של האדם שביצע את ההזמנה",
|
||||
"kbar_search_placeholder": "הקלד/י פקודה או חפש/י...",
|
||||
"invalid_credential": "נראה שתוקף ההרשאה פג או שההרשאה בוטלה. יש להתקין מחדש שוב.",
|
||||
"choose_common_schedule_team_event": "בחירת לוח זמנים משותף",
|
||||
"choose_common_schedule_team_event_description": "יש להפעיל אפשרות זו אם רוצים להשתמש בלוח זמנים משותף בין המארחים. אם האפשרות הזו מבוטלת, כל מארח יוזמן לפי לוח הזמנים המשמש כברירת המחדל שלו.",
|
||||
@@ -1370,5 +1398,43 @@
|
||||
"test_preview": "בדיקת התצוגה המקדימה",
|
||||
"route_to": "ניתוב אל",
|
||||
"test_preview_description": "לבדוק את טופס הניתוב שלך בלי לשלוח נתונים",
|
||||
"test_routing": "בדיקת ניתוב"
|
||||
"test_routing": "בדיקת ניתוב",
|
||||
"payment_app_disabled": "מנהל/ת מערכת השבית/ה אפליקציית תשלומים",
|
||||
"edit_event_type": "עריכת סוג האירוע",
|
||||
"collective_scheduling": "תזמון שיתופי",
|
||||
"make_it_easy_to_book": "לקבוע בקלות פגישה עם חברי הצוות במועד שמתאים לכולם.",
|
||||
"find_the_best_person": "למצוא את האדם הכי מתאים שגם זמין לפגישה, ולעבור בסבב דרך כל חברי הצוות.",
|
||||
"fixed_round_robin": "בוצע תיקון של הסבב",
|
||||
"add_one_fixed_attendee": "הוסף/י משתתף/ת קבוע/ה אחד/ת ועבור/י בסבב בין מספר משתתפים.",
|
||||
"calcom_is_better_with_team": "Cal.com טוב יותר לשימוש עם צוותים",
|
||||
"add_your_team_members": "הוסף/י את חברי הצוות לסוגי האירועים שלך. השתמש/י בתזמון שיתופי כדי לכלול את כולם או מצא/י את האדם הכי מתאים בעזרת תזמון בסבב.",
|
||||
"booking_limit_reached": "הגעת להגבלת ההזמנות עבור סוג אירוע זה",
|
||||
"admin_has_disabled": "מנהל/ת מערכת השבית/ה את {{appName}}",
|
||||
"disabled_app_affects_event_type": "מנהל/ת מערכת השבית/ה את {{appName}}, ויש לכך השפעה על האירוע שלך מסוג {{eventType}}",
|
||||
"disable_payment_app": "מנהל/ת המערכת השבית/ה את {{appName}}, ויש לכך השפעה על סוג האירוע שלך בשם {{title}}. המשתתפים עדיין יוכלו להזמין אירוע מסוג זה, אבל לא תוצג להם בקשה לשלם. ניתן להסתיר את סוג האירוע הזה על מנת למנוע מצב זה עד שמנהל/ת המערכת יפעיל/תפעיל שוב את שיטת התשלום.",
|
||||
"payment_disabled_still_able_to_book": "המשתתפים עדיין יוכלו להזמין אירוע מסוג זה, אבל לא תוצג להם בקשה לשלם. ניתן להסתיר את סוג האירוע הזה על מנת למנוע מצב זה עד שמנהל/ת המערכת יפעיל/תפעיל שוב את שיטת התשלום.",
|
||||
"app_disabled_with_event_type": "מנהל/ת המערכת השבית/ה את {{appName}}, ויש לכך השפעה על האירוע שלך מסוג {{title}}.",
|
||||
"app_disabled_video": "מנהל/ת המערכת השבית/ה את {{appName}}, ועשויה להיות לכך השפעה על סוגי האירועים שלך. אם יש לך סוגי אירועים שבהם המיקום הוא {{appName}}, ייעשה שימוש בברירת המחדל, Cal Video.",
|
||||
"app_disabled_subject": "האפליקציה {{appName}} הושבתה",
|
||||
"navigate_installed_apps": "עבור/י אל האפליקציות המותקנות",
|
||||
"disabled_calendar": "אם הגדרת לוח שנה אחר, הזמנות חדשות יתווספו אליו. אם לא, קשר/י לוח שנה חדש כדי לא להחמיץ הזמנות חדשות.",
|
||||
"enable_apps": "הפעלת אפליקציות",
|
||||
"enable_apps_description": "הפעל/י אפליקציות שמשתמשים יכולים לשלב עם Cal.com",
|
||||
"app_is_enabled": "האפליקציה {{appName}} מופעלת",
|
||||
"app_is_disabled": "האפליקציה {{appName}} מושבתת",
|
||||
"keys_have_been_saved": "המפתחות נשמרו",
|
||||
"disable_app": "השבתת האפליקציה",
|
||||
"disable_app_description": "השבתת האפליקציה הזו עלולה לגרום בעיות באופן שבו המשתמשים שלך יהיו באינטראקציה עם Cal",
|
||||
"edit_keys": "עריכת מפתחות",
|
||||
"no_available_apps": "אין אפליקציות זמינות",
|
||||
"no_available_apps_description": "ודא/י שיש אפליקציות בפריסה שלך בנתיב 'packages/app-store'",
|
||||
"no_apps": "אף אפליקציה לא מופעלת במופע הזה של Cal",
|
||||
"apps_settings": "הגדרות אפליקציות",
|
||||
"fill_this_field": "יש להזין מידע בשדה הזה",
|
||||
"options": "אפשרויות",
|
||||
"enter_option": "הזנת ה-{{index}} של האפשרות",
|
||||
"add_an_option": "הוספת אפשרות",
|
||||
"radio": "לחצן אפשרויות",
|
||||
"event_type_duplicate_copy_text": "{{slug}}-copy",
|
||||
"set_as_default": "הגדר/י כברירת מחדל"
|
||||
}
|
||||
|
||||
@@ -16,8 +16,8 @@
|
||||
"event_request_cancelled": "Il tuo evento programmato è stato cancellato",
|
||||
"organizer": "Organizzatore",
|
||||
"need_to_reschedule_or_cancel": "È necessario riprogrammare o annullare?",
|
||||
"cancellation_reason": "Motivo dell'annullamento",
|
||||
"cancellation_reason_placeholder": "Perché stai annullando? (facoltativo)",
|
||||
"cancellation_reason": "Motivo dell'annullamento (facoltativo)",
|
||||
"cancellation_reason_placeholder": "Perché stai annullando?",
|
||||
"rejection_reason": "Motivo del rifiuto",
|
||||
"rejection_reason_title": "Rifiutare la richiesta di prenotazione?",
|
||||
"rejection_reason_description": "Sei sicuro di voler rifiutare la prenotazione? Informeremo la persona che ha cercato di prenotare. Puoi indicare il motivo qui sotto.",
|
||||
@@ -52,6 +52,7 @@
|
||||
"still_waiting_for_approval": "Un evento è ancora in attesa di approvazione",
|
||||
"event_is_still_waiting": "La richiesta d'evento è ancora in attesa: {{attendeeName}} - {{date}} - {{eventType}}",
|
||||
"no_more_results": "Nessun altro risultato",
|
||||
"no_results": "Nessun risultato",
|
||||
"load_more_results": "Carica più risultati",
|
||||
"integration_meeting_id": "{{integrationName}} meeting ID: {{meetingId}}",
|
||||
"confirmed_event_type_subject": "Confermato: {{eventType}} con {{name}} il {{date}}",
|
||||
@@ -248,6 +249,7 @@
|
||||
"add_to_calendar": "Aggiungi al calendario",
|
||||
"add_another_calendar": "Aggiungi un altro calendario",
|
||||
"other": "Altro",
|
||||
"email_sign_in_subject": "Link di accesso a {{appName}}",
|
||||
"emailed_you_and_attendees": "Abbiamo inviato via email a te e agli altri partecipanti un invito al calendario con tutti i dettagli.",
|
||||
"emailed_you_and_attendees_recurring": "Abbiamo inviato via email a te e agli altri partecipanti un invito al primo di questi eventi ricorrenti.",
|
||||
"emailed_you_and_any_other_attendees": "Tu e tutti gli altri partecipanti siete stati inviati via email con queste informazioni.",
|
||||
@@ -419,7 +421,8 @@
|
||||
"forgotten_secret_description": "Nel caso la parola segreta venga persa o dimenticata, è possibile cambiarla, ma tieni presente che tutte le integrazioni che la utilizzano dovranno essere aggiornate",
|
||||
"current_incorrect_password": "La password attuale non è corretta",
|
||||
"password_hint_caplow": "Combinazione di caratteri maiuscoli e minuscoli",
|
||||
"password_hint_min": "La lunghezza minima è di 7 caratteri",
|
||||
"password_hint_min": "La lunghezza minima è di 8 caratteri",
|
||||
"password_hint_admin_min": "La lunghezza minima è di 15 caratteri",
|
||||
"password_hint_num": "Deve contenere almeno 1 numero",
|
||||
"invalid_password_hint": "La password deve avere una lunghezza minima di 7 caratteri e deve contenere almeno 1 numero e una combinazione di caratteri maiuscoli e minuscoli",
|
||||
"incorrect_password": "La password non è corretta.",
|
||||
@@ -463,11 +466,14 @@
|
||||
"booking_confirmation": "Conferma il tuo {{eventTypeTitle}} con {{profileName}}",
|
||||
"booking_reschedule_confirmation": "Riprogramma il tuo {{eventTypeTitle}} con {{profileName}}",
|
||||
"in_person_meeting": "Link o riunione di persona",
|
||||
"attendeeInPerson": "Di persona (indirizzo del partecipante)",
|
||||
"inPerson": "Di persona (indirizzo dell'organizzatore)",
|
||||
"link_meeting": "Collegamento riunione",
|
||||
"phone_call": "Numero di telefono del partecipante",
|
||||
"your_number": "Il tuo numero di telefono",
|
||||
"phone_number": "Numero Di Telefono",
|
||||
"attendee_phone_number": "Numero di telefono del partecipante",
|
||||
"organizer_phone_number": "Numero di telefono organizzatore",
|
||||
"host_phone_number": "Il tuo numero di telefono",
|
||||
"enter_phone_number": "Inserisci numero di telefono",
|
||||
"reschedule": "Riprogramma",
|
||||
@@ -504,7 +510,7 @@
|
||||
"add_team_members_description": "Invita altri utenti a unirsi al tuo team",
|
||||
"add_team_member": "Aggiungi un membro del team",
|
||||
"invite_new_member": "Invita un nuovo membro",
|
||||
"invite_new_member_description": "Nota: il <1>costo di un posto aggiuntivo (15$/m)</1> verrà addebitato sul tuo abbonamento.",
|
||||
"invite_new_member_description": "Nota: Sul tuo abbonamento verrà addebitato <1>un posto aggiuntivo (15$/m)</1>.",
|
||||
"invite_new_team_member": "Invita qualcuno nel tuo team.",
|
||||
"change_member_role": "Cambia il ruolo del membro del team",
|
||||
"disable_cal_branding": "Disabilita il branding {{appName}}",
|
||||
@@ -554,6 +560,10 @@
|
||||
"collective": "Collettivo",
|
||||
"collective_description": "Pianifica le riunioni quando tutti i membri del team selezionati sono disponibili.",
|
||||
"duration": "Durata",
|
||||
"available_durations": "Durate disponibili",
|
||||
"default_duration": "Durata predefinita",
|
||||
"default_duration_no_options": "Scegliere prima delle durate disponibili",
|
||||
"multiple_duration_mins": "{{count}} $t(minute_timeUnit)",
|
||||
"minutes": "Minuti",
|
||||
"round_robin": "Round Robin",
|
||||
"round_robin_description": "Ciclo di riunioni tra più membri del team.",
|
||||
@@ -601,7 +611,7 @@
|
||||
"monthly_other": "mesi",
|
||||
"yearly_one": "anno",
|
||||
"yearly_other": "anni",
|
||||
"plus_more": "altri {{count}}",
|
||||
"plus_more": "Altri {{count}}",
|
||||
"max": "Max",
|
||||
"single_theme": "Tema Singolo",
|
||||
"brand_color": "Colore del Marchio",
|
||||
@@ -619,6 +629,7 @@
|
||||
"teams": "Team",
|
||||
"team": "Team",
|
||||
"team_billing": "Fatturazione team",
|
||||
"team_billing_description": "Gestisci la fatturazione per il tuo team",
|
||||
"upgrade_to_flexible_pro_title": "Abbiamo cambiato la fatturazione per i team",
|
||||
"upgrade_to_flexible_pro_message": "Alcuni membri del tuo team non hanno un posto. Aggiorna il tuo piano Pro per coprire i posti mancanti.",
|
||||
"changed_team_billing_info": "A partire da gennaio 2022, applichiamo una tariffazione in base ai posti per i membri dei team. I membri del tuo team che utilizzavano Pro gratuitamente dispongono ora di un periodo di prova di 14 giorni. Terminata la prova, questi membri saranno nascosti dal tuo team, se non aggiornerai il piano.",
|
||||
@@ -694,6 +705,7 @@
|
||||
"hide_event_type": "Nascondi tipo evento",
|
||||
"edit_location": "Aggiungi un luogo",
|
||||
"into_the_future": "nel futuro",
|
||||
"when_booked_with_less_than_notice": "Quando si prenota con un avviso inferiore a <time></time>",
|
||||
"within_date_range": "All'interno di un intervallo di date",
|
||||
"indefinitely_into_future": "Indefinitamente nel futuro",
|
||||
"add_new_custom_input_field": "Aggiungi un nuovo campo di input personalizzato",
|
||||
@@ -713,6 +725,8 @@
|
||||
"delete_account_confirmation_message": "Sei sicuro di voler eliminare il tuo account {{appName}}? Chiunque abbia il link del tuo account non potrà più utilizzarlo per prenotare e le preferenze che hai salvato andranno perse.",
|
||||
"integrations": "Integrazioni",
|
||||
"apps": "App",
|
||||
"apps_description": "Abilita le app per la tua istanza di Cal",
|
||||
"apps_listing": "Elenco delle app",
|
||||
"category_apps": "App {{category}}",
|
||||
"app_store": "App Store",
|
||||
"app_store_description": "Collegare persone, tecnologia e luogo di lavoro.",
|
||||
@@ -736,6 +750,7 @@
|
||||
"toggle_calendars_conflict": "Attiva/disattiva i calendari in cui desideri controllare i conflitti per evitare doppie prenotazioni.",
|
||||
"select_destination_calendar": "Crea eventi su",
|
||||
"connect_additional_calendar": "Collega calendario aggiuntivo",
|
||||
"calendar_updated_successfully": "Calendario aggiornato correttamente",
|
||||
"conferencing": "Conferenze",
|
||||
"calendar": "Calendario",
|
||||
"payments": "Pagamenti",
|
||||
@@ -768,6 +783,7 @@
|
||||
"trending_apps": "App di tendenza",
|
||||
"explore_apps": "App {{category}}",
|
||||
"installed_apps": "App installate",
|
||||
"free_to_use_apps": "Gratuito",
|
||||
"no_category_apps": "Nessuna app {{category}}",
|
||||
"no_category_apps_description_calendar": "Aggiungi un'app di calendario per controllare i conflitti ed evitare doppie prenotazioni",
|
||||
"no_category_apps_description_conferencing": "Prova ad aggiungere un'app di conferenza per integrare le videochiamate con i clienti",
|
||||
@@ -784,7 +800,7 @@
|
||||
"analytics": "Analisi",
|
||||
"empty_installed_apps_headline": "Nessuna app installata",
|
||||
"empty_installed_apps_description": "Le app consentono di ottimizzare il flusso di lavoro e di migliorare significativamente la pianificazione.",
|
||||
"empty_installed_apps_button": "Esplora l'App Store o installa dalle app sottostanti",
|
||||
"empty_installed_apps_button": "Esplora l'App Store",
|
||||
"manage_your_connected_apps": "Gestisci le app installate o modifica le impostazioni",
|
||||
"browse_apps": "Sfoglia app",
|
||||
"features": "Funzionalità",
|
||||
@@ -806,6 +822,8 @@
|
||||
"verify_wallet": "Verifica Wallet",
|
||||
"connect_metamask": "Connetti Metamask",
|
||||
"create_events_on": "Crea eventi su:",
|
||||
"enterprise_license": "Questa è una funzione Enterprise",
|
||||
"enterprise_license_description": "Per abilitare questa funzione, ottenere una chiave di distribuzione presso la console {{consoleUrl}} e aggiungerla al proprio .env come CALCOM_LICENSE_KEY. Nel caso il team possieda già una licenza, contattare {{supportMail}} per assistenza.",
|
||||
"missing_license": "Licenza mancante",
|
||||
"signup_requires": "È necessaria una licenza commerciale",
|
||||
"signup_requires_description": "{{companyName}} attualmente non offre una versione open source gratuita della pagina di registrazione. Per avere accesso completo ai componenti di registrazione è necessario acquisire una licenza commerciale. Per un uso personale consigliamo Prisma Data Platform o qualsiasi altra interfaccia Postgres per creare account.",
|
||||
@@ -897,6 +915,7 @@
|
||||
"user_impersonation_heading": "Accesso con altra identità",
|
||||
"user_impersonation_description": "Consente al nostro team di supporto di effettuare l'accesso temporaneo a tuo nome per risolvere rapidamente gli eventuali problemi da te segnalati.",
|
||||
"team_impersonation_description": "Consente ai membri del tuo team di accedere temporaneamente con il tuo nome.",
|
||||
"allow_booker_to_select_duration": "Consenti alla persona che prenota di selezionare la durata",
|
||||
"impersonate_user_tip": "Ogni utilizzo di questa funzionalità viene controllato.",
|
||||
"impersonating_user_warning": "Accesso con l'identità dell'utente \"{{user}}\".",
|
||||
"impersonating_stop_instructions": "<0>Fai clic qui per interrompere</0>.",
|
||||
@@ -1014,6 +1033,9 @@
|
||||
"error_removing_app": "Errore durante la rimozione dell'app",
|
||||
"web_conference": "Conferenza Web",
|
||||
"requires_confirmation": "Richiede conferma",
|
||||
"always_requires_confirmation": "Sempre",
|
||||
"requires_confirmation_threshold": "Richiede conferma se si prenota con un avviso di < {{time}} $t({{unit}}_timeUnit)",
|
||||
"may_require_confirmation": "Può richiedere conferma",
|
||||
"nr_event_type_one": "{{count}} tipo di evento",
|
||||
"nr_event_type_other": "{{count}} tipi di evento",
|
||||
"add_action": "Aggiungi azione",
|
||||
@@ -1101,6 +1123,9 @@
|
||||
"event_limit_tab_description": "Con quale frequenza è possibile fare una prenotazione",
|
||||
"event_advanced_tab_description": "Impostazioni calendario e altro...",
|
||||
"event_advanced_tab_title": "Avanzate",
|
||||
"event_setup_multiple_duration_error": "Impostazione evento: In caso di più durate è richiesta almeno 1 opzione.",
|
||||
"event_setup_multiple_duration_default_error": "Impostazione evento: Selezionare una durata predefinita valida.",
|
||||
"event_setup_booking_limits_error": "I limiti per le prenotazioni devono essere specificati in ordine crescente [giorno,settimana,mese,anno]",
|
||||
"select_which_cal": "Seleziona il calendario al quale aggiungere prenotazioni",
|
||||
"custom_event_name": "Nome evento personalizzato",
|
||||
"custom_event_name_description": "Crea nomi di eventi personalizzati da visualizzare nell'evento del calendario",
|
||||
@@ -1154,8 +1179,11 @@
|
||||
"invoices": "Fatture",
|
||||
"embeds": "Integrazioni",
|
||||
"impersonation": "Accesso con altra identità",
|
||||
"impersonation_description": "Impostazioni per gestire gli accessi con altra identità",
|
||||
"users": "Utenti",
|
||||
"profile_description": "Gestisci le impostazioni del tuo profilo {{appName}}",
|
||||
"users_description": "Qui è possibile trovare l'elenco di tutti gli utenti",
|
||||
"users_listing": "Elenco degli utenti",
|
||||
"general_description": "Gestisci le impostazioni di lingua e fuso orario",
|
||||
"calendars_description": "Configura come i tipi di eventi devono interagire con i tuoi calendari",
|
||||
"appearance_description": "Gestisci le impostazioni di aspetto delle tue prenotazioni",
|
||||
@@ -1345,21 +1373,22 @@
|
||||
"billing_frequency": "Frequenza di fatturazione",
|
||||
"monthly": "Mensile",
|
||||
"yearly": "Annuale",
|
||||
"checkout": "Checkout",
|
||||
"checkout": "Pagamento",
|
||||
"your_team_disbanded_successfully": "Il tuo team è stato sciolto correttamente",
|
||||
"error_creating_team": "Errore durante la creazione del team",
|
||||
"you": "Tu",
|
||||
"send_email": "Invia e-mail",
|
||||
"member_already_invited": "Membro già invitato",
|
||||
"enter_email_or_username": "Immettere un indirizzo e-mail o un nome utente",
|
||||
"team_name_taken": "Nome già occupato",
|
||||
"must_enter_team_name": "Immettere un nome del team",
|
||||
"team_url_required": "Immettere un URL del team",
|
||||
"team_name_taken": "Nome già utilizzato",
|
||||
"must_enter_team_name": "Necessario immettere un nome per il team",
|
||||
"team_url_required": "Immettere un URL per il team",
|
||||
"team_url_taken": "URL già occupato",
|
||||
"team_publish": "Pubblica team",
|
||||
"number_sms_notifications": "Numero di telefono (notifiche SMS)",
|
||||
"attendee_email_workflow": "E-mail partecipante",
|
||||
"attendee_email_info": "E-mail della persona che prenota",
|
||||
"kbar_search_placeholder": "Digitare un comando o eseguire una ricerca...",
|
||||
"invalid_credential": "Errore! Sembra che l'autorizzazione sia scaduta o che sia stata revocata. Prova a reinstallare.",
|
||||
"choose_common_schedule_team_event": "Scegli un programma comune",
|
||||
"choose_common_schedule_team_event_description": "Abilita questa opzione se desideri utilizzare un programma comune per tutti gli organizzatori. Quando l'opzione è disabilitata, ciascun organizzatore verrà prenotato in base al proprio programma predefinito.",
|
||||
@@ -1370,5 +1399,45 @@
|
||||
"test_preview": "Test anteprima",
|
||||
"route_to": "Instrada a",
|
||||
"test_preview_description": "Esegui un test del modulo di instradamento senza inviare alcun dato",
|
||||
"test_routing": "Test instradamento"
|
||||
"test_routing": "Test instradamento",
|
||||
"payment_app_disabled": "Un amministratore ha disabilitato un'app di pagamento",
|
||||
"edit_event_type": "Modifica tipo di evento",
|
||||
"collective_scheduling": "Pianificazione collettiva",
|
||||
"make_it_easy_to_book": "Facilita la prenotazione del tuo team quando tutti sono disponibili.",
|
||||
"find_the_best_person": "Trova la persona più adatta disponibile e passa tra i membri del team.",
|
||||
"fixed_round_robin": "Round robin fisso",
|
||||
"add_one_fixed_attendee": "Aggiungi un partecipante fisso e fai intervenire a turno altri partecipanti.",
|
||||
"calcom_is_better_with_team": "Cal.com funziona meglio in team",
|
||||
"add_your_team_members": "Aggiungi i membri del tuo team ai tuoi tipi di eventi. Usa la pianificazione collettiva per includere tutti o trova la persona più adatta con la pianificazione round robin.",
|
||||
"booking_limit_reached": "È stato raggiunto il limite di prenotazione per questo tipo di evento",
|
||||
"admin_has_disabled": "Un amministratore ha disabilitato {{appName}}",
|
||||
"disabled_app_affects_event_type": "Un amministratore ha disabilitato {{appName}}, il che influenza il tuo tipo di evento {{eventType}}",
|
||||
"disable_payment_app": "L'amministratore ha disabilitato {{appName}}, il che influenza il tuo tipo di evento {{title}}. I partecipanti sono ancora in grado di prenotare questo tipo di evento, ma non gli verrà richiesto di pagare. Per evitarlo, è possibile nascondere questo tipo di evento fino a che l'amministratore non riattivi il tuo metodo di pagamento.",
|
||||
"payment_disabled_still_able_to_book": "I partecipanti sono ancora in grado di prenotare questo tipo di evento, ma non gli verrà richiesto di pagare. Per evitarlo, è possibile nascondere questo tipo di evento fino a che l'amministratore non riattivi il tuo metodo di pagamento.",
|
||||
"app_disabled_with_event_type": "L'amministratore ha disabilitato {{appName}}, il che influenza il tuo tipo di evento {{title}}.",
|
||||
"app_disabled_video": "L'amministratore ha disabilitato {{appName}}, il che potrebbe influenzare i tuoi tipi di eventi. Se hai dei tipi di eventi che utilizzano {{appName}} come luogo, allora verrà usato Cal Video come luogo predefinito.",
|
||||
"app_disabled_subject": "{{appName}} è stato disabilitato",
|
||||
"navigate_installed_apps": "Vai alle app installate",
|
||||
"disabled_calendar": "Se si dispone di un altro calendario installato, le nuove prenotazioni saranno aggiunte a quel calendario. Se così non fosse, connettere un nuovo calendario in modo da non perdere nessuna nuova prenotazione.",
|
||||
"enable_apps": "Abilita app",
|
||||
"enable_apps_description": "Abilita le app che gli utenti possono integrare con Cal.com",
|
||||
"app_is_enabled": "{{appName}} è abilitato",
|
||||
"app_is_disabled": "{{appName}} è disabilitato",
|
||||
"keys_have_been_saved": "Le chiavi sono state salvate",
|
||||
"disable_app": "Disabilita app",
|
||||
"disable_app_description": "La disattivazione di questa app potrebbe causare problemi con il modo in cui i tuoi utenti interagiscono con Cal",
|
||||
"edit_keys": "Modifica chiavi",
|
||||
"admin_apps_description": "Abilita le app per la tua istanza di Cal",
|
||||
"no_available_apps": "Nessuna app disponibile",
|
||||
"no_available_apps_description": "Assicurarsi che ci siano delle applicazioni nella propria distribuzione in 'packages/app-store'",
|
||||
"no_apps": "Non ci sono applicazioni abilitate in questa istanza di Cal",
|
||||
"apps_settings": "Impostazioni delle app",
|
||||
"fill_this_field": "Compilare il campo",
|
||||
"options": "Opzioni",
|
||||
"enter_option": "Immetti opzione {{index}}",
|
||||
"add_an_option": "Aggiungi un'opzione",
|
||||
"radio": "Radio",
|
||||
"event_type_duplicate_copy_text": "{{slug}}-copia",
|
||||
"set_as_default": "Imposta come predefinito",
|
||||
"hide_eventtype_details": "Nascondi dettagli tipo di evento"
|
||||
}
|
||||
|
||||
@@ -16,8 +16,8 @@
|
||||
"event_request_cancelled": "スケジュールされていた予定がキャンセルされました",
|
||||
"organizer": "主催者",
|
||||
"need_to_reschedule_or_cancel": "再スケジュールまたはキャンセルが必要ですか?",
|
||||
"cancellation_reason": "キャンセルの理由",
|
||||
"cancellation_reason_placeholder": "キャンセルが必要な理由を教えてください (任意)",
|
||||
"cancellation_reason": "キャンセルの理由 (オプション)",
|
||||
"cancellation_reason_placeholder": "キャンセルが必要な理由をお教えください",
|
||||
"rejection_reason": "拒否の理由",
|
||||
"rejection_reason_title": "予約のリクエストを拒否しますか?",
|
||||
"rejection_reason_description": "この予約を拒否してよろしいですか?予約を試みたユーザーに通知を送ります。拒否の理由は、下にご記入いただけます。",
|
||||
@@ -52,6 +52,7 @@
|
||||
"still_waiting_for_approval": "イベントはまだ承認待ちです",
|
||||
"event_is_still_waiting": "イベントリクエストはまだ待機中です: {{attendeeName}} - {{date}} - {{eventType}}",
|
||||
"no_more_results": "他の結果はありません",
|
||||
"no_results": "結果はありません",
|
||||
"load_more_results": "さらに結果を読み込む",
|
||||
"integration_meeting_id": "{{integrationName}} ミーティング ID: {{meetingId}}",
|
||||
"confirmed_event_type_subject": "確認済: {{date}} の {{name}} との {{eventType}}",
|
||||
@@ -108,7 +109,7 @@
|
||||
"link_expires": "追記: 有効期限は {{expiresIn}} 時間後に切れます。",
|
||||
"upgrade_to_per_seat": "座席ごとにアップグレードする",
|
||||
"team_upgrade_seats_details": "あなたのチームに所属する {{memberCount}} 人のメンバーのうち、{{unpaidCount}} 名分のライセンスが未払いとなっています。ライセンスごとの料金は、${{seatPrice}} / 月ですので、あなたのメンバーシップの合計金額は、${{totalCost}} / 月になると予想されます。",
|
||||
"team_upgrade_banner_description": "新しいチームプランをお試しいただきありがとうございます。あなたのチーム「{{teamName}}」はアップグレードが必要なようです。",
|
||||
"team_upgrade_banner_description": "新しいチームプランをお試しいただき、ありがとうございます。あなたのチーム「{{teamName}}」には、アップグレードが必要なようです。",
|
||||
"team_upgrade_banner_action": "アップグレードはこちら",
|
||||
"team_upgraded_successfully": "チームのアップグレードが正常に完了しました!",
|
||||
"use_link_to_reset_password": "以下のリンクを使用してパスワードをリセットしてください",
|
||||
@@ -248,6 +249,7 @@
|
||||
"add_to_calendar": "カレンダーに追加",
|
||||
"add_another_calendar": "別のカレンダーを追加",
|
||||
"other": "その他",
|
||||
"email_sign_in_subject": "{{appName}} のサインインリンク",
|
||||
"emailed_you_and_attendees": "あなたと他の出席者にすべての詳細を記載したカレンダーの招待状を電子メールで送信しました。",
|
||||
"emailed_you_and_attendees_recurring": "あなたと他の出席者にこの繰り返しイベント初回のカレンダーの招待状を電子メールで送信しました。",
|
||||
"emailed_you_and_any_other_attendees": "あなたと他の参加者にこの情報を電子メールで送信しました。",
|
||||
@@ -419,7 +421,8 @@
|
||||
"forgotten_secret_description": "このシークレットを紛失または忘れた場合は変更が可能です。しかしこのシークレットを使っている連携はすべて最新のものにする必要があります",
|
||||
"current_incorrect_password": "現在のパスワードが正しくありません",
|
||||
"password_hint_caplow": "アルファベットの大文字と小文字を両方使用してください",
|
||||
"password_hint_min": "7 文字以上入力してください",
|
||||
"password_hint_min": "8 文字以上入力してください",
|
||||
"password_hint_admin_min": "15 文字以上入力してください",
|
||||
"password_hint_num": "少なくとも 1 文字は数字を含めてください",
|
||||
"invalid_password_hint": "パスワードには少なくとも 1 文字以上数字を含め、アルファベットの大文字と小文字を両方使用した上で 7 文字以上の長さに設定してください",
|
||||
"incorrect_password": "パスワードが正しくありません。",
|
||||
@@ -463,11 +466,14 @@
|
||||
"booking_confirmation": "{{profileName}} の{{eventTypeTitle}} を確認",
|
||||
"booking_reschedule_confirmation": "{{profileName}} の {{eventTypeTitle}} をスケジュール変更する",
|
||||
"in_person_meeting": "リンクまたは対面ミーティング",
|
||||
"attendeeInPerson": "対面(出席者のアドレス)",
|
||||
"inPerson": "対面(主催者のアドレス)",
|
||||
"link_meeting": "ミーティングをリンク",
|
||||
"phone_call": "出席者の電話番号",
|
||||
"your_number": "あなたの電話番号",
|
||||
"phone_number": "電話番号",
|
||||
"attendee_phone_number": "出席者の電話番号",
|
||||
"organizer_phone_number": "主催者の電話番号",
|
||||
"host_phone_number": "あなたの電話番号",
|
||||
"enter_phone_number": "電話番号を入力",
|
||||
"reschedule": "スケジュールの変更",
|
||||
@@ -504,7 +510,7 @@
|
||||
"add_team_members_description": "他のユーザーをチームに招待する",
|
||||
"add_team_member": "チームメンバーを追加",
|
||||
"invite_new_member": "新しいチームメンバーを招待",
|
||||
"invite_new_member_description": "注意:これによりサブスクリプションに<1>追加座席分(月15ドル)の費用が加算されます。</1>",
|
||||
"invite_new_member_description": "注: これにより、サブスクリプションに<1>追加の座席料金 (15 米ドル/メンバー) が加算されます。</1>",
|
||||
"invite_new_team_member": "チームに誰かを招待する。",
|
||||
"change_member_role": "チームメンバーの役割を変更する",
|
||||
"disable_cal_branding": "{{appName}} のブランディングを無効化",
|
||||
@@ -554,6 +560,10 @@
|
||||
"collective": "全体",
|
||||
"collective_description": "選択したすべてのチームメンバーが利用可能な場合、ミーティングをスケジュールします。",
|
||||
"duration": "時間",
|
||||
"available_durations": "空いている時間",
|
||||
"default_duration": "デフォルトの時間",
|
||||
"default_duration_no_options": "最初に空いている時間を選択してください",
|
||||
"multiple_duration_mins": "{{count}} $t(minute_timeUnit)",
|
||||
"minutes": "分",
|
||||
"round_robin": "ラウンドロビン",
|
||||
"round_robin_description": "複数のチームメンバー間のミーティングを定期化する。",
|
||||
@@ -601,7 +611,7 @@
|
||||
"monthly_other": "月",
|
||||
"yearly_one": "年",
|
||||
"yearly_other": "年",
|
||||
"plus_more": "{{count}} 回以上",
|
||||
"plus_more": "あと {{count}} 回",
|
||||
"max": "最大",
|
||||
"single_theme": "シングルテーマ",
|
||||
"brand_color": "ブランドカラー",
|
||||
@@ -619,6 +629,7 @@
|
||||
"teams": "チーム",
|
||||
"team": "チーム",
|
||||
"team_billing": "チームの請求",
|
||||
"team_billing_description": "チームへの請求を管理します",
|
||||
"upgrade_to_flexible_pro_title": "チームへの請求内容を変更しました",
|
||||
"upgrade_to_flexible_pro_message": "あなたのチームには座席がないメンバーがいます。Pro プランへとアップグレードし、不足している座席を確保してください。",
|
||||
"changed_team_billing_info": "2022 年 1 月より、チームのメンバーには座席単位で料金が請求されます。Pro プランを無料でご利用いただいていたチームメンバーにつきましては、現在は 14 日間のトライアル期間中となっています。今すぐアップグレードしない限り、トライアル期間の終了とともにこれらのメンバーはあなたのチームにおいて非表示となります。",
|
||||
@@ -694,6 +705,7 @@
|
||||
"hide_event_type": "イベントタイプを非表示にする",
|
||||
"edit_location": "場所を編集",
|
||||
"into_the_future": "将来の日付",
|
||||
"when_booked_with_less_than_notice": "<time></time>未満の通知で予約された場合",
|
||||
"within_date_range": "日付の範囲内で",
|
||||
"indefinitely_into_future": "未定の将来の日",
|
||||
"add_new_custom_input_field": "新しいカスタム入力フィールドを追加する",
|
||||
@@ -713,6 +725,7 @@
|
||||
"delete_account_confirmation_message": "あなたの {{appName}} アカウントを本当に削除してもよろしいですか?あなたのアカウントリンクを共有しているユーザーは、そのアカウントを使用して予約を行うことができなくなり、保存していた設定も失われます。",
|
||||
"integrations": "連携",
|
||||
"apps": "アプリ",
|
||||
"apps_listing": "アプリ一覧",
|
||||
"category_apps": "{{category}} アプリ",
|
||||
"app_store": "App Store",
|
||||
"app_store_description": "人とテクノロジーと職場をつなぐ。",
|
||||
@@ -736,6 +749,7 @@
|
||||
"toggle_calendars_conflict": "ダブルブッキングを防ぐために、スケジュールの重なりをチェックするカレンダーを切り替えてください。",
|
||||
"select_destination_calendar": "以下にイベントを作成する",
|
||||
"connect_additional_calendar": "別のカレンダーを接続する",
|
||||
"calendar_updated_successfully": "カレンダーが正常に更新されました",
|
||||
"conferencing": "ミーティング中",
|
||||
"calendar": "カレンダー",
|
||||
"payments": "お支払い",
|
||||
@@ -768,6 +782,7 @@
|
||||
"trending_apps": "人気のアプリ",
|
||||
"explore_apps": "{{category}} アプリ",
|
||||
"installed_apps": "インストールされているアプリ",
|
||||
"free_to_use_apps": "無料",
|
||||
"no_category_apps": "{{category}} アプリはありません",
|
||||
"no_category_apps_description_calendar": "ダブルブッキングを防ぐために、スケジュールの重複をチェックするカレンダーアプリを追加しましょう",
|
||||
"no_category_apps_description_conferencing": "会議アプリを追加して、顧客とのビデオ通話を統合しましょう",
|
||||
@@ -784,7 +799,7 @@
|
||||
"analytics": "分析",
|
||||
"empty_installed_apps_headline": "アプリがインストールされていません",
|
||||
"empty_installed_apps_description": "アプリを使えば、ワークフローの質を高め、スケジュールライフを大幅に改善することができます。",
|
||||
"empty_installed_apps_button": "App Store で探す",
|
||||
"empty_installed_apps_button": "App Store を見る",
|
||||
"manage_your_connected_apps": "インストール済みアプリの管理や設定の変更を行う",
|
||||
"browse_apps": "アプリを閲覧",
|
||||
"features": "特徴",
|
||||
@@ -806,6 +821,8 @@
|
||||
"verify_wallet": "ウォレットを確認する",
|
||||
"connect_metamask": "メタマスクを接続する",
|
||||
"create_events_on": "以下にイベントを作成する:",
|
||||
"enterprise_license": "これは企業向けの機能です",
|
||||
"enterprise_license_description": "この機能を有効にするには、{{consoleUrl}} コンソールでデプロイメントキーを入手して .env に CALCOM_LICENSE_KEY として追加してください。既にチームがライセンスを持っている場合は {{supportMail}} にお問い合わせください。",
|
||||
"missing_license": "ライセンスが見つかりません",
|
||||
"signup_requires": "商用ライセンスが必要です",
|
||||
"signup_requires_description": "{{companyName}} は、現時点ではサインアップページの無料のオープンソース版を提供しておりません。サインアップコンポーネントへのフルアクセスをご利用いただくためには、商用ライセンスを取得する必要があります。個人での利用につきましては、Prisma Data Platform またはその他の Postgres インターフェースを使用してアカウントの作成を行うことをお勧めしております。",
|
||||
@@ -897,6 +914,7 @@
|
||||
"user_impersonation_heading": "ユーザーなりすまし",
|
||||
"user_impersonation_description": "サポートチームがあなたとして一時的にサインインすることを許可し、あなたが当社に報告した問題を迅速に解決できるようにします。",
|
||||
"team_impersonation_description": "あなたのチームメンバーが一時的にあなたとしてサインインできるようになります。",
|
||||
"allow_booker_to_select_duration": "予約者が時間を選択できるようにする",
|
||||
"impersonate_user_tip": "この機能の使用はすべて監査されています。",
|
||||
"impersonating_user_warning": "ユーザー名 \"{{user}}\" になりすましています。",
|
||||
"impersonating_stop_instructions": "<0>停止するにはここをクリック</0>。",
|
||||
@@ -1014,6 +1032,9 @@
|
||||
"error_removing_app": "アプリの削除中にエラーが発生しました",
|
||||
"web_conference": "ウェブ会議",
|
||||
"requires_confirmation": "確認が必要です",
|
||||
"always_requires_confirmation": "常に",
|
||||
"requires_confirmation_threshold": "< {{time}} $t({{unit}}_timeUnit) の通知で予約された場合には確認が必要です",
|
||||
"may_require_confirmation": "確認が必要な場合もあります",
|
||||
"nr_event_type_one": "{{count}} 種類のイベントタイプ",
|
||||
"nr_event_type_other": "{{count}} 種類のイベントタイプ",
|
||||
"add_action": "アクションを追加",
|
||||
@@ -1101,6 +1122,9 @@
|
||||
"event_limit_tab_description": "予約できる頻度",
|
||||
"event_advanced_tab_description": "カレンダー設定など...",
|
||||
"event_advanced_tab_title": "詳細設定",
|
||||
"event_setup_multiple_duration_error": "イベント設定:複数の期間には少なくとも1つのオプションが必要です。",
|
||||
"event_setup_multiple_duration_default_error": "イベント設定:有効なデフォルト期間を選択してください。",
|
||||
"event_setup_booking_limits_error": "予約の上限の日時表記は昇順にする必要があります。[日、週、月、年]",
|
||||
"select_which_cal": "予約を追加するカレンダーを選択してください",
|
||||
"custom_event_name": "カスタムイベント名",
|
||||
"custom_event_name_description": "カレンダーのイベントに表示するカスタマイズされたイベント名を作成します",
|
||||
@@ -1154,8 +1178,11 @@
|
||||
"invoices": "請求書",
|
||||
"embeds": "埋め込み",
|
||||
"impersonation": "なりすまし",
|
||||
"impersonation_description": "ユーザーなりすましを管理するための設定",
|
||||
"users": "ユーザー",
|
||||
"profile_description": "{{appName}} プロフィールの設定を管理します",
|
||||
"users_description": "ここにはすべてのユーザーの一覧が表示されます",
|
||||
"users_listing": "ユーザー一覧",
|
||||
"general_description": "言語とタイムゾーンの設定を管理します",
|
||||
"calendars_description": "イベントの種類とカレンダーの連携方法を設定します",
|
||||
"appearance_description": "予約画面の外観設定を管理します",
|
||||
@@ -1229,7 +1256,7 @@
|
||||
"exchange_compression": "GZip 圧縮",
|
||||
"routing_forms_description": "作成したすべてのフォームとルートをここで確認できます。",
|
||||
"routing_forms_send_email_owner": "所有者にメールを送信",
|
||||
"routing_forms_send_email_owner_description": "フォーム送信時に所有者にメールを送信します",
|
||||
"routing_forms_send_email_owner_description": "フォームの送信時に所有者にメールを送信します",
|
||||
"add_new_form": "新しいフォームを追加",
|
||||
"form_description": "予約者をルーティングするフォームを作成します",
|
||||
"copy_link_to_form": "フォームへのリンクをコピー",
|
||||
@@ -1296,7 +1323,7 @@
|
||||
"fetching_calendars_error": "カレンダーの取得中にエラーが発生しました。<1>もう一度お試しいただく</1>か、カスタマーサポートまでお問い合わせください。",
|
||||
"calendar_connection_fail": "カレンダーの接続に失敗しました",
|
||||
"booking_confirmation_success": "正常に予約を確認しました",
|
||||
"booking_rejection_success": "正常に予約を拒否しました",
|
||||
"booking_rejection_success": "予約を正常に拒否しました",
|
||||
"booking_confirmation_fail": "予約の確認に失敗しました",
|
||||
"we_wont_show_again": "次回から表示しない",
|
||||
"couldnt_update_timezone": "タイムゾーンを更新できませんでした",
|
||||
@@ -1342,33 +1369,72 @@
|
||||
"limit_future_bookings_description": "今後いつまでこのイベントを予約できるかを設定します",
|
||||
"no_event_types": "イベントタイプは設定されていません",
|
||||
"no_event_types_description": "{{name}}はあなたが予約するイベントのタイプを設定していません。",
|
||||
"billing_frequency": "請求頻度",
|
||||
"monthly": "月ごと",
|
||||
"yearly": "年ごと",
|
||||
"checkout": "精算",
|
||||
"your_team_disbanded_successfully": "チームは正常に解散しました",
|
||||
"billing_frequency": "請求の頻度",
|
||||
"monthly": "毎月",
|
||||
"yearly": "毎年",
|
||||
"checkout": "チェックアウト",
|
||||
"your_team_disbanded_successfully": "チームは正常に解散されました",
|
||||
"error_creating_team": "チームの作成中にエラーが発生しました",
|
||||
"you": "あなた",
|
||||
"send_email": "メールを送信",
|
||||
"member_already_invited": "メンバーは既に招待されています",
|
||||
"enter_email_or_username": "メールアドレスまたはユーザー名を入力してください",
|
||||
"team_name_taken": "この名前は既に使用されています",
|
||||
"must_enter_team_name": "チーム名を入力する必要があります",
|
||||
"team_url_required": "チームの URL を入力する必要があります",
|
||||
"must_enter_team_name": "チーム名の入力は必須です",
|
||||
"team_url_required": "チームの URL の入力は必須です",
|
||||
"team_url_taken": "この URL は既に使用されています",
|
||||
"team_publish": "チームを公開",
|
||||
"number_sms_notifications": "電話番号(SMS 通知)",
|
||||
"attendee_email_workflow": "出席者のメールアドレス",
|
||||
"attendee_email_info": "予約者のメールアドレス",
|
||||
"invalid_credential": "おっと!許可が期限切れになったか、取り消されたようです。もう一度インストールし直してください。",
|
||||
"kbar_search_placeholder": "コマンドを入力するか、検索...",
|
||||
"invalid_credential": "アクセス許可の有効期限が切れたか、取り消されたようです。もう一度インストールしてください。",
|
||||
"choose_common_schedule_team_event": "共通のスケジュールを選択",
|
||||
"choose_common_schedule_team_event_description": "ホスト間で共通のスケジュールを使用する場合は、これを有効にします。無効にすると、各ホストはデフォルトのスケジュールに基づいて予約されます。",
|
||||
"choose_common_schedule_team_event_description": "ホスト間で共通のスケジュールを使用する場合には、これを有効にしてください。無効にすると、各ホストに対してはデフォルトのスケジュールに基づいて予約が行われます。",
|
||||
"reason": "理由",
|
||||
"sender_id": "送信者 ID",
|
||||
"sender_id_error_message": "文字、数字、スペースのみ使用できます(最大 11 文字)",
|
||||
"sender_id_error_message": "文字、数字、スペースのみが使用可能です (最大 11 文字)",
|
||||
"test_routing_form": "ルーティングフォームをテスト",
|
||||
"test_preview": "テストプレビュー",
|
||||
"route_to": "ルート先",
|
||||
"test_preview": "プレビューをテスト",
|
||||
"route_to": "ルーティング先",
|
||||
"test_preview_description": "データを送信せずにルーティングフォームをテストします",
|
||||
"test_routing": "ルーティングをテスト"
|
||||
"test_routing": "ルーティングをテスト",
|
||||
"payment_app_disabled": "管理者が決済アプリを無効にしました",
|
||||
"edit_event_type": "イベントタイプを編集",
|
||||
"collective_scheduling": "全体スケジューリング",
|
||||
"make_it_easy_to_book": "誰もが参加可能な場合にチームの予約を簡単にします。",
|
||||
"find_the_best_person": "参加できる最適な人を見つけて、チームで繰り返し分担する。",
|
||||
"fixed_round_robin": "固定ラウンドロビン",
|
||||
"add_one_fixed_attendee": "決まった出席者を1人追加して、多数の出席者で持ち回りにします。",
|
||||
"calcom_is_better_with_team": "Cal.comはチームで使った方がよいです",
|
||||
"add_your_team_members": "イベントタイプにチームメンバーを追加します。全体スケジュールを使って、全員を含めるか、ラウンドロビンスケジューリングを使って、最適な人を見つけます。",
|
||||
"booking_limit_reached": "このイベントタイプの予約上限に達しました",
|
||||
"admin_has_disabled": "管理者が {{appName}} を無効にしました",
|
||||
"disabled_app_affects_event_type": "管理者が {{appName}} を無効にしているため、あなたのイベントタイプ {{eventType}} に影響があります",
|
||||
"disable_payment_app": "管理者が {{appName}} を無効にしているため、あなたのイベントタイプ {{title}} に影響すがあります。出席者はこのタイプのイベントを予約することはできますが、支払いを促されることはありません。管理者が支払い方法を再有効化するまで出席者が予約しないよう、このイベントタイプを非表示にすることができます。",
|
||||
"payment_disabled_still_able_to_book": "出席者はこのタイプのイベントを予約することはできますが、支払いを促されることはありません。管理者が支払い方法を再有効化するまで出席者が予約しないよう、このイベントタイプを非表示にすることができます。",
|
||||
"app_disabled_with_event_type": "管理者が {{appName}} を無効にしているため、あなたのイベントタイプ {{title}} に影響があります。",
|
||||
"app_disabled_video": "管理者が {{appName}} を無効にしているため、あなたのイベントタイプに影響する可能性があります。場所として {{appName}} を使ったイベントタイプがある場合はデフォルトの Cal Video になります。",
|
||||
"app_disabled_subject": "{{appName}} は無効になっています",
|
||||
"navigate_installed_apps": "インストールされているアプリに移動",
|
||||
"disabled_calendar": "別のカレンダーがインストールされている場合は、新しい予約はそこに追加されます。そうでない場合は新しい予約を見逃さないために新しいカレンダーを接続してください。",
|
||||
"enable_apps": "アプリを有効にする",
|
||||
"enable_apps_description": "ユーザーが Cal.com と連携できるアプリを有効にします",
|
||||
"app_is_enabled": "{{appName}} は有効です",
|
||||
"app_is_disabled": "{{appName}} は無効です",
|
||||
"keys_have_been_saved": "キーが保存されました",
|
||||
"disable_app": "アプリを無効化",
|
||||
"disable_app_description": "このアプリを無効にすると、ユーザーの Cal の操作に問題が発生する可能性があります",
|
||||
"edit_keys": "キーを編集",
|
||||
"no_available_apps": "利用可能なアプリはありません",
|
||||
"no_available_apps_description": "「packages/app-store」以下のデプロイメントにアプリがあることを確認してください",
|
||||
"no_apps": "Cal のこのインスタンスで有効になっているアプリはありません",
|
||||
"apps_settings": "アプリ設定",
|
||||
"fill_this_field": "このフィールドに入力してください",
|
||||
"options": "オプション",
|
||||
"enter_option": "オプション {{index}} を入力してください",
|
||||
"add_an_option": "オプションを追加",
|
||||
"radio": "ラジオボタン",
|
||||
"event_type_duplicate_copy_text": "{{slug}} をコピー",
|
||||
"set_as_default": "デフォルトとして設定"
|
||||
}
|
||||
|
||||
@@ -16,8 +16,8 @@
|
||||
"event_request_cancelled": "회의 일정이 취소되었습니다.",
|
||||
"organizer": "주최자",
|
||||
"need_to_reschedule_or_cancel": "다시 일정을 잡거나 취소하시겠습니까?",
|
||||
"cancellation_reason": "취소 사유",
|
||||
"cancellation_reason_placeholder": "왜 취소를 선택하셨나요? (선택사항)",
|
||||
"cancellation_reason": "취소 사유(선택사항)",
|
||||
"cancellation_reason_placeholder": "취소하는 이유가 무엇인가요?",
|
||||
"rejection_reason": "거부 사유",
|
||||
"rejection_reason_title": "예약 요청을 거부하시겠습니까?",
|
||||
"rejection_reason_description": "예약을 거부하시겠습니까? 예약하려고 시도하셨던 다른 분께 알려드릴 것입니다. 해당 사유는 아래에서 제공하실 수 있습니다.",
|
||||
@@ -52,6 +52,7 @@
|
||||
"still_waiting_for_approval": "이벤트가 아직 승인을 기다리고 있습니다.",
|
||||
"event_is_still_waiting": "이벤트 요청이 아직 대기중입니다: {{attendeeName}} - {{date}} - {{eventType}}",
|
||||
"no_more_results": "더 이상 결과 없음",
|
||||
"no_results": "결과 없음",
|
||||
"load_more_results": "더 많은 결과 보기",
|
||||
"integration_meeting_id": "{{integrationName}} 회의 ID: {{meetingId}}",
|
||||
"confirmed_event_type_subject": "확인됨: {{date}}, {{name}} 의 {{eventType}}",
|
||||
@@ -108,8 +109,8 @@
|
||||
"link_expires": "{{expiresIn}} 시간 안에 만료됩니다.",
|
||||
"upgrade_to_per_seat": "시트 단위로 업그레이드",
|
||||
"team_upgrade_seats_details": "귀하의 팀원 {{memberCount}}명 중 {{unpaidCount}}명의 시트 비용이 미지급되었습니다. 시트당 ${{seatPrice}}/m로 계산시, 예상 총 멤버십 비용은 ${{totalCost}}/m입니다.",
|
||||
"team_upgrade_banner_description": "당사의 새로운 팀 플랜을 사용해 주셔서 감사합니다. \"{{teamName}}\" 팀을 업그레이드해야 합니다.",
|
||||
"team_upgrade_banner_action": "여기에서 업그레이드",
|
||||
"team_upgrade_banner_description": "당사의 새로운 팀 플랜을 사용해 주셔서 감사합니다. 귀하의 \"{{teamName}}\" 팀에 업그레이드가 필요한 것으로 확인되었습니다.",
|
||||
"team_upgrade_banner_action": "여기서 업그레이드",
|
||||
"team_upgraded_successfully": "팀이 성공적으로 업그레이드되었습니다!",
|
||||
"use_link_to_reset_password": "비밀번호를 재설정하시려면 아래 링크를 사용하세요.",
|
||||
"hey_there": "안녕하세요.",
|
||||
@@ -248,6 +249,7 @@
|
||||
"add_to_calendar": "캘린더에 추가하기",
|
||||
"add_another_calendar": "다른 캘린더 추가",
|
||||
"other": "더 보기",
|
||||
"email_sign_in_subject": "{{appName}}의 로그인 링크",
|
||||
"emailed_you_and_attendees": "당신과 다른 참여자들에게 상세 사항이 담긴 캘린더 초대 이메일을 보냈습니다.",
|
||||
"emailed_you_and_attendees_recurring": "귀하와 다른 참석자들에게 이 되풀이 이벤트의 첫 이벤트에 대한 예약 초대장을 이메일로 발송했습니다.",
|
||||
"emailed_you_and_any_other_attendees": "당신과 다른 참여자들이 이 정보가 담긴 이메일을 주고 받았습니다.",
|
||||
@@ -420,6 +422,7 @@
|
||||
"current_incorrect_password": "현재 비밀번호가 잘못되었습니다.",
|
||||
"password_hint_caplow": "대문자와 소문자의 혼합",
|
||||
"password_hint_min": "최소 7자 길이",
|
||||
"password_hint_admin_min": "최소 15자 길이",
|
||||
"password_hint_num": "1개 이상 숫자 포함",
|
||||
"invalid_password_hint": "비밀번호는 7자 이상이어야 하고 숫자가 하나 이상 포함되어야 하며 대문자와 소문자가 혼합되어야 합니다",
|
||||
"incorrect_password": "비밀번호가 잘못되었습니다",
|
||||
@@ -463,11 +466,14 @@
|
||||
"booking_confirmation": "{{profileName}}로 {{eventTypeTitle}} 확인",
|
||||
"booking_reschedule_confirmation": "{{profileName}}을 사용하여 {{eventTypeTitle}} 일정을 변경하세요.",
|
||||
"in_person_meeting": "온라인 또는 오프라인 회의",
|
||||
"attendeeInPerson": "직접 방문(참석자 주소)",
|
||||
"inPerson": "방문(주최자 주소)",
|
||||
"link_meeting": "회의 링크",
|
||||
"phone_call": "참석자 전화 번호",
|
||||
"your_number": "본인 전화 번호",
|
||||
"phone_number": "전화 번호",
|
||||
"attendee_phone_number": "참석자 전화 번호",
|
||||
"organizer_phone_number": "주최자 전화번호",
|
||||
"host_phone_number": "본인 전화 번호",
|
||||
"enter_phone_number": "전화 번호 입력",
|
||||
"reschedule": "일정 변경",
|
||||
@@ -504,7 +510,7 @@
|
||||
"add_team_members_description": "다른 사람을 팀에 초대",
|
||||
"add_team_member": "팀원 추가",
|
||||
"invite_new_member": "새 팀원 초대",
|
||||
"invite_new_member_description": "참고: 이렇게 하면 해당 구독에 <1>추가 좌석 비용($15/m)</1>이 발생합니다.",
|
||||
"invite_new_member_description": "참고: 이로 인해 해당 구독에 <1>추가 시트 비용($15/m)</1>이 발생합니다.",
|
||||
"invite_new_team_member": "누군가를 팀에 초대하기",
|
||||
"change_member_role": "팀원 역할 변경",
|
||||
"disable_cal_branding": "{{appName}} 브랜딩 비활성화",
|
||||
@@ -554,6 +560,10 @@
|
||||
"collective": "집단",
|
||||
"collective_description": "선택한 모든 팀원이 참석할 수 있을 때 회의를 예약합니다.",
|
||||
"duration": "기간",
|
||||
"available_durations": "사용 가능한 기간",
|
||||
"default_duration": "기본 기간",
|
||||
"default_duration_no_options": "사용 가능한 기간을 먼저 선택하세요",
|
||||
"multiple_duration_mins": "{{count}} $t(minute_timeUnit)",
|
||||
"minutes": "분",
|
||||
"round_robin": "라운드 로빈",
|
||||
"round_robin_description": "여러 팀 구성원 간의 주기적인 회의",
|
||||
@@ -619,6 +629,7 @@
|
||||
"teams": "팀",
|
||||
"team": "팀",
|
||||
"team_billing": "팀 비용 청구",
|
||||
"team_billing_description": "팀의 청구 관리",
|
||||
"upgrade_to_flexible_pro_title": "팀에 대한 청구를 변경했습니다",
|
||||
"upgrade_to_flexible_pro_message": "팀에 시트가 없는 구성원이 있습니다. 누락된 시트를 보완하려면 Pro 플랜을 업그레이드하세요.",
|
||||
"changed_team_billing_info": "2022년 1월부터 팀원에 대해 시트별로 요금을 부과합니다. 무료로 Pro를 사용하던 팀원은 이제 14일 평가판을 사용할 수 있습니다. 평가판 기한이 만료되고 업그레이드하지 않으면 이 팀원은 팀에서 숨겨집니다.",
|
||||
@@ -694,6 +705,7 @@
|
||||
"hide_event_type": "이벤트 타입 숨기기",
|
||||
"edit_location": "위치 수정",
|
||||
"into_the_future": "미래로",
|
||||
"when_booked_with_less_than_notice": "<time></time>회 미만 통지로 예약한 경우",
|
||||
"within_date_range": "기간 내",
|
||||
"indefinitely_into_future": "무한히 미래로",
|
||||
"add_new_custom_input_field": "새 사용자 정의 입력 필드 추가",
|
||||
@@ -713,6 +725,8 @@
|
||||
"delete_account_confirmation_message": "{{appName}} 계정을 삭제하시겠습니까? 계정 링크를 공유한 사람은 더 이상 이 링크를 사용하여 예약할 수 없으며 저장한 모든 기본 설정이 손실됩니다.",
|
||||
"integrations": "통합",
|
||||
"apps": "앱",
|
||||
"apps_description": "Cal 인스턴스용 앱 활성화",
|
||||
"apps_listing": "앱 목록화",
|
||||
"category_apps": "{{category}} 앱",
|
||||
"app_store": "앱 스토어",
|
||||
"app_store_description": "사람, 기술, 직장을 연결합니다.",
|
||||
@@ -736,6 +750,7 @@
|
||||
"toggle_calendars_conflict": "중복 예약을 방지하기 위해 충돌을 확인하려는 캘린더를 전환합니다.",
|
||||
"select_destination_calendar": "이벤트 작성일",
|
||||
"connect_additional_calendar": "추가 캘린더 연결",
|
||||
"calendar_updated_successfully": "캘린더가 업데이트되었습니다",
|
||||
"conferencing": "회의",
|
||||
"calendar": "달력",
|
||||
"payments": "결제",
|
||||
@@ -768,6 +783,7 @@
|
||||
"trending_apps": "트랜드 앱",
|
||||
"explore_apps": "{{category}} 앱",
|
||||
"installed_apps": "설치된 앱",
|
||||
"free_to_use_apps": "무료",
|
||||
"no_category_apps": "{{category}} 앱 없음",
|
||||
"no_category_apps_description_calendar": "중복 예약을 방지하기 위해 충돌을 확인하려는 캘린더 앱을 추가합니다",
|
||||
"no_category_apps_description_conferencing": "고객과 화상 통화를 통합하려면 회의 앱을 추가해 보세요",
|
||||
@@ -784,7 +800,7 @@
|
||||
"analytics": "분석",
|
||||
"empty_installed_apps_headline": "설치된 앱 없음",
|
||||
"empty_installed_apps_description": "앱을 통해 워크플로를 강화하고 일정 관리 수명을 대폭 향상할 수 있습니다.",
|
||||
"empty_installed_apps_button": "앱 스토어를 둘러보거나 아래 앱 중에서 설치",
|
||||
"empty_installed_apps_button": "앱 스토어 둘러보기",
|
||||
"manage_your_connected_apps": "설치된 앱 관리 또는 설정 변경",
|
||||
"browse_apps": "앱 찾아보기",
|
||||
"features": "기능",
|
||||
@@ -806,6 +822,8 @@
|
||||
"verify_wallet": "지갑 인증",
|
||||
"connect_metamask": "메타마스크 연결",
|
||||
"create_events_on": "이벤트 생성일:",
|
||||
"enterprise_license": "엔터프라이즈 기능입니다",
|
||||
"enterprise_license_description": "이 기능을 활성화하려면 {{consoleUrl}} 콘솔에서 배포 키를 가져와 .env에 CALCOM_LICENSE_KEY로 추가하세요. 팀에 이미 라이선스가 있는 경우 {{supportMail}}에 문의하여 도움을 받으세요.",
|
||||
"missing_license": "라이선스 없음",
|
||||
"signup_requires": "상용 라이선스 필요",
|
||||
"signup_requires_description": "지금은 {{companyName}}에서 가입 페이지의 무료 오픈 소스 버전을 제공하지 않습니다. 가입 구성 요소에 대한 정식 액세스 권한을 받으려면 상용 라이선스를 취득해야 합니다. 개인 용도의 경우 Prisma Data Platform 또는 기타 Postgres 인터페이스를 사용하여 계정을 생성하는 것이 좋습니다.",
|
||||
@@ -897,6 +915,7 @@
|
||||
"user_impersonation_heading": "사용자 가장",
|
||||
"user_impersonation_description": "신고하신 문제를 신속하게 해결할 수 있도록 지원 팀이 귀하의 계정에 일시적으로 로그인할 수 있게 허용합니다.",
|
||||
"team_impersonation_description": "팀 구성원이 일시적으로 귀하의 자격으로 로그인할 수 있게 합니다.",
|
||||
"allow_booker_to_select_duration": "예약자가 기간을 선택하도록 허용",
|
||||
"impersonate_user_tip": "이 기능의 사용은 모두 감사됩니다.",
|
||||
"impersonating_user_warning": "\"{{user}}\"의 사용자 이름을 가장하는 중입니다.",
|
||||
"impersonating_stop_instructions": "<0>중지하려면 여기를 클릭하십시오</0>.",
|
||||
@@ -1014,6 +1033,9 @@
|
||||
"error_removing_app": "앱 제거 중 오류 발생",
|
||||
"web_conference": "웹 화상 회의",
|
||||
"requires_confirmation": "확인 필수",
|
||||
"always_requires_confirmation": "항상",
|
||||
"requires_confirmation_threshold": "< {{time}} $t({{unit}}_timeUnit) 알림으로 예약한 경우 확인이 필요합니다",
|
||||
"may_require_confirmation": "확인이 필요할 수 있음",
|
||||
"nr_event_type_one": "{{count}} 이벤트 타입",
|
||||
"nr_event_type_other": "{{count}} 이벤트 타입",
|
||||
"add_action": "작업 추가",
|
||||
@@ -1101,6 +1123,9 @@
|
||||
"event_limit_tab_description": "예약 가능 횟수",
|
||||
"event_advanced_tab_description": "캘린더 설정 및 기타...",
|
||||
"event_advanced_tab_title": "고급",
|
||||
"event_setup_multiple_duration_error": "이벤트 설정: 복수 기간에는 최소 1개의 옵션이 필요합니다.",
|
||||
"event_setup_multiple_duration_default_error": "이벤트 설정: 유효한 기본 기간을 선택하십시오.",
|
||||
"event_setup_booking_limits_error": "예약 한도는 오름차순이어야 합니다. [일,주,월,년]",
|
||||
"select_which_cal": "예약을 추가할 캘린더 선택",
|
||||
"custom_event_name": "사용자 정의 이벤트 이름",
|
||||
"custom_event_name_description": "캘린더 이벤트에 표시할 사용자 정의 이벤트 이름 만들기",
|
||||
@@ -1154,8 +1179,11 @@
|
||||
"invoices": "청구서",
|
||||
"embeds": "내장",
|
||||
"impersonation": "가장",
|
||||
"impersonation_description": "사용자 가장을 관리하기 위한 설정",
|
||||
"users": "사용자",
|
||||
"profile_description": "사용자 {{appName}} 프로필 설정 관리",
|
||||
"users_description": "여기에서 모든 사용자 목록을 찾을 수 있습니다",
|
||||
"users_listing": "사용자 목록화",
|
||||
"general_description": "언어 및 시간대 설정 관리",
|
||||
"calendars_description": "이벤트 타입이 캘린더와 상호 작용하는 방식 구성",
|
||||
"appearance_description": "예약 모양 설정 관리",
|
||||
@@ -1296,7 +1324,7 @@
|
||||
"fetching_calendars_error": "캘린더를 가져오는 중 문제가 발생했습니다. <1>다시 시도</1>하거나 고객 지원에 문의하십시오.",
|
||||
"calendar_connection_fail": "캘린더 연결 실패",
|
||||
"booking_confirmation_success": "예약 확인 성공",
|
||||
"booking_rejection_success": "예약 거부 성공",
|
||||
"booking_rejection_success": "예약이 거부됨",
|
||||
"booking_confirmation_fail": "예약 확인 실패",
|
||||
"we_wont_show_again": "다시 표시 안 함",
|
||||
"couldnt_update_timezone": "시간대를 업데이트할 수 없습니다",
|
||||
@@ -1347,28 +1375,68 @@
|
||||
"yearly": "연간",
|
||||
"checkout": "체크아웃",
|
||||
"your_team_disbanded_successfully": "귀하의 팀이 성공적으로 해산되었습니다",
|
||||
"error_creating_team": "팀을 만드는 중 오류가 발생했습니다",
|
||||
"you": "나",
|
||||
"error_creating_team": "팀을 만드는 중 오류 발생",
|
||||
"you": "귀하",
|
||||
"send_email": "이메일 보내기",
|
||||
"member_already_invited": "구성원이 이미 초대되었습니다",
|
||||
"enter_email_or_username": "이메일 또는 사용자 이름을 입력하세요",
|
||||
"team_name_taken": "이미 사용 중인 이름입니다",
|
||||
"must_enter_team_name": "팀 이름을 입력하세요",
|
||||
"team_url_required": "팀 URL을 입력해야 합니다",
|
||||
"team_url_required": "팀 URL을 입력하세요",
|
||||
"team_url_taken": "이미 사용 중인 URL입니다",
|
||||
"team_publish": "팀 게시",
|
||||
"number_sms_notifications": "전화번호 (SMS notifications)",
|
||||
"attendee_email_workflow": "참석자 이메일",
|
||||
"attendee_email_info": "예약자 이메일",
|
||||
"kbar_search_placeholder": "명령어를 입력하거나 검색하세요...",
|
||||
"invalid_credential": "죄송합니다! 권한이 만료되었거나 취소된 것 같습니다. 다시 설치하십시오.",
|
||||
"choose_common_schedule_team_event": "공통 일정을 선택하세요",
|
||||
"choose_common_schedule_team_event_description": "호스트 간에 공통 일정을 사용하려면 이 옵션을 활성화하십시오. 비활성화되면 각 호스트는 기본 일정에 따라 예약됩니다.",
|
||||
"reason": "이유",
|
||||
"choose_common_schedule_team_event": "공통 일정 선택",
|
||||
"choose_common_schedule_team_event_description": "호스트 간에 공통 일정을 사용하려면 이 옵션을 활성화하세요. 비활성화되면 각 호스트는 기본 일정에 따라 예약됩니다.",
|
||||
"reason": "사유",
|
||||
"sender_id": "발신자 ID",
|
||||
"sender_id_error_message": "영문, 숫자, 공백만 허용(최대 11자)",
|
||||
"test_routing_form": "라우팅 양식 테스트",
|
||||
"test_preview": "테스트 미리보기",
|
||||
"test_preview": "미리보기 테스트",
|
||||
"route_to": "목표 경로",
|
||||
"test_preview_description": "데이터를 제출하지 않고 라우팅 양식 테스트",
|
||||
"test_routing": "라우팅 테스트"
|
||||
"test_routing": "라우팅 테스트",
|
||||
"payment_app_disabled": "관리자가 결제 앱을 비활성화했습니다",
|
||||
"edit_event_type": "이벤트 타입 편집",
|
||||
"collective_scheduling": "집단 일정 관리",
|
||||
"make_it_easy_to_book": "모든 사람이 참석할 수 있을 때 팀을 쉽게 예약할 수 있게 합니다.",
|
||||
"find_the_best_person": "가능한 최상의 인원을 찾고 팀원을 순환 배정하십시오.",
|
||||
"fixed_round_robin": "고정 라운드 로빈",
|
||||
"add_one_fixed_attendee": "한 명의 고정 참석자를 추가하고 여러 참석자를 통해 라운드 로빈을 추가합니다.",
|
||||
"calcom_is_better_with_team": "Cal.com은 팀과 함께라면 더욱 좋습니다",
|
||||
"add_your_team_members": "이벤트 타입에 팀원을 추가하세요. 집단 일정 관리를 사용해 모든 사람을 포함하거나 라운드 로빈 일정 관리로 가장 적합한 인원을 찾으십시오.",
|
||||
"booking_limit_reached": "이 이벤트 타입에 대한 예약 한도에 도달했습니다",
|
||||
"admin_has_disabled": "관리자가 {{appName}} 앱을 비활성화했습니다",
|
||||
"disabled_app_affects_event_type": "관리자가 이벤트 타입 {{eventType}}에 영향을 미치는 {{appName}} 앱을 비활성화했습니다",
|
||||
"disable_payment_app": "관리자가 이벤트 타입 {{title}}에 영향을 미치는 {{appName}} 앱을 비활성화했습니다. 참석자는 여전히 이러한 타입의 이벤트를 예약할 수 있지만 결제하라는 메시지는 표시되지 않습니다. 관리자가 결제 수단을 다시 활성화할 때까지 이를 방지하기 위해 이벤트 타입을 숨길 수 있습니다.",
|
||||
"payment_disabled_still_able_to_book": "참석자는 여전히 이러한 타입의 이벤트를 예약할 수 있지만 결제하라는 메시지는 표시되지 않습니다. 관리자가 결제 수단을 다시 활성화할 때까지 이를 방지하기 위해 이벤트 타입을 숨길 수 있습니다.",
|
||||
"app_disabled_with_event_type": "관리자가 이벤트 타입 {{title}}에 영향을 미치는 {{appName}} 앱을 비활성화했습니다.",
|
||||
"app_disabled_video": "관리자가 이벤트 타입에 영향을 미칠 수 있는 {{appName}} 앱을 비활성화했습니다. 위치가 {{appName}} 앱에 대한 이벤트 타입이 있는 경우 기본적으로 Cal Video로 설정됩니다.",
|
||||
"app_disabled_subject": "{{appName}} 앱이 비활성화되었습니다",
|
||||
"navigate_installed_apps": "설치된 앱으로 이동",
|
||||
"disabled_calendar": "다른 캘린더를 설치한 경우 새 예약이 추가됩니다. 그렇지 않은 경우 새로운 예약을 놓치지 않도록 새 캘린더를 연결하십시오.",
|
||||
"enable_apps": "앱 활성화",
|
||||
"enable_apps_description": "사용자가 Cal.com과 통합할 수 있는 앱 활성화",
|
||||
"app_is_enabled": "{{appName}} 앱이 활성화되었습니다",
|
||||
"app_is_disabled": "{{appName}} 앱이 비활성화되었습니다",
|
||||
"keys_have_been_saved": "키가 저장되었습니다",
|
||||
"disable_app": "앱 비활성화",
|
||||
"disable_app_description": "이 앱을 비활성화하면 사용자가 Cal과 상호 작용하는 방식에 문제가 발생할 수 있습니다",
|
||||
"edit_keys": "키 편집",
|
||||
"admin_apps_description": "Cal 인스턴스용 앱 활성화",
|
||||
"no_available_apps": "사용 가능한 앱이 없습니다",
|
||||
"no_available_apps_description": "'packages/app-store' 아래 배포에 앱이 있는지 확인하세요",
|
||||
"no_apps": "Cal의 이 인스턴스에서 활성화된 앱이 없습니다",
|
||||
"apps_settings": "앱 설정",
|
||||
"fill_this_field": "이 필드에 입력하세요",
|
||||
"options": "선택사항",
|
||||
"enter_option": "선택사항 {{index}} 입력",
|
||||
"add_an_option": "선택사항 추가",
|
||||
"radio": "라디오",
|
||||
"event_type_duplicate_copy_text": "{{slug}}-카피",
|
||||
"set_as_default": "기본값으로 설정"
|
||||
}
|
||||
|
||||
@@ -16,8 +16,8 @@
|
||||
"event_request_cancelled": "Uw geplande gebeurtenis is geannuleerd",
|
||||
"organizer": "Organisator",
|
||||
"need_to_reschedule_or_cancel": "Moet u verplaatsen of annuleren?",
|
||||
"cancellation_reason": "Reden voor annulering",
|
||||
"cancellation_reason_placeholder": "Waarom annuleert u? (optioneel)",
|
||||
"cancellation_reason": "Reden voor annulering (optioneel)",
|
||||
"cancellation_reason_placeholder": "Waarom annuleert u?",
|
||||
"rejection_reason": "Reden voor weigering",
|
||||
"rejection_reason_title": "Boekingsverzoek weigeren?",
|
||||
"rejection_reason_description": "Weet u zeker dat u de boeking wilt weigeren? We informeren de persoon die probeerde te boeken. U kunt hieronder een reden opgeven.",
|
||||
@@ -52,6 +52,7 @@
|
||||
"still_waiting_for_approval": "Er is nog een openstaande goedkeuring voor een evenement",
|
||||
"event_is_still_waiting": "Openstaand verzoek voor evenement: {{attendeeName}} - {{date}} - {{eventType}}",
|
||||
"no_more_results": "Geen verdere resultaten",
|
||||
"no_results": "Geen resultaten",
|
||||
"load_more_results": "Meer resultaten laden",
|
||||
"integration_meeting_id": "{{integrationName}} afspraak ID: {{meetingId}}",
|
||||
"confirmed_event_type_subject": "Bevestigd: {{eventType}} met {{name}} op {{date}}",
|
||||
@@ -108,7 +109,7 @@
|
||||
"link_expires": "p.s. De uitnodiging verloopt over {{expiresIn}} uur.",
|
||||
"upgrade_to_per_seat": "Upgraden naar per plaats",
|
||||
"team_upgrade_seats_details": "Van de {{memberCount}} leden in uw team zijn {{unpaidCount}} plaats(en) onbetaald. Voor $ {{seatPrice}}/maand per plaats bedragen de geschatte totale kosten van uw abonnement $ {{totalCost}}/maand.",
|
||||
"team_upgrade_banner_description": "Bedankt voor het testen van ons nieuwe teamabonnement. We hebben gemerkt dat uw team \"{{teamName}}\" moet worden geüpgraded.",
|
||||
"team_upgrade_banner_description": "Bedankt voor het testen van ons nieuwe teamabonnement. We hebben geconstateerd dat uw team \"{{teamName}}\" moet worden geüpgraded.",
|
||||
"team_upgrade_banner_action": "Hier upgraden",
|
||||
"team_upgraded_successfully": "Uw team is geüpgraded!",
|
||||
"use_link_to_reset_password": "Gebruik de onderstaande link om uw wachtwoord te resetten",
|
||||
@@ -248,6 +249,7 @@
|
||||
"add_to_calendar": "Toevoegen aan kalender",
|
||||
"add_another_calendar": "Andere agenda toevoegen",
|
||||
"other": "Overige",
|
||||
"email_sign_in_subject": "Uw aanmeldingslink voor {{appName}}",
|
||||
"emailed_you_and_attendees": "We hebben u en de andere deelnemende een kalender uitnodiging met alle details gestuurd.",
|
||||
"emailed_you_and_attendees_recurring": "We hebben u en de andere deelnemers een agenda-uitnodiging voor de eerste van deze terugkerende gebeurtenissen gestuurd.",
|
||||
"emailed_you_and_any_other_attendees": "U en alle andere deelnemers zijn gemaild met deze informatie.",
|
||||
@@ -419,7 +421,8 @@
|
||||
"forgotten_secret_description": "Als u dit geheim vergeten of verloren bent, kunt u het wijzigen. Maar wees u ervan bewust dat alle integraties die dit geheim gebruiken bijgewerkt moeten worden",
|
||||
"current_incorrect_password": "Uw wachtwoord is verkeerd",
|
||||
"password_hint_caplow": "Mix van hoofd- en kleine letters",
|
||||
"password_hint_min": "Minimaal 7 tekens lang",
|
||||
"password_hint_min": "Minimaal 8 tekens lang",
|
||||
"password_hint_admin_min": "Minimaal 15 tekens lang",
|
||||
"password_hint_num": "Minimaal 1 cijfer bevatten",
|
||||
"invalid_password_hint": "Het wachtwoord moet minimaal 7 tekens lang zijn, minimaal 1 cijfer bevatten en bestaan uit een mix van hoofd- en kleine letters",
|
||||
"incorrect_password": "Uw wachtwoord is incorrect.",
|
||||
@@ -463,11 +466,14 @@
|
||||
"booking_confirmation": "Bevestig uw {{eventTypeTitle}} met {{profileName}}",
|
||||
"booking_reschedule_confirmation": "Opnieuw plannen van uw {{eventTypeTitle}} met {{profileName}}",
|
||||
"in_person_meeting": "Online of persoonlijk afspreken",
|
||||
"attendeeInPerson": "Persoonlijk (adres deelnemer)",
|
||||
"inPerson": "Persoonlijk (adres organisator)",
|
||||
"link_meeting": "Vergadering koppelen",
|
||||
"phone_call": "Telefoonnummer deelnemer",
|
||||
"your_number": "Uw telefoonnummer",
|
||||
"phone_number": "Telefoon nummer",
|
||||
"attendee_phone_number": "Telefoonnummer deelnemer",
|
||||
"organizer_phone_number": "Telefoonnummer organisator",
|
||||
"host_phone_number": "Uw telefoonnummer",
|
||||
"enter_phone_number": "Telefoonnummer",
|
||||
"reschedule": "Boeking wijzigen",
|
||||
@@ -554,6 +560,10 @@
|
||||
"collective": "Collectief",
|
||||
"collective_description": "Plan vergaderingen wanneer alle geselecteerde teamleden beschikbaar zijn.",
|
||||
"duration": "Looptijd",
|
||||
"available_durations": "Beschikbare duur",
|
||||
"default_duration": "Standaardduur",
|
||||
"default_duration_no_options": "Kies eerst de beschikbare duur",
|
||||
"multiple_duration_mins": "{{count}} $t(minute_timeUnit)",
|
||||
"minutes": "Minuten",
|
||||
"round_robin": "Round Robin",
|
||||
"round_robin_description": "Afspraken wisselen tussen meerdere teamleden.",
|
||||
@@ -619,6 +629,7 @@
|
||||
"teams": "Teams",
|
||||
"team": "Team",
|
||||
"team_billing": "Teamfacturatie",
|
||||
"team_billing_description": "Beheer de facturering voor uw team",
|
||||
"upgrade_to_flexible_pro_title": "We hebben het factureren gewijzigd voor teams",
|
||||
"upgrade_to_flexible_pro_message": "Er zijn leden in uw team zonder een plaats. Upgrade uw Pro-abonnement om de ontbrekende plaatsen te dekken.",
|
||||
"changed_team_billing_info": "Vanaf januari 2022 rekenen we per plaats voor teamleden. Leden van uw team die Pro gratis hadden, hebben nu een proefperiode van 14 dagen. Zodra hun proefperiode afloopt, worden deze leden verborgen voor uw team, tenzij u nu upgradet.",
|
||||
@@ -694,6 +705,7 @@
|
||||
"hide_event_type": "Verberg evenement",
|
||||
"edit_location": "Locatie wijzigen",
|
||||
"into_the_future": "in de toekomst",
|
||||
"when_booked_with_less_than_notice": "Wanneer geboekt met minder dan <time></time> kennisgeving",
|
||||
"within_date_range": "Binnen een datumbereik",
|
||||
"indefinitely_into_future": "Voor onbepaalde tijd",
|
||||
"add_new_custom_input_field": "Nieuw invoerveld toevoegen",
|
||||
@@ -713,6 +725,7 @@
|
||||
"delete_account_confirmation_message": "Weet u zeker dat u uw {{appName}}-account wilt verwijderen? Iedereen met wie u uw accountlink gedeeld heeft, kan er niet meer mee boeken en alle voorkeuren die u opgeslagen heeft gaan verloren.",
|
||||
"integrations": "Integraties",
|
||||
"apps": "Apps",
|
||||
"apps_listing": "App-beschrijving",
|
||||
"category_apps": "apps voor {{category}}",
|
||||
"app_store": "App Store",
|
||||
"app_store_description": "Mensen, technologie en de werkplek verbinden.",
|
||||
@@ -736,6 +749,7 @@
|
||||
"toggle_calendars_conflict": "Schakel de agenda's in die u wilt controleren op conflicten om dubbele boekingen te voorkomen.",
|
||||
"select_destination_calendar": "Maak gebeurtenissen aan op",
|
||||
"connect_additional_calendar": "Extra agenda kopppelen",
|
||||
"calendar_updated_successfully": "Agenda bijgewerkt",
|
||||
"conferencing": "Confereren",
|
||||
"calendar": "Agenda",
|
||||
"payments": "Betalingen",
|
||||
@@ -768,6 +782,7 @@
|
||||
"trending_apps": "Trending apps",
|
||||
"explore_apps": "{{category}}-apps",
|
||||
"installed_apps": "Geinstalleerde apps",
|
||||
"free_to_use_apps": "Gratis",
|
||||
"no_category_apps": "Geen apps voor {{category}}",
|
||||
"no_category_apps_description_calendar": "Voeg een agenda-app toe om te controleren op conflicten om dubbele boekingen te voorkomen",
|
||||
"no_category_apps_description_conferencing": "Probeer een conferentieapp toe te voegen om videogesprekken met uw klanten te integreren",
|
||||
@@ -784,7 +799,7 @@
|
||||
"analytics": "Analyse",
|
||||
"empty_installed_apps_headline": "Geen apps geïnstalleerd",
|
||||
"empty_installed_apps_description": "Met apps kunt u uw workflow en uw planning aanzienlijk verbeteren.",
|
||||
"empty_installed_apps_button": "Ontdek de App Store",
|
||||
"empty_installed_apps_button": "Bladeren in App Store",
|
||||
"manage_your_connected_apps": "Beheer uw geïnstalleerde apps of wijzig instellingen",
|
||||
"browse_apps": "Door apps bladeren",
|
||||
"features": "Functies",
|
||||
@@ -806,6 +821,8 @@
|
||||
"verify_wallet": "Wallet verifiëren",
|
||||
"connect_metamask": "Metamasker verbinden",
|
||||
"create_events_on": "Maak gebeurtenissen aan in de",
|
||||
"enterprise_license": "Dit is een bedrijfsfunctie",
|
||||
"enterprise_license_description": "Om deze functie in te schakelen, krijgt u een implementatiesleutel op de {{consoleUrl}}-console en voegt u deze toe aan uw .env als CALCOM_LICENSE_KEY. Als uw team al een licentie heeft, neem dan contact op met {{supportMail}} voor hulp.",
|
||||
"missing_license": "Ontbrekende licentie",
|
||||
"signup_requires": "Commerciële licentie vereist",
|
||||
"signup_requires_description": "{{companyName}} biedt momenteel geen gratis opensourceversie van de registratiepagina aan. Om volledige toegang te krijgen tot de registratieonderdelen moet u een commerciële licentie verkrijgen. Voor persoonlijk gebruik raden we aan om accounts aan te maken op het Prisma Data Platform of een andere Postgres-interface.",
|
||||
@@ -897,6 +914,7 @@
|
||||
"user_impersonation_heading": "Imitatie van gebruiker",
|
||||
"user_impersonation_description": "Hiermee kan ons ondersteuningsteam tijdelijk als u inloggen zodat we eventuele problemen die u aan ons meldt snel op kunnen lossen.",
|
||||
"team_impersonation_description": "Hiermee kunnen uw teamleden zich tijdelijk aanmelden als u.",
|
||||
"allow_booker_to_select_duration": "Booker toestaan om een duur te selecteren",
|
||||
"impersonate_user_tip": "Alle gebruik van deze functie wordt gecontroleerd.",
|
||||
"impersonating_user_warning": "Gebruikersnaam \"{{user}}\" wordt geïmiteerd.",
|
||||
"impersonating_stop_instructions": "<0>Klik hier om te stoppen</0>.",
|
||||
@@ -1014,6 +1032,9 @@
|
||||
"error_removing_app": "Fout bij het verwijderen van de app",
|
||||
"web_conference": "Webconferentie",
|
||||
"requires_confirmation": "Vereist bevestiging",
|
||||
"always_requires_confirmation": "Altijd",
|
||||
"requires_confirmation_threshold": "Vereist bevestiging als geboekt met < {{time}} $t({{unit}}_timeUnit) kennisgeving",
|
||||
"may_require_confirmation": "Kan bevestiging vereisen",
|
||||
"nr_event_type_one": "{{count}} gebeurtenistype",
|
||||
"nr_event_type_other": "{{count}} gebeurtenistypen",
|
||||
"add_action": "Actie toevoegen",
|
||||
@@ -1101,6 +1122,9 @@
|
||||
"event_limit_tab_description": "Hoe vaak u geboekt kunt worden",
|
||||
"event_advanced_tab_description": "Agenda-instellingen en meer...",
|
||||
"event_advanced_tab_title": "Geavanceerd",
|
||||
"event_setup_multiple_duration_error": "Gebeurtenisconfiguratie: voor meerdere duren is minimaal 1 optie vereist.",
|
||||
"event_setup_multiple_duration_default_error": "Gebeurtenisconfiguratie: selecteer een geldige standaardduur.",
|
||||
"event_setup_booking_limits_error": "Reserveringslimieten moeten in oplopende volgorde zijn. [dag, week, maand, jaar]",
|
||||
"select_which_cal": "Selecteer aan welke agenda u boekingen wilt toevoegen",
|
||||
"custom_event_name": "Aangepaste gebeurtenisnaam",
|
||||
"custom_event_name_description": "Maak aangepaste gebeurtenisnamen om weer te geven op agendagebeurtenissen",
|
||||
@@ -1154,8 +1178,11 @@
|
||||
"invoices": "Facturen",
|
||||
"embeds": "Ingesloten opties",
|
||||
"impersonation": "Imitatie",
|
||||
"impersonation_description": "Instellingen voor imitatie van gebruiker beheren",
|
||||
"users": "Gebruikers",
|
||||
"profile_description": "Beheer de instellingen van uw {{appName}}-profiel",
|
||||
"users_description": "Hier vindt u een lijst met alle gebruikers",
|
||||
"users_listing": "Gebruikersbeschrijving",
|
||||
"general_description": "Beheer de instellingen voor uw taal en tijdzone",
|
||||
"calendars_description": "Configureer hoe uw typen gebeurtenissen samenwerken met uw agenda's",
|
||||
"appearance_description": "Beheer de instellingen voor uw boekingsweergave",
|
||||
@@ -1360,6 +1387,7 @@
|
||||
"number_sms_notifications": "Telefoonnummer (sms-meldingen)",
|
||||
"attendee_email_workflow": "E-mailadres deelnemer",
|
||||
"attendee_email_info": "Het e-mailadres van de persoon die boekt",
|
||||
"kbar_search_placeholder": "Typ een opdracht of zoek...",
|
||||
"invalid_credential": "Oh nee! Het lijkt erop dat de machtiging is verlopen of is ingetrokken. Installeer het opnieuw.",
|
||||
"choose_common_schedule_team_event": "Kies een gemeenschappelijke planning",
|
||||
"choose_common_schedule_team_event_description": "Schakel dit in als u een gemeenschappelijke planning tussen organisatoren wilt gebruiken. Indien uitgeschakeld, wordt elke organisator geboekt op basis van zijn standaardplanning.",
|
||||
@@ -1370,5 +1398,43 @@
|
||||
"test_preview": "Voorbeeld testen",
|
||||
"route_to": "Routeren naar",
|
||||
"test_preview_description": "Test uw routeringsformulier zonder gegevens te versturen",
|
||||
"test_routing": "Routering testen"
|
||||
"test_routing": "Routering testen",
|
||||
"payment_app_disabled": "Een beheerder heeft een betaalapp uitgeschakeld",
|
||||
"edit_event_type": "Gebeurtenistype bewerken",
|
||||
"collective_scheduling": "Collectieve planning",
|
||||
"make_it_easy_to_book": "Maak het gemakkelijk om uw team te boeken wanneer iedereen beschikbaar is.",
|
||||
"find_the_best_person": "Zoek de beste beschikbare persoon en blader door uw team.",
|
||||
"fixed_round_robin": "Vaste round robin",
|
||||
"add_one_fixed_attendee": "Voeg één vaste deelnemer en round robin toe via een aantal deelnemers.",
|
||||
"calcom_is_better_with_team": "Cal.com is beter met teams",
|
||||
"add_your_team_members": "Voeg uw teamleden toe aan uw gebeurtenistypes. Gebruik collectieve planning om iedereen op te nemen of zoek de meest geschikte persoon met round robin-planning.",
|
||||
"booking_limit_reached": "Boekingslimiet voor dit gebeurtenistype is bereikt",
|
||||
"admin_has_disabled": "Een beheerder heeft {{appName}} uitgeschakeld",
|
||||
"disabled_app_affects_event_type": "Een beheerder heeft {{appName}} uitgeschakeld die van invloed is op uw gebeurtenistype {{eventType}}",
|
||||
"disable_payment_app": "De beheerder heeft {{appName}} uitgeschakeld die van invloed is op uw gebeurtenistype {{title}}. Deelnemers kunnen dit tyoe gebeurtenissen nog steeds boeken, maar worden niet gevraagd te betalen. U kunt het gebeurtenistype verbergen om dit te voorkomen totdat uw beheerde de betaalmethode opnieuw inschakelt.",
|
||||
"payment_disabled_still_able_to_book": "Deelnemers kunnen dit type gebeurtenis nog steeds boeken, maar worden niet gevraagd te betalen. U kunt het gebeurtenistype verbergen om dit te voorkomen totdat uw beheerde de betaalmethode opnieuw inschakelt.",
|
||||
"app_disabled_with_event_type": "De beheerder heeft {{appName}} uitgeschakeld die van invloed is op uw gebeurtenistype {{title}}.",
|
||||
"app_disabled_video": "De beheerde heeft {{appName}} uitgeschakeld, wat van invloed kan zijn op uw gebeurtenistypes. Als u gebeurtenistypes heeft met {{appName}} als locatie, is het standaard Cal Video.",
|
||||
"app_disabled_subject": "{{appName}} is uitgeschakeld",
|
||||
"navigate_installed_apps": "Naar geïnstalleerde apps",
|
||||
"disabled_calendar": "Als u een andere agenda heeft geïnstalleerd, worden nieuwe boekingen daaraan toegevoegd. Zo niet, koppel dan een nieuwe agenda zodat u geen nieuwe boekingen mist.",
|
||||
"enable_apps": "Apps inschakelen",
|
||||
"enable_apps_description": "Schakel apps in die gebruikers kunnen integreren met Cal.com",
|
||||
"app_is_enabled": "{{appName}} is ingeschakeld",
|
||||
"app_is_disabled": "{{appName}} is uitgeschakeld",
|
||||
"keys_have_been_saved": "Sleutels zijn opgeslagen",
|
||||
"disable_app": "App uitschakelen",
|
||||
"disable_app_description": "Het uitschakelen van deze app kan problemen veroorzaken met de interactie tussen uw gebruikers en Cal",
|
||||
"edit_keys": "Sleutels bewerken",
|
||||
"no_available_apps": "Er zijn geen beschikbare apps",
|
||||
"no_available_apps_description": "Zorg ervoor dat er apps zijn in uw implementatie onder \"packages/app-store\"",
|
||||
"no_apps": "Er zijn geen apps ingeschakeld in dit exemplaar van Cal",
|
||||
"apps_settings": "Apps-instellingen",
|
||||
"fill_this_field": "Vul dit veld in",
|
||||
"options": "Opties",
|
||||
"enter_option": "Voer optie {{index}} in",
|
||||
"add_an_option": "Voeg een optie toe",
|
||||
"radio": "Radio",
|
||||
"event_type_duplicate_copy_text": "{{slug}}-kopie",
|
||||
"set_as_default": "Als standaard instellen"
|
||||
}
|
||||
|
||||
@@ -52,6 +52,7 @@
|
||||
"still_waiting_for_approval": "Wydarzenie nadal oczekuje na zatwierdzenie",
|
||||
"event_is_still_waiting": "Prośba o wydarzenie nadal czeka: {{attendeeName}} - {{date}} - {{eventType}}",
|
||||
"no_more_results": "Brak więcej wyników",
|
||||
"no_results": "Brak wyników",
|
||||
"load_more_results": "Wczytaj więcej wyników",
|
||||
"integration_meeting_id": "{{integrationName}} ID spotkania: {{meetingId}}",
|
||||
"confirmed_event_type_subject": "Potwierdzono: {{eventType}} z {{name}} w {{date}}",
|
||||
@@ -248,6 +249,7 @@
|
||||
"add_to_calendar": "Dodaj do kalendarza",
|
||||
"add_another_calendar": "Dodaj kolejny kalendarz",
|
||||
"other": "Inne",
|
||||
"email_sign_in_subject": "Twój link logowania do aplikacji {{appName}}",
|
||||
"emailed_you_and_attendees": "Wysłaliśmy Ci i innym uczestnikom zaproszenie do kalendarza ze wszystkimi szczegółami.",
|
||||
"emailed_you_and_attendees_recurring": "Wysłaliśmy Ci oraz innym uczestnikom zaproszenie do kalendarza dotyczące pierwszego z tych cyklicznych wydarzeń.",
|
||||
"emailed_you_and_any_other_attendees": "Ty i inni uczestnicy dostali e-mail z tymi informacjami.",
|
||||
@@ -420,6 +422,7 @@
|
||||
"current_incorrect_password": "Bieżące hasło jest nieprawidłowe",
|
||||
"password_hint_caplow": "Kombinacja wielkich i małych liter",
|
||||
"password_hint_min": "Długość co najmniej 8 znaków",
|
||||
"password_hint_admin_min": "Długość co najmniej 15 znaków",
|
||||
"password_hint_num": "Zawrzyj co najmniej 1 cyfrę",
|
||||
"invalid_password_hint": "Hasło musi składać się z co najmniej 7 znaków, zawierać co najmniej jedną cyfrę oraz kombinację wielkich i małych liter",
|
||||
"incorrect_password": "Hasło jest nieprawidłowe.",
|
||||
@@ -463,11 +466,14 @@
|
||||
"booking_confirmation": "Potwierdź {{eventTypeTitle}} z {{profileName}}",
|
||||
"booking_reschedule_confirmation": "Przełóż Twój {{eventTypeTitle}} z {{profileName}}",
|
||||
"in_person_meeting": "Link lub spotkanie osób",
|
||||
"attendeeInPerson": "Osobiście (adres uczestnika)",
|
||||
"inPerson": "Osobiście (adres organizatora)",
|
||||
"link_meeting": "Link do spotkania",
|
||||
"phone_call": "Numer telefonu uczestnika",
|
||||
"your_number": "Twój numer telefonu",
|
||||
"phone_number": "Numer telefonu",
|
||||
"attendee_phone_number": "Numer telefonu uczestnika",
|
||||
"organizer_phone_number": "Numer telefonu organizatora",
|
||||
"host_phone_number": "Twój numer telefonu",
|
||||
"enter_phone_number": "Podaj numer telefonu",
|
||||
"reschedule": "Przełóż",
|
||||
@@ -554,6 +560,10 @@
|
||||
"collective": "Zbiór",
|
||||
"collective_description": "Zaplanuj spotkania, gdy wszyscy wybrani członkowie zespołu są dostępni.",
|
||||
"duration": "Czas trwania",
|
||||
"available_durations": "Dostępne czasy trwania",
|
||||
"default_duration": "Domyślny czas trwania",
|
||||
"default_duration_no_options": "Proszę najpierw wybrać dostępne czasy trwania",
|
||||
"multiple_duration_mins": "{{count}} $t(minute_timeUnit)",
|
||||
"minutes": "Minuty",
|
||||
"round_robin": "Round Robin",
|
||||
"round_robin_description": "Cykl spotkań między wieloma członkami zespołu.",
|
||||
@@ -619,6 +629,7 @@
|
||||
"teams": "Drużyny",
|
||||
"team": "Zespół",
|
||||
"team_billing": "Rozliczenie zespołu",
|
||||
"team_billing_description": "Zarządzaj rozliczeniami swojego zespołu",
|
||||
"upgrade_to_flexible_pro_title": "Zmieniliśmy rozliczenie dla zespołów",
|
||||
"upgrade_to_flexible_pro_message": "W twoim zespole nie ma miejsca. Ulepsz swój plan pro aby pokryć brakujące miejsca.",
|
||||
"changed_team_billing_info": "Od stycznia 2022 r. obciążamy członków zespołu opłatami za miejsce. Członkowie zespołu, którzy mieli PRO za darmo są teraz w 14-dniowym okresie próbnym. Po wygaśnięciu okresu próbnego członkowie ci zostaną ukryci przed Twoim zespołem, chyba że ulepszysz teraz.",
|
||||
@@ -694,6 +705,7 @@
|
||||
"hide_event_type": "Ukryj typ zdarzenia",
|
||||
"edit_location": "Edytuj lokalizację",
|
||||
"into_the_future": "w przyszłość",
|
||||
"when_booked_with_less_than_notice": "W przypadku rezerwacji z wyprzedzeniem krótszym niż <time></time>",
|
||||
"within_date_range": "W zakresie dat",
|
||||
"indefinitely_into_future": "Na czas nieokreślony w przyszłości",
|
||||
"add_new_custom_input_field": "Dodaj nowe niestandardowe pole wprowadzania",
|
||||
@@ -713,6 +725,7 @@
|
||||
"delete_account_confirmation_message": "Czy na pewno chcesz usunąć swój {{appName}}. umówić konto? Każdy, kto udostępnił link do Twojego konta, nie będzie już mógł zarezerwować za jego pomocą i wszystkie zapisane preferencje zostaną utracone.",
|
||||
"integrations": "Integracje",
|
||||
"apps": "Aplikacje",
|
||||
"apps_listing": "Informacje o aplikacji",
|
||||
"category_apps": "Aplikacje z kategorii {{category}}",
|
||||
"app_store": "Sklep App Store",
|
||||
"app_store_description": "Łączymy ludzi, technologię i miejsca pracy.",
|
||||
@@ -736,6 +749,7 @@
|
||||
"toggle_calendars_conflict": "Przełącz kalendarze, które chcesz sprawdzić pod kątem konfliktów, aby uniknąć podwójnych rezerwacji.",
|
||||
"select_destination_calendar": "Utwórz wydarzenia na",
|
||||
"connect_additional_calendar": "Połącz dodatkowy kalendarz",
|
||||
"calendar_updated_successfully": "Kalendarz został pomyślnie zaktualizowany",
|
||||
"conferencing": "Konferencja",
|
||||
"calendar": "Kalendarz",
|
||||
"payments": "Płatności",
|
||||
@@ -768,6 +782,7 @@
|
||||
"trending_apps": "Popularne aplikacje",
|
||||
"explore_apps": "Aplikacje z kategorii {{category}}",
|
||||
"installed_apps": "Zainstalowane aplikacje",
|
||||
"free_to_use_apps": "Darmowe",
|
||||
"no_category_apps": "Brak aplikacji z kategorii {{category}}",
|
||||
"no_category_apps_description_calendar": "Dodaj aplikację kalendarza, aby wykrywać konflikty i unikać podwójnych rezerwacji",
|
||||
"no_category_apps_description_conferencing": "Dodaj aplikację konferencyjną, aby uzyskać możliwość nawiązywania połączeń wideo z klientami.",
|
||||
@@ -806,6 +821,8 @@
|
||||
"verify_wallet": "Zweryfikuj portfel",
|
||||
"connect_metamask": "Podłącz Metamask",
|
||||
"create_events_on": "Utwórz wydarzenia w",
|
||||
"enterprise_license": "To funkcja dla przedsiębiorstw",
|
||||
"enterprise_license_description": "Aby włączyć tę funkcję, uzyskaj klucz wdrożenia na konsoli {{consoleUrl}} i dodaj go do swojego pliku .env jako CALCOM_LICENSE_KEY. Jeśli Twój zespół ma już licencję, napisz na adres {{supportMail}}, aby uzyskać pomoc.",
|
||||
"missing_license": "Brakująca licencja",
|
||||
"signup_requires": "Wymagana licencja handlowa",
|
||||
"signup_requires_description": "{{companyName}} obecnie nie oferuje darmowej otwartej wersji strony rejestracji. Aby uzyskać pełny dostęp do komponentów rejestracji, musisz zdobyć licencję komercyjną. Do użytku osobistego zalecamy platformę danych Prisma lub jakikolwiek inny interfejs Postgres do tworzenia kont.",
|
||||
@@ -897,6 +914,7 @@
|
||||
"user_impersonation_heading": "Podszywanie się pod użytkownika",
|
||||
"user_impersonation_description": "Pozwala naszemu zespołowi pomocy na tymczasowe zalogowanie się jako użytkownik w celu szybkiego rozwiązania wszelkich zgłaszanych nam problemów.",
|
||||
"team_impersonation_description": "Umożliwia administratorom Twojego zespołu tymczasowe logowanie się jako Ty.",
|
||||
"allow_booker_to_select_duration": "Zezwól rezerwującemu na wybranie czasu trwania",
|
||||
"impersonate_user_tip": "Wszystkie przypadki użycia tej funkcji są kontrolowane.",
|
||||
"impersonating_user_warning": "Podszywanie się pod użytkownika „{{user}}”.",
|
||||
"impersonating_stop_instructions": "<0>Kliknij tutaj, aby zatrzymać</0>.",
|
||||
@@ -1014,6 +1032,9 @@
|
||||
"error_removing_app": "Błąd podczas usuwania aplikacji",
|
||||
"web_conference": "Konferencja internetowa",
|
||||
"requires_confirmation": "Wymaga potwierdzenia",
|
||||
"always_requires_confirmation": "Zawsze",
|
||||
"requires_confirmation_threshold": "Wymaga potwierdzenia w przypadku rezerwacji z wyprzedzeniem < {{time}} $t({{unit}}_timeUnit)",
|
||||
"may_require_confirmation": "Może wymagać potwierdzenia",
|
||||
"nr_event_type_one": "Liczba typów wydarzenia: {{count}}",
|
||||
"nr_event_type_other": "Liczba typów wydarzenia: {{count}}",
|
||||
"add_action": "Dodaj czynność",
|
||||
@@ -1101,6 +1122,9 @@
|
||||
"event_limit_tab_description": "Jak często można rezerwować Twoje usługi",
|
||||
"event_advanced_tab_description": "Ustawienia kalendarza i więcej...",
|
||||
"event_advanced_tab_title": "Zaawansowane",
|
||||
"event_setup_multiple_duration_error": "Konfiguracja wydarzeń: wiele czasów trwania wymaga co najmniej 1 opcji.",
|
||||
"event_setup_multiple_duration_default_error": "Konfiguracja wydarzenia: wybierz prawidłowy domyślny czas trwania.",
|
||||
"event_setup_booking_limits_error": "Limity rezerwacji muszą być podane w kolejności rosnącej. [dzień,tydzień,miesiąc,rok]",
|
||||
"select_which_cal": "Wybierz kalendarz, do którego chcesz dodać rezerwacje.",
|
||||
"custom_event_name": "Niestandardowa nazwa wydarzenia",
|
||||
"custom_event_name_description": "Utwórz niestandardowe nazwy wydarzeń, które będą wyświetlać się w kalendarzu wydarzeń.",
|
||||
@@ -1154,8 +1178,11 @@
|
||||
"invoices": "Faktury",
|
||||
"embeds": "Osadzenia",
|
||||
"impersonation": "Podszywanie się",
|
||||
"impersonation_description": "Ustawienia do zarządzania podszywaniem się pod użytkownika",
|
||||
"users": "Użytkownicy",
|
||||
"profile_description": "Zarządzaj ustawieniami swojego profilu {{appName}}",
|
||||
"users_description": "Tutaj znajdziesz listę wszystkich użytkowników",
|
||||
"users_listing": "Lista użytkowników",
|
||||
"general_description": "Zarządzaj ustawieniami języka i strefy czasowej.",
|
||||
"calendars_description": "Skonfiguruj sposoby interakcji typów wydarzeń z kalendarzami",
|
||||
"appearance_description": "Zarządzaj ustawieniami wyglądu rezerwacji",
|
||||
@@ -1360,6 +1387,7 @@
|
||||
"number_sms_notifications": "Numer telefonu (powiadomienia SMS)",
|
||||
"attendee_email_workflow": "Adres e-mail uczestnika",
|
||||
"attendee_email_info": "Adres e-mail osoby rezerwującej",
|
||||
"kbar_search_placeholder": "Wpisz polecenie lub wyszukaj...",
|
||||
"invalid_credential": "O nie! Wygląda na to, że uprawnienia wygasły lub zostały cofnięte. Zainstaluj aplikację ponownie.",
|
||||
"choose_common_schedule_team_event": "Wybierz wspólny harmonogram",
|
||||
"choose_common_schedule_team_event_description": "Włącz tę opcję, jeśli chcesz używać wspólnego harmonogramu gospodarzy. Jeśli ją wyłączysz, rezerwacje u każdego gospodarza będą dokonywane na podstawie jego domyślnego harmonogramu.",
|
||||
@@ -1370,5 +1398,43 @@
|
||||
"test_preview": "Przetestuj podgląd",
|
||||
"route_to": "Przekieruj do",
|
||||
"test_preview_description": "Przetestuj swój formularz przekierowania bez przesyłania jakichkolwiek danych",
|
||||
"test_routing": "Przetestuj przekierowanie"
|
||||
"test_routing": "Przetestuj przekierowanie",
|
||||
"payment_app_disabled": "Administrator wyłączył aplikację płatniczą",
|
||||
"edit_event_type": "Edytuj typ wydarzenia",
|
||||
"collective_scheduling": "Zbiorowe ustalanie harmonogramu",
|
||||
"make_it_easy_to_book": "Uprość rezerwację zespołu, gdy wszyscy są dostępni.",
|
||||
"find_the_best_person": "Znajdź najlepszą dostępną osobę i przejrzyj listę członków swojego zespołu.",
|
||||
"fixed_round_robin": "Stały algorytm karuzelowy",
|
||||
"add_one_fixed_attendee": "Dodaj jednego stałego uczestnika i przeglądaj uczestników zgodnie z algorytmem karuzelowym",
|
||||
"calcom_is_better_with_team": "Usługa Cal.com jest lepsza z zespołami",
|
||||
"add_your_team_members": "Dodaj członków zespołu do typów wydarzeń. Użyj zbiorowego ustalania harmonogramu, aby uwzględnić wszystkich, lub znajdź najodpowiedniejszą osobę za pomocą algorytmu karuzelowego.",
|
||||
"booking_limit_reached": "Osiągnięto limit rezerwacji tego typu wydarzenia",
|
||||
"admin_has_disabled": "Administrator wyłączył aplikację {{appName}}",
|
||||
"disabled_app_affects_event_type": "Administrator wyłączył aplikację {{appName}}, która ma wpływ na Twój typ wydarzenia ({{eventType}})",
|
||||
"disable_payment_app": "Administrator wyłączył aplikację {{appName}}, która ma wpływ na Twój typ wydarzenia ({{title}}). Uczestnicy nadal mogą rezerwować wydarzenie tego typu, ale nie zostaną poproszeni o płatność. Możesz ukryć ten typ wydarzenia, aby temu zapobiec, póki administrator nie uruchomi ponownie Twojej metody płatności.",
|
||||
"payment_disabled_still_able_to_book": "Uczestnicy nadal mogą rezerwować wydarzenie tego typu, ale nie zostaną poproszeni o płatność. Możesz ukryć ten typ wydarzenia, aby temu zapobiec, póki administrator nie uruchomi ponownie Twojej metody płatności.",
|
||||
"app_disabled_with_event_type": "Administrator wyłączył aplikację {{appName}}, która ma wpływ na Twój typ wydarzenia ({{title}}).",
|
||||
"app_disabled_video": "Administrator wyłączył aplikację {{appName}}, która może mieć wpływ na Twoje typy wydarzeń. Jeśli masz typy wydarzeń z aplikacją {{appName}} jako lokalizacją, domyślnym wyborem będzie wideo w usłudze Cal.",
|
||||
"app_disabled_subject": "Aplikacja {{appName}} została wyłączona",
|
||||
"navigate_installed_apps": "Przejdź do zainstalowanych aplikacji",
|
||||
"disabled_calendar": "Jeśli masz zainstalowany inny kalendarz, nowe rezerwacje zostaną dodane do niego. Jeśli nie, podłącz nowy kalendarz, aby nie przegapić żadnych nowych rezerwacji.",
|
||||
"enable_apps": "Włącz aplikacje",
|
||||
"enable_apps_description": "Włącz aplikacje, które użytkownicy mogą zintegrować z usługą Cal.com",
|
||||
"app_is_enabled": "Aplikacja {{appName}} jest włączona",
|
||||
"app_is_disabled": "Aplikacja {{appName}} jest wyłączona",
|
||||
"keys_have_been_saved": "Klucze zostały zapisane",
|
||||
"disable_app": "Wyłącz aplikację",
|
||||
"disable_app_description": "Wyłączenie tej aplikacji może spowodować problemy z korzystaniem z usługi Cal dla Twoich użytkowników",
|
||||
"edit_keys": "Edytuj klucze",
|
||||
"no_available_apps": "Brak dostępnych aplikacji",
|
||||
"no_available_apps_description": "Upewnij się, że w Twoim wdrożeniu w folderze „packages/app-store” znajdują są aplikacje.",
|
||||
"no_apps": "W tym wystąpieniu usługi Cal nie ma włączonych aplikacji",
|
||||
"apps_settings": "Ustawienia aplikacji",
|
||||
"fill_this_field": "Wypełnij to pole",
|
||||
"options": "Opcje",
|
||||
"enter_option": "Wprowadź opcję {{index}}",
|
||||
"add_an_option": "Dodaj opcję",
|
||||
"radio": "Przycisk radiowy",
|
||||
"event_type_duplicate_copy_text": "{{slug}}-kopia",
|
||||
"set_as_default": "Ustaw jako domyślne"
|
||||
}
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
"organizer": "Organizador",
|
||||
"need_to_reschedule_or_cancel": "Precisa reagendar ou cancelar?",
|
||||
"cancellation_reason": "Motivo do cancelamento",
|
||||
"cancellation_reason_placeholder": "Por que você está cancelando? (opcional)",
|
||||
"cancellation_reason_placeholder": "Por que você está cancelando?",
|
||||
"rejection_reason": "Motivo da recusa",
|
||||
"rejection_reason_title": "Recusar a solicitação de reserva?",
|
||||
"rejection_reason_description": "Tem certeza de que deseja recusar a reserva? Avisaremos a pessoa que tentou reservar. Se quiser, informe um motivo abaixo.",
|
||||
@@ -52,6 +52,7 @@
|
||||
"still_waiting_for_approval": "Um evento ainda aguarda aprovação",
|
||||
"event_is_still_waiting": "Solicitação de evento pendente: {{attendeeName}} - {{date}} - {{eventType}}",
|
||||
"no_more_results": "Não existem mais resultados",
|
||||
"no_results": "Nenhum resultado",
|
||||
"load_more_results": "Carregar mais resultados",
|
||||
"integration_meeting_id": "ID da reunião de {{integrationName}}: {{meetingId}}",
|
||||
"confirmed_event_type_subject": "Confirmado: {{eventType}} com {{name}} em {{date}}",
|
||||
@@ -248,6 +249,7 @@
|
||||
"add_to_calendar": "Adicionar ao calendário",
|
||||
"add_another_calendar": "Adicionar outro calendário",
|
||||
"other": "Outras",
|
||||
"email_sign_in_subject": "Seu link de login para {{appName}}",
|
||||
"emailed_you_and_attendees": "Enviamos um email para você e para os outros participantes com um convite de calendário com todos os detalhes.",
|
||||
"emailed_you_and_attendees_recurring": "Enviamos um e-mail para você e para os outros participantes com um convite de calendário para o primeiro desses eventos recorrentes.",
|
||||
"emailed_you_and_any_other_attendees": "Esta informação foi enviada para você e para todos os outros participantes.",
|
||||
@@ -419,7 +421,7 @@
|
||||
"forgotten_secret_description": "Caso tenha perdido ou esquecido o segredo, você poderá alterá-lo. Mas fique ciente de que todas as integrações com esse segredo precisarão ser atualizadas",
|
||||
"current_incorrect_password": "Senha atual está incorreta",
|
||||
"password_hint_caplow": "Mistura de letras maiúsculas e minúsculas",
|
||||
"password_hint_min": "Mínimo de sete caracteres",
|
||||
"password_hint_min": "Mínimo de oito caracteres",
|
||||
"password_hint_admin_min": "No mínimo 15 caracteres",
|
||||
"password_hint_num": "Contém pelo menos um número",
|
||||
"invalid_password_hint": "A senha precisa ter pelo menos sete caracteres com pelo menos um número e ser uma combinação de letras maiúsculas e minúsculas",
|
||||
@@ -464,11 +466,14 @@
|
||||
"booking_confirmation": "Confirme seu {{eventTypeTitle}} com {{profileName}}",
|
||||
"booking_reschedule_confirmation": "Reagende seu {{eventTypeTitle}} com {{profileName}}",
|
||||
"in_person_meeting": "Reunião presencial",
|
||||
"attendeeInPerson": "Pessoalmente (endereço do participante)",
|
||||
"inPerson": "Pessoalmente (endereço do organizador)",
|
||||
"link_meeting": "Vincular reunião",
|
||||
"phone_call": "Número de telefone do participante",
|
||||
"your_number": "Seu número de telefone",
|
||||
"phone_number": "Número de Telefone",
|
||||
"attendee_phone_number": "Número de telefone do participante",
|
||||
"organizer_phone_number": "Número de telefone do organizador",
|
||||
"host_phone_number": "Seu número de telefone",
|
||||
"enter_phone_number": "Digite o número de telefone",
|
||||
"reschedule": "Reagendar",
|
||||
@@ -555,6 +560,10 @@
|
||||
"collective": "Coletivo",
|
||||
"collective_description": "Agende reuniões quando todos os membros selecionados do time estiverem disponíveis.",
|
||||
"duration": "Duração",
|
||||
"available_durations": "Durações disponíveis",
|
||||
"default_duration": "Duração padrão",
|
||||
"default_duration_no_options": "Escolha as durações disponíveis primeiro",
|
||||
"multiple_duration_mins": "{{count}} $t(minute_timeUnit)",
|
||||
"minutes": "Minutos",
|
||||
"round_robin": "Round Robin",
|
||||
"round_robin_description": "Reuniões recorrentes entre vários membros da equipe.",
|
||||
@@ -620,6 +629,7 @@
|
||||
"teams": "Times",
|
||||
"team": "Equipe",
|
||||
"team_billing": "Cobrança da equipe",
|
||||
"team_billing_description": "Gerenciar cobrança para sua equipe",
|
||||
"upgrade_to_flexible_pro_title": "Alteramos a cobrança para equipes",
|
||||
"upgrade_to_flexible_pro_message": "Há membros da sua equipe que não têm assento. Atualize para o plano Pro para incluir os assentos faltando.",
|
||||
"changed_team_billing_info": "A partir de janeiro de 2022, a cobrança dos membros de equipe será realizada por assento. Os membros da sua equipe que tinham o plano PRO gratuito receberam um teste de 14 dias. Ao fim do teste, eles serão ocultos da sua equipe, a não ser que você atualize agora.",
|
||||
@@ -695,6 +705,7 @@
|
||||
"hide_event_type": "Ocultar Tipo de Evento",
|
||||
"edit_location": "Editar Localização",
|
||||
"into_the_future": "no futuro",
|
||||
"when_booked_with_less_than_notice": "Reserva feita com menos de <time></time> de antecedência",
|
||||
"within_date_range": "Dentro de um período",
|
||||
"indefinitely_into_future": "Indefinidamente no futuro",
|
||||
"add_new_custom_input_field": "Adicionar novo campo personalizado",
|
||||
@@ -714,6 +725,7 @@
|
||||
"delete_account_confirmation_message": "Você tem certeza de que deseja apagar sua conta {{appName}}? Qualquer pessoa que você compartilhou seu link de reservas não poderá mais utilizá-lo para agendar novos eventos e todas as suas preferências serão perdidas.",
|
||||
"integrations": "Integrações",
|
||||
"apps": "Apps",
|
||||
"apps_listing": "Listagem de aplicativos",
|
||||
"category_apps": "Aplicativos de {{category}}",
|
||||
"app_store": "App Store",
|
||||
"app_store_description": "Conectando pessoas, tecnologia e o ambiente de trabalho.",
|
||||
@@ -737,6 +749,7 @@
|
||||
"toggle_calendars_conflict": "Ative/desative os calendários que você quiser para verificar conflitos e evitar reservas repetidas.",
|
||||
"select_destination_calendar": "Criar eventos em",
|
||||
"connect_additional_calendar": "Conectar calendário adicional",
|
||||
"calendar_updated_successfully": "Calendário atualizado com êxito",
|
||||
"conferencing": "Conferência",
|
||||
"calendar": "Calendário",
|
||||
"payments": "Pagamentos",
|
||||
@@ -769,6 +782,7 @@
|
||||
"trending_apps": "Apps em alta",
|
||||
"explore_apps": "{{category}} aplicativos",
|
||||
"installed_apps": "Apps instalados",
|
||||
"free_to_use_apps": "Grátis",
|
||||
"no_category_apps": "Sem aplicativos de {{category}}",
|
||||
"no_category_apps_description_calendar": "Adicione um aplicativo de calendário para verificar se há conflitos para evitar agendamentos duplos",
|
||||
"no_category_apps_description_conferencing": "Tente adicionar um aplicativo de conferência para integrar chamadas de vídeo com seus clientes",
|
||||
@@ -807,6 +821,8 @@
|
||||
"verify_wallet": "Verificar carteira",
|
||||
"connect_metamask": "Conecte o Metamask",
|
||||
"create_events_on": "Criar eventos em",
|
||||
"enterprise_license": "Este não é um recurso corporativo",
|
||||
"enterprise_license_description": "Para ativar este recurso, obtenha uma chave de desenvolvimento no console {{consoleUrl}} e adicione ao seu .env como CALCOM_LICENSE_KEY. Caso sua equipe já tenha uma licença, entre em contato com {{supportMail}} para obter ajuda.",
|
||||
"missing_license": "Falta a licença",
|
||||
"signup_requires": "Licença comercial obrigatória",
|
||||
"signup_requires_description": "Atualmente a {{companyName}} não oferece nenhuma versão gratuita de código aberto da página de inscrição. Para obter acesso completo aos componentes da inscrição, você precisa adquirir uma licença comercial. Para uso pessoal, recomendamos o Prisma Data Platform ou outras interfaces em Postgres para criação de contas.",
|
||||
@@ -898,6 +914,7 @@
|
||||
"user_impersonation_heading": "Representação do usuário",
|
||||
"user_impersonation_description": "Permite que a nossa equipe de suporte entre temporariamente como você para ajudar a resolver rapidamente os problemas relatados.",
|
||||
"team_impersonation_description": "Permite que os administradores da sua equipe façam login como você.",
|
||||
"allow_booker_to_select_duration": "Permitir que o reservante selecione a duração",
|
||||
"impersonate_user_tip": "Todos os usos desse recurso são auditados.",
|
||||
"impersonating_user_warning": "Representando o nome de usuário \"{{user}}\".",
|
||||
"impersonating_stop_instructions": "<0>Clique aqui para parar</0>.",
|
||||
@@ -1015,6 +1032,9 @@
|
||||
"error_removing_app": "Erro ao remover o aplicativo",
|
||||
"web_conference": "Conferência via web",
|
||||
"requires_confirmation": "Requer confirmação",
|
||||
"always_requires_confirmation": "Sempre",
|
||||
"requires_confirmation_threshold": "Requer confirmação caso a reserva seja feita com menos de {{time}} $t({{unit}}_timeUnit) de antecedência",
|
||||
"may_require_confirmation": "Pode exigir confirmação",
|
||||
"nr_event_type_one": "{{count}} tipo de evento",
|
||||
"nr_event_type_other": "{{count}} tipos de evento",
|
||||
"add_action": "Adicionar ação",
|
||||
@@ -1102,6 +1122,9 @@
|
||||
"event_limit_tab_description": "Com que frequência você pode receber reserva",
|
||||
"event_advanced_tab_description": "Configurações de calendário e muito mais...",
|
||||
"event_advanced_tab_title": "Avançado",
|
||||
"event_setup_multiple_duration_error": "Configuração do evento: múltiplas durações requerem pelo menos uma opção.",
|
||||
"event_setup_multiple_duration_default_error": "Configuração de evento: selecione uma duração padrão válida.",
|
||||
"event_setup_booking_limits_error": "Limites de reserva devem estar em ordem crescente. [dia, semana, mês, ano,]",
|
||||
"select_which_cal": "Selecione para qual calendário adicionar reservas",
|
||||
"custom_event_name": "Nome de evento personalizado",
|
||||
"custom_event_name_description": "Criar nomes de eventos personalizados para exibir no evento do calendário",
|
||||
@@ -1155,8 +1178,11 @@
|
||||
"invoices": "Faturas",
|
||||
"embeds": "Incorporados",
|
||||
"impersonation": "Representação",
|
||||
"impersonation_description": "Configurações para gerenciar representação de usuário",
|
||||
"users": "Usuários",
|
||||
"profile_description": "Gerencie as configurações para o seu perfil {{appName}}",
|
||||
"users_description": "Aqui você poderá encontrar uma lista de todos os usuários",
|
||||
"users_listing": "Listagem de usuários",
|
||||
"general_description": "Gerencie as configurações para seu idioma e fuso horário",
|
||||
"calendars_description": "Configure como seus tipos de evento interagem com seus calendários",
|
||||
"appearance_description": "Gerencie as configurações da aparência da sua reserva",
|
||||
@@ -1356,11 +1382,12 @@
|
||||
"team_name_taken": "Este nome já está em uso",
|
||||
"must_enter_team_name": "É preciso inserir um nome de equipe",
|
||||
"team_url_required": "É preciso inserir uma URL de equipe",
|
||||
"team_url_taken": "Esta URL já está em uso",
|
||||
"team_url_taken": "Este URL já está em uso",
|
||||
"team_publish": "Publicar equipe",
|
||||
"number_sms_notifications": "Número de telefone (notificações de SMS)",
|
||||
"attendee_email_workflow": "E-mail do participante",
|
||||
"attendee_email_info": "O e-mail da pessoa que fez a reserva",
|
||||
"kbar_search_placeholder": "Digite um comando ou procure...",
|
||||
"invalid_credential": "Ah, não! Parece que a permissão expirou ou foi revogada. Reinstale novamente.",
|
||||
"choose_common_schedule_team_event": "Escolha uma agenda compartilhada",
|
||||
"choose_common_schedule_team_event_description": "Ative esta opção se você quiser usar uma agenda compartilhada entre os hosts. Ao desativar esta opção, cada host será reservado conforme seu horário padrão.",
|
||||
@@ -1368,8 +1395,46 @@
|
||||
"sender_id": "ID do remetente",
|
||||
"sender_id_error_message": "Apenas letras, números e espaços permitidos (no máx. 11 caracteres)",
|
||||
"test_routing_form": "Testar formulário de roteamento",
|
||||
"test_preview": "Testar prévia",
|
||||
"test_preview": "Visualizar teste",
|
||||
"route_to": "Direcionar para",
|
||||
"test_preview_description": "Teste seu formulário de roteamento sem enviar dados",
|
||||
"test_routing": "Testar roteamento"
|
||||
"test_routing": "Testar roteamento",
|
||||
"payment_app_disabled": "Um administrador desativou um aplicativo de pagamento",
|
||||
"edit_event_type": "Editar tipo de evento",
|
||||
"collective_scheduling": "Programação coletiva",
|
||||
"make_it_easy_to_book": "Facilite a reserva da sua equipe quando todos estiverem disponíveis.",
|
||||
"find_the_best_person": "Encontre a pessoa mais indicada disponível e percorra sua equipe.",
|
||||
"fixed_round_robin": "Round-robin fixo",
|
||||
"add_one_fixed_attendee": "Adicione um participante fixo e utilize o round-robin em uma determinada quantidade de participantes.",
|
||||
"calcom_is_better_with_team": "Cal.com é melhor com equipes",
|
||||
"add_your_team_members": "Adicione membros da sua equipe ao seus tipos de evento. Use programação coletiva para incluir todos ou encontre a pessoa mais apropriada pela programação com round-robin.",
|
||||
"booking_limit_reached": "O limite de reseva para este tipo de evento foi atingido",
|
||||
"admin_has_disabled": "Um administrador desativou {{appName}}",
|
||||
"disabled_app_affects_event_type": "Um administrador desativou {{appName}}, afetando seu tipo de evento {{eventType}}",
|
||||
"disable_payment_app": "O administrador desativou {{appName}}, afetando o seu tipo de evento {{title}}. Os participantes ainda poderão reservar este tipo de evento, mas não será solicitado pagamento. Você poderá ocultar o tipo de evento para impedir isso até o adiministrador reativar seu método de pagamento.",
|
||||
"payment_disabled_still_able_to_book": "Os participantes ainda poderão reservar este tipo de evento, mas não será solicitado pagamento. Você poderá ocultar o tipo de evento para impedir isso até o adiministrador reativar seu método de pagamento.",
|
||||
"app_disabled_with_event_type": "O administrador desativou {{appName}}, afetando seu tipo de evento {{title}}.",
|
||||
"app_disabled_video": "O administrador desativou {{appName}}, afetando seus tipos de evento. Se você tiver tipos de evento com {{appName}} como localização, o vídeo do Cal será definido como padrão.",
|
||||
"app_disabled_subject": "{{appName}} foi desativado",
|
||||
"navigate_installed_apps": "Ir para aplicativos instalados",
|
||||
"disabled_calendar": "Se você tiver outro calendário instalado, novas reservas serão adicionadas a ele. Caso contrário, conecte um novo calendário para não perder novas reservas.",
|
||||
"enable_apps": "Ativar aplicativos",
|
||||
"enable_apps_description": "Ative aplicativos que os usuários possam integrar com o Cal.com",
|
||||
"app_is_enabled": "{{appName}} foi ativado",
|
||||
"app_is_disabled": "{{appName}} foi desativado",
|
||||
"keys_have_been_saved": "As chaves foram salvas",
|
||||
"disable_app": "Desativar aplicativo",
|
||||
"disable_app_description": "Desativar este aplicativo pode causar problemas para a interação dos usuários com o Cal",
|
||||
"edit_keys": "Editar chaves",
|
||||
"no_available_apps": "Não há aplicativos disponíveis",
|
||||
"no_available_apps_description": "Verifique se há aplicativos na sua implantação, em \"packages/app-store\"",
|
||||
"no_apps": "Não há aplicativos ativados nesta instância do Cal",
|
||||
"apps_settings": "Configurações do app",
|
||||
"fill_this_field": "Preencha este campo",
|
||||
"options": "Opções",
|
||||
"enter_option": "insira a opção {{index}}",
|
||||
"add_an_option": "Adicionar uma opção",
|
||||
"radio": "Rádio",
|
||||
"event_type_duplicate_copy_text": "{{slug}}-cópia",
|
||||
"set_as_default": "Definir como padrão"
|
||||
}
|
||||
|
||||
@@ -52,6 +52,7 @@
|
||||
"still_waiting_for_approval": "Um evento ainda aguarda aprovação",
|
||||
"event_is_still_waiting": "Pedido de evento pendente: {{attendeeName}} - {{date}} - {{eventType}}",
|
||||
"no_more_results": "Não existem mais resultados",
|
||||
"no_results": "Sem resultados",
|
||||
"load_more_results": "Carregar mais resultados",
|
||||
"integration_meeting_id": "ID da reunião de {{integrationName}}: {{meetingId}}",
|
||||
"confirmed_event_type_subject": "Confirmado: {{eventType}} com {{name}} em {{date}}",
|
||||
@@ -248,6 +249,7 @@
|
||||
"add_to_calendar": "Adicionar ao calendário",
|
||||
"add_another_calendar": "Adicionar outro calendário",
|
||||
"other": "Outras",
|
||||
"email_sign_in_subject": "A sua ligação de início de sessão para {{appName}}",
|
||||
"emailed_you_and_attendees": "Enviámos um email para si e para os outros participantes com um convite de calendário com todos os detalhes.",
|
||||
"emailed_you_and_attendees_recurring": "Enviámos um email para si e para os outros participantes com um convite de calendário para o primeiro destes eventos recorrentes.",
|
||||
"emailed_you_and_any_other_attendees": "Esta informação foi enviada para si e para todos os outros participantes.",
|
||||
@@ -420,6 +422,7 @@
|
||||
"current_incorrect_password": "A senha atual está incorreta",
|
||||
"password_hint_caplow": "Mistura de letras maiúsculas e minúsculas",
|
||||
"password_hint_min": "Tamanho mínimo de 7 caracteres",
|
||||
"password_hint_admin_min": "Tamanho mínimo de 15 caracteres",
|
||||
"password_hint_num": "Contém pelo menos 1 número",
|
||||
"invalid_password_hint": "A palavra-passe deve ter no mínimo 7 caracteres, com pelo menos um número e uma mistura de letras maiúsculas e minúsculas",
|
||||
"incorrect_password": "Palavra-Passe incorreta",
|
||||
@@ -463,11 +466,14 @@
|
||||
"booking_confirmation": "Confirme o seu {{eventTypeTitle}} com {{profileName}}",
|
||||
"booking_reschedule_confirmation": "Reagende o seu {{eventTypeTitle}} com {{profileName}}",
|
||||
"in_person_meeting": "Ligação ou reunião presencial",
|
||||
"attendeeInPerson": "Pessoalmente (endereço do participante)",
|
||||
"inPerson": "Pessoalmente (endereço do organizador)",
|
||||
"link_meeting": "Ligar reunião",
|
||||
"phone_call": "Número de telefone do participante",
|
||||
"your_number": "O seu número de telefone",
|
||||
"phone_number": "Número de Telefone",
|
||||
"attendee_phone_number": "Número de telefone do participante",
|
||||
"organizer_phone_number": "Número de telefone do organizador",
|
||||
"host_phone_number": "O seu número de telefone",
|
||||
"enter_phone_number": "Inserir Número do Telefone",
|
||||
"reschedule": "Reagendar",
|
||||
@@ -554,6 +560,10 @@
|
||||
"collective": "Coletivo",
|
||||
"collective_description": "Agende reuniões quando todos os membros selecionados da equipa estiverem disponíveis.",
|
||||
"duration": "Duração",
|
||||
"available_durations": "Durações disponíveis",
|
||||
"default_duration": "Duração predefinida",
|
||||
"default_duration_no_options": "Por favor, selecione primeiro as durações disponíveis",
|
||||
"multiple_duration_mins": "{{count}} $t(minute_timeUnit)",
|
||||
"minutes": "Minutos",
|
||||
"round_robin": "Round Robin",
|
||||
"round_robin_description": "Reuniões de ciclo entre vários membros da equipa.",
|
||||
@@ -619,6 +629,7 @@
|
||||
"teams": "Equipas",
|
||||
"team": "Equipa",
|
||||
"team_billing": "Facturação da equipa",
|
||||
"team_billing_description": "Gerir a faturação para a sua equipa",
|
||||
"upgrade_to_flexible_pro_title": "Alterámos os termos de facturação",
|
||||
"upgrade_to_flexible_pro_message": "Há membros sem lugar na sua equipa. Actualize para o plano Pro para cobrir os lugares em falta.",
|
||||
"changed_team_billing_info": "Desde Janeiro de 2022 a cobrança é efectuada por cada lugar de membro da equipa. Os membros da sua equipa que tivessem a versão Pro gratuitamente, estão agora num período experimental de 14 dias. Assim que este período expirar, estes membros ficarão ocultos da sua equipa, a menos que actualize agora.",
|
||||
@@ -694,6 +705,7 @@
|
||||
"hide_event_type": "Ocultar Tipo de Evento",
|
||||
"edit_location": "Editar Localização",
|
||||
"into_the_future": "no futuro",
|
||||
"when_booked_with_less_than_notice": "Quando reservado com aviso prévio inferior a <time></time>",
|
||||
"within_date_range": "Dentro de um período",
|
||||
"indefinitely_into_future": "Indefinidamente para o futuro",
|
||||
"add_new_custom_input_field": "Adicionar novo campo personalizado",
|
||||
@@ -713,6 +725,8 @@
|
||||
"delete_account_confirmation_message": "De certeza que quer eliminar a sua conta {{appName}}? Qualquer pessoa com quem tenha partilhado esta ligação de equipa deixará de poder fazer reservas através da respetiva ligação, e quaisquer preferências que tenha guardado serão perdidas.",
|
||||
"integrations": "Integrações",
|
||||
"apps": "Aplicações",
|
||||
"apps_description": "Ativar aplicações para a sua instância do Cal",
|
||||
"apps_listing": "Lista de aplicações",
|
||||
"category_apps": "Aplicações de {{category}}",
|
||||
"app_store": "App Store",
|
||||
"app_store_description": "Ligar pessoas, tecnologia e o local de trabalho.",
|
||||
@@ -736,6 +750,7 @@
|
||||
"toggle_calendars_conflict": "Escolha os calendários que deseja verificar para evitar conflitos e duplicação de reservas.",
|
||||
"select_destination_calendar": "Criar eventos em",
|
||||
"connect_additional_calendar": "Ligar um calendário adicional",
|
||||
"calendar_updated_successfully": "Calendário atualizado com sucesso",
|
||||
"conferencing": "Conferência",
|
||||
"calendar": "Calendário",
|
||||
"payments": "Pagamentos",
|
||||
@@ -768,6 +783,7 @@
|
||||
"trending_apps": "Aplicações em destaque",
|
||||
"explore_apps": "Aplicações de {{category}}",
|
||||
"installed_apps": "Aplicações instaladas",
|
||||
"free_to_use_apps": "Grátis",
|
||||
"no_category_apps": "Sem aplicações de {{category}}",
|
||||
"no_category_apps_description_calendar": "Adicione uma aplicação de calendário para verificar se existem conflitos e assim evitar sobreposição de marcações",
|
||||
"no_category_apps_description_conferencing": "Experimente adicionar uma aplicação de conferência para integrar chamadas de vídeo com os seus clientes",
|
||||
@@ -806,6 +822,8 @@
|
||||
"verify_wallet": "Verificar carteira",
|
||||
"connect_metamask": "Ligar Metamask",
|
||||
"create_events_on": "Criar eventos em:",
|
||||
"enterprise_license": "Esta é uma funcionalidade empresarial",
|
||||
"enterprise_license_description": "Para ativar esta funcionalidade, obtenha uma chave de instalação na consola {{consoleUrl}} e adicione-a ao seu .env como CALCOM_LICENSE_KEY. Se a sua equipa já tem uma licença, entre em contacto com {{supportMail}} para obter ajuda.",
|
||||
"missing_license": "Licença em falta",
|
||||
"signup_requires": "Necessita de licença comercial",
|
||||
"signup_requires_description": "De momento a {{companyName}} não oferece uma versão gratuita de código aberto da página de registo. Para aceder completamente aos componentes de registo tem de adquirir uma licença comercial. Para uso pessoal, recomendamos a Prisma Data Platform ou qualquer outra interface Postgres para criar contas.",
|
||||
@@ -897,6 +915,7 @@
|
||||
"user_impersonation_heading": "Representação de utilizador",
|
||||
"user_impersonation_description": "Permite à nossa equipa de suporte iniciar sessão temporariamente em seu nome para rapidamente resolver quaisquer erros que nos reporte.",
|
||||
"team_impersonation_description": "Permite que os administradores da sua equipa iniciem a sessão temporariamente em seu nome.",
|
||||
"allow_booker_to_select_duration": "Permitir que o responsável pela reserva selecione a duração",
|
||||
"impersonate_user_tip": "Todas as utilizações desta funcionalidade são auditadas.",
|
||||
"impersonating_user_warning": "Representar o nome de utilizador \"{{user}}\".",
|
||||
"impersonating_stop_instructions": "<0>Clique aqui para parar</0>.",
|
||||
@@ -1014,6 +1033,9 @@
|
||||
"error_removing_app": "Erro ao remover a aplicação",
|
||||
"web_conference": "Conferência web",
|
||||
"requires_confirmation": "Requer confirmação",
|
||||
"always_requires_confirmation": "Sempre",
|
||||
"requires_confirmation_threshold": "Requer confirmação se reservado com um aviso prévio inferior a {{time}} $t({{unit}}_timeUnit)",
|
||||
"may_require_confirmation": "Pode necessitar de confirmação",
|
||||
"nr_event_type_one": "{{count}} tipo de evento",
|
||||
"nr_event_type_other": "{{count}} tipos de evento",
|
||||
"add_action": "Adicionar acção",
|
||||
@@ -1101,6 +1123,9 @@
|
||||
"event_limit_tab_description": "Com que frequência pode ser reservado",
|
||||
"event_advanced_tab_description": "Definições do calendário e muito mais...",
|
||||
"event_advanced_tab_title": "Avançado",
|
||||
"event_setup_multiple_duration_error": "Configuração do evento: durações múltiplas requerem pelo menos 1 opção.",
|
||||
"event_setup_multiple_duration_default_error": "Configuração do evento: por favor, selecione uma duração predefinida válida.",
|
||||
"event_setup_booking_limits_error": "Os limites de reserva devem estar ordenados de forma ascendente. [dia,semana,mês,ano]",
|
||||
"select_which_cal": "Selecione para que calendário devem ser adicionadas as marcações",
|
||||
"custom_event_name": "Nome de evento personalizado",
|
||||
"custom_event_name_description": "Crie nomes de eventos personalizados a mostrar no calendário de eventos",
|
||||
@@ -1154,8 +1179,11 @@
|
||||
"invoices": "Faturas",
|
||||
"embeds": "Incorporações",
|
||||
"impersonation": "Representação",
|
||||
"impersonation_description": "Definições para gerir a personificação de utilizadores",
|
||||
"users": "Utilizadores",
|
||||
"profile_description": "Gerir as definições para o seu perfil {{appName}}",
|
||||
"users_description": "Aqui pode encontrar uma lista de todos os utilizadores",
|
||||
"users_listing": "Lista de utilizadores",
|
||||
"general_description": "Faça a gestão das definições do seu idioma e fuso horário",
|
||||
"calendars_description": "Configure como os tipos de evento devem interagir com os seus calendários",
|
||||
"appearance_description": "Faça a gestão das definições de aparência da sua reserva",
|
||||
@@ -1360,6 +1388,7 @@
|
||||
"number_sms_notifications": "Número de telefone (notificações SMS)",
|
||||
"attendee_email_workflow": "E-mail do participante",
|
||||
"attendee_email_info": "O e-mail do responsável pela reserva",
|
||||
"kbar_search_placeholder": "Digite um comando ou pesquise...",
|
||||
"invalid_credential": "Oh não! Parece que a permissão expirou ou foi revogada. Por favor, reinstale novamente.",
|
||||
"choose_common_schedule_team_event": "Escolha uma agenda comum",
|
||||
"choose_common_schedule_team_event_description": "Ative esta opção se quiser utilizar uma agenda comum entre anfitriões. Quando desativada, cada anfitrião será reservado com base na respetiva agenda pré-definida.",
|
||||
@@ -1370,5 +1399,44 @@
|
||||
"test_preview": "Pré-visualização do teste",
|
||||
"route_to": "Encaminhar para",
|
||||
"test_preview_description": "Teste o encaminhamento do seu formulário sem submeter qualquer dado",
|
||||
"test_routing": "Testar encaminhamento"
|
||||
"test_routing": "Testar encaminhamento",
|
||||
"payment_app_disabled": "Um administrador desativou uma aplicação de pagamentos",
|
||||
"edit_event_type": "Editar o tipo de evento",
|
||||
"collective_scheduling": "Agendamento coletivo",
|
||||
"make_it_easy_to_book": "Faça com que seja simples reservar a sua equipa quando todos estiverem disponíveis.",
|
||||
"find_the_best_person": "Encontre a melhor pessoa disponível e navegue na sua equipa.",
|
||||
"fixed_round_robin": "Distribuição equilibrada fixa",
|
||||
"add_one_fixed_attendee": "Adicione um participante fixo e distribua de forma equilibrada a partir de um número de participantes.",
|
||||
"calcom_is_better_with_team": "O Cal.com é melhor com equipas",
|
||||
"add_your_team_members": "Adicione os membros da sua equipa aos seus tipos de eventos. Utilize o agendamento coletivo para incluir todos os membros ou encontre a pessoa mais adequada com o agendamento baseado numa distribuição equilibrada.",
|
||||
"booking_limit_reached": "O limite de reservas para este tipo de evento foi atingido",
|
||||
"admin_has_disabled": "{{appName}} foi desativada por um administrador",
|
||||
"disabled_app_affects_event_type": "{{appName}} foi desativada por um administrador o que afeta o seu tipo de evento {{eventType}}",
|
||||
"disable_payment_app": "O administrador desativou {{appName}} o que afeta o seu tipo de evento {{title}}. Os participantes ainda poderão reservar este tipo de evento, mas não será solicitado que façam qualquer pagamento. Pode ocultar o tipo de evento para evitar esta situação, até que o seu administrador reative o seu método de pagamento.",
|
||||
"payment_disabled_still_able_to_book": "Os participantes ainda poderão reservar este tipo de evento, mas não será solicitado que façam qualquer pagamento. Pode ocultar o tipo de evento para evitar esta situação, até que o seu administrador reative o seu método de pagamento.",
|
||||
"app_disabled_with_event_type": "O administrador desativou {{appName}} o que afeta o seu tipo de evento {{title}}.",
|
||||
"app_disabled_video": "O administrador desativou {{appName}} o que afeta os seus tipos de eventos. Se tiver tipos de eventos com {{appName}} como o sítio, então o mesmo será predefinido para o Cal Video.",
|
||||
"app_disabled_subject": "{{appName}} foi desativada",
|
||||
"navigate_installed_apps": "Ir para as aplicações instaladas",
|
||||
"disabled_calendar": "Se tiver outro calendário instalado, os novos pedidos serão adicionados ao mesmo. Se não é este o caso, deve associar um novo calendário para garantir que não perde novas reservas.",
|
||||
"enable_apps": "Ativar aplicações",
|
||||
"enable_apps_description": "Ativar aplicações que os utilizadores podem integrar com o Cal.com",
|
||||
"app_is_enabled": "{{appName}} foi ativada",
|
||||
"app_is_disabled": "{{appName}} foi desativada",
|
||||
"keys_have_been_saved": "As chaves foram guardadas",
|
||||
"disable_app": "Desativar a aplicação",
|
||||
"disable_app_description": "A desativação desta aplicação pode causar problemas na forma como os seus utilizadores interagem com o Cal",
|
||||
"edit_keys": "Editar chaves",
|
||||
"admin_apps_description": "Ativar aplicações para a sua instância do Cal",
|
||||
"no_available_apps": "Não existem aplicações disponíveis",
|
||||
"no_available_apps_description": "Por favor, certifique-se que existem aplicações na sua instalação em 'packages/app-store'",
|
||||
"no_apps": "Não existem aplicações ativas nesta instância do Cal",
|
||||
"apps_settings": "Definições de aplicações",
|
||||
"fill_this_field": "Por favor, preencha este campo",
|
||||
"options": "Opções",
|
||||
"enter_option": "Insira a opção {{index}}",
|
||||
"add_an_option": "Adicione uma opção",
|
||||
"radio": "Radio",
|
||||
"event_type_duplicate_copy_text": "{{slug}}-copia",
|
||||
"set_as_default": "Predefinir"
|
||||
}
|
||||
|
||||
@@ -714,6 +714,7 @@
|
||||
"delete_account_confirmation_message": "Sigur doriți să vă ștergeți contul {{appName}}? Persoanele cărora le-ați transmis linkul contului dvs. nu vor mai putea rezerva folosindu-l și orice preferințe pe care le-ați salvat se vor pierde.",
|
||||
"integrations": "Integrări",
|
||||
"apps": "Aplicații",
|
||||
"apps_listing": "Listare aplicații",
|
||||
"category_apps": " Aplicații {{category}}",
|
||||
"app_store": "App Store",
|
||||
"app_store_description": "Creăm conexiuni între oameni, tehnologii și locuri de muncă.",
|
||||
@@ -1102,6 +1103,7 @@
|
||||
"event_limit_tab_description": "Cât de des puteți fi rezervat",
|
||||
"event_advanced_tab_description": "Setări calendar și mai multe...",
|
||||
"event_advanced_tab_title": "Avansat",
|
||||
"event_setup_booking_limits_error": "Limitele de rezervare trebuie să fie în ordine crescătoare. [zi,săptămână,lună,an]",
|
||||
"select_which_cal": "Alegeți la ce calendar se adaugă rezervările",
|
||||
"custom_event_name": "Nume eveniment personalizat",
|
||||
"custom_event_name_description": "Creați nume de evenimente personalizate pentru a fi afișate pe evenimentul calendarului",
|
||||
@@ -1372,5 +1374,9 @@
|
||||
"route_to": "Direcționați către",
|
||||
"test_preview_description": "Testați-vă formularul de redirecționare fără a trimite date",
|
||||
"test_routing": "Testați redirecționarea",
|
||||
"booking_limit_reached": "A fost atinsă limita de rezervare pentru acest tip de eveniment"
|
||||
"find_the_best_person": "Găsește cea mai bună persoană disponibilă și treci succesiv prin membrii echipei tale.",
|
||||
"booking_limit_reached": "A fost atinsă limita de rezervare pentru acest tip de eveniment",
|
||||
"keys_have_been_saved": "Cheile au fost salvate",
|
||||
"radio": "Radio",
|
||||
"event_type_duplicate_copy_text": "{{slug}}-copie"
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user