Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
de446db434 | ||
|
|
81546412bf | ||
|
|
459530fba3 | ||
|
|
42766b42c0 | ||
|
|
38b3563350 | ||
|
|
37159914cf | ||
|
|
268bf68532 | ||
|
|
b02c7e01d5 | ||
|
|
45d10a3bc4 | ||
|
|
9250b20c1d | ||
|
|
d9da311141 | ||
|
|
89a52dad21 | ||
|
|
2a1acc1294 | ||
|
|
8302990f84 | ||
|
|
5a03b61d63 | ||
|
|
6b6f239936 | ||
|
|
9c2748e8e9 | ||
|
|
bb5cc33737 | ||
|
|
5616a64827 | ||
|
|
33530ad8c8 | ||
|
|
fe14839f1b | ||
|
|
15123c1aa5 | ||
|
|
71ee9c72fe | ||
|
|
5503539856 | ||
|
|
6548f01efa | ||
|
|
518a4484d6 | ||
|
|
3535a25a59 | ||
|
|
06cc6741e6 | ||
|
|
ed1478e1ba | ||
|
|
854c05d673 | ||
|
|
bcf5fb18c5 | ||
|
|
3f822e814b | ||
|
|
4fd25c7215 | ||
|
|
f42bed2a55 | ||
|
|
469c205033 | ||
|
|
31551f3b9e | ||
|
|
69925af17c | ||
|
|
2502868ebc | ||
|
|
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 |
@@ -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 }}"
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
<!-- PROJECT LOGO -->
|
||||
<p align="center">
|
||||
<a href="https://github.com/calcom/cal.com">
|
||||
<img src="https://user-images.githubusercontent.com/8019099/133430653-24422d2a-3c8d-4052-9ad6-0580597151ee.png" alt="Logo">
|
||||
|
||||
<img src="https://user-images.githubusercontent.com/8019099/210054112-5955e812-a76e-4160-9ddd-58f2c72f1cce.png" alt="Logo">
|
||||
</a>
|
||||
|
||||
<h3 align="center">Cal.com (formerly Calendso)</h3>
|
||||
@@ -37,7 +36,7 @@
|
||||
<a href="https://hub.docker.com/r/calendso/calendso"><img src="https://img.shields.io/docker/pulls/calendso/calendso"></a>
|
||||
<a href="https://twitter.com/calcom"><img src="https://img.shields.io/twitter/follow/calcom?style=flat"></a>
|
||||
<a href="https://twitch.tv/calcomtv"><img src="https://img.shields.io/twitch/status/calcomtv?style=flat"></a>
|
||||
<a href="https://github.com/orgs/calcom/projects/9"><img src="https://img.shields.io/badge/Help%20Wanted-Contribute-blue"></a>
|
||||
<a href="https://github.com/calcom/cal.com/issues?q=is:issue+is:open+label:%22%F0%9F%99%8B%F0%9F%8F%BB%E2%80%8D%E2%99%82%EF%B8%8Fhelp+wanted%22"><img src="https://img.shields.io/badge/Help%20Wanted-Contribute-blue"></a>
|
||||
<a href="https://cal.com/figma"><img src="https://img.shields.io/badge/Figma-Design%20System-blueviolet"></a>
|
||||
<a href="https://calendso.slack.com/archives/C02BY67GMMW"><img src="https://img.shields.io/badge/translations-contribute-brightgreen" /></a>
|
||||
<a href="https://www.contributor-covenant.org/version/1/4/code-of-conduct/ "><img src="https://img.shields.io/badge/Contributor%20Covenant-1.4-purple" /></a>
|
||||
@@ -310,7 +309,7 @@ Please see our [contributing guide](/CONTRIBUTING.md).
|
||||
|
||||
### Good First Issues
|
||||
|
||||
We have a list of [help wanted](https://github.com/orgs/calcom/projects/1/views/25) that contain small features and bugs which have a relatively limited scope. This is a great place to get started, gain experience, and get familiar with our contribution process.
|
||||
We have a list of [help wanted](https://github.com/calcom/cal.com/issues?q=is:issue+is:open+label:%22%F0%9F%99%8B%F0%9F%8F%BB%E2%80%8D%E2%99%82%EF%B8%8Fhelp+wanted%22) that contain small features and bugs which have a relatively limited scope. This is a great place to get started, gain experience, and get familiar with our contribution process.
|
||||
|
||||
## Integrations
|
||||
|
||||
|
||||
+1
-1
Submodule apps/api updated: 12f19ff7c0...604d937661
+1
-1
Submodule apps/console updated: ad226cef6e...2d577dd9ed
@@ -14,14 +14,13 @@ Cal.com uses [TailwindCSS](https://tailwindcss.com) as a replacement for traditi
|
||||
|
||||
CSS files should be stored in the `styles` directory within the codebase.
|
||||
|
||||
Within the `styles` directory, you will find two CSS files, `fonts.css` and `global.css`. We suggest not to add to these files, and instead create new CSS files and import them into the application. This helps reduce conflicts when pulling in changes that we've made to either of the existing CSS files.
|
||||
Within the `styles` directory, you will find a single CSS file, `global.css`. We suggest not to add to this file, and instead create new CSS files and import them into the application. This helps reduce conflicts when pulling in changes that we've made to either of the existing CSS files.
|
||||
|
||||
## Adding new stylesheets
|
||||
Firstly, create the CSS file inside the `styles` directory.
|
||||
|
||||
Then, open the `pages/_app.tsx` file, and you will see the following two lines:
|
||||
```javascript
|
||||
import "../styles/fonts.css";
|
||||
import "../styles/globals.css";
|
||||
```
|
||||
|
||||
|
||||
@@ -189,3 +189,7 @@
|
||||
padding: 24px !important;
|
||||
}
|
||||
}
|
||||
|
||||
.docs-story {
|
||||
padding: 24px !important;
|
||||
}
|
||||
|
||||
@@ -639,7 +639,7 @@ const ChooseEmbedTypesDialogContent = () => {
|
||||
<div className="flex items-start">
|
||||
{embeds.map((embed, index) => (
|
||||
<button
|
||||
className="mr-2 w-1/3 border border-transparent p-3 text-left hover:rounded-md hover:border-gray-200 hover:bg-neutral-100"
|
||||
className="w-1/3 border border-transparent p-3 text-left hover:rounded-md hover:border-gray-200 hover:bg-neutral-100 ltr:mr-2 rtl:ml-2"
|
||||
key={index}
|
||||
data-testid={embed.type}
|
||||
onClick={() => {
|
||||
@@ -914,7 +914,7 @@ const EmbedTypeCodeAndPreviewDialogContent = ({
|
||||
<div
|
||||
className={classNames(
|
||||
"mt-4 flex items-center justify-start",
|
||||
embedType === "floating-popup" ? "space-x-2" : "hidden"
|
||||
embedType === "floating-popup" ? "space-x-2 rtl:space-x-reverse" : "hidden"
|
||||
)}>
|
||||
<Switch
|
||||
defaultChecked={true}
|
||||
@@ -1010,7 +1010,7 @@ const EmbedTypeCodeAndPreviewDialogContent = ({
|
||||
</CollapsibleTrigger>
|
||||
<CollapsibleContent>
|
||||
<div className="mt-6 text-sm">
|
||||
<div className="mb-4 flex items-center justify-start space-x-2">
|
||||
<div className="mb-4 flex items-center justify-start space-x-2 rtl:space-x-reverse">
|
||||
<Switch
|
||||
checked={previewState.hideEventTypeDetails}
|
||||
onCheckedChange={(checked) => {
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { useTranslation } from "next-i18next";
|
||||
import { useEffect } from "react";
|
||||
|
||||
import { getDirFromLang } from "@calcom/lib/i18n";
|
||||
import { trpc } from "@calcom/trpc/react";
|
||||
|
||||
export function useViewerI18n() {
|
||||
@@ -21,12 +22,16 @@ export function useViewerI18n() {
|
||||
*/
|
||||
const I18nLanguageHandler = (): null => {
|
||||
const { i18n } = useTranslation("common");
|
||||
const locale = useViewerI18n().data?.locale;
|
||||
const locale = useViewerI18n().data?.locale || "en";
|
||||
|
||||
useEffect(() => {
|
||||
if (locale && i18n.language && i18n.language !== locale) {
|
||||
if (typeof i18n.changeLanguage === "function") i18n.changeLanguage(locale);
|
||||
}
|
||||
|
||||
const dir = getDirFromLang(locale);
|
||||
document.documentElement.setAttribute("lang", locale);
|
||||
document.documentElement.setAttribute("dir", dir);
|
||||
}, [locale, i18n]);
|
||||
|
||||
return null;
|
||||
|
||||
@@ -15,7 +15,7 @@ import {
|
||||
List,
|
||||
ShellSubHeading,
|
||||
showToast,
|
||||
SkeletonLoader,
|
||||
AppSkeletonLoader as SkeletonLoader,
|
||||
Switch,
|
||||
} from "@calcom/ui";
|
||||
|
||||
@@ -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">
|
||||
|
||||
@@ -56,7 +56,7 @@ function IntegrationListItem(props: {
|
||||
<ListItemText component="p">{props.description}</ListItemText>
|
||||
{/* Alert error that key stopped working. */}
|
||||
{props.invalidCredential && (
|
||||
<div className="flex items-center space-x-2">
|
||||
<div className="flex items-center space-x-2 rtl:space-x-reverse">
|
||||
<Icon.FiAlertCircle className="w-8 text-red-500 sm:w-4" />
|
||||
<ListItemText component="p" className="whitespace-pre-wrap text-red-500">
|
||||
{t("invalid_credential")}
|
||||
|
||||
@@ -1,10 +1,13 @@
|
||||
import { getEventLocationType, locationKeyToString } from "@calcom/app-store/locations";
|
||||
import { classNames } from "@calcom/lib";
|
||||
import { useLocale } from "@calcom/lib/hooks/useLocale";
|
||||
import { Icon, Tooltip } from "@calcom/ui";
|
||||
|
||||
import { Props } from "./pages/AvailabilityPage";
|
||||
|
||||
export function AvailableEventLocations({ locations }: { locations: Props["eventType"]["locations"] }) {
|
||||
const { t } = useLocale();
|
||||
|
||||
return locations.length ? (
|
||||
<div className="dark:text-darkgray-600 mr-6 flex w-full flex-col space-y-2 break-words text-sm text-gray-600">
|
||||
{locations.map((location) => {
|
||||
@@ -16,19 +19,19 @@ export function AvailableEventLocations({ locations }: { locations: Props["event
|
||||
return (
|
||||
<div key={location.type} className="flex flex-row items-center text-sm font-medium">
|
||||
{eventLocationType.iconUrl === "/link.svg" ? (
|
||||
<Icon.FiLink className="dark:text-darkgray-600 mr-[10px] ml-[2px] h-4 w-4 opacity-70 dark:opacity-100 " />
|
||||
<Icon.FiLink className="dark:text-darkgray-600 ml-[2px] h-4 w-4 opacity-70 ltr:mr-[10px] rtl:ml-[10px] dark:opacity-100 " />
|
||||
) : (
|
||||
<img
|
||||
src={eventLocationType.iconUrl}
|
||||
className={classNames(
|
||||
"mr-[10px] ml-[2px] h-4 w-4 opacity-70 dark:opacity-100 ",
|
||||
"ml-[2px] h-4 w-4 opacity-70 ltr:mr-[10px] rtl:ml-[10px] dark:opacity-100 ",
|
||||
!eventLocationType.iconUrl?.includes("api") ? "dark:invert" : ""
|
||||
)}
|
||||
alt={`${eventLocationType.label} icon`}
|
||||
/>
|
||||
)}
|
||||
<Tooltip content={locationKeyToString(location)}>
|
||||
<p className="truncate">{locationKeyToString(location)}</p>
|
||||
<Tooltip content={t(locationKeyToString(location) ?? "")}>
|
||||
<p className="truncate">{t(locationKeyToString(location) ?? "")}</p>
|
||||
</Tooltip>
|
||||
</div>
|
||||
);
|
||||
|
||||
@@ -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">
|
||||
@@ -71,7 +71,7 @@ const AvailableTimes: FC<AvailableTimesProps> = ({
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div className="-mb-5 grid flex-grow grid-cols-1 gap-x-2 overflow-y-auto sm:block md:h-[364px]">
|
||||
<div className="flex-grow overflow-y-auto sm:block md:h-[364px]">
|
||||
{slots.length > 0 &&
|
||||
slots.map((slot) => {
|
||||
type BookingURL = {
|
||||
@@ -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;
|
||||
@@ -96,7 +95,7 @@ const BookingDescription: FC<Props> = (props) => {
|
||||
<div>
|
||||
<Icon.FiInfo
|
||||
className={classNames(
|
||||
"mr-[10px] ml-[2px] inline-block h-4 w-4",
|
||||
"ml-[2px] inline-block h-4 w-4 ltr:mr-[10px] rtl:ml-[10px]",
|
||||
isBookingPage && "dark:text-darkgray-600 -mt-1 text-gray-500"
|
||||
)}
|
||||
/>
|
||||
@@ -113,7 +112,7 @@ const BookingDescription: FC<Props> = (props) => {
|
||||
isBookingPage && "dark:text-darkgray-600 text-sm font-medium text-gray-600"
|
||||
)}>
|
||||
<div>
|
||||
<Icon.FiCheckSquare className="mr-[10px] ml-[2px] inline-block h-4 w-4 " />
|
||||
<Icon.FiCheckSquare className="ml-[2px] inline-block h-4 w-4 ltr:mr-[10px] rtl:ml-[10px] " />
|
||||
</div>
|
||||
{requiresConfirmationText}
|
||||
</div>
|
||||
@@ -128,7 +127,7 @@ const BookingDescription: FC<Props> = (props) => {
|
||||
)}>
|
||||
<Icon.FiClock
|
||||
className={classNames(
|
||||
"min-h-4 min-w-4 mr-[10px] ml-[2px] inline-block",
|
||||
"min-h-4 min-w-4 ml-[2px] inline-block ltr:mr-[10px] rtl:ml-[10px]",
|
||||
isBookingPage && "mt-[2px]"
|
||||
)}
|
||||
/>
|
||||
|
||||
@@ -4,6 +4,7 @@ import { useState } from "react";
|
||||
|
||||
import { EventLocationType, getEventLocationType } from "@calcom/app-store/locations";
|
||||
import dayjs from "@calcom/dayjs";
|
||||
import ViewRecordingsDialog from "@calcom/features/ee/video/ViewRecordingsDialog";
|
||||
import classNames from "@calcom/lib/classNames";
|
||||
import { formatTime } from "@calcom/lib/date-fns";
|
||||
import { useLocale } from "@calcom/lib/hooks/useLocale";
|
||||
@@ -22,15 +23,16 @@ import {
|
||||
showToast,
|
||||
TextArea,
|
||||
Tooltip,
|
||||
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];
|
||||
|
||||
@@ -48,6 +50,7 @@ function BookingListItem(booking: BookingItemProps) {
|
||||
const router = useRouter();
|
||||
const [rejectionReason, setRejectionReason] = useState<string>("");
|
||||
const [rejectionDialogIsOpen, setRejectionDialogIsOpen] = useState(false);
|
||||
const [viewRecordingsDialogIsOpen, setViewRecordingsDialogIsOpen] = useState<boolean>(false);
|
||||
const mutation = trpc.viewer.bookings.confirm.useMutation({
|
||||
onSuccess: (data) => {
|
||||
if (data.status === BookingStatus.REJECTED) {
|
||||
@@ -112,6 +115,17 @@ function BookingListItem(booking: BookingItemProps) {
|
||||
},
|
||||
];
|
||||
|
||||
const showRecordingActions: ActionType[] = [
|
||||
{
|
||||
id: "view_recordings",
|
||||
label: t("view_recordings"),
|
||||
onClick: () => {
|
||||
setViewRecordingsDialogIsOpen(true);
|
||||
},
|
||||
disabled: mutation.isLoading,
|
||||
},
|
||||
];
|
||||
|
||||
let bookedActions: ActionType[] = [
|
||||
{
|
||||
id: "cancel",
|
||||
@@ -158,6 +172,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">
|
||||
@@ -202,7 +220,7 @@ function BookingListItem(booking: BookingItemProps) {
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
const showRecordingsButtons = booking.location === "integrations:daily" && isPast && isConfirmed;
|
||||
return (
|
||||
<>
|
||||
<RescheduleDialog
|
||||
@@ -216,7 +234,14 @@ function BookingListItem(booking: BookingItemProps) {
|
||||
isOpenDialog={isOpenSetLocationDialog}
|
||||
setShowLocationModal={setIsOpenLocationDialog}
|
||||
/>
|
||||
|
||||
{showRecordingsButtons && (
|
||||
<ViewRecordingsDialog
|
||||
booking={booking}
|
||||
isOpenDialog={viewRecordingsDialogIsOpen}
|
||||
setIsOpenDialog={setViewRecordingsDialogIsOpen}
|
||||
timeFormat={user?.timeFormat ?? null}
|
||||
/>
|
||||
)}
|
||||
{/* NOTE: Should refactor this dialog component as is being rendered multiple times */}
|
||||
<Dialog open={rejectionDialogIsOpen} onOpenChange={setRejectionDialogIsOpen}>
|
||||
<DialogContent>
|
||||
@@ -248,7 +273,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 +300,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 +363,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 ltr:mr-2 rtl:ml-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>
|
||||
@@ -376,6 +398,7 @@ function BookingListItem(booking: BookingItemProps) {
|
||||
</>
|
||||
) : null}
|
||||
{isPast && isPending && !isConfirmed ? <TableActions actions={bookedActions} /> : null}
|
||||
{showRecordingsButtons && <TableActions actions={showRecordingActions} />}
|
||||
{isCancelled && booking.rescheduled && (
|
||||
<div className="hidden h-full items-center md:flex">
|
||||
<RequestSentMessage />
|
||||
@@ -531,13 +554,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;
|
||||
|
||||
@@ -17,6 +17,7 @@ import {
|
||||
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";
|
||||
@@ -27,7 +28,7 @@ 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 useRouterQuery from "@lib/hooks/useRouterQuery";
|
||||
@@ -151,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,
|
||||
@@ -217,7 +221,7 @@ function TimezoneDropdown({
|
||||
<Popover.Root open={isTimeOptionsOpen} onOpenChange={setIsTimeOptionsOpen}>
|
||||
<Popover.Trigger className="min-w-32 dark:text-darkgray-600 radix-state-open:bg-gray-200 dark:radix-state-open:bg-darkgray-200 group relative mb-2 -ml-2 !mt-2 inline-block self-start rounded-md px-2 py-2 text-left text-gray-600">
|
||||
<p className="flex items-center text-sm font-medium">
|
||||
<Icon.FiGlobe className="min-h-4 min-w-4 mr-[10px] ml-[2px] -mt-[2px] inline-block" />
|
||||
<Icon.FiGlobe className="min-h-4 min-w-4 ml-[2px] -mt-[2px] inline-block ltr:mr-[10px] rtl:ml-[10px]" />
|
||||
{timeZone}
|
||||
{isTimeOptionsOpen ? (
|
||||
<Icon.FiChevronUp className="min-h-4 min-w-4 ml-1 inline-block" />
|
||||
@@ -364,7 +368,7 @@ const AvailabilityPage = ({ profile, eventType, ...restProps }: Props) => {
|
||||
<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 " />
|
||||
<Icon.FiRefreshCcw className="float-left mt-[7px] ml-[2px] inline-block h-4 w-4 ltr:mr-[10px] rtl:ml-[10px] " />
|
||||
<div>
|
||||
<p className="mb-1 -ml-2 inline px-2 py-1">
|
||||
{getRecurringFreq({ t, recurringEvent: eventType.recurringEvent })}
|
||||
@@ -389,7 +393,7 @@ const AvailabilityPage = ({ profile, eventType, ...restProps }: Props) => {
|
||||
)}
|
||||
{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" />
|
||||
<Icon.FiCreditCard className="ml-[2px] -mt-1 inline-block h-4 w-4 ltr:mr-[10px] rtl:ml-[10px]" />
|
||||
<IntlProvider locale="en">
|
||||
<FormattedNumber
|
||||
value={stripeAppData.price / 100.0}
|
||||
@@ -410,7 +414,7 @@ const AvailabilityPage = ({ profile, eventType, ...restProps }: Props) => {
|
||||
{t("former_time")}
|
||||
</p>
|
||||
<p className="text-gray-500 line-through dark:text-darkgray-600">
|
||||
<CalendarIcon className="mr-[10px] -mt-1 inline-block h-4 w-4 text-gray-500" />
|
||||
<CalendarIcon className="ltr:mr-[10px] rtl:ml-[10px] -mt-1 inline-block h-4 w-4 text-gray-500" />
|
||||
{typeof booking.startTime === "string" && parseDate(dayjs(booking.startTime), i18n)}
|
||||
</p>
|
||||
</div>
|
||||
|
||||
@@ -143,6 +143,7 @@ const BookingPage = ({
|
||||
isSuccessBookingPage: true,
|
||||
email: bookingForm.getValues("email"),
|
||||
eventTypeSlug: eventType.slug,
|
||||
formerTime: booking?.startTime.toString(),
|
||||
},
|
||||
});
|
||||
},
|
||||
@@ -158,6 +159,7 @@ const BookingPage = ({
|
||||
allRemainingBookings: true,
|
||||
email: bookingForm.getValues("email"),
|
||||
eventTypeSlug: eventType.slug,
|
||||
formerTime: booking?.startTime.toString(),
|
||||
},
|
||||
});
|
||||
},
|
||||
@@ -299,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/") }
|
||||
@@ -355,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:
|
||||
@@ -386,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:
|
||||
@@ -472,7 +501,7 @@ const BookingPage = ({
|
||||
<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" />
|
||||
<Icon.FiCreditCard className="ml-[2px] -mt-1 inline-block h-4 w-4 ltr:mr-[10px] rtl:ml-[10px]" />
|
||||
<IntlProvider locale="en">
|
||||
<FormattedNumber
|
||||
value={stripeAppData.price / 100.0}
|
||||
@@ -484,7 +513,7 @@ const BookingPage = ({
|
||||
)}
|
||||
{!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" />
|
||||
<Icon.FiRefreshCw className="ml-[2px] inline-block h-4 w-4 ltr:mr-[10px] rtl:ml-[10px]" />
|
||||
<p className="-ml-2 inline-block items-center px-2">
|
||||
{getEveryFreqFor({
|
||||
t,
|
||||
@@ -495,7 +524,7 @@ const BookingPage = ({
|
||||
</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" />
|
||||
<Icon.FiCalendar className="ml-[2px] mt-[2px] inline-block h-4 w-4 ltr:mr-[10px] rtl:ml-[10px]" />
|
||||
<div className="text-sm font-medium">
|
||||
{(rescheduleUid || !eventType.recurringEvent?.freq) && `${parseDate(date, i18n)}`}
|
||||
{!rescheduleUid &&
|
||||
@@ -523,7 +552,7 @@ const BookingPage = ({
|
||||
{t("former_time")}
|
||||
</p>
|
||||
<p className="line-through ">
|
||||
<Icon.FiCalendar className="mr-[10px] ml-[2px] -mt-1 inline-block h-4 w-4" />
|
||||
<Icon.FiCalendar className="ml-[2px] -mt-1 inline-block h-4 w-4 ltr:mr-[10px] rtl:ml-[10px]" />
|
||||
{typeof booking.startTime === "string" && parseDate(dayjs(booking.startTime), i18n)}
|
||||
</p>
|
||||
</div>
|
||||
@@ -531,7 +560,7 @@ const BookingPage = ({
|
||||
{!!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 ${
|
||||
className={`ml-[2px] mt-[2px] inline-block h-4 w-4 ltr:mr-[10px] rtl:ml-[10px] ${
|
||||
booking && booking.attendees.length / eventType.seatsPerTimeSlot >= 0.5
|
||||
? "text-rose-600"
|
||||
: booking && booking.attendees.length / eventType.seatsPerTimeSlot >= 0.33
|
||||
@@ -594,7 +623,7 @@ const BookingPage = ({
|
||||
/>
|
||||
{bookingForm.formState.errors.email && (
|
||||
<div className="mt-2 flex items-center text-sm text-red-700 ">
|
||||
<Icon.FiInfo className="mr-2 h-3 w-3" />
|
||||
<Icon.FiInfo className="h-3 w-3 ltr:mr-2 rtl:ml-2" />
|
||||
<p>{t("email_validation_error")}</p>
|
||||
</div>
|
||||
)}
|
||||
@@ -635,8 +664,8 @@ const BookingPage = ({
|
||||
value={location.type}
|
||||
defaultChecked={i === 0}
|
||||
/>
|
||||
<span className="text-sm ltr:ml-2 rtl:mr-2 dark:text-white">
|
||||
{locationKeyToString(location)}
|
||||
<span className="text-sm ltr:ml-2 ltr:mr-2 rtl:ml-2 dark:text-white">
|
||||
{t(locationKeyToString(location) ?? "")}
|
||||
</span>
|
||||
</label>
|
||||
);
|
||||
@@ -660,7 +689,7 @@ const BookingPage = ({
|
||||
{selectedLocationType === LocationType.Phone
|
||||
? t("phone_number")
|
||||
: selectedLocationType === LocationType.AttendeeInPerson
|
||||
? t("Address")
|
||||
? t("address")
|
||||
: ""}
|
||||
</label>
|
||||
<div className="mt-1">
|
||||
@@ -687,7 +716,7 @@ const BookingPage = ({
|
||||
</div>
|
||||
{bookingForm.formState.errors.phone && (
|
||||
<div className="mt-2 flex items-center text-sm text-red-700 ">
|
||||
<Icon.FiInfo className="mr-2 h-3 w-3" />
|
||||
<Icon.FiInfo className="h-3 w-3 ltr:mr-2 rtl:ml-2" />
|
||||
<p>{t("invalid_number")}</p>
|
||||
</div>
|
||||
)}
|
||||
@@ -771,6 +800,7 @@ const BookingPage = ({
|
||||
{input.options && input.type === EventTypeCustomInputType.RADIO && (
|
||||
<div className="flex">
|
||||
<Group
|
||||
name={`customInputs.${input.id}`}
|
||||
required={input.required}
|
||||
onValueChange={(e) => {
|
||||
bookingForm.setValue(`customInputs.${input.id}`, e);
|
||||
@@ -779,9 +809,9 @@ const BookingPage = ({
|
||||
{input.options.map((option, i) => (
|
||||
<RadioField
|
||||
label={option.label}
|
||||
key={`option.${i}.radio`}
|
||||
key={`option.${input.id}.${i}.radio`}
|
||||
value={option.label}
|
||||
id={`option.${i}.radio`}
|
||||
id={`option.${input.id}.${i}.radio`}
|
||||
/>
|
||||
))}
|
||||
</>
|
||||
@@ -793,6 +823,23 @@ const BookingPage = ({
|
||||
</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="h-3 w-3 ltr:mr-2 rtl:ml-2" />
|
||||
<p>{t("invalid_number")}</p>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
))}
|
||||
{!eventType.disableGuests && guestToggle && (
|
||||
@@ -867,7 +914,7 @@ const BookingPage = ({
|
||||
</div>
|
||||
{bookingForm.formState.errors.smsReminderNumber && (
|
||||
<div className="mt-2 flex items-center text-sm text-red-700 ">
|
||||
<Icon.FiInfo className="mr-2 h-3 w-3" />
|
||||
<Icon.FiInfo className="h-3 w-3 ltr:mr-2 rtl:ml-2" />
|
||||
<p>{t("invalid_number")}</p>
|
||||
</div>
|
||||
)}
|
||||
|
||||
@@ -354,7 +354,7 @@ export const EditLocationDialog = (props: ISetLocationDialog) => {
|
||||
/>
|
||||
{selectedLocation && LocationOptions}
|
||||
<DialogFooter>
|
||||
<div className="mt-4 flex justify-end space-x-2">
|
||||
<div className="mt-4 flex justify-end space-x-2 rtl:space-x-reverse">
|
||||
<Button
|
||||
onClick={() => {
|
||||
setShowLocationModal(false);
|
||||
|
||||
@@ -149,7 +149,7 @@ export const AvailabilityTab = ({ isTeamEvent }: { isTeamEvent: boolean }) => {
|
||||
<span className="w-16 sm:w-28 sm:text-left">
|
||||
{format(dayRange.startTime, timeFormat === 12)}
|
||||
</span>
|
||||
<span className="ml-4">-</span>
|
||||
<span className="ltr:ml-4 rtl:mr-4">-</span>
|
||||
<div className="ml-6">{format(dayRange.endTime, timeFormat === 12)}</div>
|
||||
</div>
|
||||
))}
|
||||
@@ -164,7 +164,7 @@ export const AvailabilityTab = ({ isTeamEvent }: { isTeamEvent: boolean }) => {
|
||||
<hr />
|
||||
<div className="flex flex-col justify-center gap-2 sm:flex-row sm:justify-between">
|
||||
<span className="flex items-center justify-center text-sm text-gray-600 sm:justify-start">
|
||||
<Icon.FiGlobe className="mr-2" />
|
||||
<Icon.FiGlobe className="ltr:mr-2 rtl:ml-2" />
|
||||
{schedule?.timeZone || <SkeletonText className="block h-5 w-32" />}
|
||||
</span>
|
||||
<Button
|
||||
|
||||
@@ -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;
|
||||
@@ -133,8 +134,8 @@ const CustomInputTypeForm: FC<Props> = (props) => {
|
||||
value={selectedCustomInput?.id || -1}
|
||||
{...register("id", { valueAsNumber: true })}
|
||||
/>
|
||||
<div className="mt-5 flex justify-end space-x-2 sm:mt-4">
|
||||
<Button onClick={onCancel} type="button" color="secondary" className="ltr:mr-2">
|
||||
<div className="mt-5 flex justify-end space-x-2 rtl:space-x-reverse sm:mt-4">
|
||||
<Button onClick={onCancel} type="button" color="secondary" className="ltr:mr-2 rtl:ml-2">
|
||||
{t("cancel")}
|
||||
</Button>
|
||||
<Button
|
||||
|
||||
@@ -1,18 +1,19 @@
|
||||
import Link from "next/link";
|
||||
import type { CustomInputParsed, EventTypeSetupInfered, FormValues } from "pages/event-types/[type]";
|
||||
import type { CustomInputParsed, EventTypeSetupProps, FormValues } from "pages/event-types/[type]";
|
||||
import { useEffect, useState } from "react";
|
||||
import { Controller, useFormContext } from "react-hook-form";
|
||||
import short from "short-uuid";
|
||||
import { v5 as uuidv5 } from "uuid";
|
||||
|
||||
import DestinationCalendarSelector from "@calcom/features/calendars/DestinationCalendarSelector";
|
||||
import { APP_NAME, CAL_URL } from "@calcom/lib/constants";
|
||||
import CustomInputItem from "@calcom/features/eventtypes/components/CustomInputItem";
|
||||
import { APP_NAME, CAL_URL, IS_SELF_HOSTED } from "@calcom/lib/constants";
|
||||
import { useLocale } from "@calcom/lib/hooks/useLocale";
|
||||
import { trpc } from "@calcom/trpc/react";
|
||||
import {
|
||||
Badge,
|
||||
Button,
|
||||
Checkbox,
|
||||
CustomInputItem,
|
||||
Dialog,
|
||||
DialogClose,
|
||||
DialogContent,
|
||||
@@ -36,7 +37,19 @@ const generateHashedLink = (id: number) => {
|
||||
return uid;
|
||||
};
|
||||
|
||||
export const EventAdvancedTab = ({ eventType, team }: Pick<EventTypeSetupInfered, "eventType" | "team">) => {
|
||||
const getRandomId = (length = 8) => {
|
||||
return (
|
||||
-1 *
|
||||
parseInt(
|
||||
Math.ceil(Math.random() * Date.now())
|
||||
.toPrecision(length)
|
||||
.toString()
|
||||
.replace(".", "")
|
||||
)
|
||||
);
|
||||
};
|
||||
|
||||
export const EventAdvancedTab = ({ eventType, team }: Pick<EventTypeSetupProps, "eventType" | "team">) => {
|
||||
const connectedCalendarsQuery = trpc.viewer.connectedCalendars.useQuery();
|
||||
const formMethods = useFormContext<FormValues>();
|
||||
const { t } = useLocale();
|
||||
@@ -51,7 +64,6 @@ export const EventAdvancedTab = ({ eventType, team }: Pick<EventTypeSetupInfered
|
||||
const [selectedCustomInputModalOpen, setSelectedCustomInputModalOpen] = useState(false);
|
||||
const [requiresConfirmation, setRequiresConfirmation] = useState(eventType.requiresConfirmation);
|
||||
const placeholderHashedLink = `${CAL_URL}/d/${hashedUrl}/${eventType.slug}`;
|
||||
|
||||
const seatsEnabled = formMethods.getValues("seatsPerTimeSlotEnabled");
|
||||
|
||||
const removeCustom = (index: number) => {
|
||||
@@ -64,6 +76,12 @@ export const EventAdvancedTab = ({ eventType, team }: Pick<EventTypeSetupInfered
|
||||
!hashedUrl && setHashedUrl(generateHashedLink(eventType.users[0]?.id ?? team?.id));
|
||||
}, [eventType.users, hashedUrl, team?.id]);
|
||||
|
||||
useEffect(() => {
|
||||
if (eventType.customInputs) {
|
||||
setCustomInputs(eventType.customInputs.sort((a, b) => a.id - b.id));
|
||||
}
|
||||
}, [eventType.customInputs]);
|
||||
|
||||
return (
|
||||
<div className="flex flex-col space-y-8">
|
||||
{/**
|
||||
@@ -239,13 +257,30 @@ export const EventAdvancedTab = ({ eventType, team }: Pick<EventTypeSetupInfered
|
||||
defaultValue={eventType.successRedirectUrl || ""}
|
||||
{...formMethods.register("successRedirectUrl")}
|
||||
/>
|
||||
<div className="mt-2 flex">
|
||||
<Checkbox
|
||||
description={t("disable_success_page")}
|
||||
// Disable if it's not Self Hosted or if the redirect url is not set
|
||||
disabled={!IS_SELF_HOSTED || !formMethods.watch("successRedirectUrl")}
|
||||
{...formMethods.register("metadata.disableSuccessPage")}
|
||||
/>
|
||||
{/*TODO: Extract it out into a component when used more than once*/}
|
||||
{!IS_SELF_HOSTED && (
|
||||
<Link href="https://cal.com/pricing">
|
||||
<a target="_blank">
|
||||
<Badge variant="orange" className="ml-2">
|
||||
Platform Only
|
||||
</Badge>
|
||||
</a>
|
||||
</Link>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</SettingsToggle>
|
||||
</>
|
||||
)}
|
||||
/>
|
||||
<hr />
|
||||
|
||||
<SettingsToggle
|
||||
data-testid="hashedLinkCheck"
|
||||
title={t("private_link")}
|
||||
@@ -374,7 +409,7 @@ export const EventAdvancedTab = ({ eventType, team }: Pick<EventTypeSetupInfered
|
||||
<Controller
|
||||
name="customInputs"
|
||||
control={formMethods.control}
|
||||
defaultValue={eventType.customInputs.sort((a, b) => a.id - b.id) || []}
|
||||
defaultValue={customInputs}
|
||||
render={() => (
|
||||
<Dialog open={selectedCustomInputModalOpen} onOpenChange={setSelectedCustomInputModalOpen}>
|
||||
<DialogContent
|
||||
@@ -386,13 +421,14 @@ export const EventAdvancedTab = ({ eventType, team }: Pick<EventTypeSetupInfered
|
||||
selectedCustomInput={selectedCustomInput}
|
||||
onSubmit={(values) => {
|
||||
const customInput: CustomInputParsed = {
|
||||
id: -1,
|
||||
id: getRandomId(),
|
||||
eventTypeId: -1,
|
||||
label: values.label,
|
||||
placeholder: values.placeholder,
|
||||
required: values.required,
|
||||
type: values.type,
|
||||
options: values.options,
|
||||
hasToBeCreated: true,
|
||||
};
|
||||
if (selectedCustomInput) {
|
||||
selectedCustomInput.label = customInput.label;
|
||||
@@ -400,6 +436,7 @@ export const EventAdvancedTab = ({ eventType, team }: Pick<EventTypeSetupInfered
|
||||
selectedCustomInput.required = customInput.required;
|
||||
selectedCustomInput.type = customInput.type;
|
||||
selectedCustomInput.options = customInput.options || undefined;
|
||||
selectedCustomInput.hasToBeCreated = false;
|
||||
// Update by id
|
||||
const inputIndex = customInputs.findIndex((input) => input.id === values.id);
|
||||
customInputs[inputIndex] = selectedCustomInput;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { EventTypeSetupInfered, FormValues } from "pages/event-types/[type]";
|
||||
import { EventTypeSetupProps, FormValues } from "pages/event-types/[type]";
|
||||
import { useFormContext } from "react-hook-form";
|
||||
|
||||
import EventTypeAppContext, { GetAppData, SetAppData } from "@calcom/app-store/EventTypeAppContext";
|
||||
@@ -9,7 +9,7 @@ import { useLocale } from "@calcom/lib/hooks/useLocale";
|
||||
import { RouterOutputs, trpc } from "@calcom/trpc/react";
|
||||
import { Button, EmptyScreen, ErrorBoundary, Icon } from "@calcom/ui";
|
||||
|
||||
type EventType = Pick<EventTypeSetupInfered, "eventType">["eventType"] &
|
||||
type EventType = Pick<EventTypeSetupProps, "eventType">["eventType"] &
|
||||
EventTypeAppCardComponentProps["eventType"];
|
||||
|
||||
function AppCardWrapper({
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { useAutoAnimate } from "@formkit/auto-animate/react";
|
||||
import * as RadioGroup from "@radix-ui/react-radio-group";
|
||||
import { EventTypeSetupInfered, FormValues } from "pages/event-types/[type]";
|
||||
import { EventTypeSetupProps, FormValues } from "pages/event-types/[type]";
|
||||
import { useMemo, useRef, useState } from "react";
|
||||
import { Controller, useFormContext, useWatch } from "react-hook-form";
|
||||
|
||||
@@ -12,7 +12,7 @@ import { PeriodType } from "@calcom/prisma/client";
|
||||
import type { BookingLimit } from "@calcom/types/Calendar";
|
||||
import { Button, DateRangePicker, Icon, Input, InputField, Label, Select, SettingsToggle } from "@calcom/ui";
|
||||
|
||||
export const EventLimitsTab = ({ eventType }: Pick<EventTypeSetupInfered, "eventType">) => {
|
||||
export const EventLimitsTab = ({ eventType }: Pick<EventTypeSetupProps, "eventType">) => {
|
||||
const { t } = useLocale();
|
||||
const formMethods = useFormContext<FormValues>();
|
||||
const minimumBookingNoticeType = useRef<DurationType>(findDurationType(eventType.minimumBookingNotice));
|
||||
@@ -197,7 +197,7 @@ export const EventLimitsTab = ({ eventType }: Pick<EventTypeSetupInfered, "event
|
||||
label={t("minimum_booking_notice")}
|
||||
type="number"
|
||||
placeholder="120"
|
||||
className="mr-2 mb-0 h-[38px] rounded-[4px]"
|
||||
className="mb-0 h-[38px] rounded-[4px] ltr:mr-2 rtl:ml-2"
|
||||
{...formMethods.register("minimumBookingNoticeInDurationType", {
|
||||
onChange: (event: React.ChangeEvent<HTMLInputElement>) =>
|
||||
onMinimumNoticeChange(event.target.value),
|
||||
@@ -327,7 +327,7 @@ export const EventLimitsTab = ({ eventType }: Pick<EventTypeSetupInfered, "event
|
||||
</div>
|
||||
)}
|
||||
{period.type === "RANGE" && (
|
||||
<div className="inline-flex space-x-2 ltr:ml-2 rtl:mr-2 rtl:space-x-reverse">
|
||||
<div className="inline-flex space-x-2 ltr:ml-2 ltr:mr-2 rtl:ml-2 rtl:space-x-reverse">
|
||||
<Controller
|
||||
name="periodDates"
|
||||
control={formMethods.control}
|
||||
@@ -347,7 +347,9 @@ export const EventLimitsTab = ({ eventType }: Pick<EventTypeSetupInfered, "event
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
{period.suffix ? <span className="ltr:ml-2 rtl:mr-2"> {period.suffix}</span> : null}
|
||||
{period.suffix ? (
|
||||
<span className="ltr:ml-2 ltr:mr-2 rtl:ml-2"> {period.suffix}</span>
|
||||
) : null}
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
@@ -410,7 +412,9 @@ const BookingLimits = () => {
|
||||
.map(([key, bookingAmount]) => {
|
||||
const bookingLimitKey = key as BookingLimitsKey;
|
||||
return (
|
||||
<div className="mb-2 flex items-center space-x-2 text-sm" key={bookingLimitKey}>
|
||||
<div
|
||||
className="mb-2 flex items-center space-x-2 text-sm rtl:space-x-reverse"
|
||||
key={bookingLimitKey}>
|
||||
<Input
|
||||
id={`${bookingLimitKey}-limit`}
|
||||
type="number"
|
||||
|
||||
@@ -1,11 +1,10 @@
|
||||
import { EventTypeSetupInfered } from "pages/event-types/[type]";
|
||||
import { useState } from "react";
|
||||
import { EventTypeSetupProps } from "pages/event-types/[type]";
|
||||
|
||||
import getStripeAppData from "@calcom/lib/getStripeAppData";
|
||||
|
||||
import RecurringEventController from "./RecurringEventController";
|
||||
|
||||
export const EventRecurringTab = ({ eventType }: Pick<EventTypeSetupInfered, "eventType">) => {
|
||||
export const EventRecurringTab = ({ eventType }: Pick<EventTypeSetupProps, "eventType">) => {
|
||||
const stripeAppData = getStripeAppData(eventType);
|
||||
|
||||
const requirePayment = stripeAppData.price > 0;
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { useAutoAnimate } from "@formkit/auto-animate/react";
|
||||
import { zodResolver } from "@hookform/resolvers/zod";
|
||||
import { isValidPhoneNumber } from "libphonenumber-js";
|
||||
import { EventTypeSetupInfered, FormValues } from "pages/event-types/[type]";
|
||||
import type { EventTypeSetupProps, FormValues } from "pages/event-types/[type]";
|
||||
import { useState } from "react";
|
||||
import { Controller, useForm, useFormContext } from "react-hook-form";
|
||||
import { MultiValue } from "react-select";
|
||||
@@ -23,7 +23,7 @@ type OptionTypeBase = {
|
||||
};
|
||||
|
||||
export const EventSetupTab = (
|
||||
props: Pick<EventTypeSetupInfered, "eventType" | "locationOptions" | "team" | "teamMembers">
|
||||
props: Pick<EventTypeSetupProps, "eventType" | "locationOptions" | "team" | "teamMembers">
|
||||
) => {
|
||||
const { t } = useLocale();
|
||||
const formMethods = useFormContext<FormValues>();
|
||||
@@ -169,7 +169,7 @@ export const EventSetupTab = (
|
||||
alt={`${eventLocationType.label} logo`}
|
||||
/>
|
||||
<span className="truncate text-sm ltr:ml-1 rtl:mr-1">
|
||||
{location[eventLocationType.defaultValueVariable] || eventLocationType.label}
|
||||
{t(location[eventLocationType.defaultValueVariable] || eventLocationType.label)}
|
||||
</span>
|
||||
</div>
|
||||
<div className="flex">
|
||||
@@ -262,12 +262,14 @@ export const EventSetupTab = (
|
||||
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 (newOptions.length === 1 && defaultDuration === null) {
|
||||
setDefaultDuration(newOptions[0]);
|
||||
formMethods.setValue("length", newOptions[0].value);
|
||||
}
|
||||
formMethods.setValue("metadata.multipleDuration", values);
|
||||
}}
|
||||
@@ -288,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>
|
||||
@@ -296,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">
|
||||
@@ -343,7 +342,7 @@ export const EventSetupTab = (
|
||||
saveLocation={saveLocation}
|
||||
defaultValues={formMethods.getValues("locations")}
|
||||
selection={
|
||||
selectedLocation ? { value: selectedLocation.value, label: selectedLocation.label } : undefined
|
||||
selectedLocation ? { value: selectedLocation.value, label: t(selectedLocation.label) } : undefined
|
||||
}
|
||||
setSelectedLocation={setSelectedLocation}
|
||||
setEditingLocationType={setEditingLocationType}
|
||||
|
||||
@@ -1,11 +1,12 @@
|
||||
import { SchedulingType } from "@prisma/client/";
|
||||
import { EventTypeSetupInfered, FormValues } from "pages/event-types/[type]";
|
||||
import { EventTypeSetupProps, 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 { Label, Select } from "@calcom/ui";
|
||||
|
||||
interface IMemberToValue {
|
||||
id: number | null;
|
||||
@@ -25,8 +26,7 @@ export const EventTeamTab = ({
|
||||
eventType,
|
||||
team,
|
||||
teamMembers,
|
||||
currentUserMembership,
|
||||
}: Pick<EventTypeSetupInfered, "eventType" | "teamMembers" | "team" | "currentUserMembership">) => {
|
||||
}: Pick<EventTypeSetupProps, "eventType" | "teamMembers" | "team">) => {
|
||||
const formMethods = useFormContext<FormValues>();
|
||||
const { t } = useLocale();
|
||||
|
||||
@@ -101,48 +101,3 @@ export const EventTeamTab = ({
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
const TeamProfileCard = ({
|
||||
id,
|
||||
name,
|
||||
hasPermsToDelete,
|
||||
email,
|
||||
username,
|
||||
}: {
|
||||
id: number;
|
||||
name: string | null;
|
||||
email: string;
|
||||
username: string | null;
|
||||
hasPermsToDelete: boolean;
|
||||
}) => {
|
||||
const formMethods = useFormContext<FormValues>();
|
||||
const avatar = `${WEBAPP_URL}/${username}/avatar.png`;
|
||||
|
||||
return (
|
||||
<div className="flex items-center border border-gray-300 px-6 py-4 first:rounded-t-md last:rounded-b-md only:rounded-md">
|
||||
<Avatar imageSrc={avatar} gravatarFallbackMd5="ajsdkwakhsd1231" size="md" alt="Team Image" />
|
||||
<div className="flex flex-col pl-3">
|
||||
<div className="">
|
||||
<span className="pr-2 text-sm font-semibold leading-none text-black">{name}</span>
|
||||
</div>
|
||||
<p className="text-sm font-normal leading-normal text-gray-700">{email}</p>
|
||||
</div>
|
||||
{hasPermsToDelete && (
|
||||
<div className="ml-auto">
|
||||
<Button
|
||||
type="button"
|
||||
size="icon"
|
||||
color="destructive"
|
||||
StartIcon={Icon.FiTrash}
|
||||
onClick={() => {
|
||||
formMethods.setValue(
|
||||
"users",
|
||||
formMethods.getValues("users").filter((user) => user !== id.toString())
|
||||
);
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -0,0 +1,179 @@
|
||||
import { EventTypeSetupProps, 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<EventTypeSetupProps, "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>
|
||||
);
|
||||
};
|
||||
@@ -1,9 +1,9 @@
|
||||
import { TFunction } from "next-i18next";
|
||||
import { useRouter } from "next/router";
|
||||
import { EventTypeSetupInfered, FormValues } from "pages/event-types/[type]";
|
||||
import { EventTypeSetupProps, 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";
|
||||
@@ -37,9 +37,9 @@ import { EmbedButton, EmbedDialog } from "@components/Embed";
|
||||
|
||||
type Props = {
|
||||
children: React.ReactNode;
|
||||
eventType: EventTypeSetupInfered["eventType"];
|
||||
currentUserMembership: EventTypeSetupInfered["currentUserMembership"];
|
||||
team: EventTypeSetupInfered["team"];
|
||||
eventType: EventTypeSetupProps["eventType"];
|
||||
currentUserMembership: EventTypeSetupProps["currentUserMembership"];
|
||||
team: EventTypeSetupProps["team"];
|
||||
disableBorder?: boolean;
|
||||
enabledAppsNumber: number;
|
||||
installedAppsNumber: number;
|
||||
@@ -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
|
||||
|
||||
@@ -57,7 +57,7 @@ export default function RecurringEventController({
|
||||
{recurringEventState && (
|
||||
<div data-testid="recurring-event-collapsible" className="text-sm">
|
||||
<div className="flex items-center">
|
||||
<p className="mr-2 text-neutral-900">{t("repeats_every")}</p>
|
||||
<p className="text-neutral-900 ltr:mr-2 rtl:ml-2">{t("repeats_every")}</p>
|
||||
<input
|
||||
type="number"
|
||||
min="1"
|
||||
@@ -89,7 +89,7 @@ export default function RecurringEventController({
|
||||
/>
|
||||
</div>
|
||||
<div className="mt-4 flex items-center">
|
||||
<p className="mr-2 text-neutral-900">{t("for_a_maximum_of")}</p>
|
||||
<p className="text-neutral-900 ltr:mr-2 rtl:ml-2">{t("for_a_maximum_of")}</p>
|
||||
<input
|
||||
type="number"
|
||||
min="1"
|
||||
@@ -105,7 +105,7 @@ export default function RecurringEventController({
|
||||
setRecurringEventState(newVal);
|
||||
}}
|
||||
/>
|
||||
<p className="mr-2 text-neutral-900">
|
||||
<p className="text-neutral-900 ltr:mr-2 rtl:ml-2">
|
||||
{t("events", {
|
||||
count: recurringEventState.count,
|
||||
})}
|
||||
|
||||
@@ -82,7 +82,7 @@ const DisableTwoFactorAuthModal = ({ onDisable, onCancel }: DisableTwoFactorAuth
|
||||
</div>
|
||||
|
||||
<div className="mt-5 sm:mt-4 sm:flex sm:flex-row-reverse">
|
||||
<Button type="submit" className="ltr:ml-2 rtl:mr-2" disabled={isDisabling}>
|
||||
<Button type="submit" className="ltr:ml-2 ltr:mr-2 rtl:ml-2" disabled={isDisabling}>
|
||||
{t("disable")}
|
||||
</Button>
|
||||
<Button color="secondary" onClick={onCancel}>
|
||||
|
||||
@@ -177,7 +177,7 @@ const EnableTwoFactorModal = ({ onEnable, onCancel }: EnableTwoFactorModalProps)
|
||||
<WithStep step={SetupStep.ConfirmPassword} current={step}>
|
||||
<Button
|
||||
type="submit"
|
||||
className="ltr:ml-2 rtl:mr-2"
|
||||
className="ltr:ml-2 ltr:mr-2 rtl:ml-2"
|
||||
onClick={handleSetup}
|
||||
disabled={password.length === 0 || isSubmitting}>
|
||||
{t("continue")}
|
||||
@@ -186,13 +186,13 @@ const EnableTwoFactorModal = ({ onEnable, onCancel }: EnableTwoFactorModalProps)
|
||||
<WithStep step={SetupStep.DisplayQrCode} current={step}>
|
||||
<Button
|
||||
type="submit"
|
||||
className="ltr:ml-2 rtl:mr-2"
|
||||
className="ltr:ml-2 ltr:mr-2 rtl:ml-2"
|
||||
onClick={() => setStep(SetupStep.EnterTotpCode)}>
|
||||
{t("continue")}
|
||||
</Button>
|
||||
</WithStep>
|
||||
<WithStep step={SetupStep.EnterTotpCode} current={step}>
|
||||
<Button type="submit" className="ltr:ml-2 rtl:mr-2" disabled={isSubmitting}>
|
||||
<Button type="submit" className="ltr:ml-2 ltr:mr-2 rtl:ml-2" disabled={isSubmitting}>
|
||||
{t("enable")}
|
||||
</Button>
|
||||
</WithStep>
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
import { ShieldCheckIcon } from "@calcom/ui";
|
||||
import { Icon } from "@calcom/ui";
|
||||
|
||||
const TwoFactorModalHeader = ({ title, description }: { title: string; description: string }) => {
|
||||
return (
|
||||
<div className="mb-4 sm:flex sm:items-start">
|
||||
<div className="bg-brand text-brandcontrast dark:bg-darkmodebrand dark:text-darkmodebrandcontrast mx-auto flex h-12 w-12 flex-shrink-0 items-center justify-center rounded-full bg-opacity-5 sm:mx-0 sm:h-10 sm:w-10">
|
||||
<ShieldCheckIcon className="h-6 w-6 text-white" />
|
||||
<Icon.ShieldCheckIcon className="h-6 w-6 text-white" />
|
||||
</div>
|
||||
<div className="mt-3 text-center sm:mt-0 sm:ml-4 sm:text-left">
|
||||
<h3 className="font-cal text-lg font-medium leading-6 text-gray-900" id="modal-title">
|
||||
|
||||
@@ -62,7 +62,7 @@ export function CalendarSwitch(props: {
|
||||
}
|
||||
);
|
||||
return (
|
||||
<div className="flex space-x-2 py-1">
|
||||
<div className="flex space-x-2 py-1 rtl:space-x-reverse">
|
||||
<Switch
|
||||
key={props.externalId}
|
||||
name="enabled"
|
||||
|
||||
@@ -90,7 +90,7 @@ const DisableTwoFactorAuthModal = ({
|
||||
</div>
|
||||
|
||||
<div className="mt-5 sm:mt-4 sm:flex sm:flex-row-reverse">
|
||||
<Button type="submit" className="ltr:ml-2 rtl:mr-2" disabled={isDisabling}>
|
||||
<Button type="submit" className="ltr:ml-2 ltr:mr-2 rtl:ml-2" disabled={isDisabling}>
|
||||
{t("disable")}
|
||||
</Button>
|
||||
<Button color="secondary" onClick={onCancel}>
|
||||
|
||||
@@ -170,7 +170,7 @@ const EnableTwoFactorModal = ({ onEnable, onCancel, open, onOpenChange }: Enable
|
||||
<WithStep step={SetupStep.ConfirmPassword} current={step}>
|
||||
<Button
|
||||
type="submit"
|
||||
className="ltr:ml-2 rtl:mr-2"
|
||||
className="ltr:ml-2 ltr:mr-2 rtl:ml-2"
|
||||
onClick={handleSetup}
|
||||
disabled={password.length === 0 || isSubmitting}>
|
||||
{t("continue")}
|
||||
@@ -179,13 +179,13 @@ const EnableTwoFactorModal = ({ onEnable, onCancel, open, onOpenChange }: Enable
|
||||
<WithStep step={SetupStep.DisplayQrCode} current={step}>
|
||||
<Button
|
||||
type="submit"
|
||||
className="ltr:ml-2 rtl:mr-2"
|
||||
className="ltr:ml-2 ltr:mr-2 rtl:ml-2"
|
||||
onClick={() => setStep(SetupStep.EnterTotpCode)}>
|
||||
{t("continue")}
|
||||
</Button>
|
||||
</WithStep>
|
||||
<WithStep step={SetupStep.EnterTotpCode} current={step}>
|
||||
<Button type="submit" className="ltr:ml-2 rtl:mr-2" disabled={isSubmitting}>
|
||||
<Button type="submit" className="ltr:ml-2 ltr:mr-2 rtl:ml-2" disabled={isSubmitting}>
|
||||
{t("enable")}
|
||||
</Button>
|
||||
</WithStep>
|
||||
|
||||
@@ -1,11 +1,12 @@
|
||||
import classNames from "classnames";
|
||||
import React from "react";
|
||||
|
||||
import { APP_NAME, LOGO } from "@calcom/lib/constants";
|
||||
|
||||
import Loader from "@components/Loader";
|
||||
import { HeadSeo } from "@components/seo/head-seo";
|
||||
|
||||
import Credits from "../../../../packages/ui/v2/core/Credits";
|
||||
|
||||
interface Props {
|
||||
title: string;
|
||||
description: string;
|
||||
@@ -23,6 +24,7 @@ export default function AuthContainer(props: React.PropsWithChildren<Props>) {
|
||||
// eslint-disable-next-line @next/next/no-img-element
|
||||
<img className="mb-auto h-4" src={LOGO} alt={`${APP_NAME} Logo`} />
|
||||
)}
|
||||
|
||||
<div className={classNames(props.showLogo ? "text-center" : "", "sm:mx-auto sm:w-full sm:max-w-md")}>
|
||||
{props.heading && <h2 className="font-cal text-center text-3xl text-neutral-900">{props.heading}</h2>}
|
||||
</div>
|
||||
@@ -35,7 +37,10 @@ export default function AuthContainer(props: React.PropsWithChildren<Props>) {
|
||||
<div className="border-1 mx-2 rounded-md border-gray-200 bg-white px-4 py-10 sm:px-10">
|
||||
{props.children}
|
||||
</div>
|
||||
<div className="mt-8 text-center text-sm text-neutral-600">{props.footerText}</div>
|
||||
<div className="mt-8 text-center text-sm text-neutral-600">
|
||||
{props.footerText}
|
||||
<Credits />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
||||
@@ -34,7 +34,7 @@ export const AvatarGroup = function AvatarGroup(props: AvatarGroupProps) {
|
||||
);
|
||||
|
||||
return (
|
||||
<li key={idx} className="-mr-2 inline-block">
|
||||
<li key={idx} className="-ltr:mr-2 inline-block rtl:ml-2">
|
||||
{item.href ? (
|
||||
<Link href={item.href}>
|
||||
<a>{avatar}</a>
|
||||
|
||||
@@ -11,17 +11,7 @@ import { User } from "@calcom/prisma/client";
|
||||
import { TRPCClientErrorLike } from "@calcom/trpc/client";
|
||||
import { RouterOutputs, trpc } from "@calcom/trpc/react";
|
||||
import type { AppRouter } from "@calcom/trpc/server/routers/_app";
|
||||
import {
|
||||
Button,
|
||||
Dialog,
|
||||
DialogClose,
|
||||
DialogContent,
|
||||
DialogHeader,
|
||||
Icon,
|
||||
Input,
|
||||
Label,
|
||||
StarIconSolid,
|
||||
} from "@calcom/ui";
|
||||
import { Button, Dialog, DialogClose, DialogContent, DialogHeader, Icon, Input, Label } from "@calcom/ui";
|
||||
|
||||
export enum UsernameChangeStatusEnum {
|
||||
UPGRADE = "UPGRADE",
|
||||
@@ -240,7 +230,7 @@ const PremiumTextfield = (props: ICustomUsernameProps) => {
|
||||
isInputUsernamePremium ? "text-orange-400" : "",
|
||||
usernameIsAvailable ? "" : ""
|
||||
)}>
|
||||
{isInputUsernamePremium ? <StarIconSolid className="mt-[2px] w-6" /> : <></>}
|
||||
{isInputUsernamePremium ? <Icon.StarIconSolid className="mt-[2px] w-6" /> : <></>}
|
||||
{!isInputUsernamePremium && usernameIsAvailable ? <Icon.FiCheck className="mt-2 w-6" /> : <></>}
|
||||
</span>
|
||||
</div>
|
||||
|
||||
@@ -7,7 +7,17 @@ import { useLocale } from "@calcom/lib/hooks/useLocale";
|
||||
import { TRPCClientErrorLike } from "@calcom/trpc/client";
|
||||
import { trpc } from "@calcom/trpc/react";
|
||||
import { AppRouter } from "@calcom/trpc/server/routers/_app";
|
||||
import { Button, Dialog, DialogClose, DialogContent, DialogHeader, Icon, Input, Label } from "@calcom/ui";
|
||||
import {
|
||||
Button,
|
||||
Dialog,
|
||||
DialogClose,
|
||||
DialogContent,
|
||||
DialogHeader,
|
||||
Icon,
|
||||
Input,
|
||||
Label,
|
||||
TextField,
|
||||
} from "@calcom/ui";
|
||||
|
||||
interface ICustomUsernameProps {
|
||||
currentUsername: string | undefined;
|
||||
@@ -77,10 +87,9 @@ const UsernameTextfield = (props: ICustomUsernameProps) => {
|
||||
|
||||
const ActionButtons = () => {
|
||||
return usernameIsAvailable && currentUsername !== inputUsernameValue ? (
|
||||
<div className="flex flex-row">
|
||||
<div className="rlt:space-x-reverse mt-px flex flex-row space-x-2 ltr:ml-2 ltr:mr-2 rtl:ml-2 rtl:space-x-reverse">
|
||||
<Button
|
||||
type="button"
|
||||
className="mx-2"
|
||||
onClick={() => setOpenDialogSaveUsername(true)}
|
||||
data-testid="update-username-btn">
|
||||
{t("update")}
|
||||
@@ -88,7 +97,6 @@ const UsernameTextfield = (props: ICustomUsernameProps) => {
|
||||
<Button
|
||||
type="button"
|
||||
color="minimal"
|
||||
className="mx-2"
|
||||
onClick={() => {
|
||||
if (currentUsername) {
|
||||
setInputUsernameValue(currentUsername);
|
||||
@@ -110,26 +118,20 @@ const UsernameTextfield = (props: ICustomUsernameProps) => {
|
||||
|
||||
return (
|
||||
<div>
|
||||
<div>
|
||||
<Label htmlFor="username">{t("username")}</Label>
|
||||
</div>
|
||||
<div className="mt-2 flex rounded-md">
|
||||
<span
|
||||
className={classNames(
|
||||
"inline-flex items-center rounded-l-md border border-r-0 border-gray-300 bg-gray-50 px-3 text-sm text-gray-500"
|
||||
)}>
|
||||
{process.env.NEXT_PUBLIC_WEBSITE_URL.replace("https://", "").replace("http://", "")}/
|
||||
</span>
|
||||
<div className="relative w-full">
|
||||
<Input
|
||||
<TextField
|
||||
ref={usernameRef}
|
||||
name="username"
|
||||
value={inputUsernameValue}
|
||||
addOnLeading={
|
||||
<>{process.env.NEXT_PUBLIC_WEBSITE_URL.replace("https://", "").replace("http://", "")}/</>
|
||||
}
|
||||
autoComplete="none"
|
||||
autoCapitalize="none"
|
||||
autoCorrect="none"
|
||||
className={classNames(
|
||||
"mb-0 mt-0 h-6 rounded-md rounded-l-none",
|
||||
"mb-0 mt-0 h-6 rounded-md ltr:rounded-l-none rtl:rounded-r-none",
|
||||
markAsError
|
||||
? "focus:shadow-0 focus:ring-shadow-0 border-red-500 focus:border-red-500 focus:outline-none focus:ring-0"
|
||||
: ""
|
||||
@@ -141,18 +143,18 @@ const UsernameTextfield = (props: ICustomUsernameProps) => {
|
||||
data-testid="username-input"
|
||||
/>
|
||||
{currentUsername !== inputUsernameValue && (
|
||||
<div className="absolute right-[2px] top-0 flex flex-row">
|
||||
<div className="absolute right-[2px] top-6 flex flex-row">
|
||||
<span className={classNames("mx-2 py-2")}>
|
||||
{usernameIsAvailable ? <Icon.FiCheck className="mt-[2px] w-6" /> : <></>}
|
||||
{usernameIsAvailable ? <Icon.FiCheck className="w-6" /> : <></>}
|
||||
</span>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
<div className="hidden md:inline">
|
||||
<div className="mt-5 hidden md:inline">
|
||||
<ActionButtons />
|
||||
</div>
|
||||
</div>
|
||||
{markAsError && <p className="mt-1 text-xs text-red-500">Username is already taken</p>}
|
||||
{markAsError && <p className="mt-1 text-xs text-red-500">{t("username_already_taken")}</p>}
|
||||
|
||||
{usernameIsAvailable && currentUsername !== inputUsernameValue && (
|
||||
<div className="mt-2 flex justify-end md:hidden">
|
||||
|
||||
@@ -109,7 +109,7 @@ function Select<
|
||||
IndicatorSeparator: () => null,
|
||||
Input: InputComponent,
|
||||
}}
|
||||
className={classNames("text-sm", className)}
|
||||
className={classNames("border-0 text-sm", className)}
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
import parser from "accept-language-parser";
|
||||
import { IncomingMessage } from "http";
|
||||
|
||||
import prisma from "@calcom/prisma";
|
||||
import { Maybe } from "@calcom/trpc/server";
|
||||
|
||||
import { getSession } from "@lib/auth";
|
||||
@@ -17,6 +16,7 @@ export function getLocaleFromHeaders(req: IncomingMessage): string {
|
||||
}
|
||||
|
||||
export const getOrSetUserLocaleFromHeaders = async (req: IncomingMessage): Promise<string> => {
|
||||
const prisma = (await import("@calcom/prisma")).default;
|
||||
const session = await getSession({ req });
|
||||
const preferredLocale = getLocaleFromHeaders(req);
|
||||
|
||||
|
||||
@@ -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.4.0",
|
||||
"version": "2.4.3",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"analyze": "ANALYZE=true next build",
|
||||
|
||||
@@ -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,7 +27,7 @@ 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 { Icon } from "@calcom/ui";
|
||||
|
||||
import { inferSSRProps } from "@lib/types/inferSSRProps";
|
||||
import { EmbedProps } from "@lib/withEmbedSsr";
|
||||
@@ -58,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">
|
||||
@@ -68,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}
|
||||
@@ -138,7 +139,7 @@ export default function User(props: inferSSRProps<typeof getServerSideProps> & E
|
||||
<h1 className="font-cal mb-1 text-3xl text-neutral-900 dark:text-white">
|
||||
{nameOrUsername}
|
||||
{user.verified && (
|
||||
<BadgeCheckIcon className="mx-1 -mt-1 inline h-6 w-6 text-blue-500 dark:text-white" />
|
||||
<Icon.BadgeCheckIcon className="mx-1 -mt-1 inline h-6 w-6 text-blue-500 dark:text-white" />
|
||||
)}
|
||||
</h1>
|
||||
<p className="dark:text-darkgray-600 text-s text-neutral-500">{user.bio}</p>
|
||||
|
||||
@@ -19,7 +19,6 @@ import { seoConfig } from "@lib/config/next-seo.config";
|
||||
|
||||
import I18nLanguageHandler from "@components/I18nLanguageHandler";
|
||||
|
||||
import "../styles/fonts.css";
|
||||
import "../styles/globals.css";
|
||||
|
||||
function MyApp(props: AppProps) {
|
||||
@@ -32,7 +31,6 @@ function MyApp(props: AppProps) {
|
||||
}
|
||||
// Use the layout defined at the page level, if available
|
||||
const getLayout = Component.getLayout ?? ((page) => page);
|
||||
|
||||
return (
|
||||
<AppProviders {...props}>
|
||||
<DefaultSeo {...seoConfig.defaultNextSeo} />
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
import Document, { DocumentContext, Head, Html, Main, NextScript, DocumentProps } from "next/document";
|
||||
import Script from "next/script";
|
||||
|
||||
import { getDirFromLang } from "@calcom/lib/i18n";
|
||||
|
||||
type Props = Record<string, unknown> & DocumentProps;
|
||||
|
||||
function toRunBeforeReactOnClient() {
|
||||
@@ -47,7 +49,7 @@ class MyDocument extends Document<Props> {
|
||||
|
||||
render() {
|
||||
const { locale } = this.props.__NEXT_DATA__;
|
||||
const dir = locale === "ar" || locale === "he" ? "rtl" : "ltr";
|
||||
const dir = getDirFromLang(locale);
|
||||
return (
|
||||
<Html lang={locale} dir={dir}>
|
||||
<Head>
|
||||
|
||||
@@ -138,7 +138,7 @@ const providers: Provider[] = [
|
||||
username: user.username,
|
||||
email: user.email,
|
||||
name: user.name,
|
||||
role: "USER",
|
||||
role: "INACTIVE_ADMIN",
|
||||
belongsToActiveTeam: hasActiveTeams,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -0,0 +1,46 @@
|
||||
import type { NextApiRequest, NextApiResponse } from "next";
|
||||
import { z } from "zod";
|
||||
|
||||
import { fetcher } from "@calcom/app-store/dailyvideo/lib/VideoApiAdapter";
|
||||
import { getSession } from "@calcom/lib/auth";
|
||||
import { defaultHandler, defaultResponder } from "@calcom/lib/server";
|
||||
|
||||
const getAccessLinkSchema = z.union([
|
||||
z.object({
|
||||
download_link: z.string(),
|
||||
expires: z.number(),
|
||||
}),
|
||||
z.object({}),
|
||||
]);
|
||||
|
||||
const requestQuery = z.object({
|
||||
recordingId: z.string(),
|
||||
});
|
||||
|
||||
async function handler(
|
||||
req: NextApiRequest,
|
||||
res: NextApiResponse<z.infer<typeof getAccessLinkSchema> | void>
|
||||
) {
|
||||
const { recordingId } = requestQuery.parse(req.query);
|
||||
const session = await getSession({ req });
|
||||
|
||||
// Check if user belong to active team
|
||||
if (!session?.user?.belongsToActiveTeam) {
|
||||
return res.status(403);
|
||||
}
|
||||
try {
|
||||
const response = await fetcher(`/recordings/${recordingId}/access-link`).then(getAccessLinkSchema.parse);
|
||||
|
||||
if ("download_link" in response && response.download_link) {
|
||||
return res.status(200).json(response);
|
||||
}
|
||||
|
||||
return res.status(400);
|
||||
} catch (err) {
|
||||
res.status(500);
|
||||
}
|
||||
}
|
||||
|
||||
export default defaultHandler({
|
||||
GET: Promise.resolve({ default: defaultResponder(handler) }),
|
||||
});
|
||||
@@ -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);
|
||||
@@ -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,4 +1,4 @@
|
||||
import { GetServerSideProps, InferGetServerSidePropsType } from "next";
|
||||
import { GetServerSidePropsContext } from "next";
|
||||
import { ChangeEventHandler, useState } from "react";
|
||||
|
||||
import { getAppRegistry, getAppRegistryWithCredentials } from "@calcom/app-store/_appRegistry";
|
||||
@@ -6,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";
|
||||
@@ -30,10 +31,7 @@ function AppsSearch({
|
||||
);
|
||||
}
|
||||
|
||||
export default function Apps({
|
||||
categories,
|
||||
appStore,
|
||||
}: InferGetServerSidePropsType<typeof getServerSideProps>) {
|
||||
export default function Apps({ categories, appStore }: inferSSRProps<typeof getServerSideProps>) {
|
||||
const { t } = useLocale();
|
||||
const [searchText, setSearchText] = useState<string | undefined>(undefined);
|
||||
|
||||
@@ -52,12 +50,16 @@ export default function Apps({
|
||||
<TrendingAppsSlider items={appStore} />
|
||||
</>
|
||||
)}
|
||||
<AllApps apps={appStore} searchText={searchText} />
|
||||
<AllApps
|
||||
apps={appStore}
|
||||
searchText={searchText}
|
||||
categories={categories.map((category) => category.name)}
|
||||
/>
|
||||
</AppsLayout>
|
||||
);
|
||||
}
|
||||
|
||||
export const getServerSideProps: GetServerSideProps = async (context) => {
|
||||
export const getServerSideProps = async (context: GetServerSidePropsContext) => {
|
||||
const ssg = await ssgInit(context);
|
||||
|
||||
const session = await getSession(context);
|
||||
|
||||
@@ -17,7 +17,7 @@ import {
|
||||
InstalledAppsLayout,
|
||||
List,
|
||||
ShellSubHeading,
|
||||
SkeletonLoader,
|
||||
AppSkeletonLoader as SkeletonLoader,
|
||||
} from "@calcom/ui";
|
||||
|
||||
import { QueryCell } from "@lib/QueryCell";
|
||||
|
||||
@@ -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";
|
||||
@@ -131,7 +132,7 @@ export default function Login({
|
||||
{...register("email")}
|
||||
/>
|
||||
<div className="relative">
|
||||
<div className="absolute right-0 -top-[6px] z-10">
|
||||
<div className="absolute -top-[6px] z-10 ltr:right-0 rtl:left-0">
|
||||
<Link href="/auth/forgot-password">
|
||||
<a tabIndex={-1} className="text-sm font-medium text-gray-600">
|
||||
{t("forgot")}
|
||||
|
||||
@@ -1,6 +1,9 @@
|
||||
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";
|
||||
@@ -24,7 +27,7 @@ export default function Setup(props: inferSSRProps<typeof getServerSideProps>) {
|
||||
{
|
||||
title: t("enable_apps"),
|
||||
description: t("enable_apps_description"),
|
||||
content: <AdminAppsList baseURL="/auth/setup" />,
|
||||
content: <AdminAppsList baseURL="/auth/setup?step=2" />,
|
||||
isLoading: false,
|
||||
},
|
||||
];
|
||||
@@ -32,14 +35,33 @@ export default function Setup(props: inferSSRProps<typeof getServerSideProps>) {
|
||||
return (
|
||||
<>
|
||||
<main className="flex items-center bg-gray-100 print:h-full">
|
||||
<WizardForm href="/auth/setup" steps={steps} disableNavigation={shouldDisable} />
|
||||
<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 () => {
|
||||
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,
|
||||
|
||||
@@ -97,7 +97,7 @@ const SetupFormStep1 = (props: { setIsLoading: (val: boolean) => void }) => {
|
||||
<TextField
|
||||
addOnLeading={
|
||||
!longWebsiteUrl && (
|
||||
<span className="items-centerpx-3 inline-flex rounded-none text-sm text-gray-500">
|
||||
<span className="inline-flex items-center rounded-none px-3 text-sm text-gray-500">
|
||||
{process.env.NEXT_PUBLIC_WEBSITE_URL}/
|
||||
</span>
|
||||
)
|
||||
|
||||
@@ -1,18 +1,30 @@
|
||||
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 (
|
||||
<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" />
|
||||
<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>
|
||||
<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>
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
@@ -174,74 +174,70 @@ 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 ({ dateOverrides, ...values }) => {
|
||||
updateMutation.mutate({
|
||||
scheduleId: schedule,
|
||||
dateOverrides: dateOverrides.flatMap((override) => override.ranges),
|
||||
...values,
|
||||
});
|
||||
}}
|
||||
className="-mx-4 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 pr-4 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>
|
||||
{data?.workingHours && <DateOverride workingHours={data.workingHours} />}
|
||||
<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>
|
||||
);
|
||||
|
||||
@@ -168,17 +168,18 @@ const querySchema = z.object({
|
||||
changes: stringToBoolean,
|
||||
reschedule: stringToBoolean,
|
||||
isSuccessBookingPage: z.string().optional(),
|
||||
formerTime: z.string().optional(),
|
||||
});
|
||||
|
||||
export default function Success(props: SuccessProps) {
|
||||
const { t } = useLocale();
|
||||
const router = useRouter();
|
||||
|
||||
const {
|
||||
allRemainingBookings,
|
||||
isSuccessBookingPage,
|
||||
cancel: isCancellationMode,
|
||||
changes,
|
||||
formerTime,
|
||||
} = querySchema.parse(router.query);
|
||||
|
||||
if ((isCancellationMode || changes) && typeof window !== "undefined") {
|
||||
@@ -425,9 +426,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>
|
||||
</>
|
||||
)}
|
||||
@@ -435,6 +438,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}
|
||||
@@ -619,7 +635,7 @@ export default function Success(props: SuccessProps) {
|
||||
encodeURIComponent(new RRule(props.eventType.recurringEvent).toString())
|
||||
: "")
|
||||
}>
|
||||
<a className="mr-2 h-10 w-10 rounded-sm border border-neutral-200 px-3 py-2 dark:border-neutral-700 dark:text-white">
|
||||
<a className="h-10 w-10 rounded-sm border border-neutral-200 px-3 py-2 ltr:mr-2 rtl:ml-2 dark:border-neutral-700 dark:text-white">
|
||||
<svg
|
||||
className="-mt-1.5 inline-block h-4 w-4"
|
||||
fill="currentColor"
|
||||
@@ -790,10 +806,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>
|
||||
))}
|
||||
@@ -808,10 +824,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>
|
||||
))}
|
||||
@@ -824,10 +840,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>
|
||||
);
|
||||
@@ -1034,6 +1050,15 @@ export async function getServerSideProps(context: GetServerSidePropsContext) {
|
||||
customInputs: customInputSchema.array().parse(eventTypeRaw.customInputs),
|
||||
};
|
||||
|
||||
if (eventType.metadata?.disableSuccessPage && eventType.successRedirectUrl) {
|
||||
return {
|
||||
redirect: {
|
||||
destination: eventType.successRedirectUrl,
|
||||
permanent: false,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
const profile = {
|
||||
name: eventType.team?.name || eventType.users[0]?.name || null,
|
||||
email: eventType.team ? null : eventType.users[0].email || null,
|
||||
|
||||
@@ -1,450 +0,0 @@
|
||||
import { BookingStatus } from "@prisma/client";
|
||||
import { createHmac } from "crypto";
|
||||
import { instance } from "gaxios";
|
||||
import { GetServerSidePropsContext } from "next";
|
||||
import { useRouter } from "next/router";
|
||||
import { useState } from "react";
|
||||
import z from "zod";
|
||||
|
||||
import { getEventLocationValue, getSuccessPageLocationMessage } from "@calcom/app-store/locations";
|
||||
import dayjs from "@calcom/dayjs";
|
||||
import { getRecurringWhen } from "@calcom/emails/src/components/WhenInfo";
|
||||
import { useLocale } from "@calcom/lib/hooks/useLocale";
|
||||
import { parseRecurringEvent } from "@calcom/lib/isRecurringEvent";
|
||||
import { processBookingConfirmation } from "@calcom/lib/server/queries/bookings/confirm";
|
||||
import prisma from "@calcom/prisma";
|
||||
import { TRPCError } from "@calcom/trpc/server";
|
||||
import { inferSSRProps } from "@calcom/types/inferSSRProps";
|
||||
import { Button, Icon, TextArea } from "@calcom/ui";
|
||||
|
||||
import { HeadSeo } from "@components/seo/head-seo";
|
||||
|
||||
enum DirectAction {
|
||||
"accept" = "accept",
|
||||
"reject" = "reject",
|
||||
}
|
||||
const actionSchema = z.nativeEnum(DirectAction);
|
||||
|
||||
const refineParse = (result: z.SafeParseReturnType<any, any>, context: z.RefinementCtx) => {
|
||||
if (result.success === false) {
|
||||
result.error.issues.map((issue) => context.addIssue(issue));
|
||||
}
|
||||
};
|
||||
|
||||
const CALENDSO_ENCRYPTION_KEY = process.env.CALENDSO_ENCRYPTION_KEY || "";
|
||||
|
||||
const pageErrors = {
|
||||
signature_mismatch: "Direct link signature doesn't match signed data",
|
||||
booking_not_found: "Direct link booking not found",
|
||||
user_not_found: "Direct link booking user not found",
|
||||
};
|
||||
|
||||
const requestSchema = z.object({
|
||||
link: z
|
||||
.array(z.string())
|
||||
.max(4)
|
||||
.superRefine((data, ctx) => {
|
||||
refineParse(actionSchema.safeParse(data[0]), ctx);
|
||||
const signedData = `${data[1]}/${data[2]}`;
|
||||
const sig = createHmac("sha1", CALENDSO_ENCRYPTION_KEY).update(signedData).digest("base64");
|
||||
if (data[3] !== sig) {
|
||||
ctx.addIssue({
|
||||
message: pageErrors.signature_mismatch,
|
||||
code: "custom",
|
||||
});
|
||||
console.log(signedData, data, data[3], "==", sig);
|
||||
}
|
||||
}),
|
||||
reason: z.string().optional(),
|
||||
});
|
||||
|
||||
function bookingContent(status: BookingStatus | undefined | null) {
|
||||
switch (status) {
|
||||
case BookingStatus.PENDING:
|
||||
// Trying to reject booking without reason
|
||||
return {
|
||||
iconColor: "gray",
|
||||
Icon: Icon.FiCalendar,
|
||||
titleKey: "event_awaiting_approval",
|
||||
subtitleKey: "someone_requested_an_event",
|
||||
};
|
||||
case BookingStatus.ACCEPTED:
|
||||
// Booking was acepted successfully
|
||||
return {
|
||||
iconColor: "green",
|
||||
Icon: Icon.FiCheck,
|
||||
titleKey: "booking_confirmed",
|
||||
subtitleKey: "emailed_you_and_any_other_attendees",
|
||||
};
|
||||
case BookingStatus.REJECTED:
|
||||
// Booking was rejected successfully
|
||||
return {
|
||||
iconColor: "red",
|
||||
Icon: Icon.FiX,
|
||||
titleKey: "booking_rejection_success",
|
||||
subtitleKey: "emailed_you_and_any_other_attendees",
|
||||
};
|
||||
default:
|
||||
// Booking was already accepted or rejected
|
||||
return {
|
||||
iconColor: "yellow",
|
||||
Icon: Icon.FiAlertTriangle,
|
||||
titleKey: "booking_already_accepted_rejected",
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
export default function Directlink({ booking, reason, status }: inferSSRProps<typeof getServerSideProps>) {
|
||||
const { t } = useLocale();
|
||||
const router = useRouter();
|
||||
const acceptPath = router.asPath.replace("reject", "accept");
|
||||
const rejectPath = router.asPath.replace("accept", "reject");
|
||||
const [cancellationReason, setCancellationReason] = useState("");
|
||||
function getRecipientStart(format: string) {
|
||||
return dayjs(booking.startTime).tz(booking?.user?.timeZone).format(format);
|
||||
}
|
||||
|
||||
function getRecipientEnd(format: string) {
|
||||
return dayjs(booking.endTime).tz(booking?.user?.timeZone).format(format);
|
||||
}
|
||||
const organizer = {
|
||||
...booking.attendees[0],
|
||||
language: {
|
||||
translate: t,
|
||||
locale: booking.attendees[0].locale ?? "en",
|
||||
},
|
||||
};
|
||||
const location: ReturnType<typeof getEventLocationValue> = Array.isArray(booking.location)
|
||||
? booking.location[0]
|
||||
: // If there is no location set then we default to Cal Video
|
||||
"integrations:daily";
|
||||
const locationToDisplay = getSuccessPageLocationMessage(location, t);
|
||||
const content = bookingContent(status);
|
||||
const recurringInfo = getRecurringWhen({
|
||||
recurringEvent: booking.eventType?.recurringEvent,
|
||||
attendee: organizer,
|
||||
});
|
||||
return (
|
||||
<>
|
||||
<HeadSeo
|
||||
title={t(content.titleKey)}
|
||||
description=""
|
||||
nextSeoProps={{
|
||||
nofollow: true,
|
||||
noindex: true,
|
||||
}}
|
||||
/>
|
||||
<div className="dark:bg-darkgray-50 desktop-transparent min-h-screen bg-gray-100 px-4">
|
||||
<main className="mx-auto max-w-3xl">
|
||||
<div className="z-50 overflow-y-auto ">
|
||||
<div className="flex items-end justify-center px-4 pt-4 pb-20 text-center sm:block sm:p-0">
|
||||
<div className="inset-0 my-4 transition-opacity sm:my-0" aria-hidden="true">
|
||||
<div
|
||||
className="main dark:bg-darkgray-100 inline-block transform overflow-hidden rounded-lg border bg-white px-8 pt-5 pb-4 text-left align-bottom transition-all dark:border-neutral-700 sm:my-[68px] sm:w-full sm:max-w-xl sm:py-8 sm:align-middle"
|
||||
role="dialog"
|
||||
aria-modal="true"
|
||||
aria-labelledby="modal-headline">
|
||||
<div
|
||||
className={`flex h-12 w-12 items-center justify-center rounded-full sm:mx-auto bg-${content.iconColor}-100`}>
|
||||
<content.Icon className={`h-5 w-5 text-${content.iconColor}-600`} />
|
||||
</div>
|
||||
<div className="mt-6 mb-8 last:mb-0 sm:text-center">
|
||||
<h3
|
||||
className="text-2xl font-semibold leading-6 text-neutral-900 dark:text-white"
|
||||
id="modal-headline">
|
||||
{t(content.titleKey)}
|
||||
</h3>
|
||||
{content.subtitleKey && (
|
||||
<div className="mt-3">
|
||||
<p className="text-neutral-600 dark:text-gray-300">{t(content.subtitleKey)}</p>
|
||||
</div>
|
||||
)}
|
||||
<div className="dark:border-darkgray-300 mt-8 grid grid-cols-3 border-t border-[#e1e1e1] pt-8 text-left text-[#313131] dark:text-gray-300">
|
||||
<div className="col-span-3 font-medium sm:col-span-1">{t("what")}</div>
|
||||
<div className="col-span-3 mb-6 last:mb-0 sm:col-span-2">{booking.title}</div>
|
||||
<div className="col-span-3 font-medium sm:col-span-1">{t("when")}</div>
|
||||
<div className="col-span-3 mb-6 last:mb-0 sm:col-span-2">
|
||||
{recurringInfo !== "" && (
|
||||
<>
|
||||
{recurringInfo}
|
||||
<br />
|
||||
</>
|
||||
)}
|
||||
{booking.eventType.recurringEvent?.count ? `${t("starting")} ` : ""}
|
||||
{t(getRecipientStart("dddd").toLowerCase())},{" "}
|
||||
{t(getRecipientStart("MMMM").toLowerCase())} {getRecipientStart("D, YYYY")}
|
||||
<br />
|
||||
{getRecipientStart("h:mma")} - {getRecipientEnd("h:mma")}{" "}
|
||||
<span style={{ color: "#888888" }}>({booking.attendees[0].timeZone})</span>
|
||||
</div>
|
||||
{(booking?.user || booking?.attendees) && (
|
||||
<>
|
||||
<div className="col-span-3 font-medium sm:col-span-1">{t("who")}</div>
|
||||
<div className="col-span-3 last:mb-0 sm:col-span-2">
|
||||
<>
|
||||
{booking?.user && (
|
||||
<div className="mb-3">
|
||||
<p>{booking.user.name}</p>
|
||||
<p className="text-[#888888]">{booking.user.email}</p>
|
||||
</div>
|
||||
)}
|
||||
{booking?.attendees.map((attendee) => (
|
||||
<div key={attendee.name} className="mb-3 last:mb-0">
|
||||
{attendee.name && <p>{attendee.name}</p>}
|
||||
<p className="text-[#888888]">{attendee.email}</p>
|
||||
</div>
|
||||
))}
|
||||
</>
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
{locationToDisplay && (
|
||||
<>
|
||||
<div className="col-span-3 mt-6 font-medium sm:col-span-1">{t("where")}</div>
|
||||
<div className="col-span-3 mt-6 sm:col-span-2">
|
||||
{locationToDisplay.startsWith("http") ? (
|
||||
<a title="Meeting Link" href={locationToDisplay}>
|
||||
{locationToDisplay}
|
||||
</a>
|
||||
) : (
|
||||
locationToDisplay
|
||||
)}
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
{booking?.description && (
|
||||
<>
|
||||
<div className="col-span-3 mt-9 font-medium sm:col-span-1">
|
||||
{t("additional_notes")}
|
||||
</div>
|
||||
<div className="col-span-3 mb-2 mt-9 sm:col-span-2">
|
||||
<p>{booking.description}</p>
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
{status === BookingStatus.REJECTED && reason && (
|
||||
<>
|
||||
<div className="col-span-3 mt-9 font-medium sm:col-span-1">
|
||||
{t("rejection_reason")}
|
||||
</div>
|
||||
<div className="col-span-3 mb-2 mt-9 sm:col-span-2">
|
||||
<p>{reason}</p>
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
{status === BookingStatus.PENDING && reason === undefined && (
|
||||
<>
|
||||
<hr className="mt-6" />
|
||||
<div className="mt-5 text-left sm:mt-6">
|
||||
<label className="font-medium text-[#313131] dark:text-white">
|
||||
{`${t("rejection_reason")} (${t("optional").toLowerCase()})`}
|
||||
</label>
|
||||
<TextArea
|
||||
value={cancellationReason}
|
||||
onChange={(e) => setCancellationReason(e.target.value)}
|
||||
className="mt-2 mb-4 w-full dark:border-gray-900 dark:bg-gray-700 dark:text-white "
|
||||
rows={3}
|
||||
/>
|
||||
<div className="flex flex-col-reverse rtl:space-x-reverse">
|
||||
<div className="ml-auto flex w-full justify-end space-x-4">
|
||||
<Button
|
||||
color="secondary"
|
||||
className="hidden text-center sm:block"
|
||||
href={acceptPath}>
|
||||
{t("booking_accept_intent")}
|
||||
</Button>
|
||||
<Button
|
||||
className="hidden sm:block"
|
||||
onClick={async () => {
|
||||
router.push(
|
||||
`${rejectPath}?reason=${encodeURIComponent(cancellationReason)}`
|
||||
);
|
||||
}}>
|
||||
{t("rejection_confirmation")}
|
||||
</Button>
|
||||
<Button
|
||||
color="secondary"
|
||||
className="block text-center sm:hidden"
|
||||
href={acceptPath}>
|
||||
{t("accept")}
|
||||
</Button>
|
||||
<Button
|
||||
className="block sm:hidden"
|
||||
onClick={async () => {
|
||||
router.push(
|
||||
`${rejectPath}?reason=${encodeURIComponent(cancellationReason)}`
|
||||
);
|
||||
}}>
|
||||
{t("reject")}
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</main>
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
export async function getServerSideProps(context: GetServerSidePropsContext) {
|
||||
const parsedQuery = requestSchema.safeParse(context.query);
|
||||
|
||||
// Parsing error, showing error 500 with message
|
||||
if (parsedQuery.success === false) {
|
||||
return {
|
||||
redirect: {
|
||||
destination: `/500?error=${parsedQuery.error.errors[0].message.concat(
|
||||
" accessing " + context.resolvedUrl
|
||||
)}`,
|
||||
permanent: false,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
const {
|
||||
link: [action, email, bookingUid],
|
||||
reason,
|
||||
} = parsedQuery.data;
|
||||
|
||||
const isAccept = action === DirectAction.accept;
|
||||
|
||||
const bookingRaw = await prisma?.booking.findFirst({
|
||||
where: {
|
||||
uid: bookingUid,
|
||||
user: {
|
||||
email,
|
||||
},
|
||||
},
|
||||
select: {
|
||||
location: true,
|
||||
description: true,
|
||||
id: true,
|
||||
recurringEventId: true,
|
||||
status: true,
|
||||
title: true,
|
||||
startTime: true,
|
||||
endTime: true,
|
||||
eventType: {
|
||||
select: {
|
||||
recurringEvent: true,
|
||||
},
|
||||
},
|
||||
attendees: {
|
||||
select: {
|
||||
locale: true,
|
||||
name: true,
|
||||
email: true,
|
||||
timeZone: true,
|
||||
},
|
||||
},
|
||||
user: {
|
||||
select: {
|
||||
id: true,
|
||||
email: true,
|
||||
name: true,
|
||||
timeZone: true,
|
||||
locale: true,
|
||||
destinationCalendar: true,
|
||||
credentials: true,
|
||||
username: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
// Booking not found, showing error 500 with message
|
||||
if (!bookingRaw) {
|
||||
return {
|
||||
redirect: {
|
||||
destination: `/500?error=${pageErrors.booking_not_found.concat(" accessing " + context.resolvedUrl)}`,
|
||||
permanent: false,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
const booking = {
|
||||
...bookingRaw,
|
||||
startTime: bookingRaw.startTime.toString(),
|
||||
endTime: bookingRaw.endTime.toString(),
|
||||
eventType: {
|
||||
...bookingRaw.eventType,
|
||||
recurringEvent: parseRecurringEvent(bookingRaw?.eventType?.recurringEvent),
|
||||
},
|
||||
attendees: bookingRaw?.attendees.map((att) => ({
|
||||
...att,
|
||||
language: {
|
||||
locale: att.locale ?? "en",
|
||||
},
|
||||
})),
|
||||
};
|
||||
|
||||
// Booking user not found, showing error 500 with message
|
||||
if (booking.user === null) {
|
||||
return {
|
||||
redirect: {
|
||||
destination: `/500?error=${pageErrors.user_not_found.concat(" accessing " + context.resolvedUrl)}`,
|
||||
permanent: false,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
// Booking already accepted or rejected
|
||||
if (booking.status !== BookingStatus.PENDING) {
|
||||
return {
|
||||
props: {
|
||||
booking,
|
||||
status: null,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
// Trying to reject booking without reason
|
||||
if (!isAccept && reason === undefined) {
|
||||
return {
|
||||
props: {
|
||||
booking,
|
||||
status: BookingStatus.PENDING,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
// Booking good to be accepted or rejected, proceeding to mark it
|
||||
let result: { status: BookingStatus | undefined } = { status: undefined };
|
||||
try {
|
||||
result = await processBookingConfirmation(
|
||||
{
|
||||
bookingId: booking.id,
|
||||
user: booking.user,
|
||||
recurringEventId: booking.recurringEventId,
|
||||
confirmed: action === DirectAction.accept,
|
||||
rejectionReason: reason,
|
||||
},
|
||||
prisma
|
||||
);
|
||||
} catch (e) {
|
||||
if (e instanceof TRPCError) {
|
||||
return {
|
||||
redirect: {
|
||||
destination: `/500?error=${e.message.concat(" accessing " + context.resolvedUrl)}`,
|
||||
permanent: false,
|
||||
},
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
props: {
|
||||
booking,
|
||||
status: result.status,
|
||||
reason: context.query.reason ?? null,
|
||||
},
|
||||
};
|
||||
}
|
||||
@@ -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,
|
||||
@@ -128,7 +137,7 @@ export default function Bookings() {
|
||||
</div>
|
||||
)}
|
||||
<div className="pt-2 xl:pt-0">
|
||||
<p className="mb-2 text-xs font-medium uppercase leading-4 text-gray-500">{t("all")}</p>
|
||||
{/* <p className="mb-2 text-xs font-medium uppercase leading-4 text-gray-500">{t("all")}</p> */}
|
||||
<div className="overflow-hidden rounded-md border border-gray-200">
|
||||
<table className="w-full max-w-full table-fixed">
|
||||
<tbody className="divide-y divide-gray-200 bg-white" data-testid="bookings">
|
||||
@@ -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() })}
|
||||
|
||||
@@ -1,26 +1,24 @@
|
||||
/* eslint-disable @typescript-eslint/no-empty-function */
|
||||
import { useAutoAnimate } from "@formkit/auto-animate/react";
|
||||
import { PeriodType, Prisma, SchedulingType } from "@prisma/client";
|
||||
import { zodResolver } from "@hookform/resolvers/zod";
|
||||
import { PeriodType, SchedulingType } from "@prisma/client";
|
||||
import { GetServerSidePropsContext } from "next";
|
||||
import { useRouter } from "next/router";
|
||||
import { useState } from "react";
|
||||
import { useForm } from "react-hook-form";
|
||||
import { z } from "zod";
|
||||
|
||||
import { StripeData } from "@calcom/app-store/stripepayment/lib/server";
|
||||
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 { EventLocationType } from "@calcom/core/location";
|
||||
import { validateBookingLimitOrder } from "@calcom/lib";
|
||||
import { CAL_URL } from "@calcom/lib/constants";
|
||||
import convertToNewDurationType from "@calcom/lib/convertToNewDurationType";
|
||||
import findDurationType from "@calcom/lib/findDurationType";
|
||||
import getStripeAppData from "@calcom/lib/getStripeAppData";
|
||||
import getEventTypeById from "@calcom/lib/getEventTypeById";
|
||||
import { useLocale } from "@calcom/lib/hooks/useLocale";
|
||||
import { HttpError } from "@calcom/lib/http-error";
|
||||
import prisma from "@calcom/prisma";
|
||||
import { customInputSchema, EventTypeMetaDataSchema } from "@calcom/prisma/zod-utils";
|
||||
import { trpc } from "@calcom/trpc/react";
|
||||
import { trpc, RouterOutputs } from "@calcom/trpc/react";
|
||||
import type { BookingLimit, RecurringEvent } from "@calcom/types/Calendar";
|
||||
import { Form, showToast } from "@calcom/ui";
|
||||
|
||||
@@ -36,10 +34,10 @@ 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";
|
||||
|
||||
import { getTranslation } from "@server/lib/i18n";
|
||||
import { ssrInit } from "@server/lib/ssr";
|
||||
|
||||
export type FormValues = {
|
||||
@@ -93,32 +91,39 @@ 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"),
|
||||
});
|
||||
|
||||
export type EventTypeSetupInfered = inferSSRProps<typeof getServerSideProps>;
|
||||
export type EventTypeSetupProps = RouterOutputs["viewer"]["eventTypes"]["get"];
|
||||
|
||||
const EventTypePage = (props: inferSSRProps<typeof getServerSideProps>) => {
|
||||
const EventTypePage = (props: EventTypeSetupProps) => {
|
||||
const { t } = useLocale();
|
||||
const utils = trpc.useContext();
|
||||
const router = useRouter();
|
||||
const { tabName } = querySchema.parse(router.query);
|
||||
|
||||
const { data: eventTypeApps } = trpc.viewer.apps.useQuery({
|
||||
extendsFeature: "EventType",
|
||||
});
|
||||
|
||||
const { eventType: dbEventType, locationOptions, team, teamMembers } = props;
|
||||
// TODO: It isn't a good idea to maintain state using setEventType. If we want to connect the SSR'd data to tRPC, we should useQuery(["viewer.eventTypes.get"]) with initialData
|
||||
// Due to this change, when Form is saved, there is no way to propagate that info to eventType (e.g. disabling stripe app doesn't allow recurring tab to be enabled without refresh).
|
||||
const [eventType, setEventType] = useState(dbEventType);
|
||||
|
||||
const router = useRouter();
|
||||
const { tabName } = querySchema.parse(router.query);
|
||||
const { eventType, locationOptions, team, teamMembers, currentUserMembership } = props;
|
||||
|
||||
const [animationParentRef] = useAutoAnimate<HTMLDivElement>();
|
||||
|
||||
const updateMutation = trpc.viewer.eventTypes.update.useMutation({
|
||||
onSuccess: async ({ eventType: newEventType }) => {
|
||||
setEventType({ ...eventType, slug: newEventType.slug });
|
||||
onSuccess: async () => {
|
||||
showToast(
|
||||
t("event_type_updated_successfully", {
|
||||
eventTypeTitle: eventType.title,
|
||||
@@ -126,6 +131,9 @@ const EventTypePage = (props: inferSSRProps<typeof getServerSideProps>) => {
|
||||
"success"
|
||||
);
|
||||
},
|
||||
async onSettled() {
|
||||
await utils.viewer.eventTypes.get.invalidate();
|
||||
},
|
||||
onError: (err) => {
|
||||
let message = "";
|
||||
if (err instanceof HttpError) {
|
||||
@@ -193,6 +201,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;
|
||||
@@ -219,14 +237,7 @@ const EventTypePage = (props: inferSSRProps<typeof getServerSideProps>) => {
|
||||
/>
|
||||
),
|
||||
availability: <AvailabilityTab isTeamEvent={!!team} />,
|
||||
team: (
|
||||
<EventTeamTab
|
||||
eventType={eventType}
|
||||
teamMembers={teamMembers}
|
||||
team={team}
|
||||
currentUserMembership={props.currentUserMembership}
|
||||
/>
|
||||
),
|
||||
team: <EventTeamTab eventType={eventType} teamMembers={teamMembers} team={team} />,
|
||||
limits: <EventLimitsTab eventType={eventType} />,
|
||||
advanced: <EventAdvancedTab eventType={eventType} team={team} />,
|
||||
recurring: <EventRecurringTab eventType={eventType} />,
|
||||
@@ -237,6 +248,7 @@ const EventTypePage = (props: inferSSRProps<typeof getServerSideProps>) => {
|
||||
workflows={eventType.workflows.map((workflowOnEventType) => workflowOnEventType.workflow)}
|
||||
/>
|
||||
),
|
||||
webhooks: <EventTeamWebhooksTab eventType={eventType} team={team} />,
|
||||
} as const;
|
||||
|
||||
return (
|
||||
@@ -248,8 +260,8 @@ const EventTypePage = (props: inferSSRProps<typeof getServerSideProps>) => {
|
||||
team={team}
|
||||
isUpdateMutationLoading={updateMutation.isLoading}
|
||||
formMethods={formMethods}
|
||||
disableBorder={tabName === "apps" || tabName === "workflows"}
|
||||
currentUserMembership={props.currentUserMembership}>
|
||||
disableBorder={tabName === "apps" || tabName === "workflows" || tabName === "webhooks"}
|
||||
currentUserMembership={currentUserMembership}>
|
||||
<Form
|
||||
form={formMethods}
|
||||
id="event-type-form"
|
||||
@@ -283,7 +295,7 @@ const EventTypePage = (props: inferSSRProps<typeof getServerSideProps>) => {
|
||||
if (metadata?.multipleDuration.length < 1) {
|
||||
throw new Error(t("event_setup_multiple_duration_error"));
|
||||
} else {
|
||||
if (input.length && !metadata?.multipleDuration?.includes(input.length)) {
|
||||
if (!input.length && !metadata?.multipleDuration?.includes(input.length)) {
|
||||
throw new Error(t("event_setup_multiple_duration_default_error"));
|
||||
}
|
||||
}
|
||||
@@ -314,6 +326,18 @@ const EventTypePage = (props: inferSSRProps<typeof getServerSideProps>) => {
|
||||
);
|
||||
};
|
||||
|
||||
const EventTypePageWrapper = (props: inferSSRProps<typeof getServerSideProps>) => {
|
||||
const { data, isLoading } = trpc.viewer.eventTypes.get.useQuery(
|
||||
{ id: props.type },
|
||||
{
|
||||
initialData: props.initialData,
|
||||
}
|
||||
);
|
||||
|
||||
if (isLoading || !data) return null;
|
||||
return <EventTypePage {...data} />;
|
||||
};
|
||||
|
||||
export const getServerSideProps = async (context: GetServerSidePropsContext) => {
|
||||
const { req, query } = context;
|
||||
const session = await getSession({ req });
|
||||
@@ -335,233 +359,27 @@ export const getServerSideProps = async (context: GetServerSidePropsContext) =>
|
||||
};
|
||||
}
|
||||
|
||||
const userSelect = Prisma.validator<Prisma.UserSelect>()({
|
||||
name: true,
|
||||
username: true,
|
||||
id: true,
|
||||
avatar: true,
|
||||
email: true,
|
||||
locale: true,
|
||||
defaultScheduleId: true,
|
||||
});
|
||||
|
||||
const rawEventType = await prisma.eventType.findFirst({
|
||||
where: {
|
||||
AND: [
|
||||
{
|
||||
OR: [
|
||||
{
|
||||
users: {
|
||||
some: {
|
||||
id: session.user.id,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
team: {
|
||||
members: {
|
||||
some: {
|
||||
userId: session.user.id,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
userId: session.user.id,
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
id: typeParam,
|
||||
},
|
||||
],
|
||||
},
|
||||
select: {
|
||||
id: true,
|
||||
title: true,
|
||||
slug: true,
|
||||
description: true,
|
||||
length: true,
|
||||
hidden: true,
|
||||
locations: true,
|
||||
eventName: true,
|
||||
customInputs: true,
|
||||
timeZone: true,
|
||||
periodType: true,
|
||||
metadata: true,
|
||||
periodDays: true,
|
||||
periodStartDate: true,
|
||||
periodEndDate: true,
|
||||
periodCountCalendarDays: true,
|
||||
requiresConfirmation: true,
|
||||
recurringEvent: true,
|
||||
hideCalendarNotes: true,
|
||||
disableGuests: true,
|
||||
minimumBookingNotice: true,
|
||||
beforeEventBuffer: true,
|
||||
afterEventBuffer: true,
|
||||
slotInterval: true,
|
||||
hashedLink: true,
|
||||
bookingLimits: true,
|
||||
successRedirectUrl: true,
|
||||
currency: true,
|
||||
team: {
|
||||
select: {
|
||||
id: true,
|
||||
slug: true,
|
||||
members: {
|
||||
where: {
|
||||
accepted: true,
|
||||
},
|
||||
select: {
|
||||
role: true,
|
||||
user: {
|
||||
select: userSelect,
|
||||
},
|
||||
},
|
||||
},
|
||||
try {
|
||||
const res = await getEventTypeById({ eventTypeId: typeParam, userId: session.user.id, prisma });
|
||||
return {
|
||||
props: {
|
||||
session,
|
||||
type: typeParam,
|
||||
trpcState: ssr.dehydrate(),
|
||||
initialData: {
|
||||
eventType: res.eventType,
|
||||
locationOptions: res.locationOptions,
|
||||
team: res.team,
|
||||
teamMembers: res.teamMembers,
|
||||
currentUserMembership: res.currentUserMembership,
|
||||
},
|
||||
},
|
||||
users: {
|
||||
select: userSelect,
|
||||
},
|
||||
schedulingType: true,
|
||||
schedule: {
|
||||
select: {
|
||||
id: true,
|
||||
},
|
||||
},
|
||||
userId: true,
|
||||
price: true,
|
||||
destinationCalendar: true,
|
||||
seatsPerTimeSlot: true,
|
||||
seatsShowAttendees: true,
|
||||
workflows: {
|
||||
include: {
|
||||
workflow: {
|
||||
include: {
|
||||
activeOn: {
|
||||
select: {
|
||||
eventType: {
|
||||
select: {
|
||||
id: true,
|
||||
title: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
steps: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
if (!rawEventType) {
|
||||
};
|
||||
} catch (err) {
|
||||
return {
|
||||
notFound: true,
|
||||
};
|
||||
}
|
||||
|
||||
const credentials = await prisma.credential.findMany({
|
||||
where: {
|
||||
userId: session.user.id,
|
||||
app: {
|
||||
enabled: true,
|
||||
},
|
||||
},
|
||||
select: {
|
||||
id: true,
|
||||
type: true,
|
||||
key: true,
|
||||
userId: true,
|
||||
appId: true,
|
||||
invalid: true,
|
||||
},
|
||||
});
|
||||
|
||||
const { locations, metadata, ...restEventType } = rawEventType;
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
||||
const newMetadata = EventTypeMetaDataSchema.parse(metadata || {})!;
|
||||
const apps = newMetadata.apps || {};
|
||||
const eventTypeWithParsedMetadata = { ...rawEventType, metadata: newMetadata };
|
||||
newMetadata.apps = {
|
||||
...apps,
|
||||
stripe: {
|
||||
...getStripeAppData(eventTypeWithParsedMetadata, true),
|
||||
currency:
|
||||
(
|
||||
credentials.find((integration) => integration.type === "stripe_payment")
|
||||
?.key as unknown as StripeData
|
||||
)?.default_currency || "usd",
|
||||
},
|
||||
giphy: getEventTypeAppData(eventTypeWithParsedMetadata, "giphy", true),
|
||||
rainbow: getEventTypeAppData(eventTypeWithParsedMetadata, "rainbow", true),
|
||||
};
|
||||
|
||||
// TODO: How to extract metadata schema from _EventTypeModel to be able to parse it?
|
||||
// const parsedMetaData = _EventTypeModel.parse(newMetadata);
|
||||
const parsedMetaData = newMetadata;
|
||||
|
||||
const parsedCustomInputs = (rawEventType.customInputs || []).map((input) => customInputSchema.parse(input));
|
||||
|
||||
const eventType = {
|
||||
...restEventType,
|
||||
schedule: rawEventType.schedule?.id || rawEventType.users[0]?.defaultScheduleId || null,
|
||||
recurringEvent: parseRecurringEvent(restEventType.recurringEvent),
|
||||
bookingLimits: parseBookingLimit(restEventType.bookingLimits),
|
||||
locations: locations as unknown as LocationObject[],
|
||||
metadata: parsedMetaData,
|
||||
customInputs: parsedCustomInputs,
|
||||
};
|
||||
|
||||
// backwards compat
|
||||
if (eventType.users.length === 0 && !eventType.team) {
|
||||
const fallbackUser = await prisma.user.findUnique({
|
||||
where: {
|
||||
id: session.user.id,
|
||||
},
|
||||
select: userSelect,
|
||||
});
|
||||
if (!fallbackUser) throw Error("The event type doesn't have user and no fallback user was found");
|
||||
eventType.users.push(fallbackUser);
|
||||
}
|
||||
const currentUser = eventType.users.find((u) => u.id === session.user.id);
|
||||
const t = await getTranslation(currentUser?.locale ?? "en", "common");
|
||||
const integrations = await getEnabledApps(credentials);
|
||||
const locationOptions = getLocationOptions(integrations, t);
|
||||
|
||||
const eventTypeObject = Object.assign({}, eventType, {
|
||||
periodStartDate: eventType.periodStartDate?.toString() ?? null,
|
||||
periodEndDate: eventType.periodEndDate?.toString() ?? null,
|
||||
});
|
||||
|
||||
const teamMembers = eventTypeObject.team
|
||||
? eventTypeObject.team.members.map((member) => {
|
||||
const user = member.user;
|
||||
user.avatar = `${CAL_URL}/${user.username}/avatar.png`;
|
||||
return user;
|
||||
})
|
||||
: [];
|
||||
|
||||
// Find the current users memebership so we can check role to enable/disable deletion.
|
||||
// Sets to null if no membership is found - this must mean we are in a none team event type
|
||||
const currentUserMembership =
|
||||
eventTypeObject.team?.members.find((el) => el.user.id === session.user.id) ?? null;
|
||||
|
||||
return {
|
||||
props: {
|
||||
session,
|
||||
eventType: eventTypeObject,
|
||||
locationOptions,
|
||||
team: eventTypeObject.team || null,
|
||||
teamMembers,
|
||||
currentUserMembership,
|
||||
trpcState: ssr.dehydrate(),
|
||||
},
|
||||
};
|
||||
};
|
||||
|
||||
export default EventTypePage;
|
||||
export default EventTypePageWrapper;
|
||||
|
||||
@@ -4,10 +4,12 @@ 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 isCalcom from "@calcom/lib/isCalcom";
|
||||
import { RouterOutputs, trpc, TRPCClientError } from "@calcom/trpc/react";
|
||||
import {
|
||||
Badge,
|
||||
@@ -23,13 +25,11 @@ import {
|
||||
DropdownMenuSeparator,
|
||||
DropdownMenuTrigger,
|
||||
EmptyScreen,
|
||||
EventTypeDescription,
|
||||
Icon,
|
||||
Shell,
|
||||
showToast,
|
||||
Switch,
|
||||
Tooltip,
|
||||
TipBanner,
|
||||
} from "@calcom/ui";
|
||||
|
||||
import { withQuery } from "@lib/QueryCell";
|
||||
@@ -78,7 +78,7 @@ const Item = ({ type, group, readOnly }: { type: EventType; group: EventTypeGrou
|
||||
className="hidden font-normal leading-4 text-gray-600 sm:inline"
|
||||
data-testid={"event-type-slug-" + type.id}>{`/${group.profile.slug}/${type.slug}`}</small>
|
||||
{readOnly && (
|
||||
<span className="rtl:mr-2inline items-center rounded-sm bg-gray-100 px-1.5 py-0.5 text-xs font-medium text-gray-800 ltr:ml-2">
|
||||
<span className="rtl:ml-2inline items-center rounded-sm bg-gray-100 px-1.5 py-0.5 text-xs font-medium text-gray-800 ltr:ml-2 ltr:mr-2">
|
||||
{t("readonly") as string}
|
||||
</span>
|
||||
)}
|
||||
@@ -258,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
|
||||
@@ -394,7 +394,7 @@ export const EventTypeList = ({ group, groupIndex, readOnly, types }: EventTypeL
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="min-w-9 mr-5 flex sm:hidden">
|
||||
<div className="min-w-9 mx-5 flex sm:hidden">
|
||||
<Dropdown>
|
||||
<DropdownMenuTrigger asChild data-testid={"event-type-options-" + type.id}>
|
||||
<Button type="button" size="icon" color="secondary" StartIcon={Icon.FiMoreHorizontal} />
|
||||
@@ -531,7 +531,7 @@ const EventTypeListHeading = ({
|
||||
<a className="font-bold">{profile?.name || ""}</a>
|
||||
</Link>
|
||||
{membershipCount && teamId && (
|
||||
<span className="relative -top-px text-xs text-neutral-500 ltr:ml-2 rtl:mr-2">
|
||||
<span className="relative -top-px text-xs text-neutral-500 ltr:ml-2 ltr:mr-2 rtl:ml-2">
|
||||
<Link href={`/settings/teams/${teamId}/members`}>
|
||||
<a>
|
||||
<Badge variant="gray">
|
||||
@@ -589,7 +589,6 @@ const EventTypesPage = () => {
|
||||
customLoader={<SkeletonLoader />}
|
||||
success={({ data }) => (
|
||||
<>
|
||||
{isCalcom && <TipBanner />}
|
||||
{data.eventTypeGroups.map((group, index) => (
|
||||
<Fragment key={group.profile.slug}>
|
||||
{/* hide list heading when there is only one (current user) */}
|
||||
@@ -608,6 +607,7 @@ const EventTypesPage = () => {
|
||||
/>
|
||||
</Fragment>
|
||||
))}
|
||||
|
||||
{data.eventTypeGroups.length === 0 && <CreateFirstEventTypeView />}
|
||||
<EmbedDialog />
|
||||
</>
|
||||
|
||||
@@ -21,7 +21,7 @@ function AdminView() {
|
||||
const enteredUsername = usernameRef.current?.value.toLowerCase();
|
||||
signIn("impersonation-auth", { username: enteredUsername });
|
||||
}}>
|
||||
<div className="flex items-center space-x-2">
|
||||
<div className="flex items-center space-x-2 rtl:space-x-reverse">
|
||||
<TextField
|
||||
containerClassName="w-full"
|
||||
name={t("user_impersonation_heading")}
|
||||
|
||||
@@ -16,7 +16,7 @@ import {
|
||||
getSettingsLayout as getLayout,
|
||||
Icon,
|
||||
Meta,
|
||||
SkeletonLoader,
|
||||
AppSkeletonLoader as SkeletonLoader,
|
||||
} from "@calcom/ui";
|
||||
|
||||
import { ssrInit } from "@server/lib/ssr";
|
||||
|
||||
@@ -177,7 +177,9 @@ const AppearanceView = () => {
|
||||
<div className="flex w-full text-sm">
|
||||
<div className="mr-1 flex-grow">
|
||||
<div className="flex items-center">
|
||||
<p className="mr-2 font-semibold">{t("disable_cal_branding", { appName: APP_NAME })}</p>
|
||||
<p className="font-semibold ltr:mr-2 rtl:ml-2">
|
||||
{t("disable_cal_branding", { appName: APP_NAME })}
|
||||
</p>
|
||||
<Badge variant="gray">{t("pro")}</Badge>
|
||||
</div>
|
||||
<p className="mt-0.5 text-gray-600">{t("removes_cal_branding", { appName: APP_NAME })}</p>
|
||||
|
||||
@@ -156,7 +156,7 @@ const CalendarsView = () => {
|
||||
)
|
||||
}
|
||||
<div className="flex-grow truncate pl-2">
|
||||
<ListItemTitle component="h3" className="mb-1 space-x-2">
|
||||
<ListItemTitle component="h3" className="mb-1 space-x-2 rtl:space-x-reverse">
|
||||
<Link href={"/apps/" + item.integration.slug}>
|
||||
{item.integration.name || item.integration.title}
|
||||
</Link>
|
||||
|
||||
@@ -82,7 +82,7 @@ const ConferencingLayout = () => {
|
||||
app.logo && <img className="h-10 w-10" src={app.logo} alt={app.title} />
|
||||
}
|
||||
<div className="flex-grow truncate pl-2">
|
||||
<ListItemTitle component="h3" className="mb-1 space-x-2">
|
||||
<ListItemTitle component="h3" className="mb-1 space-x-2 rtl:space-x-reverse">
|
||||
<h3 className="truncate text-sm font-medium text-neutral-900">{app.title}</h3>
|
||||
</ListItemTitle>
|
||||
<ListItemText component="p">{app.description}</ListItemText>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -340,7 +340,7 @@ const ProfileForm = ({
|
||||
render={({ field: { value } }) => (
|
||||
<>
|
||||
<Avatar alt="" imageSrc={value} gravatarFallbackMd5={emailMd5} size="lg" />
|
||||
<div className="ml-4">
|
||||
<div className="ltr:ml-4 rtl:mr-4">
|
||||
<ImageUploader
|
||||
target="avatar"
|
||||
id="avatar-upload"
|
||||
|
||||
@@ -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")}
|
||||
|
||||
@@ -5,13 +5,14 @@ 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 { useToggleQuery } from "@lib/hooks/useToggleQuery";
|
||||
import { inferSSRProps } from "@lib/types/inferSSRProps";
|
||||
@@ -37,18 +38,18 @@ 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}`}>
|
||||
<a className="flex justify-between px-6 py-4" data-testid="event-type-link">
|
||||
<div className="flex-shrink">
|
||||
<div className="flex flex-wrap items-center space-x-2">
|
||||
<div className="flex flex-wrap items-center space-x-2 rtl:space-x-reverse">
|
||||
<h2 className="dark:text-darkgray-700 text-sm font-semibold text-gray-700">{type.title}</h2>
|
||||
</div>
|
||||
<EventTypeDescription className="text-sm" eventType={type} />
|
||||
@@ -96,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" />
|
||||
|
||||
@@ -14,8 +14,11 @@ function Teams() {
|
||||
heading={t("teams")}
|
||||
subtitle={t("create_manage_teams_collaborative")}
|
||||
CTA={
|
||||
<Button type="button" href={`${WEBAPP_URL}/settings/teams/new`}>
|
||||
<Icon.FiPlus className="inline-block h-3.5 w-3.5 text-white group-hover:text-black ltr:mr-2 rtl:ml-2" />
|
||||
<Button
|
||||
size="fab"
|
||||
StartIcon={Icon.FiPlus}
|
||||
type="button"
|
||||
href={`${WEBAPP_URL}/settings/teams/new?returnTo=/teams`}>
|
||||
{t("new")}
|
||||
</Button>
|
||||
}>
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -1 +1 @@
|
||||
{"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":{"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]"}}
|
||||
{"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]"}}
|
||||
@@ -385,6 +385,7 @@
|
||||
"go_to_billing_portal": "انتقل إلى بوابة الفوترة",
|
||||
"need_anything_else": "هل تحتاج إلى أي شيء آخر؟",
|
||||
"further_billing_help": "إذا كنت تحتاج إلى أي مساعدة إضافية بخصوص الفوترة، فإن فريق الدعم لدينا في انتظارك لتقديم المساعدة.",
|
||||
"contact_our_support_team": "الاتصال بفريق الدعم لدينا",
|
||||
"uh_oh": "عذرًا!",
|
||||
"no_event_types_have_been_setup": "لم يقم هذا المستخدم بإعداد أي أنواع للحدث حتى الآن.",
|
||||
"edit_logo": "تعديل الشعار",
|
||||
@@ -1389,7 +1390,7 @@
|
||||
"attendee_email_info": "البريد الإلكتروني للشخص الحجز",
|
||||
"kbar_search_placeholder": "اكتب أمرًا أو بحثًا...",
|
||||
"invalid_credential": "لا! يبدو أن الصلاحية انتهت أو تم إلغاؤها. يرجى إعادة التثبيت مرة أخرى.",
|
||||
"choose_common_schedule_team_event": "اختر جدولاً زمنياً مشتركاً",
|
||||
"choose_common_schedule_team_event": "اختر جدولًا زمنيًا مشتركًا",
|
||||
"choose_common_schedule_team_event_description": "قم بتمكين هذا الخيار إذا كنت ترغب في استخدام جدول زمني مشترك بين المضيفين. عند تعطيل هذا الخيار، سيتم حجز كل مضيف على أساس جدوله الافتراضي.",
|
||||
"reason": "السبب",
|
||||
"sender_id": "معرّف المرسل",
|
||||
|
||||
@@ -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.",
|
||||
@@ -383,6 +385,7 @@
|
||||
"go_to_billing_portal": "Přejít na fakturační portál",
|
||||
"need_anything_else": "Potřebujete ještě něco?",
|
||||
"further_billing_help": "Pokud potřebujete další pomoc s fakturací, náš tým podpory je zde, aby vám pomohl.",
|
||||
"contact_our_support_team": "Kontaktovat tým podpory",
|
||||
"uh_oh": "Ale ne!",
|
||||
"no_event_types_have_been_setup": "Tento uživatel zatím nezaložil žádné typy událostí.",
|
||||
"edit_logo": "Upravit logo",
|
||||
@@ -419,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é.",
|
||||
@@ -462,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",
|
||||
@@ -553,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.",
|
||||
@@ -618,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.",
|
||||
@@ -693,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",
|
||||
@@ -712,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ě.",
|
||||
@@ -768,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",
|
||||
@@ -806,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ů.",
|
||||
@@ -897,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>.",
|
||||
@@ -1014,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",
|
||||
@@ -1101,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í",
|
||||
@@ -1154,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",
|
||||
@@ -1360,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.",
|
||||
@@ -1370,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",
|
||||
@@ -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",
|
||||
@@ -370,6 +384,7 @@
|
||||
"go_to_billing_portal": "Zum Rechnungsportal gehen",
|
||||
"need_anything_else": "Brauchen Sie etwas anderes?",
|
||||
"further_billing_help": "Wenn Sie weitere Hilfe bei der Rechnungsstellung benötigen, hilft Ihnen unser Support-Team gerne weiter.",
|
||||
"contact_our_support_team": "Kontaktieren Sie unser Support-Team",
|
||||
"uh_oh": "Uh oh!",
|
||||
"no_event_types_have_been_setup": "Dieser Benutzer hat noch keine Termintypen eingerichtet.",
|
||||
"edit_logo": "Logo bearbeiten",
|
||||
@@ -406,6 +421,7 @@
|
||||
"current_incorrect_password": "Aktuelles Passwort ist falsch",
|
||||
"password_hint_caplow": "Mischung aus Groß- und Kleinbuchstaben",
|
||||
"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",
|
||||
@@ -438,22 +454,28 @@
|
||||
"additional_guests": "+ Weitere Gäste",
|
||||
"your_name": "Ihr Name",
|
||||
"email_address": "E-Mail Adresse",
|
||||
"enter_valid_email": "Bitte geben Sie eine gültige Emaildresse ein",
|
||||
"enter_valid_email": "Bitte geben Sie eine gültige E-Mail-Adresse ein",
|
||||
"location": "Ort",
|
||||
"address": "Adresse",
|
||||
"enter_address": "Geben Sie eine Adresse ein",
|
||||
"in_person_attendee_address": "In Person (Adresse von Ihnen)",
|
||||
"yes": "Ja",
|
||||
"no": "Nein",
|
||||
"additional_notes": "Zusätzliche Notizen",
|
||||
"booking_fail": "Termin konnte nicht gebucht werden.",
|
||||
"reschedule_fail": "Termin konnte nicht neugeplant werden.",
|
||||
"share_additional_notes": "Bitten teilen Sie Notizen zur Vorbereitung des Termins, falls nötig.",
|
||||
"share_additional_notes": "Teilen Sie uns weitere Informationen mit, die zur Vorbereitung des Termins hilfreich sind.",
|
||||
"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",
|
||||
@@ -493,6 +515,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",
|
||||
@@ -538,6 +562,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.",
|
||||
@@ -609,6 +637,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.",
|
||||
@@ -657,19 +686,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",
|
||||
@@ -686,6 +724,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",
|
||||
@@ -713,6 +752,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",
|
||||
@@ -788,6 +828,7 @@
|
||||
"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.",
|
||||
@@ -876,6 +917,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>.",
|
||||
@@ -889,11 +931,15 @@
|
||||
"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>",
|
||||
@@ -901,6 +947,7 @@
|
||||
"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",
|
||||
@@ -988,6 +1035,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",
|
||||
@@ -1075,6 +1125,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",
|
||||
@@ -1088,8 +1141,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.",
|
||||
@@ -1099,6 +1154,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",
|
||||
@@ -1167,6 +1223,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",
|
||||
@@ -1182,6 +1239,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",
|
||||
@@ -1191,6 +1249,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",
|
||||
@@ -1210,11 +1269,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",
|
||||
@@ -1223,6 +1284,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}}.",
|
||||
@@ -1230,12 +1292,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",
|
||||
@@ -1338,5 +1402,43 @@
|
||||
"route_to": "Weiterleiten zu",
|
||||
"test_preview_description": "Testen Sie Ihr Weiterleitungsformular, ohne Daten zu senden",
|
||||
"test_routing": "Testweiterleitung",
|
||||
"admin_apps_description": "Hier findest du eine Auflistung deiner Apps"
|
||||
"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"
|
||||
}
|
||||
|
||||
@@ -388,6 +388,7 @@
|
||||
"further_billing_help": "If you need any further help with billing, our support team are here to help.",
|
||||
"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",
|
||||
@@ -459,6 +460,9 @@
|
||||
"email_address": "Email address",
|
||||
"enter_valid_email": "Please enter a valid email",
|
||||
"location": "Location",
|
||||
"address": "Address",
|
||||
"enter_address": "Enter address",
|
||||
"in_person_attendee_address": "In Person (Attendee Address)",
|
||||
"yes": "yes",
|
||||
"no": "no",
|
||||
"additional_notes": "Additional notes",
|
||||
@@ -1090,6 +1094,10 @@
|
||||
"navigate": "Navigate",
|
||||
"open": "Open",
|
||||
"close": "Close",
|
||||
"upgrade": "Upgrade",
|
||||
"upgrade_to_access_recordings_title": "Upgrade to access recordings",
|
||||
"upgrade_to_access_recordings_description":"Recordings are only available as part of our teams plan. Upgrade to start recording your calls",
|
||||
"recordings_are_part_of_the_teams_plan":"Recordings are part of the teams plan",
|
||||
"team_feature_teams": "This is a Team feature. Upgrade to Team to see your team's availability.",
|
||||
"team_feature_workflows": "This is a Team feature. Upgrade to Team to automate your event notifications and reminders with Workflows.",
|
||||
"show_eventtype_on_profile": "Show on Profile",
|
||||
@@ -1147,8 +1155,11 @@
|
||||
"confirm_delete_account_modal": "Are you sure you want to delete your {{appName}} account?",
|
||||
"delete_my_account": "Delete my account",
|
||||
"start_of_week": "Start of week",
|
||||
"recordings_title": "Recordings",
|
||||
"recording": "Recording",
|
||||
"select_calendars": "Select which calendars you want to check for conflicts to prevent double bookings.",
|
||||
"check_for_conflicts": "Check for conflicts",
|
||||
"view_recordings": "View recordings",
|
||||
"adding_events_to": "Adding events to",
|
||||
"follow_system_preferences": "Follow system preferences",
|
||||
"custom_brand_colors": "Custom brand colors",
|
||||
@@ -1215,11 +1226,12 @@
|
||||
"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",
|
||||
"download_responses": "Download Responses",
|
||||
"download": "Download",
|
||||
"create_your_first_form": "Create your first form",
|
||||
"create_your_first_form_description": "With Routing Forms you can ask qualifying questions and route to the correct person or event type.",
|
||||
"create_your_first_webhook": "Create your first Webhook",
|
||||
@@ -1394,6 +1406,7 @@
|
||||
"attendee_email_info": "The person booking's email",
|
||||
"kbar_search_placeholder": "Type a command or search...",
|
||||
"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",
|
||||
@@ -1441,6 +1454,11 @@
|
||||
"enter_option": "Enter Option {{index}}",
|
||||
"add_an_option": "Add an option",
|
||||
"radio": "Radio",
|
||||
"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",
|
||||
@@ -1455,6 +1473,8 @@
|
||||
"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",
|
||||
@@ -1462,5 +1482,11 @@
|
||||
"no_availability_in_month": "No availability in {{month}}",
|
||||
"view_next_month": "View next month",
|
||||
"send_code" : "Send code",
|
||||
"number_verified": "Number Verified"
|
||||
"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",
|
||||
"disable_success_page":"Disable Success Page (only works if you have a redirect URL)",
|
||||
"invalid_admin_password": "You are set as an admin but you do not have a password length of at least 15 characters",
|
||||
"change_password_admin": "Change Password to gain admin access",
|
||||
"username_already_taken": "Username is already taken"
|
||||
}
|
||||
|
||||
@@ -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.",
|
||||
@@ -383,6 +385,7 @@
|
||||
"go_to_billing_portal": "Ir al portal de facturación",
|
||||
"need_anything_else": "¿Necesita algo más?",
|
||||
"further_billing_help": "Si necesita más ayuda con la facturación, nuestro equipo de soporte está aquí para ayudarlo.",
|
||||
"contact_our_support_team": "Contacta con nuestro equipo de soporte",
|
||||
"uh_oh": "Uh oh!",
|
||||
"no_event_types_have_been_setup": "Este usuario aún no ha configurado ningún tipo de evento.",
|
||||
"edit_logo": "Cambiar la marca",
|
||||
@@ -419,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.",
|
||||
@@ -462,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",
|
||||
@@ -553,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.",
|
||||
@@ -618,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.",
|
||||
@@ -693,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",
|
||||
@@ -712,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.",
|
||||
@@ -735,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",
|
||||
@@ -767,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",
|
||||
@@ -805,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.",
|
||||
@@ -896,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>.",
|
||||
@@ -1013,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",
|
||||
@@ -1100,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",
|
||||
@@ -1153,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",
|
||||
@@ -1359,6 +1387,7 @@
|
||||
"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": "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.",
|
||||
@@ -1369,5 +1398,43 @@
|
||||
"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"
|
||||
}
|
||||
|
||||
@@ -385,6 +385,7 @@
|
||||
"go_to_billing_portal": "Accéder au portail de facturation",
|
||||
"need_anything_else": "Besoin d'autre chose ?",
|
||||
"further_billing_help": "Si vous avez besoin d'aide pour la facturation, notre équipe d'assistance est là pour vous aider.",
|
||||
"contact_our_support_team": "Contactez notre équipe d'assistance",
|
||||
"uh_oh": "Oups !",
|
||||
"no_event_types_have_been_setup": "Cet utilisateur n'a pas encore configuré de types d'événements.",
|
||||
"edit_logo": "Modifier le logo",
|
||||
@@ -1400,5 +1401,41 @@
|
||||
"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",
|
||||
"admin_apps_description": "Activer les applications pour votre instance de Cal"
|
||||
"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": "שלחנו לך ולמשתתפים האחרים, אם ישנם כאלה, הודעת דוא\"ל עם הפרטים האלה.",
|
||||
@@ -383,6 +385,7 @@
|
||||
"go_to_billing_portal": "מעבר אל פורטל החיובים",
|
||||
"need_anything_else": "צריך משהו נוסף?",
|
||||
"further_billing_help": "אם דרוש לך סיוע נוסף בענייני חיוב, צוות התמיכה שלנו כאן כדי לעזור.",
|
||||
"contact_our_support_team": "יצירת קשר עם צוות התמיכה",
|
||||
"uh_oh": "אוי, לא!",
|
||||
"no_event_types_have_been_setup": "משתמש זה עדיין לא הגדיר סוג אירוע.",
|
||||
"edit_logo": "עריכת לוגו",
|
||||
@@ -419,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": "הסיסמה שגויה.",
|
||||
@@ -462,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": "שינוי המועד שנקבע",
|
||||
@@ -553,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": "פגישות מחזוריות בין חברי צוות מרובים.",
|
||||
@@ -600,7 +611,7 @@
|
||||
"monthly_other": "חודשים",
|
||||
"yearly_one": "שנה",
|
||||
"yearly_other": "שנים",
|
||||
"plus_more": "ועוד {{count}}",
|
||||
"plus_more": "{{count}} נוספים",
|
||||
"max": "מקסימום",
|
||||
"single_theme": "ערכת נושא בודדת",
|
||||
"brand_color": "צבע המותג",
|
||||
@@ -618,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 יום. ברגע שהתוקף של גרסת הניסיון יסתיים, חברי צוות אלה יוסתרו מהצוות, אלא אם תשדרג כעת.",
|
||||
@@ -693,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": "הוספת שדה קלט מותאם אישית חדש",
|
||||
@@ -712,6 +725,7 @@
|
||||
"delete_account_confirmation_message": "בטוח שברצונך למחוק את חשבון {{appName}} שלך? כל מי ששיתפת איתו את הקישור לחשבון לא יוכל יותר להזמין באמצעותו, וכל ההעדפות ששמרת יאבדו.",
|
||||
"integrations": "שילובים",
|
||||
"apps": "אפליקציות",
|
||||
"apps_listing": "פירוט האפליקציות",
|
||||
"category_apps": "אפליקציות בקטגוריה {{category}}",
|
||||
"app_store": "App Store",
|
||||
"app_store_description": "מקשרים בין אנשים, טכנולוגיה ומקום העבודה.",
|
||||
@@ -735,6 +749,7 @@
|
||||
"toggle_calendars_conflict": "סמן/י את לוחות השנה שבהם ברצונך לבדוק אם יש התנגשויות כדי למנוע כפל הזמנות.",
|
||||
"select_destination_calendar": "יצירת אירועים ב",
|
||||
"connect_additional_calendar": "חיבור לוח שנה נוסף",
|
||||
"calendar_updated_successfully": "עדכון לוח השנה בוצע בהצלחה",
|
||||
"conferencing": "שיחות ועידה",
|
||||
"calendar": "לוח שנה",
|
||||
"payments": "תשלומים",
|
||||
@@ -767,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": "נסה/י להוסיף אפליקציית שיחות ועידה כדי לשלב שיחות וידאו עם הלקוחות",
|
||||
@@ -805,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 ליצירת חשבונות.",
|
||||
@@ -896,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>.",
|
||||
@@ -1013,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": "הוספת פעולה",
|
||||
@@ -1100,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": "ניתן ליצור שמות אירועים בהתאמה אישית שיוצגו באירוע בלוח השנה",
|
||||
@@ -1153,8 +1178,11 @@
|
||||
"invoices": "חשבוניות",
|
||||
"embeds": "הטמעות",
|
||||
"impersonation": "התחזות",
|
||||
"impersonation_description": "הגדרות לניהול התחזות למשתמשים",
|
||||
"users": "משתמשים",
|
||||
"profile_description": "ניהול הגדרות עבור פרופיל {{appName}} שלך",
|
||||
"users_description": "כאן אפשר למצוא רשימה של כל המשתמשים",
|
||||
"users_listing": "רישום משתמש",
|
||||
"general_description": "ניהול הגדרות השפה ואזור הזמן",
|
||||
"calendars_description": "הגדרת האינטראקציה בין סוגי האירועים שלך לבין לוחות השנה שלך",
|
||||
"appearance_description": "ניהול ההגדרות של מראה ההזמנות שלך",
|
||||
@@ -1359,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": "יש להפעיל אפשרות זו אם רוצים להשתמש בלוח זמנים משותף בין המארחים. אם האפשרות הזו מבוטלת, כל מארח יוזמן לפי לוח הזמנים המשמש כברירת המחדל שלו.",
|
||||
@@ -1369,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": "הגדר/י כברירת מחדל"
|
||||
}
|
||||
|
||||
@@ -385,6 +385,7 @@
|
||||
"go_to_billing_portal": "Vai al portale di fatturazione",
|
||||
"need_anything_else": "Hai bisogno di altro?",
|
||||
"further_billing_help": "Se hai bisogno di ulteriore aiuto per la fatturazione, il nostro team di supporto è qui per aiutarti.",
|
||||
"contact_our_support_team": "Contatta il nostro team di supporto",
|
||||
"uh_oh": "Uh oh!",
|
||||
"no_event_types_have_been_setup": "Questo utente non ha ancora impostato alcun tipo di evento.",
|
||||
"edit_logo": "Modifica logo",
|
||||
|
||||
@@ -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}}",
|
||||
@@ -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": "あなたと他の参加者にこの情報を電子メールで送信しました。",
|
||||
@@ -383,6 +385,7 @@
|
||||
"go_to_billing_portal": "請求ポータルに移動",
|
||||
"need_anything_else": "他に必要なものはありませんか?",
|
||||
"further_billing_help": "請求に関するサポートが必要な場合は、サポートチームがお手伝いします。",
|
||||
"contact_our_support_team": "サポートチームに問い合わせる",
|
||||
"uh_oh": "おっと!",
|
||||
"no_event_types_have_been_setup": "このユーザーはまだイベントタイプを設定していません。",
|
||||
"edit_logo": "ロゴを編集",
|
||||
@@ -419,6 +422,7 @@
|
||||
"current_incorrect_password": "現在のパスワードが正しくありません",
|
||||
"password_hint_caplow": "アルファベットの大文字と小文字を両方使用してください",
|
||||
"password_hint_min": "8 文字以上入力してください",
|
||||
"password_hint_admin_min": "15 文字以上入力してください",
|
||||
"password_hint_num": "少なくとも 1 文字は数字を含めてください",
|
||||
"invalid_password_hint": "パスワードには少なくとも 1 文字以上数字を含め、アルファベットの大文字と小文字を両方使用した上で 7 文字以上の長さに設定してください",
|
||||
"incorrect_password": "パスワードが正しくありません。",
|
||||
@@ -462,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": "スケジュールの変更",
|
||||
@@ -553,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": "複数のチームメンバー間のミーティングを定期化する。",
|
||||
@@ -618,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 日間のトライアル期間中となっています。今すぐアップグレードしない限り、トライアル期間の終了とともにこれらのメンバーはあなたのチームにおいて非表示となります。",
|
||||
@@ -693,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": "新しいカスタム入力フィールドを追加する",
|
||||
@@ -712,6 +725,7 @@
|
||||
"delete_account_confirmation_message": "あなたの {{appName}} アカウントを本当に削除してもよろしいですか?あなたのアカウントリンクを共有しているユーザーは、そのアカウントを使用して予約を行うことができなくなり、保存していた設定も失われます。",
|
||||
"integrations": "連携",
|
||||
"apps": "アプリ",
|
||||
"apps_listing": "アプリ一覧",
|
||||
"category_apps": "{{category}} アプリ",
|
||||
"app_store": "App Store",
|
||||
"app_store_description": "人とテクノロジーと職場をつなぐ。",
|
||||
@@ -735,6 +749,7 @@
|
||||
"toggle_calendars_conflict": "ダブルブッキングを防ぐために、スケジュールの重なりをチェックするカレンダーを切り替えてください。",
|
||||
"select_destination_calendar": "以下にイベントを作成する",
|
||||
"connect_additional_calendar": "別のカレンダーを接続する",
|
||||
"calendar_updated_successfully": "カレンダーが正常に更新されました",
|
||||
"conferencing": "ミーティング中",
|
||||
"calendar": "カレンダー",
|
||||
"payments": "お支払い",
|
||||
@@ -767,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": "会議アプリを追加して、顧客とのビデオ通話を統合しましょう",
|
||||
@@ -805,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 インターフェースを使用してアカウントの作成を行うことをお勧めしております。",
|
||||
@@ -896,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>。",
|
||||
@@ -1013,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": "アクションを追加",
|
||||
@@ -1100,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": "カレンダーのイベントに表示するカスタマイズされたイベント名を作成します",
|
||||
@@ -1153,8 +1178,11 @@
|
||||
"invoices": "請求書",
|
||||
"embeds": "埋め込み",
|
||||
"impersonation": "なりすまし",
|
||||
"impersonation_description": "ユーザーなりすましを管理するための設定",
|
||||
"users": "ユーザー",
|
||||
"profile_description": "{{appName}} プロフィールの設定を管理します",
|
||||
"users_description": "ここにはすべてのユーザーの一覧が表示されます",
|
||||
"users_listing": "ユーザー一覧",
|
||||
"general_description": "言語とタイムゾーンの設定を管理します",
|
||||
"calendars_description": "イベントの種類とカレンダーの連携方法を設定します",
|
||||
"appearance_description": "予約画面の外観設定を管理します",
|
||||
@@ -1359,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": "ホスト間で共通のスケジュールを使用する場合には、これを有効にしてください。無効にすると、各ホストに対してはデフォルトのスケジュールに基づいて予約が行われます。",
|
||||
@@ -1369,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": "決まった出席者を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": "デフォルトとして設定"
|
||||
}
|
||||
|
||||
@@ -385,6 +385,7 @@
|
||||
"go_to_billing_portal": "결제 포털로 이동",
|
||||
"need_anything_else": "다른 것이 필요하십니까?",
|
||||
"further_billing_help": "청구와 관련하여 추가 도움이 필요한 경우 지원 팀이 도와드리겠습니다.",
|
||||
"contact_our_support_team": "지원팀에 문의하기",
|
||||
"uh_oh": "오!",
|
||||
"no_event_types_have_been_setup": "사용자가 이벤트 타입을 설정하지 않았습니다.",
|
||||
"edit_logo": "로고 수정하기",
|
||||
|
||||
@@ -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}}",
|
||||
@@ -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.",
|
||||
@@ -383,6 +385,7 @@
|
||||
"go_to_billing_portal": "Ga naar het facturatiepaneel",
|
||||
"need_anything_else": "Nog iets nodig?",
|
||||
"further_billing_help": "Als u verdere hulp nodig heeft bij facturering, is ons ondersteuningsteam er om u te helpen.",
|
||||
"contact_our_support_team": "Neem contact op met onze klantenservice",
|
||||
"uh_oh": "Oeps!",
|
||||
"no_event_types_have_been_setup": "Deze gebruiker heeft nog geen evenementen.",
|
||||
"edit_logo": "Bewerk logo",
|
||||
@@ -419,6 +422,7 @@
|
||||
"current_incorrect_password": "Uw wachtwoord is verkeerd",
|
||||
"password_hint_caplow": "Mix van hoofd- en kleine letters",
|
||||
"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.",
|
||||
@@ -462,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",
|
||||
@@ -553,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.",
|
||||
@@ -618,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.",
|
||||
@@ -693,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",
|
||||
@@ -712,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.",
|
||||
@@ -735,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",
|
||||
@@ -767,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",
|
||||
@@ -805,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.",
|
||||
@@ -896,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>.",
|
||||
@@ -1013,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",
|
||||
@@ -1100,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",
|
||||
@@ -1153,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",
|
||||
@@ -1359,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.",
|
||||
@@ -1369,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"
|
||||
}
|
||||
|
||||
@@ -303,6 +303,7 @@
|
||||
"cancelling_all_recurring": "Dette er alle gjenværende forekomster i den gjentakende hendelsen.",
|
||||
"error_with_status_code_occured": "Det oppstod en feil med statuskoden {{status}}.",
|
||||
"booking_already_cancelled": "Denne bookingen var allerede kansellert",
|
||||
"booking_already_accepted_rejected": "Denne bookingen var allerede akseptert eller avvist",
|
||||
"go_back_home": "Gå til hjem",
|
||||
"or_go_back_home": "Eller gå tilbake til hjem",
|
||||
"no_availability": "Utilgjengelig",
|
||||
@@ -385,6 +386,9 @@
|
||||
"go_to_billing_portal": "Gå til betalingsportalen",
|
||||
"need_anything_else": "Trenger du noe annet?",
|
||||
"further_billing_help": "Hvis du trenger ytterligere hjelp med betaling, er supportteamet vårt her for å hjelpe.",
|
||||
"contact": "Kontakt",
|
||||
"our_support_team": "vårt support-team",
|
||||
"contact_our_support_team": "Kontakt supportteamet vårt",
|
||||
"uh_oh": "Uh oh!",
|
||||
"no_event_types_have_been_setup": "Denne brukeren har ikke konfigurert noen hendelsestyper ennå.",
|
||||
"edit_logo": "Rediger logo",
|
||||
@@ -628,6 +632,7 @@
|
||||
"teams": "Team",
|
||||
"team": "Team",
|
||||
"team_billing": "Team Fakturering",
|
||||
"team_billing_description": "Administrer betaling for ditt team",
|
||||
"upgrade_to_flexible_pro_title": "Vi har endret fakturering for team",
|
||||
"upgrade_to_flexible_pro_message": "Det er medlemmer i teamet ditt uten sete. Oppgrader proffplanen din for å dekke manglende seter.",
|
||||
"changed_team_billing_info": "Fra januar 2022 tar vi betalt per sete for teammedlemmer. Medlemmer av teamet ditt som hadde PRO gratis, har nå en 14 dagers prøveversjon. Når prøveperioden deres utløper, vil disse medlemmene bli skjult for teamet ditt med mindre du oppgraderer nå.",
|
||||
@@ -703,6 +708,7 @@
|
||||
"hide_event_type": "Skjul hendelsestype",
|
||||
"edit_location": "Rediger sted",
|
||||
"into_the_future": "i fremtiden",
|
||||
"when_booked_with_less_than_notice": "Når booket med mindre enn <time></time> varsel",
|
||||
"within_date_range": "Innenfor en datoperiode",
|
||||
"indefinitely_into_future": "Uendelig inn i fremtiden",
|
||||
"add_new_custom_input_field": "Legg til nytt egendefinert input felt",
|
||||
@@ -722,6 +728,8 @@
|
||||
"delete_account_confirmation_message": "Er du sikker på at du vil slette {{appName}}-kontoen din? Alle du har delt konto-lenken med, vil ikke lenger kunne booke ved å bruke den, og eventuelle innstillinger du har lagret vil gå tapt.",
|
||||
"integrations": "Integrasjoner",
|
||||
"apps": "Apper",
|
||||
"apps_description": "Her finner du en liste over appene dine",
|
||||
"apps_listing": "App liste",
|
||||
"category_apps": "{{category}} apper",
|
||||
"app_store": "App Butikken",
|
||||
"app_store_description": "Kobler sammen folk, teknologi og arbeidsplassen.",
|
||||
@@ -745,6 +753,7 @@
|
||||
"toggle_calendars_conflict": "Huk av kalenderne du vil sjekke for konfliker for å hindre dobbelt-bookinger.",
|
||||
"select_destination_calendar": "Opprett hendelser på",
|
||||
"connect_additional_calendar": "Koble til enda en kalender",
|
||||
"calendar_updated_successfully": "Kalenderen er oppdatert",
|
||||
"conferencing": "Konferansering",
|
||||
"calendar": "Kalender",
|
||||
"payments": "Betalinger",
|
||||
@@ -1027,6 +1036,9 @@
|
||||
"error_removing_app": "Feil ved fjerning av app",
|
||||
"web_conference": "Nett-konferanse",
|
||||
"requires_confirmation": "Krever bekreftelse",
|
||||
"always_requires_confirmation": "Alltid",
|
||||
"requires_confirmation_threshold": "Krever bekreftelse hvis booket med < {{time}} $t({{unit}}_timeUnit) varsel",
|
||||
"may_require_confirmation": "Kan kreve bekreftelse",
|
||||
"nr_event_type_one": "{{count}} hendelsestype",
|
||||
"nr_event_type_other": "{{count}} hendelsestyper",
|
||||
"add_action": "Legg til handling",
|
||||
@@ -1079,6 +1091,10 @@
|
||||
"navigate": "Naviger",
|
||||
"open": "Åpne",
|
||||
"close": "Lukk",
|
||||
"upgrade": "Oppgrader",
|
||||
"upgrade_to_access_recordings_title": "Oppgrader for å få tilgang til opptak",
|
||||
"upgrade_to_access_recordings_description": "Opptak er kun tilgjengelig som en del av team-planen vår. Oppgrader for å begynne å ta opp samtalene dine",
|
||||
"recordings_are_part_of_the_teams_plan": "Opptak er en del av team-planen",
|
||||
"team_feature_teams": "Dette er en Team-funksjon. Oppgrader til Team for å se teamets tilgjengelighet.",
|
||||
"team_feature_workflows": "Dette er en Team-funksjon. Oppgrader til Team for å automatisere hendelsesvarslene og påminnelsene dine med arbeidsflyter.",
|
||||
"show_eventtype_on_profile": "Vis på Profil",
|
||||
@@ -1136,8 +1152,11 @@
|
||||
"confirm_delete_account_modal": "Er du sikker på at du vil slette {{appName}}-kontoen din?",
|
||||
"delete_my_account": "Slett kontoen min",
|
||||
"start_of_week": "Begynnelsen av uken",
|
||||
"recordings_title": "Opptak",
|
||||
"recording": "Opptak",
|
||||
"select_calendars": "Velg hvilke kalendere du vil sjekke for konflikter for å forhindre dobbeltbookinger.",
|
||||
"check_for_conflicts": "Se etter konflikter",
|
||||
"view_recordings": "Vis opptak",
|
||||
"adding_events_to": "Legger til hendelser til",
|
||||
"follow_system_preferences": "Følg systempreferansene",
|
||||
"custom_brand_colors": "Egendefinerte merkevare-farger",
|
||||
@@ -1170,8 +1189,11 @@
|
||||
"invoices": "Fakturaer",
|
||||
"embeds": "Innbygginger",
|
||||
"impersonation": "Etterligning",
|
||||
"impersonation_description": "Innstillinger for å administrere etterligning av brukere",
|
||||
"users": "Brukere",
|
||||
"profile_description": "Administrer innstillinger for {{appName}} profilen din",
|
||||
"users_description": "Her finner du en liste over alle brukere",
|
||||
"users_listing": "Bruker liste",
|
||||
"general_description": "Administrer innstillinger for språk og tidssone",
|
||||
"calendars_description": "Konfigurer hvordan hendelsestypene dine samhandler med kalenderne dine",
|
||||
"appearance_description": "Administrer innstillinger for booking-utseendet",
|
||||
@@ -1206,6 +1228,7 @@
|
||||
"to": "Til",
|
||||
"workflow_turned_on_successfully": "Arbeidsflyten for {{workflowName}} ble {{offOn}} slått av",
|
||||
"download_responses": "Last ned Respons",
|
||||
"download": "Nedlasting",
|
||||
"create_your_first_form": "Lag ditt første skjema",
|
||||
"create_your_first_form_description": "Med Viderekoblings-skjema kan du stille kvalifiserende spørsmål og videresende til riktig person eller hendelsestype.",
|
||||
"create_your_first_webhook": "Lag din første Webhook",
|
||||
@@ -1314,6 +1337,8 @@
|
||||
"booking_confirmation_success": "Booking-bekreftelsen var vellykket",
|
||||
"booking_rejection_success": "Booking-avvisningen var vellykket",
|
||||
"booking_confirmation_fail": "Booking-bekreftelse feilet",
|
||||
"booking_tentative": "Denne bookingen er foreløpig",
|
||||
"booking_accept_intent": "Oops, jeg vil akseptere",
|
||||
"we_wont_show_again": "Vi vil ikke vise dette igjen",
|
||||
"couldnt_update_timezone": "Vi kunne ikke oppdatere tidssonen",
|
||||
"updated_timezone_to": "Oppdaterte tidssone til {{formattedCurrentTz}}",
|
||||
@@ -1376,7 +1401,9 @@
|
||||
"number_sms_notifications": "Telefonnummer (SMS varsler)",
|
||||
"attendee_email_workflow": "Deltakerens e-post",
|
||||
"attendee_email_info": "Den som booker sin e-post",
|
||||
"kbar_search_placeholder": "Skriv inn en kommando eller søk...",
|
||||
"invalid_credential": "Å nei! Det ser ut til at tillatelsen er utløpt eller tilbakekalt. Vennligst installer på nytt.",
|
||||
"reschedule_reason_success_page": "Årsak for endring av tidspunkt",
|
||||
"choose_common_schedule_team_event": "Velg en felles timeplan",
|
||||
"choose_common_schedule_team_event_description": "Aktiver dette hvis du vil bruke en felles tidsplan mellom verter. Når den er deaktivert, vil hver vert bookes basert på deres standard tidsplan.",
|
||||
"reason": "Årsak",
|
||||
@@ -1387,10 +1414,25 @@
|
||||
"route_to": "Videresend til",
|
||||
"test_preview_description": "Test viderekoblings-skjemaet ditt uten å sende noen data",
|
||||
"test_routing": "Test Viderekobling",
|
||||
"payment_app_disabled": "En administrator har deaktivert en betalingsapp",
|
||||
"edit_event_type": "Rediger hendelsestype",
|
||||
"collective_scheduling": "Kollektiv planlegging av tidspunkt",
|
||||
"make_it_easy_to_book": "Gjør det enkelt å booke teamet ditt når alle er tilgjengelige.",
|
||||
"find_the_best_person": "Finn den beste personen tilgjengelig og bla gjennom teamet ditt.",
|
||||
"fixed_round_robin": "Fast round robin",
|
||||
"add_one_fixed_attendee": "Legg til én fast deltaker og round robin gjennom et antall deltakere.",
|
||||
"calcom_is_better_with_team": "Cal.com er bedre med team",
|
||||
"add_your_team_members": "Legg til team-medlemmene dine i hendelsestypene dine. Bruk kollektiv planlegging av tidspunkt for å inkludere alle eller finn den mest passende personen med round robin-planlegging.",
|
||||
"booking_limit_reached": "Booking-grensen for denne hendelsestypen er nådd",
|
||||
"admin_has_disabled": "En administrator har deaktivert {{appName}}",
|
||||
"fill_this_field": "Vennligst fyll ut dette feltet",
|
||||
"options": "Alternativer",
|
||||
"enter_option": "Angi alternativ {{index}}",
|
||||
"add_an_option": "Legg til et alternativ",
|
||||
"radio": "Radio"
|
||||
"radio": "Radio",
|
||||
"create_your_first_team_webhook_description": "Opprett din første webhook for denne team-hendelsestypen",
|
||||
"create_webhook_team_event_type": "Opprett en webhook for denne team-hendelsestypen",
|
||||
"disable_success_page": "Deaktiver Suksess-side (fungerer bare hvis du har en omdirigerings-URL)",
|
||||
"invalid_admin_password": "Du er satt som administrator, men du har ikke en passordlengde på minst 15 tegn",
|
||||
"change_password_admin": "Endre passord for å få administratortilgang"
|
||||
}
|
||||
|
||||
@@ -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.",
|
||||
@@ -383,6 +385,7 @@
|
||||
"go_to_billing_portal": "Przejdź do portalu rozliczeniowego",
|
||||
"need_anything_else": "Potrzebujesz czegoś innego?",
|
||||
"further_billing_help": "Jeśli potrzebujesz dalszej pomocy przy rozliczaniu, nasz zespół wsparcia jest tutaj, aby pomóc.",
|
||||
"contact_our_support_team": "Skontaktuj się z naszym zespołem wsparcia",
|
||||
"uh_oh": "Uh oh!",
|
||||
"no_event_types_have_been_setup": "Ten użytkownik nie ustawił jeszcze żadnych typów wydarzeń.",
|
||||
"edit_logo": "Edytuj logo",
|
||||
@@ -419,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.",
|
||||
@@ -462,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łóż",
|
||||
@@ -553,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.",
|
||||
@@ -618,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.",
|
||||
@@ -693,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",
|
||||
@@ -712,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.",
|
||||
@@ -735,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",
|
||||
@@ -767,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.",
|
||||
@@ -805,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.",
|
||||
@@ -896,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>.",
|
||||
@@ -1013,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ść",
|
||||
@@ -1100,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ń.",
|
||||
@@ -1153,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",
|
||||
@@ -1359,15 +1387,54 @@
|
||||
"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.",
|
||||
"reason": "Powód",
|
||||
"sender_id": "Identyfikator nadawcy",
|
||||
"sender_id_error_message": "Dozwolone są tylko litery, cyfry i spacje (maksymalnie 11 znaków)",
|
||||
"test_routing_form": "Przetestuj formularz przekierowania",
|
||||
"test_routing_form": "Testowanie formularza przekierowania",
|
||||
"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"
|
||||
}
|
||||
|
||||
@@ -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.",
|
||||
@@ -383,6 +385,7 @@
|
||||
"go_to_billing_portal": "Ir para o portal de pagamento",
|
||||
"need_anything_else": "Precisa de algo mais?",
|
||||
"further_billing_help": "Se precisar de mais ajuda com o faturamento, o nosso time de suporte está aqui para ajudar.",
|
||||
"contact_our_support_team": "Fale com a nossa equipe de suporte",
|
||||
"uh_oh": "Oh oh!",
|
||||
"no_event_types_have_been_setup": "Este usuário ainda não definiu nenhum tipo de evento.",
|
||||
"edit_logo": "Editar logotipo",
|
||||
@@ -463,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",
|
||||
@@ -554,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.",
|
||||
@@ -619,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.",
|
||||
@@ -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": "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",
|
||||
@@ -713,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.",
|
||||
@@ -736,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",
|
||||
@@ -768,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",
|
||||
@@ -806,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.",
|
||||
@@ -897,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>.",
|
||||
@@ -1014,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",
|
||||
@@ -1101,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",
|
||||
@@ -1154,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",
|
||||
@@ -1360,6 +1387,7 @@
|
||||
"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.",
|
||||
@@ -1370,5 +1398,43 @@
|
||||
"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"
|
||||
}
|
||||
|
||||
@@ -385,6 +385,7 @@
|
||||
"go_to_billing_portal": "Ir para o portal de pagamento",
|
||||
"need_anything_else": "Precisa de algo mais?",
|
||||
"further_billing_help": "Se precisar de mais ajuda com a faturação, a nossa equipa de suporte está aqui para ajudar.",
|
||||
"contact_our_support_team": "Contacte a nossa equipa de suporte",
|
||||
"uh_oh": "Uh oh!",
|
||||
"no_event_types_have_been_setup": "Este utilizador ainda não configurou nenhum tipo de evento.",
|
||||
"edit_logo": "Editar logótipo",
|
||||
|
||||
@@ -52,6 +52,7 @@
|
||||
"still_waiting_for_approval": "Un eveniment încă așteaptă aprobare",
|
||||
"event_is_still_waiting": "Solicitarea evenimentului este încă în așteptare: {{attendeeName}} - {{date}} - {{eventType}}",
|
||||
"no_more_results": "Nu mai există rezultate",
|
||||
"no_results": "Niciun rezultat",
|
||||
"load_more_results": "Încărcați mai multe rezultate",
|
||||
"integration_meeting_id": "{{integrationName}} ședință ID: {{meetingId}}",
|
||||
"confirmed_event_type_subject": "Confirmat: {{eventType}} cu {{name}} pe {{date}}",
|
||||
@@ -248,6 +249,7 @@
|
||||
"add_to_calendar": "Adaugă în calendar",
|
||||
"add_another_calendar": "Adăugați alt calendar",
|
||||
"other": "Altele",
|
||||
"email_sign_in_subject": "Linkul tău de conectare pentru {{appName}}",
|
||||
"emailed_you_and_attendees": "V-am trimis un e-mail dumneavoastră şi celuilalt participant la o invitaţie în calendar cu toate detaliile.",
|
||||
"emailed_you_and_attendees_recurring": "V-am trimis un e-mail dvs. și celorlalți participanți cu o invitație în calendar pentru primul dintre aceste evenimente recurente.",
|
||||
"emailed_you_and_any_other_attendees": "Dumneavoastră şi oricare alţi participanţi aţi primit prin e-mail aceste informaţii.",
|
||||
@@ -383,6 +385,7 @@
|
||||
"go_to_billing_portal": "Accesați portalul de facturare",
|
||||
"need_anything_else": "Aveți nevoie de altceva?",
|
||||
"further_billing_help": "Dacă ai nevoie de ajutor suplimentar pentru facturare, echipa noastră de asistență este aici pentru a te ajuta.",
|
||||
"contact_our_support_team": "Contactează echipa noastră de suport",
|
||||
"uh_oh": "Uh oh!",
|
||||
"no_event_types_have_been_setup": "Acest utilizator nu a configurat încă niciun tip de eveniment.",
|
||||
"edit_logo": "Editare logo",
|
||||
@@ -463,11 +466,14 @@
|
||||
"booking_confirmation": "Confirmă {{eventTypeTitle}} cu {{profileName}}",
|
||||
"booking_reschedule_confirmation": "Reprogramează {{eventTypeTitle}} cu {{profileName}}",
|
||||
"in_person_meeting": "Link sau întâlnire în persoană",
|
||||
"attendeeInPerson": "În persoană (adresă participant)",
|
||||
"inPerson": "În persoană (adresă organizator)",
|
||||
"link_meeting": "Link întâlnire",
|
||||
"phone_call": "Număr de telefon participant",
|
||||
"your_number": "Numărul dvs. de telefon",
|
||||
"phone_number": "Număr de telefon",
|
||||
"attendee_phone_number": "Număr de telefon participant",
|
||||
"organizer_phone_number": "Număr de telefon organizator",
|
||||
"host_phone_number": "Numărul dvs. de telefon",
|
||||
"enter_phone_number": "Introduceți numărul de telefon",
|
||||
"reschedule": "Reprogrameaza",
|
||||
@@ -554,6 +560,10 @@
|
||||
"collective": "Colectiv",
|
||||
"collective_description": "Planifică ședințe când toți membrii selecționați ai echipei sunt disponibili.",
|
||||
"duration": "Durata",
|
||||
"available_durations": "Durate disponibile",
|
||||
"default_duration": "Durată implicită",
|
||||
"default_duration_no_options": "Alege mai întâi duratele disponibile",
|
||||
"multiple_duration_mins": "{{count}} $t(minute_timeUnit)",
|
||||
"minutes": "Minute",
|
||||
"round_robin": "Round Robin",
|
||||
"round_robin_description": "Întâlniri ciclice între mai mulţi membri ai echipei.",
|
||||
@@ -619,6 +629,7 @@
|
||||
"teams": "Echipe",
|
||||
"team": "Echipă",
|
||||
"team_billing": "Facturare echipă",
|
||||
"team_billing_description": "Gestionează facturarea pentru echipa ta",
|
||||
"upgrade_to_flexible_pro_title": "Am schimbat facturarea pentru echipe",
|
||||
"upgrade_to_flexible_pro_message": "Există membri fără licență în echipa dvs. Faceți upgrade la planul Pro pentru a acoperi licențele lipsă.",
|
||||
"changed_team_billing_info": "Începând din ianuarie 2022, se percepe un preț per licență pentru membrii echipei. Membrii echipei dvs. care au avut gratuit planul PRO sunt acum într-o perioadă de probă de 14 zile. Odată ce perioada de probă expiră, acești membri vor fi ascunși în echipa dvs. dacă nu faceți upgrade acum.",
|
||||
@@ -694,6 +705,7 @@
|
||||
"hide_event_type": "Ascunde tipul de eveniment",
|
||||
"edit_location": "Editați locația",
|
||||
"into_the_future": "în viitor",
|
||||
"when_booked_with_less_than_notice": "Când se rezervă cu aviz mai scurt de <time></time>",
|
||||
"within_date_range": "Intr-un interval de timp",
|
||||
"indefinitely_into_future": "Pe termen nelimitat în viitor",
|
||||
"add_new_custom_input_field": "Adaugă un nou câmp personalizat de introdus date",
|
||||
@@ -713,6 +725,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ă.",
|
||||
@@ -736,6 +749,7 @@
|
||||
"toggle_calendars_conflict": "Comutați calendarele în care doriți să verificați dacă există conflicte, pentru a preveni rezervările suprapuse.",
|
||||
"select_destination_calendar": "Creați evenimente în",
|
||||
"connect_additional_calendar": "Conectați calendarul suplimentar",
|
||||
"calendar_updated_successfully": "Calendar actualizat cu succes",
|
||||
"conferencing": "Conferință",
|
||||
"calendar": "Calendar",
|
||||
"payments": "Plăți",
|
||||
@@ -768,6 +782,7 @@
|
||||
"trending_apps": "Aplicații populare",
|
||||
"explore_apps": "Aplicații {{category}}",
|
||||
"installed_apps": "Aplicații instalate",
|
||||
"free_to_use_apps": "Gratuit",
|
||||
"no_category_apps": "Nicio aplicație {{category}}",
|
||||
"no_category_apps_description_calendar": "Adăugați o aplicație calendar pentru a verifica dacă există conflicte și a evita rezervările suprapuse",
|
||||
"no_category_apps_description_conferencing": "Încercați să adăugați o aplicație de conferință pentru a integra apelul video cu clienții dvs.",
|
||||
@@ -806,6 +821,8 @@
|
||||
"verify_wallet": "Verificați portofelul",
|
||||
"connect_metamask": "Conectați Metamask",
|
||||
"create_events_on": "Creați evenimente în",
|
||||
"enterprise_license": "Aceasta este o caracteristică de întreprindere",
|
||||
"enterprise_license_description": "Pentru a activa această caracteristică, obține o cheie de implementare la consola {{consoleUrl}} și adaug-o la .env ca CALCOM_LICENSE_KEY. Dacă echipa ta are deja o licență, te rugăm să contactezi {{supportMail}} pentru ajutor.",
|
||||
"missing_license": "Licență lipsă",
|
||||
"signup_requires": "Licență comercială necesară",
|
||||
"signup_requires_description": "În prezent, {{companyName}} nu oferă o versiune open-source gratuită a paginii de înscriere. Pentru a primi acces deplin la componentele de înscriere, trebuie să obțineți o licență comercială. Pentru uz personal, recomandăm Prisma Data Platform sau orice altă interfață Postgres pentru a crea conturi.",
|
||||
@@ -897,6 +914,7 @@
|
||||
"user_impersonation_heading": "Reprezentare utilizator",
|
||||
"user_impersonation_description": "Permite echipei noastre de asistență să se conecteze temporar în locul dvs. pentru a ne ajuta să rezolvăm orice probleme pe care ni le raportați.",
|
||||
"team_impersonation_description": "Permite membrilor echipei să se conecteze temporar din contul dvs.",
|
||||
"allow_booker_to_select_duration": "Permite persoanei care face rezervarea să selecteze durata",
|
||||
"impersonate_user_tip": "Toate utilizările acestei caracteristici sunt verificate.",
|
||||
"impersonating_user_warning": "Reprezentare nume de utilizator „{{user}}”.",
|
||||
"impersonating_stop_instructions": "<0>Faceți clic aici pentru a înceta</0>.",
|
||||
@@ -1014,6 +1032,9 @@
|
||||
"error_removing_app": "Eroare la ștergerea aplicației",
|
||||
"web_conference": "Conferință web",
|
||||
"requires_confirmation": "Necesită confirmare",
|
||||
"always_requires_confirmation": "Întotdeauna",
|
||||
"requires_confirmation_threshold": "Necesită confirmare dacă este rezervat cu aviz de < {{time}} $t({{unit}}_timeUnit)",
|
||||
"may_require_confirmation": "Poate necesita confirmare",
|
||||
"nr_event_type_one": "{{count}} tip de eveniment",
|
||||
"nr_event_type_other": "{{count}} (de) tipuri de evenimente",
|
||||
"add_action": "Adăugare acțiune",
|
||||
@@ -1101,6 +1122,9 @@
|
||||
"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_multiple_duration_error": "Configurare eveniment: duratele multiple necesită cel puțin o opțiune.",
|
||||
"event_setup_multiple_duration_default_error": "Configurare eveniment: selectează o durată implicită validă.",
|
||||
"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",
|
||||
@@ -1154,8 +1178,11 @@
|
||||
"invoices": "Facturi",
|
||||
"embeds": "Încorporări",
|
||||
"impersonation": "Reprezentare",
|
||||
"impersonation_description": "Setări pentru gestionarea reprezentării utilizatorului",
|
||||
"users": "Utilizatori",
|
||||
"profile_description": "Gestionați setările profilului dvs. {{appName}}",
|
||||
"users_description": "Aici poți găsi o listă a tuturor utilizatorilor",
|
||||
"users_listing": "Listare utilizatori",
|
||||
"general_description": "Gestionați setările pentru limbă și fus orar",
|
||||
"calendars_description": "Configurați modul în care interacționează tipurile de evenimente cu calendarele dvs.",
|
||||
"appearance_description": "Gestionați setările pentru aspectul rezervărilor dvs.",
|
||||
@@ -1360,6 +1387,7 @@
|
||||
"number_sms_notifications": "Număr de telefon (notificări SMS)",
|
||||
"attendee_email_workflow": "E-mail participant",
|
||||
"attendee_email_info": "E-mailul persoanei care efectuează rezervarea",
|
||||
"kbar_search_placeholder": "Scrie o comandă sau caută...",
|
||||
"invalid_credential": "Vai, nu! Se pare că permisiunea a expirat sau a fost revocată. Reinstalați din nou.",
|
||||
"choose_common_schedule_team_event": "Alegeți un program comun",
|
||||
"choose_common_schedule_team_event_description": "Activați această opțiune dacă doriți să folosiți un program comun între gazde. Atunci când este dezactivată, fiecare gazdă va fi rezervată în funcție de programul său implicit.",
|
||||
@@ -1371,5 +1399,42 @@
|
||||
"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"
|
||||
"payment_app_disabled": "Un administrator a dezactivat o aplicație de plată",
|
||||
"edit_event_type": "Editează tipul de eveniment",
|
||||
"collective_scheduling": "Programare colectivă",
|
||||
"make_it_easy_to_book": "Facilitează rezervarea echipei tale când toată lumea este disponibilă.",
|
||||
"find_the_best_person": "Găsește cea mai bună persoană disponibilă și treci succesiv prin membrii echipei tale.",
|
||||
"fixed_round_robin": "Sistem fiecare-cu-fiecare fix",
|
||||
"add_one_fixed_attendee": "Adaugă un participant fix şi unul din sistemul fiecare-cu-fiecare dintr-un număr de participanţi.",
|
||||
"calcom_is_better_with_team": "Cal.com funcționează mai bine cu echipe",
|
||||
"add_your_team_members": "Adaugă membrii echipei tale la tipurile tale de evenimente. Folosește programarea colectivă pentru a include pe toată lumea sau găsește persoana cea mai potrivită cu programarea fiecare-cu-fiecare.",
|
||||
"booking_limit_reached": "A fost atinsă limita de rezervare pentru acest tip de eveniment",
|
||||
"admin_has_disabled": "Un administrator a dezactivat {{appName}}",
|
||||
"disabled_app_affects_event_type": "Un administrator a dezactivat {{appName}} care afectează tipul tău de eveniment {{eventType}}",
|
||||
"disable_payment_app": "Administratorul a dezactivat {{appName}} care afectează tipul tău de eveniment {{title}}. Participanții încă pot să facă rezervări pentru acest tip de eveniment, dar nu li se va solicita să plătească. Poți ascunde tipul de eveniment pentru a preveni acest lucru până când administratorul tău reactivează metoda ta de plată.",
|
||||
"payment_disabled_still_able_to_book": "Participanții încă pot să facă rezervări pentru acest tip de eveniment, dar nu li se va solicita să plătească. Poți ascunde tipul de eveniment pentru a preveni acest lucru până când administratorul tău reactivează metoda ta de plată.",
|
||||
"app_disabled_with_event_type": "Administratorul a dezactivat {{appName}} care afectează tipul tău de eveniment {{title}}.",
|
||||
"app_disabled_video": "Administratorul a dezactivat {{appName}} care poate afecta tipurile tale de evenimente. Dacă ai tipuri de evenimente cu {{appName}} ca locație, atunci va fi setat implicit la Cal Video.",
|
||||
"app_disabled_subject": "{{appName}} a fost dezactivat",
|
||||
"navigate_installed_apps": "Mergi la aplicațiile instalate",
|
||||
"disabled_calendar": "Dacă ai un alt calendar instalat, rezervările noi vor fi adăugate la acesta. Dacă nu ai, conectează un calendar nou, astfel încât să nu ratezi nicio rezervare nouă.",
|
||||
"enable_apps": "Activează aplicații",
|
||||
"enable_apps_description": "Activează aplicațiile pe care utilizatorii le pot integra cu Cal.com",
|
||||
"app_is_enabled": "{{appName}} este activat",
|
||||
"app_is_disabled": "{{appName}} este dezactivat",
|
||||
"keys_have_been_saved": "Cheile au fost salvate",
|
||||
"disable_app": "Dezactivează aplicația",
|
||||
"disable_app_description": "Dezactivarea acestei aplicații poate cauza probleme cu modul în care utilizatorii interacționează cu Cal",
|
||||
"edit_keys": "Editează chei",
|
||||
"no_available_apps": "Nu există nicio aplicație disponibilă",
|
||||
"no_available_apps_description": "Asigură-te că există aplicații în implementare sub „pachete/magazin de aplicații”",
|
||||
"no_apps": "Nu există nicio aplicație activată în această instanță de Cal",
|
||||
"apps_settings": "Setări aplicații",
|
||||
"fill_this_field": "Te rugăm să completezi acest câmp",
|
||||
"options": "Opțiuni",
|
||||
"enter_option": "Introdu opțiunea {{index}}",
|
||||
"add_an_option": "Adaugă o opțiune",
|
||||
"radio": "Radio",
|
||||
"event_type_duplicate_copy_text": "{{slug}}-copie",
|
||||
"set_as_default": "Setează ca implicit"
|
||||
}
|
||||
|
||||
@@ -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": "Подтверждено: {{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": "Вы и другие участники были уведомлены по электронной почте.",
|
||||
@@ -383,6 +385,7 @@
|
||||
"go_to_billing_portal": "Перейти на платёжный портал",
|
||||
"need_anything_else": "Нужно что-нибудь еще?",
|
||||
"further_billing_help": "Если вам нужна дальнейшая помощь с оплатой счета, наша служба поддержки готова помочь.",
|
||||
"contact_our_support_team": "Свяжитесь с нашей службой поддержки",
|
||||
"uh_oh": "О нет!",
|
||||
"no_event_types_have_been_setup": "Этот пользователь еще не создал ни одного события.",
|
||||
"edit_logo": "Изменить логотип",
|
||||
@@ -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-дневная пробная версия. Если вы не перейдете на тарифный план Pro сейчас, по истечении этого периода такие члены команды будут скрыты.",
|
||||
@@ -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": "Настройка события: чтобы выбрать несколько вариантов продолжительности, требуется как минимум 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": "Настройка внешнего вида страниц бронирования",
|
||||
@@ -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": "Позволяет организаторам использовать общее расписание. Если общее расписание отключено, то для каждого организатора бронирование выполняется в соответствии с его индивидуальным расписанием по умолчанию.",
|
||||
@@ -1371,5 +1399,42 @@
|
||||
"route_to": "Цель маршрута",
|
||||
"test_preview_description": "Проверить форму маршрутизации без отправки данных",
|
||||
"test_routing": "Проверить машрутизацию",
|
||||
"booking_limit_reached": "Достигнут лимит бронирования для этого типа события"
|
||||
"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}}- копия",
|
||||
"set_as_default": "Использовать по умолчанию"
|
||||
}
|
||||
|
||||
@@ -385,6 +385,7 @@
|
||||
"go_to_billing_portal": "Idite na portal naplate",
|
||||
"need_anything_else": "Treba li vam još nešto?",
|
||||
"further_billing_help": "Ako vam treba pomoć sa naplatom, naš tim podrške je tu da pomogne.",
|
||||
"contact_our_support_team": "Kontaktirjate naš tim podrške",
|
||||
"uh_oh": "O ne!",
|
||||
"no_event_types_have_been_setup": "Ovaj korisnik još nije podesio tipove događaja.",
|
||||
"edit_logo": "Uredi logo",
|
||||
|
||||
@@ -385,6 +385,7 @@
|
||||
"go_to_billing_portal": "Gå till faktureringsportalen",
|
||||
"need_anything_else": "Behöver du något annat?",
|
||||
"further_billing_help": "Om du behöver ytterligare hjälp med fakturering finns vårt supportteam här för att hjälpa till.",
|
||||
"contact_our_support_team": "Kontakta vårt kundsupportteam",
|
||||
"uh_oh": "Åh nej!",
|
||||
"no_event_types_have_been_setup": "Den här användaren har inte skapat några händelsetyper ännu.",
|
||||
"edit_logo": "Ändra logotyp",
|
||||
|
||||
@@ -385,6 +385,7 @@
|
||||
"go_to_billing_portal": "Fatura portalına git",
|
||||
"need_anything_else": "Başka bir şeye ihtiyacınız var mı?",
|
||||
"further_billing_help": "Faturalandırma konusunda daha fazla yardıma ihtiyacınız olursa destek ekibimiz size yardımcı olmaya hazır.",
|
||||
"contact_our_support_team": "Destek ekibimizle iletişime geçin",
|
||||
"uh_oh": "Hay aksi!",
|
||||
"no_event_types_have_been_setup": "Bu kullanıcı henüz etkinlik türü ayarlamadı.",
|
||||
"edit_logo": "Logoyu düzenle",
|
||||
|
||||
@@ -385,6 +385,7 @@
|
||||
"go_to_billing_portal": "Перейти на портал виставлення рахунків",
|
||||
"need_anything_else": "Потрібно щось інше?",
|
||||
"further_billing_help": "Якщо вам потрібна додаткова допомога з виставленням рахунків, наша служба підтримки готова її надати.",
|
||||
"contact_our_support_team": "Зв’язатися зі службою підтримки",
|
||||
"uh_oh": "Отакої!",
|
||||
"no_event_types_have_been_setup": "Цей користувач ще не налаштував жодних типів заходів.",
|
||||
"edit_logo": "Редагувати логотип",
|
||||
|
||||
@@ -385,6 +385,7 @@
|
||||
"go_to_billing_portal": "Đi tới cổng thanh toán",
|
||||
"need_anything_else": "Cần gì nữa không?",
|
||||
"further_billing_help": "Nếu bạn cần thêm bất kỳ trợ giúp nào về thanh toán, nhóm hỗ trợ của chúng tôi luôn sẵn sàng trợ giúp.",
|
||||
"contact_our_support_team": "Liên hệ với nhóm hỗ trợ của chúng tôi",
|
||||
"uh_oh": "\bÔi không!",
|
||||
"no_event_types_have_been_setup": "Người dùng này chưa thiết lập bất kỳ loại sự kiện nào.",
|
||||
"edit_logo": "Chỉnh sửa logo",
|
||||
@@ -1401,5 +1402,40 @@
|
||||
"payment_app_disabled": "Một quản trị viên đã vô hiệu hoá một ứng dụng thanh toán",
|
||||
"edit_event_type": "Sửa loại sự kiện",
|
||||
"collective_scheduling": "Lên lịch tập thể",
|
||||
"admin_apps_description": "Bật các ứng dụng cho thực thể Cal của bạn"
|
||||
"make_it_easy_to_book": "Tạo điều kiện dễ dàng đặt lịch cho nhóm của bạn khi mọi người đều rảnh.",
|
||||
"find_the_best_person": "Tìm người tốt nhất có được và xoay vòng trong nhóm bạn.",
|
||||
"fixed_round_robin": "Round robin cố định",
|
||||
"add_one_fixed_attendee": "Thêm một người tham dự và round robin cố định thông qua số người tham dự.",
|
||||
"calcom_is_better_with_team": "Cal.com tốt hơn với nhóm",
|
||||
"add_your_team_members": "Thêm những thành viên nhóm của bạn vào những loại sự kiện của bạn. Sử dụng lên lịch tập thể để bao gồm mọi người hoặc tìm người thích hợp nhất với chức năng lên lịch round robin.",
|
||||
"booking_limit_reached": "Đã đạt mức giới hạn đặt hẹn cho loại sự kiện này",
|
||||
"admin_has_disabled": "Một quản trị viên đã tắt {{appName}}",
|
||||
"disabled_app_affects_event_type": "Một quản trị viên đã tắt {{appName}} vốn có ảnh hưởng đến loại sự kiện {{eventType}}",
|
||||
"disable_payment_app": "Một quản trị viên đã tắt {{appName}} vốn có ảnh hưởng đến loại sự kiện {{title}}. Người tham dự vẫn có thể đặt hẹn cho loại sự kiện này nhưng sẽ được nhắc trả phí. Bạn có thể ẩn loại sự kiện này để tránh điều này cho đến khi quản trị viên kích hoạt lại phương thức thanh toán của bạn.",
|
||||
"payment_disabled_still_able_to_book": "Người tham dự vẫn có thể đặt hẹn cho loại sự kiện này nhưng sẽ được nhắc trả phí. Bạn có thể ẩn loại sự kiện này để tránh điều này cho đến khi quản trị viên kích hoạt lại phương thức thanh toán của bạn.",
|
||||
"app_disabled_with_event_type": "Quản trị viên đã tắt {{appName}} vốn có ảnh hưởng đến loại sự kiện {{title}}.",
|
||||
"app_disabled_video": "Quản trị viên đã tắt {{appName}} vốn có ảnh hưởng đến những loại sự kiện của bạn. Nếu bạn có những loại sự kiện với {{appName}} ở dạng vị trí thì nó sẽ mặc định gắn với Cal Video.",
|
||||
"app_disabled_subject": "{{appName}} đã được tắt",
|
||||
"navigate_installed_apps": "Đến những ứng dụng được cài đặt",
|
||||
"disabled_calendar": "Nếu bạn có lịch khác được cài đặt, những mục đặt hẹn mới sẽ được thêm vào đó. Nếu không thì hãy kết nối với lịch mới để bạn không bỏ lỡ bất cứ mục đặt hẹn mới nào.",
|
||||
"enable_apps": "Kích hoạt ứng dụng",
|
||||
"enable_apps_description": "Kích hoạt những ứng dụng mà người dùng có thể tích hợp với Cal.com",
|
||||
"app_is_enabled": "{{appName}} đã được kích hoạt",
|
||||
"app_is_disabled": "{{appName}} đã được vô hiệu hoá",
|
||||
"keys_have_been_saved": "Các khoá đã được lưu lại",
|
||||
"disable_app": "Vô hiệu hoá ứng dụng",
|
||||
"disable_app_description": "Việc vô hiệu hoá ứng dụng này có thể gây rắc rối cho cách thức người dùng tương tác với Cal",
|
||||
"edit_keys": "Sửa các khoá",
|
||||
"admin_apps_description": "Bật các ứng dụng cho thực thể Cal của bạn",
|
||||
"no_available_apps": "Không có ứng dụng nào khả dụng",
|
||||
"no_available_apps_description": "Vui lòng bảo đảm rằng có những ứng dụng trong phần triển khai trong 'packages/app-store'",
|
||||
"no_apps": "Không ứng dụng được kích hoạt cho thể hiện này của Cal",
|
||||
"apps_settings": "Cài đặt của ứng dụng",
|
||||
"fill_this_field": "Vui lòng điền vào trường này",
|
||||
"options": "Tuỳ chọn",
|
||||
"enter_option": "Nhập vào tuỳ chọn {{index}}",
|
||||
"add_an_option": "Thêm một tuỳ chọn",
|
||||
"radio": "Radio",
|
||||
"event_type_duplicate_copy_text": "{{slug}}-copy",
|
||||
"set_as_default": "Đặt làm mặc định"
|
||||
}
|
||||
|
||||
@@ -385,6 +385,7 @@
|
||||
"go_to_billing_portal": "转到账单门户网站",
|
||||
"need_anything_else": "还有其他需要?",
|
||||
"further_billing_help": "如果您在支付帐单时需要任何进一步的帮助,我们的支持团队会给您提供帮助。",
|
||||
"contact_our_support_team": "联系我们的支持团队",
|
||||
"uh_oh": "糟糕!",
|
||||
"no_event_types_have_been_setup": "此用户尚未设置任何活动类型。",
|
||||
"edit_logo": "编辑标志",
|
||||
@@ -704,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": "新增自定义输入字段",
|
||||
@@ -1032,6 +1034,7 @@
|
||||
"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}} 种活动类型",
|
||||
@@ -1400,8 +1403,13 @@
|
||||
"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}}。参与者仍然能预约此类型的活动,但不会被提示付款。您可以隐藏该活动类型来防止出现这种情况,直到管理员重新启用您的支付方式。",
|
||||
@@ -1410,6 +1418,7 @@
|
||||
"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}} 已启用",
|
||||
@@ -1427,5 +1436,7 @@
|
||||
"options": "选项",
|
||||
"enter_option": "输入选项 {{index}}",
|
||||
"add_an_option": "添加选项",
|
||||
"radio": "无线电",
|
||||
"event_type_duplicate_copy_text": "{{slug}}-副本",
|
||||
"set_as_default": "设置为默认"
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user