Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
50151403c4 | ||
|
|
7aa131f349 | ||
|
|
d88bdc368b | ||
|
|
255938fda0 | ||
|
|
5766d6f5f4 | ||
|
|
9d299c6d5f | ||
|
|
f49783b453 | ||
|
|
246fce3ab8 | ||
|
|
82f262f60d | ||
|
|
da8d2da368 | ||
|
|
f01058e073 | ||
|
|
8e369d3fb5 | ||
|
|
11c44db609 | ||
|
|
9d911cbb59 | ||
|
|
30a887df6f | ||
|
|
62fea25eb9 | ||
|
|
d43d8700d0 | ||
|
|
e7ed20ea27 | ||
|
|
5e12b5defe | ||
|
|
d241a522fb | ||
|
+2 |
ae929f27b0 | ||
|
|
369d7c4e28 | ||
|
|
4438ca2a63 | ||
|
|
75589db569 | ||
|
|
3752ac767a | ||
|
+3 |
f3e2cf5075 | ||
|
|
92a29593aa | ||
|
|
367c5d89cc | ||
|
|
f21f36547c | ||
|
|
d3f8d954e7 | ||
|
|
27372d624d | ||
|
|
a5d2f2444a | ||
|
|
6d45e1c7c7 | ||
|
|
48419469a6 | ||
|
|
045ebb6e01 | ||
|
|
c78ea5de0b | ||
|
|
d1a787315c | ||
|
|
ce1f1f3c47 | ||
|
|
2f8bd3c07a | ||
|
|
d2f27a0463 | ||
|
|
9134ad8c5e | ||
|
|
506036e751 | ||
|
|
5e80f5056d | ||
|
|
9304ca1415 | ||
|
|
fb246fdee6 | ||
|
|
7b9e77f43a | ||
|
|
47df21322d | ||
|
|
6017806763 | ||
|
|
b347f29d6c | ||
|
|
c26cf74aec | ||
|
|
760ed74a11 | ||
|
|
145fb09b73 | ||
|
|
dd14e827e1 | ||
|
|
246c90c10f | ||
|
|
a42f703c1d | ||
|
|
7256dbf84f | ||
|
|
f5faebad67 | ||
|
+3 |
be15affa5d | ||
|
|
58dd5308ac | ||
|
|
14a6c5a03f | ||
|
|
5af20f5a7b | ||
|
|
8478363a23 | ||
|
|
19b3157c94 | ||
|
|
d4dd451c26 | ||
|
|
6c046f6507 | ||
|
|
a792d31939 | ||
|
|
fc997739b4 | ||
|
|
542d9aa3c6 | ||
|
|
8f3e088db7 | ||
|
|
699313ac70 | ||
|
|
fca7087e7d | ||
|
|
a6b16490c0 | ||
|
|
5da735c418 | ||
|
|
f9ef883f3d | ||
|
|
9ddbaf0966 | ||
|
|
0695ce7edb | ||
|
|
74f0d39997 | ||
|
|
85ab3fb164 | ||
|
|
ab417ac267 | ||
|
|
24635af730 | ||
|
|
682f0c66ff | ||
|
|
ace27ca84e | ||
|
|
ce41397517 | ||
|
|
81aba55710 | ||
|
|
c5fc3a7e8e | ||
|
|
f628ac4366 | ||
|
|
6e2e252c49 | ||
|
|
10d3a126aa | ||
|
|
341c39cb6b | ||
|
|
91909281bc | ||
|
|
f14b13a1ba | ||
|
|
ca859c871c | ||
|
|
6e49a3e1c3 | ||
|
|
830f42bf9a | ||
|
|
0830523b84 | ||
|
|
612b293a70 | ||
|
|
3ecfa75f86 | ||
|
|
631e974769 | ||
|
|
42c128b790 | ||
|
|
7d1065d228 | ||
|
|
e2747f89d0 | ||
|
|
a1d4589e66 | ||
|
|
7d2f87a13e | ||
|
|
4e7200a44b | ||
|
|
52959fe257 | ||
|
|
61b010a60a | ||
|
|
4e6e484d8b | ||
|
|
0a2de203a6 | ||
|
|
48ee7a956c | ||
|
|
ae46d615ef | ||
|
|
9b6d5d2ff8 | ||
|
|
ec0352da20 | ||
|
|
7e65d5d61d | ||
|
|
f855f24d5c | ||
|
|
c2057c4cc2 | ||
|
|
1640264e40 | ||
|
|
579fd399c3 | ||
|
|
1de00d46bf | ||
|
|
01db3ad14e | ||
|
|
c1cb02a9d1 | ||
|
|
344710d1f9 | ||
|
|
6f0b4f94e6 | ||
|
|
c6ad2de2f9 | ||
|
|
9ae3a0eaba | ||
|
|
2f3d7318a4 | ||
|
|
6e71de7ca3 | ||
|
|
7d277ad89f | ||
|
|
ac276a9654 | ||
|
|
588748d78e | ||
|
|
25711ef18e | ||
|
|
440f53714b | ||
|
|
22f6d8ab9b | ||
|
|
57f0d115cf | ||
|
|
23bc6aa600 | ||
|
|
abdb196f56 | ||
|
|
8c0e2b5129 | ||
|
|
cf32287109 | ||
|
|
2ef8e230c5 | ||
|
|
546d0d50c4 | ||
|
|
33e8198779 | ||
|
|
e7dd0ff3e9 | ||
|
|
1b2707d4f0 | ||
|
|
00071bcdf0 | ||
|
|
fc5cc5b8bc | ||
|
|
1e79a55825 | ||
|
|
4645bbcb75 | ||
|
|
95b903110f | ||
|
|
2917455324 | ||
|
|
d71765848c | ||
|
|
cf7b7d7d3d | ||
|
|
96aaa36751 | ||
|
|
52e74245a4 | ||
|
|
cc03b132e6 |
No files matched your search
@@ -8,6 +8,8 @@ on:
|
|||||||
concurrency:
|
concurrency:
|
||||||
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
|
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
|
||||||
cancel-in-progress: true
|
cancel-in-progress: true
|
||||||
|
env:
|
||||||
|
NODE_OPTIONS: "--max-old-space-size=8192"
|
||||||
jobs:
|
jobs:
|
||||||
check-types:
|
check-types:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
@@ -20,8 +22,13 @@ jobs:
|
|||||||
|
|
||||||
- name: Use Node 16.x
|
- name: Use Node 16.x
|
||||||
uses: actions/setup-node@v3
|
uses: actions/setup-node@v3
|
||||||
|
|
||||||
with:
|
with:
|
||||||
node-version: 16.x
|
node-version: 16.x
|
||||||
cache: "yarn"
|
cache: "yarn"
|
||||||
|
|
||||||
|
- name: Show info
|
||||||
|
run: node -e "console.log(require('v8').getHeapStatistics())"
|
||||||
|
|
||||||
- run: yarn --frozen-lockfile
|
- run: yarn --frozen-lockfile
|
||||||
- run: yarn type-check
|
- run: yarn type-check
|
||||||
@@ -31,7 +31,7 @@
|
|||||||
<a href="https://news.ycombinator.com/item?id=26817795"><img src="https://img.shields.io/badge/Hacker%20News-311-%23FF6600" alt="Hacker News"></a>
|
<a href="https://news.ycombinator.com/item?id=26817795"><img src="https://img.shields.io/badge/Hacker%20News-311-%23FF6600" alt="Hacker News"></a>
|
||||||
<a href="https://github.com/calcom/cal.com/blob/main/LICENSE"><img src="https://img.shields.io/badge/license-AGPLv3-purple" alt="License"></a>
|
<a href="https://github.com/calcom/cal.com/blob/main/LICENSE"><img src="https://img.shields.io/badge/license-AGPLv3-purple" alt="License"></a>
|
||||||
<a href="https://github.com/calcom/cal.com/pulse"><img src="https://img.shields.io/github/commit-activity/m/calcom/cal.com" alt="Commits-per-month"></a>
|
<a href="https://github.com/calcom/cal.com/pulse"><img src="https://img.shields.io/github/commit-activity/m/calcom/cal.com" alt="Commits-per-month"></a>
|
||||||
<a href="https://cal.com/pricing"><img src="https://img.shields.io/badge/Pricing-%2412%2Fmonth-brightgreen" alt="Pricing"></a>
|
<a href="https://cal.com/pricing"><img src="https://img.shields.io/badge/Pricing-Free-brightgreen" alt="Pricing"></a>
|
||||||
<a href="https://jitsu.com?utm_source=github/calcom/cal.com"><img src="https://img.shields.io/badge/Metrics_tracked_by-JITSU-AA00FF?logo=data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAA4AAAAOCAYAAAAfSC3RAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAACKSURBVHgBrZDRCYAwDEQv6gCOoKO4hOCXI9QVnEZwiY5iF5GaVClaBNtioCSUvCR3tMJaxIfZgW4AGUoEPVwgPZoS0Dmgg3NBVDFNbMIsmYCak3J1jDk9iCQvsKJvkzr71N81Gj6vDT/LU2P6RhY63jcafk3YJEbgeZpiFyc/5HJKv8Ef273NSfABGbQfUZhnOSAAAAAASUVORK5CYII=" alt="Jitsu Tracked"></a>
|
<a href="https://jitsu.com?utm_source=github/calcom/cal.com"><img src="https://img.shields.io/badge/Metrics_tracked_by-JITSU-AA00FF?logo=data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAA4AAAAOCAYAAAAfSC3RAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAACKSURBVHgBrZDRCYAwDEQv6gCOoKO4hOCXI9QVnEZwiY5iF5GaVClaBNtioCSUvCR3tMJaxIfZgW4AGUoEPVwgPZoS0Dmgg3NBVDFNbMIsmYCak3J1jDk9iCQvsKJvkzr71N81Gj6vDT/LU2P6RhY63jcafk3YJEbgeZpiFyc/5HJKv8Ef273NSfABGbQfUZhnOSAAAAAASUVORK5CYII=" alt="Jitsu Tracked"></a>
|
||||||
<img src="https://api.checklyhq.com/v1/badges/checks/5e048048-1b51-47ba-9209-60607507622e?responseTime=true" alt="Checkly Availability" />
|
<img src="https://api.checklyhq.com/v1/badges/checks/5e048048-1b51-47ba-9209-60607507622e?responseTime=true" alt="Checkly Availability" />
|
||||||
<a href="https://hub.docker.com/r/calendso/calendso"><img src="https://img.shields.io/docker/pulls/calendso/calendso"></a>
|
<a href="https://hub.docker.com/r/calendso/calendso"><img src="https://img.shields.io/docker/pulls/calendso/calendso"></a>
|
||||||
|
|||||||
+1
-1
Submodule apps/api updated: fcb9ca6ace...7e9226fabc.
@@ -6,7 +6,7 @@ title: Vercel
|
|||||||
|
|
||||||
## Requirements
|
## Requirements
|
||||||
|
|
||||||
You need a PostgresDB database hosted somewhere. [Heroku](https://www.heroku.com) and [Supabase](https://supabase.com/) offer great free options.
|
You need a PostgresDB database hosted somewhere. [Supabase](https://supabase.com/) offers a great free option.
|
||||||
|
|
||||||
## Getting Started
|
## Getting Started
|
||||||
|
|
||||||
|
|||||||
@@ -15,14 +15,15 @@
|
|||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@calcom/dayjs": "*",
|
"@calcom/dayjs": "*",
|
||||||
"@calcom/ui": "*",
|
"@calcom/ui": "*",
|
||||||
"@radix-ui/react-avatar": "^0.1.4",
|
"@radix-ui/react-avatar": "^1.0.0",
|
||||||
"@radix-ui/react-collapsible": "^0.1.0",
|
"@radix-ui/react-collapsible": "^1.0.0",
|
||||||
"@radix-ui/react-dialog": "^0.1.0",
|
"@radix-ui/react-dialog": "^1.0.0",
|
||||||
"@radix-ui/react-dropdown-menu": "^0.1.1",
|
"@radix-ui/react-dropdown-menu": "^1.0.0",
|
||||||
"@radix-ui/react-id": "^0.1.0",
|
"@radix-ui/react-id": "^1.0.0",
|
||||||
"@radix-ui/react-radio-group": "^0.1.1",
|
"@radix-ui/react-popover": "^1.0.0",
|
||||||
"@radix-ui/react-slider": "^0.1.1",
|
"@radix-ui/react-radio-group": "^1.0.0",
|
||||||
"@radix-ui/react-switch": "^0.1.1",
|
"@radix-ui/react-slider": "^1.0.0",
|
||||||
|
"@radix-ui/react-switch": "^1.0.0",
|
||||||
"@radix-ui/react-tooltip": "^1.0.0",
|
"@radix-ui/react-tooltip": "^1.0.0",
|
||||||
"next": "^12.2.5",
|
"next": "^12.2.5",
|
||||||
"next-transpile-modules": "^9.0.0",
|
"next-transpile-modules": "^9.0.0",
|
||||||
|
|||||||
@@ -426,7 +426,7 @@ paths:
|
|||||||
- installed: true
|
- installed: true
|
||||||
type: caldav_calendar
|
type: caldav_calendar
|
||||||
credential: null
|
credential: null
|
||||||
title: CalDav Server
|
title: CalDav (Beta)
|
||||||
imageSrc: integrations/caldav.svg
|
imageSrc: integrations/caldav.svg
|
||||||
description: For personal and business calendars
|
description: For personal and business calendars
|
||||||
__N_SSP: true
|
__N_SSP: true
|
||||||
|
|||||||
@@ -1,15 +1,14 @@
|
|||||||
import { Collapsible, CollapsibleContent, CollapsibleTrigger } from "@radix-ui/react-collapsible";
|
import { Collapsible, CollapsibleContent, CollapsibleTrigger } from "@radix-ui/react-collapsible";
|
||||||
import classNames from "classnames";
|
import classNames from "classnames";
|
||||||
import { useRouter } from "next/router";
|
import { NextRouter, useRouter } from "next/router";
|
||||||
import { createRef, forwardRef, MutableRefObject, RefObject, useRef, useState } from "react";
|
import { createRef, forwardRef, MutableRefObject, RefObject, useRef, useState } from "react";
|
||||||
import { components, ControlProps } from "react-select";
|
import { components, ControlProps } from "react-select";
|
||||||
|
|
||||||
import { useLocale } from "@calcom/lib/hooks/useLocale";
|
import { useLocale } from "@calcom/lib/hooks/useLocale";
|
||||||
import { Dialog, DialogClose, DialogContent } from "@calcom/ui/Dialog";
|
|
||||||
import { Icon } from "@calcom/ui/Icon";
|
import { Icon } from "@calcom/ui/Icon";
|
||||||
import { InputLeading, Label, TextArea, TextField } from "@calcom/ui/form/fields";
|
import { InputLeading, Label, TextArea, TextField } from "@calcom/ui/form/fields";
|
||||||
import { HorizontalTabs, showToast } from "@calcom/ui/v2";
|
import { Button, HorizontalTabs, showToast, Switch } from "@calcom/ui/v2";
|
||||||
import { Button, Switch } from "@calcom/ui/v2";
|
import { Dialog, DialogClose, DialogContent } from "@calcom/ui/v2/core/Dialog";
|
||||||
|
|
||||||
import { EMBED_LIB_URL, WEBAPP_URL } from "@lib/config/constants";
|
import { EMBED_LIB_URL, WEBAPP_URL } from "@lib/config/constants";
|
||||||
|
|
||||||
@@ -46,6 +45,23 @@ const getDimension = (dimension: string) => {
|
|||||||
return dimension;
|
return dimension;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const goto = (router: NextRouter, searchParams: Record<string, string>) => {
|
||||||
|
const newQuery = new URLSearchParams(router.asPath.split("?")[1]);
|
||||||
|
Object.keys(searchParams).forEach((key) => {
|
||||||
|
newQuery.set(key, searchParams[key]);
|
||||||
|
});
|
||||||
|
router.push(`${router.asPath.split("?")[0]}?${newQuery.toString()}`, undefined, {
|
||||||
|
shallow: true,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const removeQueryParams = (router: NextRouter, queryParams: string[]) => {
|
||||||
|
queryParams.forEach((param) => {
|
||||||
|
delete router.query[param];
|
||||||
|
});
|
||||||
|
router.push(`${router.asPath.split("?")[0]}?${router.query.toString()}`);
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* It allows us to show code with certain reusable blocks indented according to the block variable placement
|
* It allows us to show code with certain reusable blocks indented according to the block variable placement
|
||||||
* So, if you add a variable ${abc} with indentation of 4 spaces, it will automatically indent all newlines in `abc` with the same indent before constructing the final string
|
* So, if you add a variable ${abc} with indentation of 4 spaces, it will automatically indent all newlines in `abc` with the same indent before constructing the final string
|
||||||
@@ -452,7 +468,7 @@ const embeds: {
|
|||||||
const tabs = [
|
const tabs = [
|
||||||
{
|
{
|
||||||
name: "HTML",
|
name: "HTML",
|
||||||
embedTabName: "embed-code",
|
href: "embedTabName=embed-code",
|
||||||
icon: Icon.FiCode,
|
icon: Icon.FiCode,
|
||||||
type: "code",
|
type: "code",
|
||||||
Component: forwardRef<
|
Component: forwardRef<
|
||||||
@@ -503,7 +519,7 @@ ${getEmbedTypeSpecificString({ embedFramework: "HTML", embedType, calLink, previ
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "React",
|
name: "React",
|
||||||
embedTabName: "embed-react",
|
href: "embedTabName=embed-react",
|
||||||
icon: Icon.FiCode,
|
icon: Icon.FiCode,
|
||||||
type: "code",
|
type: "code",
|
||||||
Component: forwardRef<
|
Component: forwardRef<
|
||||||
@@ -543,8 +559,8 @@ ${getEmbedTypeSpecificString({ embedFramework: "react", embedType, calLink, prev
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "Preview",
|
name: "Preview",
|
||||||
embedTabName: "embed-preview",
|
href: "embedTabName=embed-preview",
|
||||||
icon: Icon.FiEye,
|
icon: Icon.FiTrello,
|
||||||
type: "iframe",
|
type: "iframe",
|
||||||
Component: forwardRef<
|
Component: forwardRef<
|
||||||
HTMLIFrameElement | HTMLTextAreaElement | null,
|
HTMLIFrameElement | HTMLTextAreaElement | null,
|
||||||
@@ -590,7 +606,7 @@ const ChooseEmbedTypesDialogContent = () => {
|
|||||||
const { t } = useLocale();
|
const { t } = useLocale();
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
return (
|
return (
|
||||||
<DialogContent size="lg">
|
<DialogContent type="creation" useOwnActionButtons size="lg">
|
||||||
<div className="mb-4">
|
<div className="mb-4">
|
||||||
<h3 className="text-lg font-bold leading-6 text-gray-900" id="modal-title">
|
<h3 className="text-lg font-bold leading-6 text-gray-900" id="modal-title">
|
||||||
{t("how_you_want_add_cal_site")}
|
{t("how_you_want_add_cal_site")}
|
||||||
@@ -606,11 +622,8 @@ const ChooseEmbedTypesDialogContent = () => {
|
|||||||
key={index}
|
key={index}
|
||||||
data-testid={embed.type}
|
data-testid={embed.type}
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
router.push({
|
goto(router, {
|
||||||
query: {
|
|
||||||
...router.query,
|
|
||||||
embedType: embed.type,
|
embedType: embed.type,
|
||||||
},
|
|
||||||
});
|
});
|
||||||
}}>
|
}}>
|
||||||
<div className="order-none box-border flex-none rounded-sm border border-solid bg-white">
|
<div className="order-none box-border flex-none rounded-sm border border-solid bg-white">
|
||||||
@@ -635,6 +648,13 @@ const EmbedTypeCodeAndPreviewDialogContent = ({
|
|||||||
const { t } = useLocale();
|
const { t } = useLocale();
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const iframeRef = useRef<HTMLIFrameElement>(null);
|
const iframeRef = useRef<HTMLIFrameElement>(null);
|
||||||
|
const s = (href: string) => {
|
||||||
|
const searchParams = new URLSearchParams(router.asPath.split("?")[1] || "");
|
||||||
|
const [a, b] = href.split("=");
|
||||||
|
searchParams.set(a, b);
|
||||||
|
return `${router.asPath.split("?")[0]}?${searchParams.toString()}`;
|
||||||
|
};
|
||||||
|
const parsedTabs = tabs.map((t) => ({ ...t, href: s(t.href) }));
|
||||||
const embedCodeRefs: Record<typeof tabs[0]["name"], RefObject<HTMLTextAreaElement>> = {};
|
const embedCodeRefs: Record<typeof tabs[0]["name"], RefObject<HTMLTextAreaElement>> = {};
|
||||||
tabs
|
tabs
|
||||||
.filter((tab) => tab.type === "code")
|
.filter((tab) => tab.type === "code")
|
||||||
@@ -661,28 +681,13 @@ const EmbedTypeCodeAndPreviewDialogContent = ({
|
|||||||
});
|
});
|
||||||
|
|
||||||
const close = () => {
|
const close = () => {
|
||||||
const noPopupQuery = {
|
removeQueryParams(router, ["dialog", ...queryParamsForDialog]);
|
||||||
...router.query,
|
|
||||||
};
|
|
||||||
|
|
||||||
delete noPopupQuery.dialog;
|
|
||||||
|
|
||||||
queryParamsForDialog.forEach((queryParam) => {
|
|
||||||
delete noPopupQuery[queryParam];
|
|
||||||
});
|
|
||||||
|
|
||||||
router.push({
|
|
||||||
query: noPopupQuery,
|
|
||||||
});
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// Use embed-code as default tab
|
// Use embed-code as default tab
|
||||||
if (!router.query.embedTabName) {
|
if (!router.query.embedTabName) {
|
||||||
router.query.embedTabName = "embed-code";
|
goto(router, {
|
||||||
router.push({
|
embedTabName: "embed-code",
|
||||||
query: {
|
|
||||||
...router.query,
|
|
||||||
},
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -779,20 +784,13 @@ const EmbedTypeCodeAndPreviewDialogContent = ({
|
|||||||
];
|
];
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<DialogContent size="lg">
|
<DialogContent size="xl" className="p-0.5" type="creation" useOwnActionButtons>
|
||||||
<div className="flex">
|
<div className="flex">
|
||||||
<div className="flex w-1/3 flex-col bg-white p-6">
|
<div className="flex w-1/3 flex-col bg-gray-50 p-8">
|
||||||
<h3 className="mb-2 flex text-xl font-bold leading-6 text-gray-900" id="modal-title">
|
<h3 className="mb-2 flex text-xl font-bold leading-6 text-gray-900" id="modal-title">
|
||||||
<button
|
<button
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
const newQuery = { ...router.query };
|
removeQueryParams(router, ["embedType", "embedTabName"]);
|
||||||
delete newQuery.embedType;
|
|
||||||
delete newQuery.embedTabName;
|
|
||||||
router.push({
|
|
||||||
query: {
|
|
||||||
...newQuery,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
}}>
|
}}>
|
||||||
<Icon.FiArrowLeft className="mr-4 w-4" />
|
<Icon.FiArrowLeft className="mr-4 w-4" />
|
||||||
</button>
|
</button>
|
||||||
@@ -1040,14 +1038,14 @@ const EmbedTypeCodeAndPreviewDialogContent = ({
|
|||||||
</Collapsible>
|
</Collapsible>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="flex w-2/3 flex-col p-6">
|
<div className="flex w-2/3 flex-col p-8">
|
||||||
<HorizontalTabs tabNameKey="embedTabName" data-testid="embed-tabs" tabs={tabs} />
|
<HorizontalTabs data-testid="embed-tabs" tabs={parsedTabs} linkProps={{ shallow: true }} />
|
||||||
{tabs.map((tab) => {
|
{tabs.map((tab) => {
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
key={tab.embedTabName}
|
key={tab.href}
|
||||||
className={classNames(
|
className={classNames(
|
||||||
router.query.embedTabName === tab.embedTabName ? "flex flex-grow flex-col" : "hidden"
|
router.query.embedTabName === tab.href.split("=")[1] ? "flex flex-grow flex-col" : "hidden"
|
||||||
)}>
|
)}>
|
||||||
<div className="flex h-[55vh] flex-grow flex-col">
|
<div className="flex h-[55vh] flex-grow flex-col">
|
||||||
{tab.type === "code" ? (
|
{tab.type === "code" ? (
|
||||||
@@ -1133,19 +1131,10 @@ export const EmbedButton = <T extends React.ElementType>({
|
|||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
className = classNames(className, "hidden lg:inline-flex");
|
className = classNames(className, "hidden lg:inline-flex");
|
||||||
const openEmbedModal = () => {
|
const openEmbedModal = () => {
|
||||||
const query = {
|
goto(router, {
|
||||||
...router.query,
|
|
||||||
dialog: "embed",
|
dialog: "embed",
|
||||||
embedUrl,
|
embedUrl,
|
||||||
};
|
});
|
||||||
router.push(
|
|
||||||
{
|
|
||||||
pathname: router.pathname,
|
|
||||||
query,
|
|
||||||
},
|
|
||||||
undefined,
|
|
||||||
{ shallow: true }
|
|
||||||
);
|
|
||||||
};
|
};
|
||||||
const Component = as ?? Button;
|
const Component = as ?? Button;
|
||||||
|
|
||||||
|
|||||||
@@ -10,7 +10,9 @@ export function useViewerI18n() {
|
|||||||
* i18n should never be clubbed with other queries, so that it's caching can be managed independently.
|
* i18n should never be clubbed with other queries, so that it's caching can be managed independently.
|
||||||
* We intend to not cache i18n query
|
* We intend to not cache i18n query
|
||||||
**/
|
**/
|
||||||
|
trpc: {
|
||||||
context: { skipBatch: true },
|
context: { skipBatch: true },
|
||||||
|
},
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -44,6 +44,11 @@ function BookingListItem(booking: BookingItemProps) {
|
|||||||
const mutation = trpc.useMutation(["viewer.bookings.confirm"], {
|
const mutation = trpc.useMutation(["viewer.bookings.confirm"], {
|
||||||
onSuccess: () => {
|
onSuccess: () => {
|
||||||
setRejectionDialogIsOpen(false);
|
setRejectionDialogIsOpen(false);
|
||||||
|
showToast(t("booking_confirmation_success"), "success");
|
||||||
|
utils.invalidateQueries("viewer.bookings");
|
||||||
|
},
|
||||||
|
onError: () => {
|
||||||
|
showToast(t("booking_confirmation_failed"), "error");
|
||||||
utils.invalidateQueries("viewer.bookings");
|
utils.invalidateQueries("viewer.bookings");
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
@@ -117,8 +122,7 @@ function BookingListItem(booking: BookingItemProps) {
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: "edit_booking",
|
id: "edit_booking",
|
||||||
label: t("edit_booking"),
|
label: t("edit"),
|
||||||
icon: Icon.FiEdit,
|
|
||||||
actions: [
|
actions: [
|
||||||
{
|
{
|
||||||
id: "reschedule",
|
id: "reschedule",
|
||||||
@@ -262,16 +266,146 @@ function BookingListItem(booking: BookingItemProps) {
|
|||||||
</DialogContent>
|
</DialogContent>
|
||||||
</Dialog>
|
</Dialog>
|
||||||
|
|
||||||
<tr className="flex hover:bg-neutral-50">
|
<tr className="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:w-48" onClick={onClick}>
|
<td className="hidden align-top ltr:pl-6 rtl:pr-6 sm:table-cell sm:min-w-[10rem]" onClick={onClick}>
|
||||||
<div className="cursor-pointer py-4">
|
<div className="cursor-pointer py-4">
|
||||||
<div className="text-sm leading-6 text-gray-900">{startTime}</div>
|
<div className="text-sm leading-6 text-gray-900">{startTime}</div>
|
||||||
<div className="text-sm text-gray-500">
|
<div className="text-sm text-gray-500">
|
||||||
{dayjs(booking.startTime).format(user && user.timeFormat === 12 ? "h:mma" : "HH:mm")} -{" "}
|
{dayjs(booking.startTime).format(user && user.timeFormat === 12 ? "h:mma" : "HH:mm")} -{" "}
|
||||||
{dayjs(booking.endTime).format(user && user.timeFormat === 12 ? "h:mma" : "HH:mm")}
|
{dayjs(booking.endTime).format(user && user.timeFormat === 12 ? "h:mma" : "HH:mm")}
|
||||||
</div>
|
</div>
|
||||||
<div className="text-sm text-gray-400">
|
|
||||||
{booking.recurringBookings &&
|
{isPending && (
|
||||||
|
<Badge className="ltr:mr-2 rtl:ml-2" variant="orange">
|
||||||
|
{t("unconfirmed")}
|
||||||
|
</Badge>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{booking.eventType?.team && (
|
||||||
|
<Badge className="ltr:mr-2 rtl:ml-2" variant="gray">
|
||||||
|
{booking.eventType.team.name}
|
||||||
|
</Badge>
|
||||||
|
)}
|
||||||
|
{!!booking?.eventType?.price && !booking.paid && (
|
||||||
|
<Badge className="ltr:mr-2 rtl:ml-2" variant="orange">
|
||||||
|
{t("pending_payment")}
|
||||||
|
</Badge>
|
||||||
|
)}
|
||||||
|
|
||||||
|
<div className="mt-2 text-sm text-gray-400">
|
||||||
|
<RecurringBookingsTooltip
|
||||||
|
booking={booking}
|
||||||
|
recurringStrings={recurringStrings}
|
||||||
|
recurringDates={recurringDates}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</td>
|
||||||
|
<td className={"w-full px-4" + (isRejected ? " line-through" : "")} onClick={onClick}>
|
||||||
|
{/* Time and Badges for mobile */}
|
||||||
|
<div className="w-full pt-4 pb-2 sm:hidden">
|
||||||
|
<div className="flex w-full items-center justify-between sm:hidden">
|
||||||
|
<div className="text-sm leading-6 text-gray-900">{startTime}</div>
|
||||||
|
<div className="pr-2 text-sm text-gray-500">
|
||||||
|
{dayjs(booking.startTime).format(user && user.timeFormat === 12 ? "h:mma" : "HH:mm")} -{" "}
|
||||||
|
{dayjs(booking.endTime).format(user && user.timeFormat === 12 ? "h:mma" : "HH:mm")}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{isPending && (
|
||||||
|
<Badge className="ltr:mr-2 rtl:ml-2 sm:hidden" variant="orange">
|
||||||
|
{t("unconfirmed")}
|
||||||
|
</Badge>
|
||||||
|
)}
|
||||||
|
{booking.eventType?.team && (
|
||||||
|
<Badge className="ltr:mr-2 rtl:ml-2 sm:hidden" variant="gray">
|
||||||
|
{booking.eventType.team.name}
|
||||||
|
</Badge>
|
||||||
|
)}
|
||||||
|
{!!booking?.eventType?.price && !booking.paid && (
|
||||||
|
<Badge className="ltr:mr-2 rtl:ml-2 sm:hidden" variant="orange">
|
||||||
|
{t("pending_payment")}
|
||||||
|
</Badge>
|
||||||
|
)}
|
||||||
|
<div className="text-sm text-gray-400 sm:hidden">
|
||||||
|
<RecurringBookingsTooltip
|
||||||
|
booking={booking}
|
||||||
|
recurringStrings={recurringStrings}
|
||||||
|
recurringDates={recurringDates}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="cursor-pointer py-4">
|
||||||
|
<div
|
||||||
|
title={booking.title}
|
||||||
|
className={classNames(
|
||||||
|
"max-w-10/12 sm:max-w-56 text-sm font-medium leading-6 text-neutral-900 md:max-w-full",
|
||||||
|
isCancelled ? "line-through" : ""
|
||||||
|
)}>
|
||||||
|
{booking.title}
|
||||||
|
<span> </span>
|
||||||
|
|
||||||
|
{!!booking?.eventType?.price && !booking.paid && (
|
||||||
|
<Tag className="hidden ltr:ml-2 rtl:mr-2 sm:inline-flex">Pending payment</Tag>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
{booking.description && (
|
||||||
|
<div
|
||||||
|
className="max-w-52 md:max-w-96 truncate text-sm text-gray-600"
|
||||||
|
title={booking.description}>
|
||||||
|
"{booking.description}"
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
{booking.attendees.length !== 0 && (
|
||||||
|
<DisplayAttendees
|
||||||
|
attendees={booking.attendees}
|
||||||
|
user={booking.user}
|
||||||
|
currentEmail={user?.email}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
{isCancelled && booking.rescheduled && (
|
||||||
|
<div className="mt-2 inline-block text-left text-sm md:hidden">
|
||||||
|
<RequestSentMessage />
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</td>
|
||||||
|
<td className="py-4 pl-4 text-right text-sm font-medium ltr:pr-4 rtl:pl-4 sm:pl-0">
|
||||||
|
{isUpcoming && !isCancelled ? (
|
||||||
|
<>
|
||||||
|
{isPending && user?.id === booking.user?.id && <TableActions actions={pendingActions} />}
|
||||||
|
{isConfirmed && <TableActions actions={bookedActions} />}
|
||||||
|
{isRejected && <div className="text-sm text-gray-500">{t("rejected")}</div>}
|
||||||
|
</>
|
||||||
|
) : null}
|
||||||
|
{isPast && isPending && !isConfirmed ? <TableActions actions={bookedActions} /> : null}
|
||||||
|
{isCancelled && booking.rescheduled && (
|
||||||
|
<div className="hidden h-full items-center md:flex">
|
||||||
|
<RequestSentMessage />
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
interface RecurringBookingsTooltipProps {
|
||||||
|
booking: BookingItemProps;
|
||||||
|
recurringStrings: string[];
|
||||||
|
recurringDates: Date[];
|
||||||
|
}
|
||||||
|
|
||||||
|
const RecurringBookingsTooltip = ({
|
||||||
|
booking,
|
||||||
|
recurringStrings,
|
||||||
|
recurringDates,
|
||||||
|
}: RecurringBookingsTooltipProps) => {
|
||||||
|
const { t } = useLocale();
|
||||||
|
|
||||||
|
return (
|
||||||
|
(booking.recurringBookings &&
|
||||||
booking.eventType?.recurringEvent?.freq &&
|
booking.eventType?.recurringEvent?.freq &&
|
||||||
(booking.listingStatus === "recurring" || booking.listingStatus === "cancelled") && (
|
(booking.listingStatus === "recurring" || booking.listingStatus === "cancelled") && (
|
||||||
<div className="underline decoration-gray-400 decoration-dashed underline-offset-2">
|
<div className="underline decoration-gray-400 decoration-dashed underline-offset-2">
|
||||||
@@ -300,77 +434,10 @@ function BookingListItem(booking: BookingItemProps) {
|
|||||||
</Tooltip>
|
</Tooltip>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)) ||
|
||||||
</div>
|
null
|
||||||
</div>
|
|
||||||
</td>
|
|
||||||
<td className={"flex-1 px-4" + (isRejected ? " line-through" : "")} onClick={onClick}>
|
|
||||||
<div className="cursor-pointer py-4">
|
|
||||||
{!!booking?.eventType?.price && !booking.paid && (
|
|
||||||
<Badge variant="orange" className="mb-2 ltr:mr-2 rtl:ml-2">
|
|
||||||
{t("pending_payment")}
|
|
||||||
</Badge>
|
|
||||||
)}
|
|
||||||
<div
|
|
||||||
title={booking.title}
|
|
||||||
className={classNames(
|
|
||||||
"max-w-56 truncate text-sm font-medium leading-6 text-neutral-900 md:max-w-max",
|
|
||||||
isCancelled ? "line-through" : ""
|
|
||||||
)}>
|
|
||||||
{booking.title}
|
|
||||||
<span> </span>
|
|
||||||
{booking.eventType?.team && <Badge variant="gray">{booking.eventType.team.name}</Badge>}
|
|
||||||
|
|
||||||
{!!booking?.eventType?.price && !booking.paid && (
|
|
||||||
<Tag className="hidden ltr:ml-2 rtl:mr-2 sm:inline-flex">Pending payment</Tag>
|
|
||||||
)}
|
|
||||||
{isPending && (
|
|
||||||
<Badge variant="orange" className="hidden ltr:ml-2 rtl:mr-2 sm:inline-flex">
|
|
||||||
{t("unconfirmed")}
|
|
||||||
</Badge>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
{booking.description && (
|
|
||||||
<div
|
|
||||||
className="max-w-52 md:max-w-96 truncate text-sm text-gray-600"
|
|
||||||
title={booking.description}>
|
|
||||||
"{booking.description}"
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
{booking.attendees.length !== 0 && (
|
|
||||||
<DisplayAttendees
|
|
||||||
attendees={booking.attendees}
|
|
||||||
user={booking.user}
|
|
||||||
currentEmail={user?.email}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
{isCancelled && booking.rescheduled && (
|
|
||||||
<div className="mt-2 inline-block text-left text-sm md:hidden">
|
|
||||||
<RequestSentMessage />
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
</td>
|
|
||||||
|
|
||||||
<td className="whitespace-nowrap py-4 text-right text-sm font-medium ltr:pr-4 rtl:pl-4">
|
|
||||||
{isUpcoming && !isCancelled ? (
|
|
||||||
<>
|
|
||||||
{isPending && user?.id === booking.user?.id && <TableActions actions={pendingActions} />}
|
|
||||||
{isConfirmed && <TableActions actions={bookedActions} />}
|
|
||||||
{isRejected && <div className="text-sm text-gray-500">{t("rejected")}</div>}
|
|
||||||
</>
|
|
||||||
) : null}
|
|
||||||
{isPast && isPending && !isConfirmed ? <TableActions actions={bookedActions} /> : null}
|
|
||||||
{isCancelled && booking.rescheduled && (
|
|
||||||
<div className="hidden h-full items-center md:flex">
|
|
||||||
<RequestSentMessage />
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
</>
|
|
||||||
);
|
);
|
||||||
}
|
};
|
||||||
|
|
||||||
interface UserProps {
|
interface UserProps {
|
||||||
id: number;
|
id: number;
|
||||||
|
|||||||
@@ -33,7 +33,7 @@ const TimeOptions: FC<Props> = ({ onToggle24hClock, onSelectTimeZone, timeFormat
|
|||||||
};
|
};
|
||||||
|
|
||||||
return selectedTimeZone !== "" ? (
|
return selectedTimeZone !== "" ? (
|
||||||
<div className="max-w-80 dark:border-darkgray-300 dark:bg-darkgray-200 absolute z-10 w-full rounded-sm border border-gray-200 bg-white px-4 pt-4 pb-3 shadow-sm">
|
<div className="dark:border-darkgray-300 dark:bg-darkgray-200 rounded-sm border border-gray-200 bg-white px-4 pt-4 pb-3 shadow-sm">
|
||||||
<div className="mb-4 flex">
|
<div className="mb-4 flex">
|
||||||
<div className="text-sm font-medium text-gray-600 dark:text-white">{t("time_options")}</div>
|
<div className="text-sm font-medium text-gray-600 dark:text-white">{t("time_options")}</div>
|
||||||
<div className="ml-auto flex items-center">
|
<div className="ml-auto flex items-center">
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
// Get router variables
|
// Get router variables
|
||||||
import { EventType } from "@prisma/client";
|
import { EventType } from "@prisma/client";
|
||||||
import { SchedulingType } from "@prisma/client";
|
import { SchedulingType } from "@prisma/client";
|
||||||
import * as Collapsible from "@radix-ui/react-collapsible";
|
import * as Popover from "@radix-ui/react-popover";
|
||||||
import { TFunction } from "next-i18next";
|
import { TFunction } from "next-i18next";
|
||||||
import { useRouter } from "next/router";
|
import { useRouter } from "next/router";
|
||||||
import { useReducer, useEffect, useMemo, useState } from "react";
|
import { useReducer, useEffect, useMemo, useState } from "react";
|
||||||
@@ -24,8 +24,7 @@ import useTheme from "@calcom/lib/hooks/useTheme";
|
|||||||
import notEmpty from "@calcom/lib/notEmpty";
|
import notEmpty from "@calcom/lib/notEmpty";
|
||||||
import { getRecurringFreq } from "@calcom/lib/recurringStrings";
|
import { getRecurringFreq } from "@calcom/lib/recurringStrings";
|
||||||
import { collectPageParameters, telemetryEventTypes, useTelemetry } from "@calcom/lib/telemetry";
|
import { collectPageParameters, telemetryEventTypes, useTelemetry } from "@calcom/lib/telemetry";
|
||||||
import { detectBrowserTimeFormat } from "@calcom/lib/timeFormat";
|
import { detectBrowserTimeFormat, getIs24hClockFromLocalStorage } from "@calcom/lib/timeFormat";
|
||||||
import { localStorage } from "@calcom/lib/webstorage";
|
|
||||||
import { trpc } from "@calcom/trpc/react";
|
import { trpc } from "@calcom/trpc/react";
|
||||||
import { Icon } from "@calcom/ui/Icon";
|
import { Icon } from "@calcom/ui/Icon";
|
||||||
import DatePicker from "@calcom/ui/v2/modules/booker/DatePicker";
|
import DatePicker from "@calcom/ui/v2/modules/booker/DatePicker";
|
||||||
@@ -79,7 +78,7 @@ const useSlots = ({
|
|||||||
usernameList: string[];
|
usernameList: string[];
|
||||||
timeZone?: string;
|
timeZone?: string;
|
||||||
}) => {
|
}) => {
|
||||||
const { data, isLoading, isIdle } = trpc.useQuery(
|
const { data, isLoading, isPaused } = trpc.useQuery(
|
||||||
[
|
[
|
||||||
"viewer.public.slots.getSchedule",
|
"viewer.public.slots.getSchedule",
|
||||||
{
|
{
|
||||||
@@ -101,8 +100,8 @@ const useSlots = ({
|
|||||||
}
|
}
|
||||||
}, [data]);
|
}, [data]);
|
||||||
|
|
||||||
// The very first time isIdle is set if auto-fetch is disabled, so isIdle should also be considered a loading state.
|
// The very first time isPaused is set if auto-fetch is disabled, so isPaused should also be considered a loading state.
|
||||||
return { slots: cachedSlots, isLoading: isLoading || isIdle };
|
return { slots: cachedSlots, isLoading: isLoading || isPaused };
|
||||||
};
|
};
|
||||||
|
|
||||||
const SlotPicker = ({
|
const SlotPicker = ({
|
||||||
@@ -176,7 +175,7 @@ const SlotPicker = ({
|
|||||||
<DatePicker
|
<DatePicker
|
||||||
isLoading={isLoading}
|
isLoading={isLoading}
|
||||||
className={classNames(
|
className={classNames(
|
||||||
"mt-8 w-full px-4 sm:mt-0 sm:min-w-[455px] md:px-5",
|
"mt-8 w-full px-4 pb-4 sm:mt-0 sm:min-w-[455px] md:px-5",
|
||||||
selectedDate
|
selectedDate
|
||||||
? "sm:dark:border-darkgray-200 border-gray-200 sm:w-1/2 sm:border-r sm:p-4 sm:pr-6 md:w-1/3"
|
? "sm:dark:border-darkgray-200 border-gray-200 sm:w-1/2 sm:border-r sm:p-4 sm:pr-6 md:w-1/3"
|
||||||
: "sm:p-4"
|
: "sm:p-4"
|
||||||
@@ -225,7 +224,7 @@ function TimezoneDropdown({
|
|||||||
const [isTimeOptionsOpen, setIsTimeOptionsOpen] = useState(false);
|
const [isTimeOptionsOpen, setIsTimeOptionsOpen] = useState(false);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
handleToggle24hClock(localStorage.getItem("timeOption.is24hClock") === "true");
|
handleToggle24hClock(!!getIs24hClockFromLocalStorage());
|
||||||
|
|
||||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||||
}, []);
|
}, []);
|
||||||
@@ -241,8 +240,8 @@ function TimezoneDropdown({
|
|||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Collapsible.Root open={isTimeOptionsOpen} onOpenChange={setIsTimeOptionsOpen} className="flex">
|
<Popover.Root open={isTimeOptionsOpen} onOpenChange={setIsTimeOptionsOpen}>
|
||||||
<Collapsible.Trigger className="min-w-32 dark:text-darkgray-600 mb-2 -ml-2 px-2 text-left text-gray-600">
|
<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 inline-block rounded-md px-2 py-2 text-left text-gray-600">
|
||||||
<p className="text-sm font-medium">
|
<p className="text-sm font-medium">
|
||||||
<Icon.FiGlobe className="mr-[10px] ml-[2px] -mt-[2px] inline-block h-4 w-4" />
|
<Icon.FiGlobe className="mr-[10px] ml-[2px] -mt-[2px] inline-block h-4 w-4" />
|
||||||
{timeZone}
|
{timeZone}
|
||||||
@@ -252,15 +251,20 @@ function TimezoneDropdown({
|
|||||||
<Icon.FiChevronDown className="ml-1 inline-block h-4 w-4" />
|
<Icon.FiChevronDown className="ml-1 inline-block h-4 w-4" />
|
||||||
)}
|
)}
|
||||||
</p>
|
</p>
|
||||||
</Collapsible.Trigger>
|
</Popover.Trigger>
|
||||||
<Collapsible.Content>
|
<Popover.Portal>
|
||||||
|
<Popover.Content
|
||||||
|
hideWhenDetached
|
||||||
|
align="start"
|
||||||
|
className="animate-fade-in-up absolute left-0 top-2 w-80 max-w-[calc(100vw_-_1.5rem)]">
|
||||||
<TimeOptions
|
<TimeOptions
|
||||||
onSelectTimeZone={handleSelectTimeZone}
|
onSelectTimeZone={handleSelectTimeZone}
|
||||||
onToggle24hClock={handleToggle24hClock}
|
onToggle24hClock={handleToggle24hClock}
|
||||||
timeFormat={timeFormat}
|
timeFormat={timeFormat}
|
||||||
/>
|
/>
|
||||||
</Collapsible.Content>
|
</Popover.Content>
|
||||||
</Collapsible.Root>
|
</Popover.Portal>
|
||||||
|
</Popover.Root>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -393,7 +397,9 @@ const AvailabilityPage = ({ profile, eventType }: Props) => {
|
|||||||
<div
|
<div
|
||||||
style={availabilityDatePickerEmbedStyles}
|
style={availabilityDatePickerEmbedStyles}
|
||||||
className={classNames(
|
className={classNames(
|
||||||
isBackgroundTransparent ? "" : "dark:bg-darkgray-100 sm:dark:border-darkgray-300 bg-white",
|
isBackgroundTransparent
|
||||||
|
? ""
|
||||||
|
: "dark:bg-darkgray-100 sm:dark:border-darkgray-300 bg-white pb-4 md:pb-0",
|
||||||
"border-bookinglightest overflow-hidden rounded-md md:border",
|
"border-bookinglightest overflow-hidden rounded-md md:border",
|
||||||
isEmbed ? "mx-auto" : maxWidth
|
isEmbed ? "mx-auto" : maxWidth
|
||||||
)}>
|
)}>
|
||||||
@@ -415,7 +421,7 @@ const AvailabilityPage = ({ profile, eventType }: Props) => {
|
|||||||
<h1 className="text-bookingdark dark:text-darkgray-900 mb-4 break-words text-xl font-semibold">
|
<h1 className="text-bookingdark dark:text-darkgray-900 mb-4 break-words text-xl font-semibold">
|
||||||
{eventType.title}
|
{eventType.title}
|
||||||
</h1>
|
</h1>
|
||||||
<div className="flex flex-col space-y-3">
|
<div className="flex flex-col items-start space-y-3">
|
||||||
{eventType?.description && (
|
{eventType?.description && (
|
||||||
<div className="dark:text-darkgray-600 flex py-1 text-sm font-medium text-gray-600">
|
<div className="dark:text-darkgray-600 flex py-1 text-sm font-medium text-gray-600">
|
||||||
<div>
|
<div>
|
||||||
@@ -499,7 +505,7 @@ const AvailabilityPage = ({ profile, eventType }: Props) => {
|
|||||||
<div className="overflow-hidden sm:flex">
|
<div className="overflow-hidden sm:flex">
|
||||||
<div
|
<div
|
||||||
className={
|
className={
|
||||||
"sm:dark:border-darkgray-200 hidden overflow-hidden border-gray-200 p-5 sm:border-r md:flex md:flex-col " +
|
"sm:dark:border-darkgray-200 hidden border-gray-200 p-5 sm:border-r md:flex md:flex-col " +
|
||||||
(isAvailableTimesVisible ? "sm:w-1/3" : recurringEventCount ? "sm:w-2/3" : "sm:w-1/2")
|
(isAvailableTimesVisible ? "sm:w-1/3" : recurringEventCount ? "sm:w-2/3" : "sm:w-1/2")
|
||||||
}>
|
}>
|
||||||
<UserAvatars
|
<UserAvatars
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import { zodResolver } from "@hookform/resolvers/zod";
|
import { zodResolver } from "@hookform/resolvers/zod";
|
||||||
import { EventTypeCustomInputType, WorkflowActions } from "@prisma/client";
|
import { EventTypeCustomInputType, WorkflowActions } from "@prisma/client";
|
||||||
import { SchedulingType } from "@prisma/client";
|
import { SchedulingType } from "@prisma/client";
|
||||||
|
import { useMutation } from "@tanstack/react-query";
|
||||||
import { isValidPhoneNumber } from "libphonenumber-js";
|
import { isValidPhoneNumber } from "libphonenumber-js";
|
||||||
import { useSession } from "next-auth/react";
|
import { useSession } from "next-auth/react";
|
||||||
import Head from "next/head";
|
import Head from "next/head";
|
||||||
@@ -9,7 +10,6 @@ import { useEffect, useMemo, useState, useReducer } from "react";
|
|||||||
import { Controller, useForm, useWatch } from "react-hook-form";
|
import { Controller, useForm, useWatch } from "react-hook-form";
|
||||||
import { FormattedNumber, IntlProvider } from "react-intl";
|
import { FormattedNumber, IntlProvider } from "react-intl";
|
||||||
import { ReactMultiEmail } from "react-multi-email";
|
import { ReactMultiEmail } from "react-multi-email";
|
||||||
import { useMutation } from "react-query";
|
|
||||||
import { v4 as uuidv4 } from "uuid";
|
import { v4 as uuidv4 } from "uuid";
|
||||||
import { z } from "zod";
|
import { z } from "zod";
|
||||||
|
|
||||||
@@ -34,11 +34,11 @@ import useTheme from "@calcom/lib/hooks/useTheme";
|
|||||||
import { HttpError } from "@calcom/lib/http-error";
|
import { HttpError } from "@calcom/lib/http-error";
|
||||||
import { getEveryFreqFor } from "@calcom/lib/recurringStrings";
|
import { getEveryFreqFor } from "@calcom/lib/recurringStrings";
|
||||||
import { collectPageParameters, telemetryEventTypes, useTelemetry } from "@calcom/lib/telemetry";
|
import { collectPageParameters, telemetryEventTypes, useTelemetry } from "@calcom/lib/telemetry";
|
||||||
import { Button } from "@calcom/ui/Button";
|
|
||||||
import { Icon } from "@calcom/ui/Icon";
|
import { Icon } from "@calcom/ui/Icon";
|
||||||
import { Tooltip } from "@calcom/ui/Tooltip";
|
import { Tooltip } from "@calcom/ui/Tooltip";
|
||||||
import PhoneInput from "@calcom/ui/form/PhoneInputLazy";
|
import PhoneInput from "@calcom/ui/form/PhoneInputLazy";
|
||||||
import { EmailInput, Form } from "@calcom/ui/form/fields";
|
import { EmailInput, Form } from "@calcom/ui/form/fields";
|
||||||
|
import { Button } from "@calcom/ui/v2";
|
||||||
|
|
||||||
import { asStringOrNull } from "@lib/asStringOrNull";
|
import { asStringOrNull } from "@lib/asStringOrNull";
|
||||||
import { timeZone } from "@lib/clock";
|
import { timeZone } from "@lib/clock";
|
||||||
@@ -199,16 +199,12 @@ const BookingPage = ({
|
|||||||
|
|
||||||
// There should only exists one default userData variable for primaryAttendee.
|
// There should only exists one default userData variable for primaryAttendee.
|
||||||
const defaultUserValues = {
|
const defaultUserValues = {
|
||||||
email: booking?.attendees[0].email
|
email: rescheduleUid
|
||||||
? booking.attendees[0].email
|
? booking?.attendees[0].email
|
||||||
: router.query.email
|
: router.query.email
|
||||||
? (router.query.email as string)
|
? (router.query.email as string)
|
||||||
: "",
|
: "",
|
||||||
name: booking?.attendees[0].name
|
name: rescheduleUid ? booking?.attendees[0].name : router.query.name ? (router.query.name as string) : "",
|
||||||
? booking.attendees[0].name
|
|
||||||
: router.query.name
|
|
||||||
? (router.query.name as string)
|
|
||||||
: "",
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const defaultValues = () => {
|
const defaultValues = () => {
|
||||||
@@ -449,7 +445,6 @@ const BookingPage = ({
|
|||||||
<div
|
<div
|
||||||
className={classNames(
|
className={classNames(
|
||||||
"main overflow-hidden",
|
"main overflow-hidden",
|
||||||
isEmbed ? "" : "border border-gray-200",
|
|
||||||
isBackgroundTransparent ? "" : "dark:border-1 dark:bg-darkgray-100 bg-white",
|
isBackgroundTransparent ? "" : "dark:border-1 dark:bg-darkgray-100 bg-white",
|
||||||
"dark:border-darkgray-300 rounded-md sm:border"
|
"dark:border-darkgray-300 rounded-md sm:border"
|
||||||
)}>
|
)}>
|
||||||
@@ -595,9 +590,7 @@ const BookingPage = ({
|
|||||||
required
|
required
|
||||||
className={classNames(
|
className={classNames(
|
||||||
inputClassName,
|
inputClassName,
|
||||||
bookingForm.formState.errors.email
|
bookingForm.formState.errors.email && "!focus:ring-red-700 !border-red-700"
|
||||||
? "border-red-700 focus:ring-red-700"
|
|
||||||
: " border-gray-300 dark:border-gray-900"
|
|
||||||
)}
|
)}
|
||||||
placeholder="you@example.com"
|
placeholder="you@example.com"
|
||||||
type="search" // Disables annoying 1password intrusive popup (non-optimal, I know I know...)
|
type="search" // Disables annoying 1password intrusive popup (non-optimal, I know I know...)
|
||||||
@@ -740,9 +733,8 @@ const BookingPage = ({
|
|||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
))}
|
))}
|
||||||
{!eventType.disableGuests && (
|
{!eventType.disableGuests && guestToggle && (
|
||||||
<div className="mb-4">
|
<div className="mb-4">
|
||||||
{guestToggle && (
|
|
||||||
<div>
|
<div>
|
||||||
<label
|
<label
|
||||||
htmlFor="guests"
|
htmlFor="guests"
|
||||||
@@ -756,7 +748,7 @@ const BookingPage = ({
|
|||||||
render={({ field: { onChange, value } }) => (
|
render={({ field: { onChange, value } }) => (
|
||||||
<ReactMultiEmail
|
<ReactMultiEmail
|
||||||
className="relative"
|
className="relative"
|
||||||
placeholder="guest@example.com"
|
placeholder={<span className="dark:text-darkgray-600">guest@example.com</span>}
|
||||||
emails={value}
|
emails={value}
|
||||||
onChange={onChange}
|
onChange={onChange}
|
||||||
getLabel={(
|
getLabel={(
|
||||||
@@ -793,7 +785,6 @@ const BookingPage = ({
|
|||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
)}
|
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
{isSmsReminderNumberNeeded && selectedLocationType !== LocationType.Phone && (
|
{isSmsReminderNumberNeeded && selectedLocationType !== LocationType.Phone && (
|
||||||
@@ -849,27 +840,28 @@ const BookingPage = ({
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="flex justify-end space-x-2 rtl:space-x-reverse">
|
<div className="flex justify-end space-x-2 rtl:space-x-reverse">
|
||||||
{!guestToggle && (
|
{!eventType.disableGuests && !guestToggle && (
|
||||||
<Button
|
<Button
|
||||||
type="button"
|
type="button"
|
||||||
color="secondary"
|
color="minimalSecondary"
|
||||||
|
size="icon"
|
||||||
|
tooltip={t("additional_guests")}
|
||||||
|
StartIcon={Icon.FiUserPlus}
|
||||||
onClick={() => setGuestToggle(!guestToggle)}
|
onClick={() => setGuestToggle(!guestToggle)}
|
||||||
className="dark:bg-darkmodebrand dark:text-darkmodebrandcontrast mr-auto rounded-md">
|
className="mr-auto"
|
||||||
<Icon.FiUserPlus className="mr-2" />
|
/>
|
||||||
{t("additional_guests")}
|
|
||||||
</Button>
|
|
||||||
)}
|
)}
|
||||||
<Button
|
<Button
|
||||||
color="minimal"
|
color="minimal"
|
||||||
type="button"
|
type="button"
|
||||||
onClick={() => router.back()}
|
onClick={() => router.back()}
|
||||||
// We override this for this component only for now - as we don't support darkmode everywhere in the app
|
// We override this for this component only for now - as we don't support darkmode everywhere in the app
|
||||||
className="dark:border-none">
|
className="dark:hover:bg-darkgray-200 dark:border-none dark:text-white">
|
||||||
{t("cancel")}
|
{t("cancel")}
|
||||||
</Button>
|
</Button>
|
||||||
<Button
|
<Button
|
||||||
type="submit"
|
type="submit"
|
||||||
className="dark:bg-darkmodebrand dark:text-darkmodebrandcontrast rounded-md"
|
className="dark:bg-darkmodebrand dark:text-darkmodebrandcontrast dark:hover:border-darkmodebrandcontrast mr-auto dark:border-transparent"
|
||||||
data-testid={rescheduleUid ? "confirm-reschedule-button" : "confirm-book-button"}
|
data-testid={rescheduleUid ? "confirm-reschedule-button" : "confirm-book-button"}
|
||||||
loading={mutation.isLoading || recurringMutation.isLoading}>
|
loading={mutation.isLoading || recurringMutation.isLoading}>
|
||||||
{rescheduleUid ? t("reschedule") : t("confirm")}
|
{rescheduleUid ? t("reschedule") : t("confirm")}
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
|
import { useMutation } from "@tanstack/react-query";
|
||||||
import { RescheduleResponse } from "pages/api/book/request-reschedule";
|
import { RescheduleResponse } from "pages/api/book/request-reschedule";
|
||||||
import React, { useState, Dispatch, SetStateAction } from "react";
|
import React, { useState, Dispatch, SetStateAction } from "react";
|
||||||
import { useMutation } from "react-query";
|
|
||||||
|
|
||||||
import { useLocale } from "@calcom/lib/hooks/useLocale";
|
import { useLocale } from "@calcom/lib/hooks/useLocale";
|
||||||
import showToast from "@calcom/lib/notification";
|
import showToast from "@calcom/lib/notification";
|
||||||
|
|||||||
@@ -14,10 +14,11 @@ const CalendarItem = (props: ICalendarItem) => {
|
|||||||
const { title, imageSrc, type } = props;
|
const { title, imageSrc, type } = props;
|
||||||
const { t } = useLocale();
|
const { t } = useLocale();
|
||||||
return (
|
return (
|
||||||
<div className="flex flex-row items-center p-5">
|
<div className="flex flex-row items-center justify-between p-5">
|
||||||
|
<div className="flex items-center space-x-3">
|
||||||
<img src={imageSrc} alt={title} className="h-8 w-8" />
|
<img src={imageSrc} alt={title} className="h-8 w-8" />
|
||||||
<p className="mx-3 text-sm font-bold">{title}</p>
|
<p className="text-sm font-bold">{title}</p>
|
||||||
|
</div>
|
||||||
<InstallAppButtonWithoutPlanCheck
|
<InstallAppButtonWithoutPlanCheck
|
||||||
type={type}
|
type={type}
|
||||||
render={(buttonProps) => (
|
render={(buttonProps) => (
|
||||||
@@ -29,8 +30,7 @@ const CalendarItem = (props: ICalendarItem) => {
|
|||||||
// Save cookie key to return url step
|
// Save cookie key to return url step
|
||||||
document.cookie = `return-to=${window.location.href};path=/;max-age=3600;SameSite=Lax`;
|
document.cookie = `return-to=${window.location.href};path=/;max-age=3600;SameSite=Lax`;
|
||||||
buttonProps && buttonProps.onClick && buttonProps?.onClick(event);
|
buttonProps && buttonProps.onClick && buttonProps?.onClick(event);
|
||||||
}}
|
}}>
|
||||||
className="ml-auto rounded-md border border-gray-200 py-[10px] px-4 text-sm font-bold">
|
|
||||||
{t("connect")}
|
{t("connect")}
|
||||||
</Button>
|
</Button>
|
||||||
)}
|
)}
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { useMutation } from "react-query";
|
import { useMutation } from "@tanstack/react-query";
|
||||||
|
|
||||||
import showToast from "@calcom/lib/notification";
|
import showToast from "@calcom/lib/notification";
|
||||||
import { trpc } from "@calcom/trpc/react";
|
import { trpc } from "@calcom/trpc/react";
|
||||||
|
|||||||
@@ -31,7 +31,8 @@ const ConnectedCalendars = (props: IConnectCalendarsProps) => {
|
|||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
{/* Already connected calendars */}
|
{/* Already connected calendars */}
|
||||||
{firstCalendar &&
|
{!queryConnectedCalendars.isLoading &&
|
||||||
|
firstCalendar &&
|
||||||
firstCalendar.integration &&
|
firstCalendar.integration &&
|
||||||
firstCalendar.integration.title &&
|
firstCalendar.integration.title &&
|
||||||
firstCalendar.integration.imageSrc && (
|
firstCalendar.integration.imageSrc && (
|
||||||
@@ -75,7 +76,7 @@ const ConnectedCalendars = (props: IConnectCalendarsProps) => {
|
|||||||
</List>
|
</List>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{queryConnectedCalendars.isLoading && (
|
{queryIntegrations.isLoading && (
|
||||||
<ul className="divide-y divide-gray-200 rounded-md border border-gray-200 bg-white p-0 dark:bg-black">
|
<ul className="divide-y divide-gray-200 rounded-md border border-gray-200 bg-white p-0 dark:bg-black">
|
||||||
{[0, 0, 0, 0].map((_item, index) => {
|
{[0, 0, 0, 0].map((_item, index) => {
|
||||||
return (
|
return (
|
||||||
|
|||||||
@@ -149,7 +149,7 @@ const UserProfile = (props: IUserProfile) => {
|
|||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
{errors.bio && (
|
{errors.bio && (
|
||||||
<p data-testid="required" className="text-xs italic text-red-500">
|
<p data-testid="required" className="py-2 text-xs text-red-500">
|
||||||
{t("required")}
|
{t("required")}
|
||||||
</p>
|
</p>
|
||||||
)}
|
)}
|
||||||
|
|||||||
@@ -85,7 +85,7 @@ const UserSettings = (props: IUserSettingsProps) => {
|
|||||||
className="w-full rounded-md border border-gray-300 text-sm"
|
className="w-full rounded-md border border-gray-300 text-sm"
|
||||||
/>
|
/>
|
||||||
{errors.name && (
|
{errors.name && (
|
||||||
<p data-testid="required" className="text-xs italic text-red-500">
|
<p data-testid="required" className="py-2 text-xs text-red-500">
|
||||||
{t("required")}
|
{t("required")}
|
||||||
</p>
|
</p>
|
||||||
)}
|
)}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
|
import { useMutation } from "@tanstack/react-query";
|
||||||
import { Fragment } from "react";
|
import { Fragment } from "react";
|
||||||
import { useMutation } from "react-query";
|
|
||||||
|
|
||||||
import { InstallAppButton } from "@calcom/app-store/components";
|
import { InstallAppButton } from "@calcom/app-store/components";
|
||||||
import { useLocale } from "@calcom/lib/hooks/useLocale";
|
import { useLocale } from "@calcom/lib/hooks/useLocale";
|
||||||
@@ -185,8 +185,8 @@ function ConnectedCalendarsList(props: Props) {
|
|||||||
) : (
|
) : (
|
||||||
<Alert
|
<Alert
|
||||||
severity="warning"
|
severity="warning"
|
||||||
title={t("calendar_error")}
|
title={t("something_went_wrong")}
|
||||||
message={item.error?.message}
|
message={t("calendar_error")}
|
||||||
actions={
|
actions={
|
||||||
<DisconnectIntegration
|
<DisconnectIntegration
|
||||||
id={item.credentialId}
|
id={item.credentialId}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
|
import { useMutation } from "@tanstack/react-query";
|
||||||
import { useState } from "react";
|
import { useState } from "react";
|
||||||
import { useMutation } from "react-query";
|
|
||||||
|
|
||||||
import showToast from "@calcom/lib/notification";
|
import showToast from "@calcom/lib/notification";
|
||||||
import { ButtonBaseProps } from "@calcom/ui/Button";
|
import { ButtonBaseProps } from "@calcom/ui/Button";
|
||||||
|
|||||||
@@ -3,9 +3,9 @@ import { useRef, useState } from "react";
|
|||||||
import { useLocale } from "@calcom/lib/hooks/useLocale";
|
import { useLocale } from "@calcom/lib/hooks/useLocale";
|
||||||
import { trpc } from "@calcom/trpc/react";
|
import { trpc } from "@calcom/trpc/react";
|
||||||
import { Button } from "@calcom/ui";
|
import { Button } from "@calcom/ui";
|
||||||
import { Alert } from "@calcom/ui/Alert";
|
|
||||||
import { Dialog, DialogContent, DialogFooter } from "@calcom/ui/Dialog";
|
|
||||||
import { Icon } from "@calcom/ui/Icon";
|
import { Icon } from "@calcom/ui/Icon";
|
||||||
|
import { Alert } from "@calcom/ui/v2/core/Alert";
|
||||||
|
import { Dialog, DialogContent, DialogFooter } from "@calcom/ui/v2/core/Dialog";
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
isOpen: boolean;
|
isOpen: boolean;
|
||||||
@@ -28,15 +28,14 @@ export default function TeamCreate(props: Props) {
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
const createTeam = (e: React.FormEvent<HTMLFormElement>) => {
|
const createTeam = () => {
|
||||||
e.preventDefault();
|
|
||||||
createTeamMutation.mutate({ name: nameRef?.current?.value });
|
createTeamMutation.mutate({ name: nameRef?.current?.value });
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<Dialog open={props.isOpen} onOpenChange={props.onClose}>
|
<Dialog open={props.isOpen} onOpenChange={props.onClose}>
|
||||||
<DialogContent>
|
<DialogContent type="creation" actionText={t("create_new_team")} actionOnClick={createTeam}>
|
||||||
<div className="mb-4 sm:flex sm:items-start">
|
<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">
|
<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">
|
||||||
<Icon.FiUsers className="text-brandcontrast h-6 w-6" />
|
<Icon.FiUsers className="text-brandcontrast h-6 w-6" />
|
||||||
@@ -50,7 +49,7 @@ export default function TeamCreate(props: Props) {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<form onSubmit={createTeam}>
|
<form>
|
||||||
<div className="mb-4">
|
<div className="mb-4">
|
||||||
<label htmlFor="name" className="block text-sm font-medium text-gray-700">
|
<label htmlFor="name" className="block text-sm font-medium text-gray-700">
|
||||||
{t("name")}
|
{t("name")}
|
||||||
@@ -66,18 +65,6 @@ export default function TeamCreate(props: Props) {
|
|||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
{errorMessage && <Alert severity="error" title={errorMessage} />}
|
{errorMessage && <Alert severity="error" title={errorMessage} />}
|
||||||
<DialogFooter>
|
|
||||||
<Button type="button" color="secondary" onClick={props.onClose}>
|
|
||||||
{t("cancel")}
|
|
||||||
</Button>
|
|
||||||
<Button
|
|
||||||
type="submit"
|
|
||||||
color="primary"
|
|
||||||
className="ltr:ml-2 rtl:mr-2"
|
|
||||||
data-testid="create-new-team-button">
|
|
||||||
{t("create_team")}
|
|
||||||
</Button>
|
|
||||||
</DialogFooter>
|
|
||||||
</form>
|
</form>
|
||||||
</DialogContent>
|
</DialogContent>
|
||||||
</Dialog>
|
</Dialog>
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import { useState } from "react";
|
import { useState } from "react";
|
||||||
|
|
||||||
import showToast from "@calcom/lib/notification";
|
|
||||||
import { inferQueryOutput, trpc } from "@calcom/trpc/react";
|
import { inferQueryOutput, trpc } from "@calcom/trpc/react";
|
||||||
|
import showToast from "@calcom/ui/v2/core/notifications";
|
||||||
|
|
||||||
import TeamListItem from "./TeamListItem";
|
import TeamListItem from "./TeamListItem";
|
||||||
|
|
||||||
|
|||||||
@@ -4,19 +4,21 @@ import Link from "next/link";
|
|||||||
import classNames from "@calcom/lib/classNames";
|
import classNames from "@calcom/lib/classNames";
|
||||||
import { getPlaceholderAvatar } from "@calcom/lib/getPlaceholderAvatar";
|
import { getPlaceholderAvatar } from "@calcom/lib/getPlaceholderAvatar";
|
||||||
import { useLocale } from "@calcom/lib/hooks/useLocale";
|
import { useLocale } from "@calcom/lib/hooks/useLocale";
|
||||||
import showToast from "@calcom/lib/notification";
|
|
||||||
import { inferQueryOutput, trpc } from "@calcom/trpc/react";
|
import { inferQueryOutput, trpc } from "@calcom/trpc/react";
|
||||||
import Button from "@calcom/ui/Button";
|
import { Icon } from "@calcom/ui/Icon";
|
||||||
import ConfirmationDialogContent from "@calcom/ui/ConfirmationDialogContent";
|
import Button from "@calcom/ui/v2/core/Button";
|
||||||
import { Dialog, DialogTrigger } from "@calcom/ui/Dialog";
|
import ButtonGroup from "@calcom/ui/v2/core/ButtonGroup";
|
||||||
|
import ConfirmationDialogContent from "@calcom/ui/v2/core/ConfirmationDialogContent";
|
||||||
|
import { Dialog, DialogTrigger } from "@calcom/ui/v2/core/Dialog";
|
||||||
import Dropdown, {
|
import Dropdown, {
|
||||||
DropdownMenuContent,
|
DropdownMenuContent,
|
||||||
DropdownMenuItem,
|
DropdownMenuItem,
|
||||||
DropdownMenuSeparator,
|
DropdownMenuSeparator,
|
||||||
DropdownMenuTrigger,
|
DropdownMenuTrigger,
|
||||||
} from "@calcom/ui/Dropdown";
|
DropdownItem,
|
||||||
import { Icon } from "@calcom/ui/Icon";
|
} from "@calcom/ui/v2/core/Dropdown";
|
||||||
import { Tooltip } from "@calcom/ui/Tooltip";
|
import { Tooltip } from "@calcom/ui/v2/core/Tooltip";
|
||||||
|
import showToast from "@calcom/ui/v2/core/notifications";
|
||||||
|
|
||||||
import Avatar from "@components/ui/Avatar";
|
import Avatar from "@components/ui/Avatar";
|
||||||
|
|
||||||
@@ -84,7 +86,7 @@ export default function TeamListItem(props: Props) {
|
|||||||
!isInvitee && "group hover:bg-neutral-50"
|
!isInvitee && "group hover:bg-neutral-50"
|
||||||
)}>
|
)}>
|
||||||
{!isInvitee ? (
|
{!isInvitee ? (
|
||||||
<Link href={"/settings/teams/" + team.id}>
|
<Link href={"/settings/teams/" + team.id + "/profile"}>
|
||||||
<a className="flex-grow cursor-pointer truncate text-sm" title={`${team.name}`}>
|
<a className="flex-grow cursor-pointer truncate text-sm" title={`${team.name}`}>
|
||||||
{teamInfo}
|
{teamInfo}
|
||||||
</a>
|
</a>
|
||||||
@@ -112,7 +114,6 @@ export default function TeamListItem(props: Props) {
|
|||||||
<DropdownMenuItem>
|
<DropdownMenuItem>
|
||||||
<Button
|
<Button
|
||||||
color="minimal"
|
color="minimal"
|
||||||
size="sm"
|
|
||||||
className="w-full rounded-none font-medium"
|
className="w-full rounded-none font-medium"
|
||||||
StartIcon={Icon.FiCheck}
|
StartIcon={Icon.FiCheck}
|
||||||
onClick={acceptInvite}>
|
onClick={acceptInvite}>
|
||||||
@@ -121,8 +122,7 @@ export default function TeamListItem(props: Props) {
|
|||||||
</DropdownMenuItem>
|
</DropdownMenuItem>
|
||||||
<DropdownMenuItem>
|
<DropdownMenuItem>
|
||||||
<Button
|
<Button
|
||||||
color="warn"
|
color="destructive"
|
||||||
size="sm"
|
|
||||||
className="w-full rounded-none font-medium"
|
className="w-full rounded-none font-medium"
|
||||||
StartIcon={Icon.FiX}
|
StartIcon={Icon.FiX}
|
||||||
onClick={declineInvite}>
|
onClick={declineInvite}>
|
||||||
@@ -137,52 +137,44 @@ export default function TeamListItem(props: Props) {
|
|||||||
{!isInvitee && (
|
{!isInvitee && (
|
||||||
<div className="flex space-x-2 rtl:space-x-reverse">
|
<div className="flex space-x-2 rtl:space-x-reverse">
|
||||||
<TeamRole role={team.role} />
|
<TeamRole role={team.role} />
|
||||||
|
<ButtonGroup combined>
|
||||||
<Tooltip side="top" content={t("copy_link_team")}>
|
<Tooltip content={t("copy_link_team")}>
|
||||||
<Button
|
<Button
|
||||||
|
color="secondary"
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
navigator.clipboard.writeText(process.env.NEXT_PUBLIC_WEBSITE_URL + "/team/" + team.slug);
|
navigator.clipboard.writeText(
|
||||||
|
process.env.NEXT_PUBLIC_WEBSITE_URL + "/team/" + team.slug
|
||||||
|
);
|
||||||
showToast(t("link_copied"), "success");
|
showToast(t("link_copied"), "success");
|
||||||
}}
|
}}
|
||||||
className="h-10 w-10 transition-none"
|
|
||||||
size="icon"
|
size="icon"
|
||||||
color="minimal"
|
StartIcon={Icon.FiLink}
|
||||||
type="button">
|
combined
|
||||||
<Icon.FiLink className="h-5 w-5 group-hover:text-gray-600" />
|
/>
|
||||||
</Button>
|
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
<Dropdown>
|
<Dropdown>
|
||||||
<DropdownMenuTrigger asChild>
|
<DropdownMenuTrigger asChild>
|
||||||
<Button type="button" color="minimal" size="icon" StartIcon={Icon.FiMoreHorizontal} />
|
<Button type="button" color="secondary" size="icon" StartIcon={Icon.FiMoreHorizontal} />
|
||||||
</DropdownMenuTrigger>
|
</DropdownMenuTrigger>
|
||||||
<DropdownMenuContent hidden={hideDropdown}>
|
<DropdownMenuContent hidden={hideDropdown}>
|
||||||
{isAdmin && (
|
{isAdmin && (
|
||||||
<DropdownMenuItem>
|
<DropdownMenuItem>
|
||||||
<Link href={"/settings/teams/" + team.id}>
|
<DropdownItem
|
||||||
<a>
|
type="button"
|
||||||
<Button
|
href={"/settings/teams/" + team.id + "/profile"}
|
||||||
color="minimal"
|
|
||||||
size="sm"
|
|
||||||
className="w-full rounded-none font-medium"
|
|
||||||
StartIcon={Icon.FiEdit2}>
|
StartIcon={Icon.FiEdit2}>
|
||||||
{t("edit_team")}
|
{t("edit_team") as string}
|
||||||
</Button>
|
</DropdownItem>
|
||||||
</a>
|
|
||||||
</Link>
|
|
||||||
</DropdownMenuItem>
|
</DropdownMenuItem>
|
||||||
)}
|
)}
|
||||||
<DropdownMenuItem>
|
<DropdownMenuItem>
|
||||||
<Link href={`${process.env.NEXT_PUBLIC_WEBSITE_URL}/team/${team.slug}`} passHref={true}>
|
<DropdownItem
|
||||||
<a target="_blank">
|
type="button"
|
||||||
<Button
|
target="_blank"
|
||||||
color="minimal"
|
href={`${process.env.NEXT_PUBLIC_WEBSITE_URL}/team/${team.slug}`}
|
||||||
size="sm"
|
|
||||||
className="w-full rounded-none font-medium"
|
|
||||||
StartIcon={Icon.FiExternalLink}>
|
StartIcon={Icon.FiExternalLink}>
|
||||||
{t("preview_team")}
|
{t("preview_team") as string}
|
||||||
</Button>
|
</DropdownItem>
|
||||||
</a>
|
|
||||||
</Link>
|
|
||||||
</DropdownMenuItem>
|
</DropdownMenuItem>
|
||||||
<DropdownMenuSeparator className="h-px bg-gray-200" />
|
<DropdownMenuSeparator className="h-px bg-gray-200" />
|
||||||
{isOwner && (
|
{isOwner && (
|
||||||
@@ -193,9 +185,8 @@ export default function TeamListItem(props: Props) {
|
|||||||
onClick={(e) => {
|
onClick={(e) => {
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
}}
|
}}
|
||||||
color="warn"
|
color="destructive"
|
||||||
size="sm"
|
className="rounded-none px-3 font-normal"
|
||||||
className="w-full rounded-none font-medium"
|
|
||||||
StartIcon={Icon.FiTrash}>
|
StartIcon={Icon.FiTrash}>
|
||||||
{t("disband_team")}
|
{t("disband_team")}
|
||||||
</Button>
|
</Button>
|
||||||
@@ -220,7 +211,7 @@ export default function TeamListItem(props: Props) {
|
|||||||
<DialogTrigger asChild>
|
<DialogTrigger asChild>
|
||||||
<Button
|
<Button
|
||||||
type="button"
|
type="button"
|
||||||
color="warn"
|
color="destructive"
|
||||||
size="lg"
|
size="lg"
|
||||||
StartIcon={Icon.FiLogOut}
|
StartIcon={Icon.FiLogOut}
|
||||||
className="w-full rounded-none"
|
className="w-full rounded-none"
|
||||||
@@ -242,6 +233,7 @@ export default function TeamListItem(props: Props) {
|
|||||||
)}
|
)}
|
||||||
</DropdownMenuContent>
|
</DropdownMenuContent>
|
||||||
</Dropdown>
|
</Dropdown>
|
||||||
|
</ButtonGroup>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -1,10 +1,7 @@
|
|||||||
import Link from "next/link";
|
import Link from "next/link";
|
||||||
import { TeamPageProps } from "pages/team/[slug]";
|
import { TeamPageProps } from "pages/team/[slug]";
|
||||||
import React from "react";
|
|
||||||
|
|
||||||
import { WEBAPP_URL } from "@calcom/lib/constants";
|
import { WEBAPP_URL } from "@calcom/lib/constants";
|
||||||
import Button from "@calcom/ui/Button";
|
|
||||||
import { Icon } from "@calcom/ui/Icon";
|
|
||||||
import { Avatar } from "@calcom/ui/v2";
|
import { Avatar } from "@calcom/ui/v2";
|
||||||
|
|
||||||
import { useLocale } from "@lib/hooks/useLocale";
|
import { useLocale } from "@lib/hooks/useLocale";
|
||||||
@@ -13,13 +10,12 @@ type TeamType = TeamPageProps["team"];
|
|||||||
type MembersType = TeamType["members"];
|
type MembersType = TeamType["members"];
|
||||||
type MemberType = MembersType[number];
|
type MemberType = MembersType[number];
|
||||||
|
|
||||||
const Team = ({ team }: TeamPageProps) => {
|
const Member = ({ member, teamName }: { member: MemberType; teamName: string | null }) => {
|
||||||
const { t } = useLocale();
|
const { t } = useLocale();
|
||||||
|
|
||||||
const Member = ({ member }: { member: MemberType }) => {
|
|
||||||
return (
|
return (
|
||||||
<Link key={member.id} href={`/${member.username}`}>
|
<Link key={member.id} href={`/${member.username}`}>
|
||||||
<div className="sm:min-w-80 sm:max-w-80 dark:bg-darkgray-200 dark:hover:bg-darkgray-300 group flex h-full flex-col space-y-2 rounded-md bg-white p-4 hover:cursor-pointer hover:bg-gray-50 ">
|
<div className="sm:min-w-80 sm:max-w-80 dark:bg-darkgray-200 dark:hover:bg-darkgray-300 group flex min-h-full w-[90%] flex-col space-y-2 rounded-md bg-white p-4 hover:cursor-pointer hover:bg-gray-50 ">
|
||||||
<Avatar
|
<Avatar
|
||||||
size="md"
|
size="md"
|
||||||
alt={member.name || ""}
|
alt={member.name || ""}
|
||||||
@@ -28,15 +24,15 @@ const Team = ({ team }: TeamPageProps) => {
|
|||||||
<section className="line-clamp-4 mt-2 w-full space-y-1">
|
<section className="line-clamp-4 mt-2 w-full space-y-1">
|
||||||
<p className="font-medium text-neutral-900 dark:text-white">{member.name}</p>
|
<p className="font-medium text-neutral-900 dark:text-white">{member.name}</p>
|
||||||
<p className="line-clamp-3 overflow-ellipsis text-sm font-normal text-neutral-500 dark:text-white">
|
<p className="line-clamp-3 overflow-ellipsis text-sm font-normal text-neutral-500 dark:text-white">
|
||||||
{member.bio || t("user_from_team", { user: member.name, team: team.name })}
|
{member.bio || t("user_from_team", { user: member.name, team: teamName })}
|
||||||
</p>
|
</p>
|
||||||
</section>
|
</section>
|
||||||
</div>
|
</div>
|
||||||
</Link>
|
</Link>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
const Members = ({ members }: { members: MembersType }) => {
|
const Members = ({ members, teamName }: { members: MembersType; teamName: string | null }) => {
|
||||||
if (!members || members.length === 0) {
|
if (!members || members.length === 0) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
@@ -44,15 +40,16 @@ const Team = ({ team }: TeamPageProps) => {
|
|||||||
return (
|
return (
|
||||||
<section className="lg:min-w-lg mx-auto flex min-w-full max-w-5xl flex-wrap justify-center gap-x-6 gap-y-6">
|
<section className="lg:min-w-lg mx-auto flex min-w-full max-w-5xl flex-wrap justify-center gap-x-6 gap-y-6">
|
||||||
{members.map((member) => {
|
{members.map((member) => {
|
||||||
return member.username !== null && <Member key={member.id} member={member} />;
|
return member.username !== null && <Member key={member.id} member={member} teamName={teamName} />;
|
||||||
})}
|
})}
|
||||||
</section>
|
</section>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const Team = ({ team }: TeamPageProps) => {
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<Members members={team.members} />
|
<Members members={team.members} teamName={team.name} />
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,50 +1,48 @@
|
|||||||
import { useState } from "react";
|
import classNames from "classnames";
|
||||||
|
import React, { useState } from "react";
|
||||||
|
import { ControllerRenderProps } from "react-hook-form";
|
||||||
|
|
||||||
import { Icon } from "@calcom/ui/Icon";
|
import { Icon } from "@calcom/ui/Icon";
|
||||||
|
|
||||||
const EditableHeading = ({
|
const EditableHeading = function EditableHeading({
|
||||||
title,
|
value,
|
||||||
onChange,
|
onChange,
|
||||||
placeholder = "",
|
isReady,
|
||||||
readOnly = false,
|
...passThroughProps
|
||||||
}: {
|
}: {
|
||||||
title: string;
|
isReady?: boolean;
|
||||||
onChange?: (value: string) => void;
|
} & Omit<JSX.IntrinsicElements["input"], "name" | "onChange"> &
|
||||||
placeholder?: string;
|
ControllerRenderProps) {
|
||||||
readOnly?: boolean;
|
|
||||||
}) => {
|
|
||||||
const [isEditing, setIsEditing] = useState(false);
|
const [isEditing, setIsEditing] = useState(false);
|
||||||
const enableEditing = () => !readOnly && setIsEditing(true);
|
const enableEditing = () => setIsEditing(true);
|
||||||
return (
|
return (
|
||||||
<div className="group relative cursor-pointer" onClick={enableEditing}>
|
<div className="group relative cursor-pointer" onClick={enableEditing}>
|
||||||
{!isEditing ? (
|
<div className="flex items-center">
|
||||||
<>
|
<label className="min-w-8 relative inline-block">
|
||||||
<h1
|
<span className="whitespace-pre text-xl tracking-normal text-transparent">{value} </span>
|
||||||
style={{ fontSize: 22, letterSpacing: "-0.0009em" }}
|
{!isEditing && isReady && (
|
||||||
className="inline pl-0 normal-case text-gray-900 focus:text-black group-hover:text-gray-500">
|
<Icon.FiEdit2 className="ml-1 inline h-4 w-4 align-top text-gray-700 group-hover:text-gray-500" />
|
||||||
{title}
|
)}
|
||||||
</h1>
|
|
||||||
{!readOnly ? (
|
|
||||||
<Icon.FiEdit2 className="ml-1 -mt-1 inline h-4 w-4 text-gray-700 group-hover:text-gray-500" />
|
|
||||||
) : null}
|
|
||||||
</>
|
|
||||||
) : (
|
|
||||||
<div style={{ marginBottom: -11 }}>
|
|
||||||
<input
|
<input
|
||||||
|
{...passThroughProps}
|
||||||
type="text"
|
type="text"
|
||||||
autoFocus
|
value={value}
|
||||||
style={{ top: -6, fontSize: 22 }}
|
|
||||||
required
|
required
|
||||||
className="relative h-10 w-full cursor-pointer border-none bg-transparent pl-0 text-gray-900 hover:text-gray-700 focus:text-black focus:outline-none focus:ring-0"
|
className={classNames(
|
||||||
placeholder={placeholder}
|
"absolute top-0 left-0 w-full cursor-pointer border-none bg-transparent p-0 align-top text-xl text-gray-900 hover:text-gray-700 focus:text-black focus:outline-none focus:ring-0"
|
||||||
defaultValue={title}
|
)}
|
||||||
|
onFocus={(e) => {
|
||||||
|
setIsEditing(true);
|
||||||
|
passThroughProps.onFocus && passThroughProps.onFocus(e);
|
||||||
|
}}
|
||||||
onBlur={(e) => {
|
onBlur={(e) => {
|
||||||
setIsEditing(false);
|
setIsEditing(false);
|
||||||
onChange && onChange(e.target.value);
|
passThroughProps.onBlur && passThroughProps.onBlur(e);
|
||||||
}}
|
}}
|
||||||
|
onChange={(e) => onChange && onChange(e.target.value)}
|
||||||
/>
|
/>
|
||||||
|
</label>
|
||||||
</div>
|
</div>
|
||||||
)}
|
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,6 +1,11 @@
|
|||||||
import React, { FC } from "react";
|
import React, { FC } from "react";
|
||||||
|
|
||||||
import Dropdown, { DropdownMenuContent, DropdownMenuItem, DropdownMenuTrigger } from "@calcom/ui/Dropdown";
|
import Dropdown, {
|
||||||
|
DropdownMenuContent,
|
||||||
|
DropdownMenuItem,
|
||||||
|
DropdownMenuTrigger,
|
||||||
|
DropdownMenuPortal,
|
||||||
|
} from "@calcom/ui/Dropdown";
|
||||||
import { Icon } from "@calcom/ui/Icon";
|
import { Icon } from "@calcom/ui/Icon";
|
||||||
import Button from "@calcom/ui/v2/core/Button";
|
import Button from "@calcom/ui/v2/core/Button";
|
||||||
|
|
||||||
@@ -43,7 +48,8 @@ const DropdownActions = ({
|
|||||||
) : (
|
) : (
|
||||||
<DropdownMenuTrigger asChild>{actionTrigger}</DropdownMenuTrigger>
|
<DropdownMenuTrigger asChild>{actionTrigger}</DropdownMenuTrigger>
|
||||||
)}
|
)}
|
||||||
<DropdownMenuContent portalled>
|
<DropdownMenuPortal>
|
||||||
|
<DropdownMenuContent>
|
||||||
{actions.map((action) => (
|
{actions.map((action) => (
|
||||||
<DropdownMenuItem key={action.id} className="focus-visible:outline-none">
|
<DropdownMenuItem key={action.id} className="focus-visible:outline-none">
|
||||||
<Button
|
<Button
|
||||||
@@ -59,20 +65,15 @@ const DropdownActions = ({
|
|||||||
</DropdownMenuItem>
|
</DropdownMenuItem>
|
||||||
))}
|
))}
|
||||||
</DropdownMenuContent>
|
</DropdownMenuContent>
|
||||||
|
</DropdownMenuPortal>
|
||||||
</Dropdown>
|
</Dropdown>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
const TableActions: FC<Props> = ({ actions }) => {
|
const TableActions: FC<Props> = ({ actions }) => {
|
||||||
const mobileActions = actions.flatMap((action) => {
|
|
||||||
if (action.actions) {
|
|
||||||
return action.actions;
|
|
||||||
}
|
|
||||||
return action;
|
|
||||||
});
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<div className="hidden space-x-2 rtl:space-x-reverse lg:flex">
|
<div className="flex space-x-2 rtl:space-x-reverse">
|
||||||
{actions.map((action) => {
|
{actions.map((action) => {
|
||||||
const button = (
|
const button = (
|
||||||
<Button
|
<Button
|
||||||
@@ -93,9 +94,6 @@ const TableActions: FC<Props> = ({ actions }) => {
|
|||||||
return <DropdownActions key={action.id} actions={action.actions} actionTrigger={button} />;
|
return <DropdownActions key={action.id} actions={action.actions} actionTrigger={button} />;
|
||||||
})}
|
})}
|
||||||
</div>
|
</div>
|
||||||
<div className="inline-block text-left lg:hidden">
|
|
||||||
<DropdownActions actions={mobileActions} />
|
|
||||||
</div>
|
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -5,14 +5,15 @@ import { MutableRefObject, useCallback, useEffect, useState } from "react";
|
|||||||
|
|
||||||
import { getPremiumPlanMode, getPremiumPlanPriceValue } from "@calcom/app-store/stripepayment/lib/utils";
|
import { getPremiumPlanMode, getPremiumPlanPriceValue } from "@calcom/app-store/stripepayment/lib/utils";
|
||||||
import { fetchUsername } from "@calcom/lib/fetchUsername";
|
import { fetchUsername } from "@calcom/lib/fetchUsername";
|
||||||
|
import hasKeyInMetadata from "@calcom/lib/hasKeyInMetadata";
|
||||||
import { useLocale } from "@calcom/lib/hooks/useLocale";
|
import { useLocale } from "@calcom/lib/hooks/useLocale";
|
||||||
import { User } from "@calcom/prisma/client";
|
import { User } from "@calcom/prisma/client";
|
||||||
import { TRPCClientErrorLike } from "@calcom/trpc/client";
|
import { TRPCClientErrorLike } from "@calcom/trpc/client";
|
||||||
import { inferQueryOutput, trpc } from "@calcom/trpc/react";
|
import { inferQueryOutput, trpc } from "@calcom/trpc/react";
|
||||||
import type { AppRouter } from "@calcom/trpc/server/routers/_app";
|
import type { AppRouter } from "@calcom/trpc/server/routers/_app";
|
||||||
import Button from "@calcom/ui/Button";
|
|
||||||
import { Dialog, DialogClose, DialogContent, DialogHeader } from "@calcom/ui/Dialog";
|
import { Dialog, DialogClose, DialogContent, DialogHeader } from "@calcom/ui/Dialog";
|
||||||
import { Icon, StarIconSolid } from "@calcom/ui/Icon";
|
import { Icon, StarIconSolid } from "@calcom/ui/Icon";
|
||||||
|
import { Button } from "@calcom/ui/v2";
|
||||||
import { Input, Label } from "@calcom/ui/v2";
|
import { Input, Label } from "@calcom/ui/v2";
|
||||||
|
|
||||||
export enum UsernameChangeStatusEnum {
|
export enum UsernameChangeStatusEnum {
|
||||||
@@ -25,7 +26,7 @@ interface ICustomUsernameProps {
|
|||||||
currentUsername: string | undefined;
|
currentUsername: string | undefined;
|
||||||
setCurrentUsername: (value: string | undefined) => void;
|
setCurrentUsername: (value: string | undefined) => void;
|
||||||
inputUsernameValue: string | undefined;
|
inputUsernameValue: string | undefined;
|
||||||
usernameRef: MutableRefObject<HTMLInputElement>;
|
usernameRef: MutableRefObject<HTMLInputElement | null>;
|
||||||
setInputUsernameValue: (value: string) => void;
|
setInputUsernameValue: (value: string) => void;
|
||||||
onSuccessMutation?: () => void;
|
onSuccessMutation?: () => void;
|
||||||
onErrorMutation?: (error: TRPCClientErrorLike<AppRouter>) => void;
|
onErrorMutation?: (error: TRPCClientErrorLike<AppRouter>) => void;
|
||||||
@@ -43,9 +44,8 @@ interface ICustomUsernameProps {
|
|||||||
| "plan"
|
| "plan"
|
||||||
| "brandColor"
|
| "brandColor"
|
||||||
| "darkBrandColor"
|
| "darkBrandColor"
|
||||||
| "metadata"
|
|
||||||
| "timeFormat"
|
| "timeFormat"
|
||||||
| "allowDynamicBooking"
|
| "metadata"
|
||||||
>;
|
>;
|
||||||
readonly?: boolean;
|
readonly?: boolean;
|
||||||
}
|
}
|
||||||
@@ -62,24 +62,13 @@ const obtainNewUsernameChangeCondition = ({
|
|||||||
if (!userIsPremium && isNewUsernamePremium && !stripeCustomer?.paidForPremium) {
|
if (!userIsPremium && isNewUsernamePremium && !stripeCustomer?.paidForPremium) {
|
||||||
return UsernameChangeStatusEnum.UPGRADE;
|
return UsernameChangeStatusEnum.UPGRADE;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (userIsPremium && !isNewUsernamePremium && getPremiumPlanMode() === "subscription") {
|
if (userIsPremium && !isNewUsernamePremium && getPremiumPlanMode() === "subscription") {
|
||||||
return UsernameChangeStatusEnum.DOWNGRADE;
|
return UsernameChangeStatusEnum.DOWNGRADE;
|
||||||
}
|
}
|
||||||
return UsernameChangeStatusEnum.NORMAL;
|
return UsernameChangeStatusEnum.NORMAL;
|
||||||
};
|
};
|
||||||
|
|
||||||
const useIsUsernamePremium = (username: string) => {
|
|
||||||
const [isCurrentUsernamePremium, setIsCurrentUsernamePremium] = useState(false);
|
|
||||||
useEffect(() => {
|
|
||||||
(async () => {
|
|
||||||
if (!username) return;
|
|
||||||
const { data } = await fetchUsername(username);
|
|
||||||
setIsCurrentUsernamePremium(data.premium);
|
|
||||||
})();
|
|
||||||
}, [username]);
|
|
||||||
return isCurrentUsernamePremium;
|
|
||||||
};
|
|
||||||
|
|
||||||
const PremiumTextfield = (props: ICustomUsernameProps) => {
|
const PremiumTextfield = (props: ICustomUsernameProps) => {
|
||||||
const { t } = useLocale();
|
const { t } = useLocale();
|
||||||
const {
|
const {
|
||||||
@@ -91,6 +80,7 @@ const PremiumTextfield = (props: ICustomUsernameProps) => {
|
|||||||
onSuccessMutation,
|
onSuccessMutation,
|
||||||
onErrorMutation,
|
onErrorMutation,
|
||||||
readonly: disabled,
|
readonly: disabled,
|
||||||
|
user,
|
||||||
} = props;
|
} = props;
|
||||||
const [usernameIsAvailable, setUsernameIsAvailable] = useState(false);
|
const [usernameIsAvailable, setUsernameIsAvailable] = useState(false);
|
||||||
const [markAsError, setMarkAsError] = useState(false);
|
const [markAsError, setMarkAsError] = useState(false);
|
||||||
@@ -98,13 +88,13 @@ const PremiumTextfield = (props: ICustomUsernameProps) => {
|
|||||||
const { paymentStatus: recentAttemptPaymentStatus } = router.query;
|
const { paymentStatus: recentAttemptPaymentStatus } = router.query;
|
||||||
const [openDialogSaveUsername, setOpenDialogSaveUsername] = useState(false);
|
const [openDialogSaveUsername, setOpenDialogSaveUsername] = useState(false);
|
||||||
const { data: stripeCustomer } = trpc.useQuery(["viewer.stripeCustomer"]);
|
const { data: stripeCustomer } = trpc.useQuery(["viewer.stripeCustomer"]);
|
||||||
const isCurrentUsernamePremium = useIsUsernamePremium(currentUsername || "");
|
const isCurrentUsernamePremium =
|
||||||
|
user && user.metadata && hasKeyInMetadata(user, "isPremium") ? !!user.metadata.isPremium : false;
|
||||||
const [isInputUsernamePremium, setIsInputUsernamePremium] = useState(false);
|
const [isInputUsernamePremium, setIsInputUsernamePremium] = useState(false);
|
||||||
|
|
||||||
const debouncedApiCall = useCallback(
|
const debouncedApiCall = useCallback(
|
||||||
debounce(async (username) => {
|
debounce(async (username: string) => {
|
||||||
const { data } = await fetchUsername(username);
|
const { data } = await fetchUsername(username);
|
||||||
setMarkAsError(!data.available && username !== currentUsername);
|
setMarkAsError(!data.available && !!currentUsername && username !== currentUsername);
|
||||||
setIsInputUsernamePremium(data.premium);
|
setIsInputUsernamePremium(data.premium);
|
||||||
setUsernameIsAvailable(data.available);
|
setUsernameIsAvailable(data.available);
|
||||||
}, 150),
|
}, 150),
|
||||||
@@ -183,8 +173,10 @@ const PremiumTextfield = (props: ICustomUsernameProps) => {
|
|||||||
onClick={() => {
|
onClick={() => {
|
||||||
if (currentUsername) {
|
if (currentUsername) {
|
||||||
setInputUsernameValue(currentUsername);
|
setInputUsernameValue(currentUsername);
|
||||||
|
if (usernameRef.current) {
|
||||||
usernameRef.current.value = currentUsername;
|
usernameRef.current.value = currentUsername;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}}>
|
}}>
|
||||||
{t("cancel")}
|
{t("cancel")}
|
||||||
</Button>
|
</Button>
|
||||||
@@ -202,6 +194,20 @@ const PremiumTextfield = (props: ICustomUsernameProps) => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
let paymentMsg = !currentUsername ? (
|
||||||
|
<span className="text-xs text-orange-400">
|
||||||
|
You need to reserve your premium username for {getPremiumPlanPriceValue()}
|
||||||
|
</span>
|
||||||
|
) : null;
|
||||||
|
|
||||||
|
if (recentAttemptPaymentStatus && recentAttemptPaymentStatus !== "paid") {
|
||||||
|
paymentMsg = (
|
||||||
|
<span className="text-sm text-red-500">
|
||||||
|
Your payment could not be completed. Your username is still not reserved
|
||||||
|
</span>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<div className="flex justify-items-center">
|
<div className="flex justify-items-center">
|
||||||
@@ -211,7 +217,7 @@ const PremiumTextfield = (props: ICustomUsernameProps) => {
|
|||||||
<span
|
<span
|
||||||
className={classNames(
|
className={classNames(
|
||||||
isInputUsernamePremium ? "border-1 border-orange-400 " : "",
|
isInputUsernamePremium ? "border-1 border-orange-400 " : "",
|
||||||
"hidden items-center rounded-l-md border border-r-0 border-gray-300 border-r-gray-300 bg-gray-50 px-3 text-sm text-gray-500 md:inline-flex"
|
"hidden h-9 items-center rounded-l-md border border-r-0 border-gray-300 border-r-gray-300 bg-gray-50 px-3 text-sm text-gray-500 md:inline-flex"
|
||||||
)}>
|
)}>
|
||||||
{process.env.NEXT_PUBLIC_WEBSITE_URL.replace("https://", "").replace("http://", "")}/
|
{process.env.NEXT_PUBLIC_WEBSITE_URL.replace("https://", "").replace("http://", "")}/
|
||||||
</span>
|
</span>
|
||||||
@@ -237,6 +243,8 @@ const PremiumTextfield = (props: ICustomUsernameProps) => {
|
|||||||
value={inputUsernameValue}
|
value={inputUsernameValue}
|
||||||
onChange={(event) => {
|
onChange={(event) => {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
|
// Reset payment status
|
||||||
|
delete router.query.paymentStatus;
|
||||||
setInputUsernameValue(event.target.value);
|
setInputUsernameValue(event.target.value);
|
||||||
}}
|
}}
|
||||||
data-testid="username-input"
|
data-testid="username-input"
|
||||||
@@ -248,7 +256,7 @@ const PremiumTextfield = (props: ICustomUsernameProps) => {
|
|||||||
isInputUsernamePremium ? "text-orange-400" : "",
|
isInputUsernamePremium ? "text-orange-400" : "",
|
||||||
usernameIsAvailable ? "" : ""
|
usernameIsAvailable ? "" : ""
|
||||||
)}>
|
)}>
|
||||||
{isInputUsernamePremium ? <StarIconSolid className="mt-[4px] w-6" /> : <></>}
|
{isInputUsernamePremium ? <StarIconSolid className="mt-[2px] w-6" /> : <></>}
|
||||||
{!isInputUsernamePremium && usernameIsAvailable ? <Icon.FiCheck className="mt-2 w-6" /> : <></>}
|
{!isInputUsernamePremium && usernameIsAvailable ? <Icon.FiCheck className="mt-2 w-6" /> : <></>}
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
@@ -260,17 +268,7 @@ const PremiumTextfield = (props: ICustomUsernameProps) => {
|
|||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
{paymentRequired ? (
|
{paymentMsg}
|
||||||
recentAttemptPaymentStatus && recentAttemptPaymentStatus !== "paid" ? (
|
|
||||||
<span className="text-sm text-red-500">
|
|
||||||
Your payment could not be completed. Your username is still not reserved
|
|
||||||
</span>
|
|
||||||
) : (
|
|
||||||
<span className="text-xs text-orange-400">
|
|
||||||
You need to reserve your premium username for {getPremiumPlanPriceValue()}
|
|
||||||
</span>
|
|
||||||
)
|
|
||||||
) : null}
|
|
||||||
{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">Username is already taken</p>}
|
||||||
|
|
||||||
{usernameIsAvailable && (
|
{usernameIsAvailable && (
|
||||||
|
|||||||
@@ -7,16 +7,15 @@ import { useLocale } from "@calcom/lib/hooks/useLocale";
|
|||||||
import { TRPCClientErrorLike } from "@calcom/trpc/client";
|
import { TRPCClientErrorLike } from "@calcom/trpc/client";
|
||||||
import { trpc } from "@calcom/trpc/react";
|
import { trpc } from "@calcom/trpc/react";
|
||||||
import { AppRouter } from "@calcom/trpc/server/routers/_app";
|
import { AppRouter } from "@calcom/trpc/server/routers/_app";
|
||||||
import Button from "@calcom/ui/Button";
|
|
||||||
import { Dialog, DialogClose, DialogContent, DialogHeader } from "@calcom/ui/Dialog";
|
import { Dialog, DialogClose, DialogContent, DialogHeader } from "@calcom/ui/Dialog";
|
||||||
import { Icon } from "@calcom/ui/Icon";
|
import { Icon } from "@calcom/ui/Icon";
|
||||||
import { Input, Label } from "@calcom/ui/v2";
|
import { Input, Label, Button } from "@calcom/ui/v2";
|
||||||
|
|
||||||
interface ICustomUsernameProps {
|
interface ICustomUsernameProps {
|
||||||
currentUsername: string | undefined;
|
currentUsername: string | undefined;
|
||||||
setCurrentUsername: (value: string | undefined) => void;
|
setCurrentUsername: (value: string | undefined) => void;
|
||||||
inputUsernameValue: string | undefined;
|
inputUsernameValue: string | undefined;
|
||||||
usernameRef: MutableRefObject<HTMLInputElement>;
|
usernameRef: MutableRefObject<HTMLInputElement | null>;
|
||||||
setInputUsernameValue: (value: string) => void;
|
setInputUsernameValue: (value: string) => void;
|
||||||
onSuccessMutation?: () => void;
|
onSuccessMutation?: () => void;
|
||||||
onErrorMutation?: (error: TRPCClientErrorLike<AppRouter>) => void;
|
onErrorMutation?: (error: TRPCClientErrorLike<AppRouter>) => void;
|
||||||
@@ -73,15 +72,14 @@ const UsernameTextfield = (props: ICustomUsernameProps) => {
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
const ActionButtons = (props: { index: string }) => {
|
const ActionButtons = () => {
|
||||||
const { index } = props;
|
|
||||||
return usernameIsAvailable && currentUsername !== inputUsernameValue ? (
|
return usernameIsAvailable && currentUsername !== inputUsernameValue ? (
|
||||||
<div className="flex flex-row">
|
<div className="flex flex-row">
|
||||||
<Button
|
<Button
|
||||||
type="button"
|
type="button"
|
||||||
className="mx-2"
|
className="mx-2"
|
||||||
onClick={() => setOpenDialogSaveUsername(true)}
|
onClick={() => setOpenDialogSaveUsername(true)}
|
||||||
data-testid={`update-username-btn-${index}`}>
|
data-testid="update-username-btn">
|
||||||
{t("update")}
|
{t("update")}
|
||||||
</Button>
|
</Button>
|
||||||
<Button
|
<Button
|
||||||
@@ -91,8 +89,10 @@ const UsernameTextfield = (props: ICustomUsernameProps) => {
|
|||||||
onClick={() => {
|
onClick={() => {
|
||||||
if (currentUsername) {
|
if (currentUsername) {
|
||||||
setInputUsernameValue(currentUsername);
|
setInputUsernameValue(currentUsername);
|
||||||
|
if (usernameRef.current) {
|
||||||
usernameRef.current.value = currentUsername;
|
usernameRef.current.value = currentUsername;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}}>
|
}}>
|
||||||
{t("cancel")}
|
{t("cancel")}
|
||||||
</Button>
|
</Button>
|
||||||
@@ -122,7 +122,7 @@ const UsernameTextfield = (props: ICustomUsernameProps) => {
|
|||||||
autoCapitalize="none"
|
autoCapitalize="none"
|
||||||
autoCorrect="none"
|
autoCorrect="none"
|
||||||
className={classNames(
|
className={classNames(
|
||||||
"mb-0 mt-0 rounded-md rounded-l-none",
|
"mb-0 mt-0 h-6 rounded-md rounded-l-none",
|
||||||
markAsError
|
markAsError
|
||||||
? "focus:shadow-0 focus:ring-shadow-0 border-red-500 focus:border-red-500 focus:outline-none focus:ring-0"
|
? "focus:shadow-0 focus:ring-shadow-0 border-red-500 focus:border-red-500 focus:outline-none focus:ring-0"
|
||||||
: ""
|
: ""
|
||||||
@@ -137,20 +137,20 @@ const UsernameTextfield = (props: ICustomUsernameProps) => {
|
|||||||
{currentUsername !== inputUsernameValue && (
|
{currentUsername !== inputUsernameValue && (
|
||||||
<div className="absolute right-[2px] top-0 flex flex-row">
|
<div className="absolute right-[2px] top-0 flex flex-row">
|
||||||
<span className={classNames("mx-2 py-2")}>
|
<span className={classNames("mx-2 py-2")}>
|
||||||
{usernameIsAvailable ? <Icon.FiCheck className="mt-[4px] w-6" /> : <></>}
|
{usernameIsAvailable ? <Icon.FiCheck className="mt-[2px] w-6" /> : <></>}
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
<div className="hidden md:inline">
|
<div className="hidden md:inline">
|
||||||
<ActionButtons index="desktop" />
|
<ActionButtons />
|
||||||
</div>
|
</div>
|
||||||
</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">Username is already taken</p>}
|
||||||
|
|
||||||
{usernameIsAvailable && currentUsername !== inputUsernameValue && (
|
{usernameIsAvailable && currentUsername !== inputUsernameValue && (
|
||||||
<div className="mt-2 flex justify-end sm:hidden">
|
<div className="mt-2 flex justify-end md:hidden">
|
||||||
<ActionButtons index="mobile" />
|
<ActionButtons />
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
<Dialog open={openDialogSaveUsername}>
|
<Dialog open={openDialogSaveUsername}>
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import Link from "next/link";
|
import Link from "next/link";
|
||||||
import { useRouter } from "next/router";
|
import { useRouter } from "next/router";
|
||||||
import React, { useEffect, useState } from "react";
|
import React, { useState } from "react";
|
||||||
|
|
||||||
import useAddAppMutation from "@calcom/app-store/_utils/useAddAppMutation";
|
import useAddAppMutation from "@calcom/app-store/_utils/useAddAppMutation";
|
||||||
import { InstallAppButton } from "@calcom/app-store/components";
|
import { InstallAppButton } from "@calcom/app-store/components";
|
||||||
@@ -9,9 +9,8 @@ import classNames from "@calcom/lib/classNames";
|
|||||||
import { useLocale } from "@calcom/lib/hooks/useLocale";
|
import { useLocale } from "@calcom/lib/hooks/useLocale";
|
||||||
import { trpc } from "@calcom/trpc/react";
|
import { trpc } from "@calcom/trpc/react";
|
||||||
import { App as AppType } from "@calcom/types/App";
|
import { App as AppType } from "@calcom/types/App";
|
||||||
import Badge from "@calcom/ui/Badge";
|
|
||||||
import { Icon } from "@calcom/ui/Icon";
|
import { Icon } from "@calcom/ui/Icon";
|
||||||
import { showToast } from "@calcom/ui/v2";
|
import { showToast, SkeletonText } from "@calcom/ui/v2";
|
||||||
import { Button, SkeletonButton, Shell } from "@calcom/ui/v2";
|
import { Button, SkeletonButton, Shell } from "@calcom/ui/v2";
|
||||||
import DisconnectIntegration from "@calcom/ui/v2/modules/integrations/DisconnectIntegration";
|
import DisconnectIntegration from "@calcom/ui/v2/modules/integrations/DisconnectIntegration";
|
||||||
|
|
||||||
@@ -37,7 +36,6 @@ const Component = ({
|
|||||||
images,
|
images,
|
||||||
}: Parameters<typeof App>[0]) => {
|
}: Parameters<typeof App>[0]) => {
|
||||||
const { t } = useLocale();
|
const { t } = useLocale();
|
||||||
const { data: user } = trpc.useQuery(["viewer.me"]);
|
|
||||||
const hasImages = images && images.length > 0;
|
const hasImages = images && images.length > 0;
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
|
|
||||||
@@ -66,19 +64,10 @@ const Component = ({
|
|||||||
const allowedMultipleInstalls = categories.indexOf("calendar") > -1;
|
const allowedMultipleInstalls = categories.indexOf("calendar") > -1;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
|
||||||
<div className="px-4 pb-3 pt-3 md:px-8 lg:px-0 lg:pt-0">
|
|
||||||
<Link href="/apps">
|
|
||||||
<a className="text-md hover:text-brand-400 inline-flex rounded-sm py-2 font-semibold text-gray-900">
|
|
||||||
<Icon.FiArrowLeft className="mr-2 h-6 w-6" /> {t("app_store")}
|
|
||||||
</a>
|
|
||||||
</Link>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className="relative flex-1 flex-col items-start justify-start px-4 md:flex md:px-8 lg:flex-row lg:px-0">
|
<div className="relative flex-1 flex-col items-start justify-start px-4 md:flex md:px-8 lg:flex-row lg:px-0">
|
||||||
{hasImages && (
|
{hasImages && (
|
||||||
<div className="flex-2 mb-4 -ml-4 -mr-4 flex w-auto snap-x snap-mandatory flex-row overflow-auto whitespace-nowrap bg-gray-100 p-4 md:mb-8 md:-ml-8 md:-mr-8 md:p-8 lg:mx-0 lg:mb-0 lg:max-w-2xl lg:flex-col lg:rounded-md">
|
<div className="flex-2 mb-4 -ml-4 -mr-4 flex min-h-[450px] w-auto snap-x snap-mandatory flex-row overflow-auto whitespace-nowrap bg-gray-100 p-4 md:mb-8 md:-ml-8 md:-mr-8 md:p-8 lg:mx-0 lg:mb-0 lg:max-w-2xl lg:flex-col lg:rounded-md">
|
||||||
{images &&
|
{images ? (
|
||||||
images.map((img) => (
|
images.map((img) => (
|
||||||
<img
|
<img
|
||||||
key={img}
|
key={img}
|
||||||
@@ -86,7 +75,10 @@ const Component = ({
|
|||||||
alt={`Screenshot of app ${name}`}
|
alt={`Screenshot of app ${name}`}
|
||||||
className="mr-4 h-auto max-h-80 max-w-[90%] snap-center rounded-md object-contain last:mb-0 md:max-h-min lg:mb-4 lg:mr-0 lg:max-w-full"
|
className="mr-4 h-auto max-h-80 max-w-[90%] snap-center rounded-md object-contain last:mb-0 md:max-h-min lg:mb-4 lg:mr-0 lg:max-w-full"
|
||||||
/>
|
/>
|
||||||
))}
|
))
|
||||||
|
) : (
|
||||||
|
<SkeletonText />
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
<div
|
<div
|
||||||
@@ -102,9 +94,7 @@ const Component = ({
|
|||||||
</div>
|
</div>
|
||||||
<h2 className="text-sm font-medium text-gray-600">
|
<h2 className="text-sm font-medium text-gray-600">
|
||||||
<Link href={`categories/${categories[0]}`}>
|
<Link href={`categories/${categories[0]}`}>
|
||||||
<a className="rounded-md bg-gray-100 p-1 text-xs capitalize text-gray-800">
|
<a className="rounded-md bg-gray-100 p-1 text-xs capitalize text-gray-800">{categories[0]}</a>
|
||||||
{categories[0]}
|
|
||||||
</a>
|
|
||||||
</Link>{" "}
|
</Link>{" "}
|
||||||
• {t("published_by", { author })}
|
• {t("published_by", { author })}
|
||||||
</h2>
|
</h2>
|
||||||
@@ -193,7 +183,7 @@ const Component = ({
|
|||||||
</span>
|
</span>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
<div className="prose prose-sm mt-8 space-x-2">{body}</div>
|
<div className="prose prose-sm mt-8">{body}</div>
|
||||||
<h4 className="mt-8 font-semibold text-gray-900 ">{t("pricing")}</h4>
|
<h4 className="mt-8 font-semibold text-gray-900 ">{t("pricing")}</h4>
|
||||||
<span>
|
<span>
|
||||||
{price === 0 ? (
|
{price === 0 ? (
|
||||||
@@ -275,17 +265,12 @@ const Component = ({
|
|||||||
)}
|
)}
|
||||||
</ul>
|
</ul>
|
||||||
<hr className="my-8" />
|
<hr className="my-8" />
|
||||||
<span className="leading-1 block text-xs text-gray-500">
|
<span className="leading-1 block text-xs text-gray-500">{t("every_app_published")}</span>
|
||||||
Every app published on the Cal.com App Store is open source and thoroughly tested via peer
|
|
||||||
reviews. Nevertheless, Cal.com, Inc. does not endorse or certify these apps unless they are
|
|
||||||
published by Cal.com. If you encounter inappropriate content or behaviour please report it.
|
|
||||||
</span>
|
|
||||||
<a className="mt-2 block text-xs text-red-500" href="mailto:help@cal.com">
|
<a className="mt-2 block text-xs text-red-500" href="mailto:help@cal.com">
|
||||||
<Icon.FiFlag className="inline h-3 w-3" /> Report App
|
<Icon.FiFlag className="inline h-3 w-3" /> {t("report_app")}
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</>
|
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -312,8 +297,10 @@ export default function App(props: {
|
|||||||
isProOnly: AppType["isProOnly"];
|
isProOnly: AppType["isProOnly"];
|
||||||
images?: string[];
|
images?: string[];
|
||||||
}) {
|
}) {
|
||||||
|
const { t } = useLocale();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Shell large isPublic>
|
<Shell large isPublic heading={t("app_store")} backPath="/apps">
|
||||||
{props.licenseRequired ? (
|
{props.licenseRequired ? (
|
||||||
<LicenseRequired>
|
<LicenseRequired>
|
||||||
<Component {...props} />
|
<Component {...props} />
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
|
import { useMutation } from "@tanstack/react-query";
|
||||||
|
import Link from "next/link";
|
||||||
import { Fragment } from "react";
|
import { Fragment } from "react";
|
||||||
import { useMutation } from "react-query";
|
|
||||||
|
|
||||||
import { InstallAppButton } from "@calcom/app-store/components";
|
import { InstallAppButton } from "@calcom/app-store/components";
|
||||||
import { useLocale } from "@calcom/lib/hooks/useLocale";
|
import { useLocale } from "@calcom/lib/hooks/useLocale";
|
||||||
@@ -153,7 +154,7 @@ function ConnectedCalendarsList(props: Props) {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
return (
|
return (
|
||||||
<List className="flex flex-col gap-6">
|
<List className="flex flex-col gap-6" noBorderTreatment>
|
||||||
{data.connectedCalendars.map((item) => (
|
{data.connectedCalendars.map((item) => (
|
||||||
<Fragment key={item.credentialId}>
|
<Fragment key={item.credentialId}>
|
||||||
{item.calendars ? (
|
{item.calendars ? (
|
||||||
@@ -163,7 +164,7 @@ function ConnectedCalendarsList(props: Props) {
|
|||||||
logo={item.integration.logo}
|
logo={item.integration.logo}
|
||||||
description={item.primary?.externalId || "No external Id"}
|
description={item.primary?.externalId || "No external Id"}
|
||||||
actions={
|
actions={
|
||||||
<div className="w-32">
|
<div className="flex w-32 justify-end">
|
||||||
<DisconnectIntegration
|
<DisconnectIntegration
|
||||||
credentialId={item.credentialId}
|
credentialId={item.credentialId}
|
||||||
trashIcon
|
trashIcon
|
||||||
@@ -193,10 +194,16 @@ function ConnectedCalendarsList(props: Props) {
|
|||||||
) : (
|
) : (
|
||||||
<Alert
|
<Alert
|
||||||
severity="warning"
|
severity="warning"
|
||||||
title={t("calendar_error")}
|
title={t("something_went_wrong")}
|
||||||
message={item.error?.message}
|
message={
|
||||||
|
<span>
|
||||||
|
<Link href={"/apps/" + item.integration.slug}>{item.integration.name}</Link>:{" "}
|
||||||
|
{t("calendar_error")}
|
||||||
|
</span>
|
||||||
|
}
|
||||||
|
iconClassName="h-10 w-10 ml-2 mr-1 mt-0.5"
|
||||||
actions={
|
actions={
|
||||||
<div className="w-32">
|
<div className="flex w-32 justify-end md:pr-1">
|
||||||
<DisconnectIntegration
|
<DisconnectIntegration
|
||||||
credentialId={item.credentialId}
|
credentialId={item.credentialId}
|
||||||
trashIcon
|
trashIcon
|
||||||
@@ -251,7 +258,7 @@ export function CalendarListContainer(props: { heading?: boolean; fromOnboarding
|
|||||||
<ShellSubHeading
|
<ShellSubHeading
|
||||||
title={t("calendar")}
|
title={t("calendar")}
|
||||||
subtitle={t("installed_app_calendar_description")}
|
subtitle={t("installed_app_calendar_description")}
|
||||||
className="flex items-center"
|
className="mb-0 flex flex-wrap items-center gap-4 md:mb-3 md:gap-0"
|
||||||
actions={
|
actions={
|
||||||
<div className="flex flex-col xl:flex-row xl:space-x-5">
|
<div className="flex flex-col xl:flex-row xl:space-x-5">
|
||||||
{!!data.connectedCalendars.length && (
|
{!!data.connectedCalendars.length && (
|
||||||
@@ -263,7 +270,7 @@ export function CalendarListContainer(props: { heading?: boolean; fromOnboarding
|
|||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
<div className="flex justify-between rounded-md border border-gray-200 bg-gray-50 p-4">
|
<div className="flex justify-between rounded-md border border-gray-200 bg-gray-50 p-4">
|
||||||
<div className="flex w-full items-center gap-4">
|
<div className="flex w-full flex-col items-start gap-4 md:flex-row md:items-center">
|
||||||
<div className="relative rounded-md border border-gray-200 bg-white p-1.5">
|
<div className="relative rounded-md border border-gray-200 bg-white p-1.5">
|
||||||
<Icon.FiCalendar className="h-8 w-8" strokeWidth="1" />
|
<Icon.FiCalendar className="h-8 w-8" strokeWidth="1" />
|
||||||
<Icon.FiPlus
|
<Icon.FiPlus
|
||||||
@@ -271,11 +278,11 @@ export function CalendarListContainer(props: { heading?: boolean; fromOnboarding
|
|||||||
strokeWidth="4"
|
strokeWidth="4"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div className="w-6/12">
|
<div className="md:w-6/12">
|
||||||
<h1 className="text-sm font-semibold">{t("create_events_on")}</h1>
|
<h1 className="text-sm font-semibold">{t("create_events_on")}</h1>
|
||||||
<p className="text-sm font-normal">{t("set_calendar")}</p>
|
<p className="text-sm font-normal">{t("set_calendar")}</p>
|
||||||
</div>
|
</div>
|
||||||
<div className="flex w-6/12 justify-end">
|
<div className="flex justify-end md:w-6/12">
|
||||||
<DestinationCalendarSelector
|
<DestinationCalendarSelector
|
||||||
onChange={mutation.mutate}
|
onChange={mutation.mutate}
|
||||||
hidePlaceholder
|
hidePlaceholder
|
||||||
|
|||||||
@@ -51,7 +51,7 @@ const DestinationCalendarSelector = ({
|
|||||||
if (selected) {
|
if (selected) {
|
||||||
setSelectedOption({
|
setSelectedOption({
|
||||||
value: `${selected.integration}:${selected.externalId}`,
|
value: `${selected.integration}:${selected.externalId}`,
|
||||||
label: `<span class="font-semibold">${selected.name}</span> (${selected.externalId})` || "",
|
label: `${selected.name} (${selected.externalId})` || "",
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}, [query.data?.connectedCalendars, value]);
|
}, [query.data?.connectedCalendars, value]);
|
||||||
@@ -66,7 +66,7 @@ const DestinationCalendarSelector = ({
|
|||||||
options: (selectedCalendar.calendars ?? [])
|
options: (selectedCalendar.calendars ?? [])
|
||||||
.filter((cal) => cal.readOnly === false)
|
.filter((cal) => cal.readOnly === false)
|
||||||
.map((cal) => ({
|
.map((cal) => ({
|
||||||
label: `<span class="font-semibold">${cal.name}</span> (${cal.externalId})` || "",
|
label: `${cal.name} (${cal.externalId})` || "",
|
||||||
value: `${cal.integration}:${cal.externalId}`,
|
value: `${cal.integration}:${cal.externalId}`,
|
||||||
})),
|
})),
|
||||||
})) ?? [];
|
})) ?? [];
|
||||||
@@ -83,9 +83,6 @@ const DestinationCalendarSelector = ({
|
|||||||
title={`${t("select_destination_calendar")}: ${selectedOption?.label || ""}`}>
|
title={`${t("select_destination_calendar")}: ${selectedOption?.label || ""}`}>
|
||||||
<Select
|
<Select
|
||||||
name="primarySelectedCalendar"
|
name="primarySelectedCalendar"
|
||||||
formatOptionLabel={function (data) {
|
|
||||||
return <span dangerouslySetInnerHTML={{ __html: data.label }} />;
|
|
||||||
}}
|
|
||||||
placeholder={
|
placeholder={
|
||||||
!hidePlaceholder ? (
|
!hidePlaceholder ? (
|
||||||
`${t("select_destination_calendar")}`
|
`${t("select_destination_calendar")}`
|
||||||
|
|||||||
@@ -32,7 +32,7 @@ function IntegrationListItem(props: {
|
|||||||
<ListItem
|
<ListItem
|
||||||
expanded={!!props.children}
|
expanded={!!props.children}
|
||||||
className={classNames(
|
className={classNames(
|
||||||
"my-0 flex-col rounded-none border-0 transition-colors duration-500",
|
"my-0 flex-col border transition-colors duration-500 first:rounded-t-md last:rounded-b-md",
|
||||||
highlight ? "bg-yellow-100" : ""
|
highlight ? "bg-yellow-100" : ""
|
||||||
)}>
|
)}>
|
||||||
<div className={classNames("flex w-full flex-1 items-center space-x-2 p-4 rtl:space-x-reverse")}>
|
<div className={classNames("flex w-full flex-1 items-center space-x-2 p-4 rtl:space-x-reverse")}>
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
import classNames from "classnames";
|
||||||
import React from "react";
|
import React from "react";
|
||||||
|
|
||||||
import { SkeletonText } from "@calcom/ui/v2";
|
import { SkeletonText } from "@calcom/ui/v2";
|
||||||
@@ -32,9 +33,13 @@ function SkeletonItem() {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export const AvailabilitySelectSkeletonLoader = () => {
|
export const SelectSkeletonLoader = ({ className }: { className?: string }) => {
|
||||||
return (
|
return (
|
||||||
<li className="group flex w-full items-center justify-between rounded-sm border border-gray-200 px-[10px] py-3">
|
<li
|
||||||
|
className={classNames(
|
||||||
|
"group flex w-full items-center justify-between rounded-sm border border-gray-200 px-[10px] py-3",
|
||||||
|
className
|
||||||
|
)}>
|
||||||
<div className="flex-grow truncate text-sm">
|
<div className="flex-grow truncate text-sm">
|
||||||
<div className="flex justify-between">
|
<div className="flex justify-between">
|
||||||
<SkeletonText className="h-4 w-32" />
|
<SkeletonText className="h-4 w-32" />
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ import Button from "@calcom/ui/v2/core/Button";
|
|||||||
import Select from "@calcom/ui/v2/core/form/Select";
|
import Select from "@calcom/ui/v2/core/form/Select";
|
||||||
import { SkeletonText } from "@calcom/ui/v2/core/skeleton";
|
import { SkeletonText } from "@calcom/ui/v2/core/skeleton";
|
||||||
|
|
||||||
import { AvailabilitySelectSkeletonLoader } from "@components/v2/availability/SkeletonLoader";
|
import { SelectSkeletonLoader } from "@components/v2/availability/SkeletonLoader";
|
||||||
|
|
||||||
type AvailabilityOption = {
|
type AvailabilityOption = {
|
||||||
label: string;
|
label: string;
|
||||||
@@ -30,7 +30,7 @@ const AvailabilitySelect = ({
|
|||||||
}) => {
|
}) => {
|
||||||
const { data, isLoading } = trpc.useQuery(["viewer.availability.list"]);
|
const { data, isLoading } = trpc.useQuery(["viewer.availability.list"]);
|
||||||
if (isLoading) {
|
if (isLoading) {
|
||||||
return <AvailabilitySelectSkeletonLoader />;
|
return <SelectSkeletonLoader />;
|
||||||
}
|
}
|
||||||
|
|
||||||
const schedules = data?.schedules || [];
|
const schedules = data?.schedules || [];
|
||||||
|
|||||||
@@ -19,6 +19,7 @@ import {
|
|||||||
DialogContent,
|
DialogContent,
|
||||||
Label,
|
Label,
|
||||||
showToast,
|
showToast,
|
||||||
|
Skeleton,
|
||||||
Switch,
|
Switch,
|
||||||
TextField,
|
TextField,
|
||||||
Tooltip,
|
Tooltip,
|
||||||
@@ -37,10 +38,10 @@ export const EventAdvancedTab = ({ eventType, team }: Pick<EventTypeSetupInfered
|
|||||||
const connectedCalendarsQuery = trpc.useQuery(["viewer.connectedCalendars"]);
|
const connectedCalendarsQuery = trpc.useQuery(["viewer.connectedCalendars"]);
|
||||||
const formMethods = useFormContext<FormValues>();
|
const formMethods = useFormContext<FormValues>();
|
||||||
const { t } = useLocale();
|
const { t } = useLocale();
|
||||||
const utils = trpc.useContext();
|
|
||||||
const [showEventNameTip, setShowEventNameTip] = useState(false);
|
const [showEventNameTip, setShowEventNameTip] = useState(false);
|
||||||
const [hashedLinkVisible, setHashedLinkVisible] = useState(!!eventType.hashedLink);
|
const [hashedLinkVisible, setHashedLinkVisible] = useState(!!eventType.hashedLink);
|
||||||
const [hashedUrl, setHashedUrl] = useState(eventType.hashedLink?.link);
|
const [hashedUrl, setHashedUrl] = useState(eventType.hashedLink?.link);
|
||||||
|
const [seatsInputVisible, setSeatsInputVisible] = useState(!!eventType.seatsPerTimeSlot);
|
||||||
const [customInputs, setCustomInputs] = useState<EventTypeCustomInput[]>(
|
const [customInputs, setCustomInputs] = useState<EventTypeCustomInput[]>(
|
||||||
eventType.customInputs.sort((a, b) => a.id - b.id) || []
|
eventType.customInputs.sort((a, b) => a.id - b.id) || []
|
||||||
);
|
);
|
||||||
@@ -49,7 +50,7 @@ export const EventAdvancedTab = ({ eventType, team }: Pick<EventTypeSetupInfered
|
|||||||
const placeholderHashedLink = `${CAL_URL}/d/${hashedUrl}/${eventType.slug}`;
|
const placeholderHashedLink = `${CAL_URL}/d/${hashedUrl}/${eventType.slug}`;
|
||||||
|
|
||||||
const animationRef = useRef(null);
|
const animationRef = useRef(null);
|
||||||
const seatsEnabled = !!eventType.seatsPerTimeSlot;
|
const seatsEnabled = formMethods.getValues("seatsPerTimeSlotEnabled");
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
animationRef.current && autoAnimate(animationRef.current);
|
animationRef.current && autoAnimate(animationRef.current);
|
||||||
@@ -136,8 +137,12 @@ export const EventAdvancedTab = ({ eventType, team }: Pick<EventTypeSetupInfered
|
|||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
<div className="flex flex-col">
|
<div className="flex flex-col">
|
||||||
<Label className="text-sm font-semibold leading-none text-black">{t("additional_inputs")}</Label>
|
<Skeleton as={Label} className="text-sm font-semibold leading-none text-black">
|
||||||
<p className="-mt-2 text-sm leading-normal text-gray-600">{t("additional_input_description")}</p>
|
{t("additional_inputs")}
|
||||||
|
</Skeleton>
|
||||||
|
<Skeleton as="p" className="-mt-2 text-sm leading-normal text-gray-600">
|
||||||
|
{t("additional_input_description")}
|
||||||
|
</Skeleton>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<ul className="my-4" ref={animationRef}>
|
<ul className="my-4" ref={animationRef}>
|
||||||
@@ -182,12 +187,12 @@ export const EventAdvancedTab = ({ eventType, team }: Pick<EventTypeSetupInfered
|
|||||||
fitToHeight={true}
|
fitToHeight={true}
|
||||||
/>
|
/>
|
||||||
<div className="flex flex-col">
|
<div className="flex flex-col">
|
||||||
<Label className="text-sm font-semibold leading-none text-black">
|
<Skeleton as={Label} className="text-sm font-semibold leading-none text-black">
|
||||||
{t("requires_confirmation")}
|
{t("requires_confirmation")}
|
||||||
</Label>
|
</Skeleton>
|
||||||
<p className="-mt-2 text-sm leading-normal text-gray-600">
|
<Skeleton as="p" className="-mt-2 text-sm leading-normal text-gray-600">
|
||||||
{t("requires_confirmation_description")}
|
{t("requires_confirmation_description")}
|
||||||
</p>
|
</Skeleton>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
@@ -207,8 +212,12 @@ export const EventAdvancedTab = ({ eventType, team }: Pick<EventTypeSetupInfered
|
|||||||
disabled={seatsEnabled}
|
disabled={seatsEnabled}
|
||||||
/>
|
/>
|
||||||
<div className="flex flex-col">
|
<div className="flex flex-col">
|
||||||
<Label className="text-sm font-semibold leading-none text-black">{t("disable_guests")}</Label>
|
<Skeleton as={Label} className="text-sm font-semibold leading-none text-black">
|
||||||
<p className="-mt-2 text-sm leading-normal text-gray-600">{t("disable_guests_description")}</p>
|
{t("disable_guests")}
|
||||||
|
</Skeleton>
|
||||||
|
<Skeleton as="p" className="-mt-2 text-sm leading-normal text-gray-600">
|
||||||
|
{t("disable_guests_description")}
|
||||||
|
</Skeleton>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
@@ -228,8 +237,12 @@ export const EventAdvancedTab = ({ eventType, team }: Pick<EventTypeSetupInfered
|
|||||||
onCheckedChange={(e) => onChange(e)}
|
onCheckedChange={(e) => onChange(e)}
|
||||||
/>
|
/>
|
||||||
<div className="flex flex-col">
|
<div className="flex flex-col">
|
||||||
<Label className="text-sm font-semibold leading-none text-black">{t("disable_notes")}</Label>
|
<Skeleton as={Label} className="text-sm font-semibold leading-none text-black">
|
||||||
<p className="-mt-2 text-sm leading-normal text-gray-600">{t("disable_notes_description")}</p>
|
{t("disable_notes")}
|
||||||
|
</Skeleton>
|
||||||
|
<Skeleton as="p" className="-mt-2 text-sm leading-normal text-gray-600">
|
||||||
|
{t("disable_notes_description")}
|
||||||
|
</Skeleton>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
@@ -253,8 +266,12 @@ export const EventAdvancedTab = ({ eventType, team }: Pick<EventTypeSetupInfered
|
|||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
<div className="flex flex-col">
|
<div className="flex flex-col">
|
||||||
<Label className="text-sm font-semibold leading-none text-black">{t("private_link")}</Label>
|
<Skeleton as={Label} className="text-sm font-semibold leading-none text-black">
|
||||||
<p className="-mt-2 text-sm leading-normal text-gray-600">{t("private_link_description")}</p>
|
{t("private_link")}
|
||||||
|
</Skeleton>
|
||||||
|
<Skeleton as="p" className="-mt-2 text-sm leading-normal text-gray-600">
|
||||||
|
{t("private_link_description")}
|
||||||
|
</Skeleton>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -293,6 +310,59 @@ export const EventAdvancedTab = ({ eventType, team }: Pick<EventTypeSetupInfered
|
|||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
/>
|
/>
|
||||||
|
<hr />
|
||||||
|
<Controller
|
||||||
|
name="seatsPerTimeSlotEnabled"
|
||||||
|
control={formMethods.control}
|
||||||
|
defaultValue={!!eventType.seatsPerTimeSlot}
|
||||||
|
render={({ field: { value, onChange } }) => (
|
||||||
|
<div className="flex space-x-3">
|
||||||
|
<Switch
|
||||||
|
name="seatsPerTimeSlotEnabled"
|
||||||
|
checked={value}
|
||||||
|
onCheckedChange={(e) => {
|
||||||
|
setSeatsInputVisible(e);
|
||||||
|
// Enabling seats will disable guests and requiring confimation until fully supported
|
||||||
|
if (e) {
|
||||||
|
formMethods.setValue("disableGuests", true);
|
||||||
|
formMethods.setValue("requiresConfirmation", false);
|
||||||
|
formMethods.setValue("seatsPerTimeSlot", 2);
|
||||||
|
} else {
|
||||||
|
formMethods.setValue("seatsPerTimeSlot", null);
|
||||||
|
}
|
||||||
|
onChange(e);
|
||||||
|
}}
|
||||||
|
fitToHeight={true}
|
||||||
|
/>
|
||||||
|
<div className="flex flex-col">
|
||||||
|
<Label className="text-sm font-semibold leading-none text-black">{t("offer_seats")}</Label>
|
||||||
|
<p className="-mt-2 text-sm leading-normal text-gray-600">{t("offer_seats_description")}</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
{seatsInputVisible && (
|
||||||
|
<Controller
|
||||||
|
name="seatsPerTimeSlot"
|
||||||
|
control={formMethods.control}
|
||||||
|
defaultValue={eventType.seatsPerTimeSlot}
|
||||||
|
render={({ field: { value, onChange } }) => (
|
||||||
|
<div className="">
|
||||||
|
<TextField
|
||||||
|
required
|
||||||
|
name="seatsPerTimeSlot"
|
||||||
|
label={t("number_of_seats")}
|
||||||
|
type="number"
|
||||||
|
defaultValue={value || 2}
|
||||||
|
addOnSuffix={<>{t("seats")}</>}
|
||||||
|
onChange={(e) => {
|
||||||
|
onChange(Number(e.target.value));
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
{showEventNameTip && (
|
{showEventNameTip && (
|
||||||
<Dialog open={showEventNameTip} onOpenChange={setShowEventNameTip}>
|
<Dialog open={showEventNameTip} onOpenChange={setShowEventNameTip}>
|
||||||
<DialogContent
|
<DialogContent
|
||||||
|
|||||||
@@ -27,13 +27,13 @@ const AppCard = ({
|
|||||||
}) => {
|
}) => {
|
||||||
return (
|
return (
|
||||||
<div className="mb-4 rounded-md border border-gray-200 p-8">
|
<div className="mb-4 rounded-md border border-gray-200 p-8">
|
||||||
<div className="mb-6 flex w-full">
|
<div className="flex w-full">
|
||||||
<img src={logo} alt={name} className="mr-3 h-auto w-[42px] rounded-sm" />
|
<img src={logo} alt={name} className="mr-3 h-auto w-[42px] rounded-sm" />
|
||||||
<div className="flex flex-col">
|
<div className="flex flex-col">
|
||||||
<span className="font-semibold leading-none text-black">{name}</span>
|
<span className="font-semibold leading-none text-black">{name}</span>
|
||||||
<p className="pt-2 text-sm font-normal text-gray-600">{description}</p>
|
<p className="pt-2 text-sm font-normal text-gray-600">{description}</p>
|
||||||
</div>
|
</div>
|
||||||
<div className="ml-auto">
|
<div className="ml-auto flex items-center">
|
||||||
<Switch onCheckedChange={switchOnClick} checked={switchChecked} />
|
<Switch onCheckedChange={switchOnClick} checked={switchChecked} />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ import { useFormContext, Controller, useWatch } from "react-hook-form";
|
|||||||
import { classNames } from "@calcom/lib";
|
import { classNames } from "@calcom/lib";
|
||||||
import { useLocale } from "@calcom/lib/hooks/useLocale";
|
import { useLocale } from "@calcom/lib/hooks/useLocale";
|
||||||
import { PeriodType } from "@calcom/prisma/client";
|
import { PeriodType } from "@calcom/prisma/client";
|
||||||
import { Select, Switch, Label, Input } from "@calcom/ui/v2";
|
import { Select, Switch, Label, Input, MinutesField } from "@calcom/ui/v2";
|
||||||
import DateRangePicker from "@calcom/ui/v2/core/form/date-range-picker/DateRangePicker";
|
import DateRangePicker from "@calcom/ui/v2/core/form/date-range-picker/DateRangePicker";
|
||||||
|
|
||||||
export const EventLimitsTab = (props: Pick<EventTypeSetupInfered, "eventType">) => {
|
export const EventLimitsTab = (props: Pick<EventTypeSetupInfered, "eventType">) => {
|
||||||
@@ -113,35 +113,12 @@ export const EventLimitsTab = (props: Pick<EventTypeSetupInfered, "eventType">)
|
|||||||
</div>
|
</div>
|
||||||
<div className="flex flex-col space-y-4 pt-4 lg:flex-row lg:space-y-0 lg:space-x-4">
|
<div className="flex flex-col space-y-4 pt-4 lg:flex-row lg:space-y-0 lg:space-x-4">
|
||||||
<div className="w-full">
|
<div className="w-full">
|
||||||
<Label htmlFor="minimumBookingNotice">{t("minimum_booking_notice")} </Label>
|
<MinutesField
|
||||||
<Controller
|
required
|
||||||
name="minimumBookingNotice"
|
label={t("minimum_booking_notice")}
|
||||||
control={formMethods.control}
|
type="number"
|
||||||
defaultValue={eventType.minimumBookingNotice || 0}
|
placeholder="120"
|
||||||
render={({ field: { onChange, value } }) => {
|
{...formMethods.register("minimumBookingNotice", { valueAsNumber: true })}
|
||||||
const minimumBookingOptions = [
|
|
||||||
{
|
|
||||||
label: t("event_buffer_default"),
|
|
||||||
value: 0,
|
|
||||||
},
|
|
||||||
...[5, 10, 15, 20, 30, 45, 60, 90, 120].map((minutes) => ({
|
|
||||||
label: minutes + " " + t("minutes"),
|
|
||||||
value: minutes,
|
|
||||||
})),
|
|
||||||
];
|
|
||||||
return (
|
|
||||||
<Select
|
|
||||||
isSearchable={false}
|
|
||||||
onChange={(val) => {
|
|
||||||
if (val) onChange(val.value);
|
|
||||||
}}
|
|
||||||
defaultValue={
|
|
||||||
minimumBookingOptions.find((option) => option.value === value) || minimumBookingOptions[0]
|
|
||||||
}
|
|
||||||
options={minimumBookingOptions}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
}}
|
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div className="w-full">
|
<div className="w-full">
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ import { getEventLocationType, EventLocationType } from "@calcom/app-store/locat
|
|||||||
import { CAL_URL } from "@calcom/lib/constants";
|
import { CAL_URL } from "@calcom/lib/constants";
|
||||||
import { useLocale } from "@calcom/lib/hooks/useLocale";
|
import { useLocale } from "@calcom/lib/hooks/useLocale";
|
||||||
import { Icon } from "@calcom/ui/Icon";
|
import { Icon } from "@calcom/ui/Icon";
|
||||||
import { Select, Label, TextField, Button } from "@calcom/ui/v2";
|
import { Select, Label, TextField, Button, Skeleton } from "@calcom/ui/v2";
|
||||||
|
|
||||||
import { slugify } from "@lib/slugify";
|
import { slugify } from "@lib/slugify";
|
||||||
|
|
||||||
@@ -222,7 +222,9 @@ export const EventSetupTab = (
|
|||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
<div>
|
<div>
|
||||||
<Label>{t("location")}</Label>
|
<Skeleton as={Label} loadingClassName="w-16">
|
||||||
|
{t("location")}
|
||||||
|
</Skeleton>
|
||||||
<Controller
|
<Controller
|
||||||
name="locations"
|
name="locations"
|
||||||
control={formMethods.control}
|
control={formMethods.control}
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
|
import { TFunction } from "next-i18next";
|
||||||
import { useRouter } from "next/router";
|
import { useRouter } from "next/router";
|
||||||
import { EventTypeSetupInfered, FormValues } from "pages/v2/event-types/[type]";
|
import { EventTypeSetupInfered, FormValues } from "pages/v2/event-types/[type]";
|
||||||
import { useEffect, useMemo, useState } from "react";
|
import { useMemo, useState } from "react";
|
||||||
import { Loader } from "react-feather";
|
import { Loader } from "react-feather";
|
||||||
import { UseFormReturn } from "react-hook-form";
|
import { UseFormReturn } from "react-hook-form";
|
||||||
|
|
||||||
@@ -9,20 +10,18 @@ import { CAL_URL } from "@calcom/lib/constants";
|
|||||||
import { useLocale } from "@calcom/lib/hooks/useLocale";
|
import { useLocale } from "@calcom/lib/hooks/useLocale";
|
||||||
import { HttpError } from "@calcom/lib/http-error";
|
import { HttpError } from "@calcom/lib/http-error";
|
||||||
import { trpc, TRPCClientError } from "@calcom/trpc/react";
|
import { trpc, TRPCClientError } from "@calcom/trpc/react";
|
||||||
import ConfirmationDialogContent from "@calcom/ui/ConfirmationDialogContent";
|
|
||||||
import { Icon } from "@calcom/ui/Icon";
|
import { Icon } from "@calcom/ui/Icon";
|
||||||
import {
|
import {
|
||||||
Button,
|
Button,
|
||||||
ButtonGroup,
|
ButtonGroup,
|
||||||
Tooltip,
|
|
||||||
showToast,
|
|
||||||
VerticalTabItemProps,
|
|
||||||
VerticalTabs,
|
|
||||||
HorizontalTabs,
|
HorizontalTabs,
|
||||||
Switch,
|
|
||||||
Label,
|
Label,
|
||||||
HorizontalTabItemProps,
|
showToast,
|
||||||
|
Switch,
|
||||||
|
Tooltip,
|
||||||
|
VerticalTabs,
|
||||||
} from "@calcom/ui/v2";
|
} from "@calcom/ui/v2";
|
||||||
|
import ConfirmationDialogContent from "@calcom/ui/v2/core/ConfirmationDialogContent";
|
||||||
import { Dialog } from "@calcom/ui/v2/core/Dialog";
|
import { Dialog } from "@calcom/ui/v2/core/Dialog";
|
||||||
import Dropdown, {
|
import Dropdown, {
|
||||||
DropdownMenuContent,
|
DropdownMenuContent,
|
||||||
@@ -31,6 +30,7 @@ import Dropdown, {
|
|||||||
} from "@calcom/ui/v2/core/Dropdown";
|
} from "@calcom/ui/v2/core/Dropdown";
|
||||||
import Shell from "@calcom/ui/v2/core/Shell";
|
import Shell from "@calcom/ui/v2/core/Shell";
|
||||||
import VerticalDivider from "@calcom/ui/v2/core/VerticalDivider";
|
import VerticalDivider from "@calcom/ui/v2/core/VerticalDivider";
|
||||||
|
import { Skeleton } from "@calcom/ui/v2/core/skeleton";
|
||||||
|
|
||||||
import { ClientSuspense } from "@components/ClientSuspense";
|
import { ClientSuspense } from "@components/ClientSuspense";
|
||||||
import { EmbedButton, EmbedDialog } from "@components/Embed";
|
import { EmbedButton, EmbedDialog } from "@components/Embed";
|
||||||
@@ -46,6 +46,59 @@ type Props = {
|
|||||||
formMethods: UseFormReturn<FormValues>;
|
formMethods: UseFormReturn<FormValues>;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
function getNavigation(props: {
|
||||||
|
t: TFunction;
|
||||||
|
eventType: Props["eventType"];
|
||||||
|
enabledAppsNumber: number;
|
||||||
|
enabledWorkflowsNumber: number;
|
||||||
|
}) {
|
||||||
|
const { eventType, t, enabledAppsNumber, enabledWorkflowsNumber } = props;
|
||||||
|
return [
|
||||||
|
{
|
||||||
|
name: "event_setup_tab_title",
|
||||||
|
href: `/event-types/${eventType.id}?tabName=setup`,
|
||||||
|
icon: Icon.FiLink,
|
||||||
|
info: `${eventType.length} Mins`, // TODO: Get this from props
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "availability",
|
||||||
|
href: `/event-types/${eventType.id}?tabName=availability`,
|
||||||
|
icon: Icon.FiCalendar,
|
||||||
|
info: `Working Hours`, // TODO: Get this from props
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "event_limit_tab_title",
|
||||||
|
href: `/event-types/${eventType.id}?tabName=limits`,
|
||||||
|
icon: Icon.FiClock,
|
||||||
|
info: `event_limit_tab_description`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "event_advanced_tab_title",
|
||||||
|
href: `/event-types/${eventType.id}?tabName=advanced`,
|
||||||
|
icon: Icon.FiSliders,
|
||||||
|
info: `event_advanced_tab_description`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "recurring",
|
||||||
|
href: `/event-types/${eventType.id}?tabName=recurring`,
|
||||||
|
icon: Icon.FiRepeat,
|
||||||
|
info: `recurring_event_tab_description`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "apps",
|
||||||
|
href: `/event-types/${eventType.id}?tabName=apps`,
|
||||||
|
icon: Icon.FiGrid,
|
||||||
|
info: `${enabledAppsNumber} ${t("active")}`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "workflows",
|
||||||
|
href: `/event-types/${eventType.id}?tabName=workflows`,
|
||||||
|
icon: Icon.FiZap,
|
||||||
|
info: `${enabledWorkflowsNumber} ${t("active")}`,
|
||||||
|
},
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
function EventTypeSingleLayout({
|
function EventTypeSingleLayout({
|
||||||
children,
|
children,
|
||||||
eventType,
|
eventType,
|
||||||
@@ -57,8 +110,8 @@ function EventTypeSingleLayout({
|
|||||||
formMethods,
|
formMethods,
|
||||||
}: Props) {
|
}: Props) {
|
||||||
const utils = trpc.useContext();
|
const utils = trpc.useContext();
|
||||||
const router = useRouter();
|
|
||||||
const { t } = useLocale();
|
const { t } = useLocale();
|
||||||
|
const router = useRouter();
|
||||||
const [deleteDialogOpen, setDeleteDialogOpen] = useState(false);
|
const [deleteDialogOpen, setDeleteDialogOpen] = useState(false);
|
||||||
|
|
||||||
const hasPermsToDelete = currentUserMembership?.role !== "MEMBER" || !currentUserMembership;
|
const hasPermsToDelete = currentUserMembership?.role !== "MEMBER" || !currentUserMembership;
|
||||||
@@ -67,6 +120,7 @@ function EventTypeSingleLayout({
|
|||||||
onSuccess: async () => {
|
onSuccess: async () => {
|
||||||
await utils.invalidateQueries(["viewer.eventTypes"]);
|
await utils.invalidateQueries(["viewer.eventTypes"]);
|
||||||
showToast(t("event_type_deleted_successfully"), "success");
|
showToast(t("event_type_deleted_successfully"), "success");
|
||||||
|
await router.push("/event-types");
|
||||||
setDeleteDialogOpen(false);
|
setDeleteDialogOpen(false);
|
||||||
},
|
},
|
||||||
onError: (err) => {
|
onError: (err) => {
|
||||||
@@ -82,73 +136,17 @@ function EventTypeSingleLayout({
|
|||||||
|
|
||||||
// Define tab navigation here
|
// Define tab navigation here
|
||||||
const EventTypeTabs = useMemo(() => {
|
const EventTypeTabs = useMemo(() => {
|
||||||
const navigation: (VerticalTabItemProps & HorizontalTabItemProps)[] = [
|
const navigation = getNavigation({ t, eventType, enabledAppsNumber, enabledWorkflowsNumber });
|
||||||
{
|
|
||||||
name: "event_setup_tab_title",
|
|
||||||
tabName: "setup",
|
|
||||||
icon: Icon.FiLink,
|
|
||||||
info: `${eventType.length} Mins`, // TODO: Get this from props
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "availability",
|
|
||||||
tabName: "availability",
|
|
||||||
icon: Icon.FiCalendar,
|
|
||||||
info: `Working Hours`, // TODO: Get this from props
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "event_limit_tab_title",
|
|
||||||
tabName: "limits",
|
|
||||||
icon: Icon.FiClock,
|
|
||||||
info: `event_limit_tab_description`,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "event_advanced_tab_title",
|
|
||||||
tabName: "advanced",
|
|
||||||
icon: Icon.FiSliders,
|
|
||||||
info: `event_advanced_tab_description`,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "recurring",
|
|
||||||
tabName: "recurring",
|
|
||||||
icon: Icon.FiRepeat,
|
|
||||||
info: `recurring_event_tab_description`,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "apps",
|
|
||||||
tabName: "apps",
|
|
||||||
icon: Icon.FiGrid,
|
|
||||||
info: `${enabledAppsNumber} ${t("active")}`,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "workflows",
|
|
||||||
tabName: "workflows",
|
|
||||||
icon: Icon.FiZap,
|
|
||||||
info: `${enabledWorkflowsNumber} ${t("active")}`,
|
|
||||||
},
|
|
||||||
];
|
|
||||||
|
|
||||||
// If there is a team put this navigation item within the tabs
|
// If there is a team put this navigation item within the tabs
|
||||||
if (team)
|
if (team)
|
||||||
navigation.splice(2, 0, {
|
navigation.splice(2, 0, {
|
||||||
name: "scheduling_type",
|
name: "scheduling_type",
|
||||||
tabName: "team",
|
href: `/event-types/${eventType.id}?tabName=team`,
|
||||||
icon: Icon.FiUsers,
|
icon: Icon.FiUsers,
|
||||||
info: eventType.schedulingType === "COLLECTIVE" ? "collective" : "round_robin",
|
info: eventType.schedulingType === "COLLECTIVE" ? "collective" : "round_robin",
|
||||||
});
|
});
|
||||||
return navigation;
|
return navigation;
|
||||||
}, [eventType, enabledAppsNumber, team]);
|
}, [t, eventType, enabledAppsNumber, enabledWorkflowsNumber, team]);
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
// Default to the first in the list
|
|
||||||
if (!router.query.tabName) {
|
|
||||||
router.push({
|
|
||||||
query: {
|
|
||||||
...router.query,
|
|
||||||
tabName: EventTypeTabs[0].tabName,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}, [EventTypeTabs, router]);
|
|
||||||
|
|
||||||
const permalink = `${CAL_URL}/${team ? `team/${team.slug}` : eventType.users[0].username}/${
|
const permalink = `${CAL_URL}/${team ? `team/${team.slug}` : eventType.users[0].username}/${
|
||||||
eventType.slug
|
eventType.slug
|
||||||
@@ -159,15 +157,18 @@ function EventTypeSingleLayout({
|
|||||||
return (
|
return (
|
||||||
<Shell
|
<Shell
|
||||||
backPath="/event-types"
|
backPath="/event-types"
|
||||||
title={t("event_type_title", { eventTypeTitle: eventType.title })}
|
title={eventType.title + " | " + t("event_type")}
|
||||||
heading={eventType.title}
|
heading={eventType.title}
|
||||||
subtitle={eventType.description || ""}
|
subtitle={eventType.description || ""}
|
||||||
CTA={
|
CTA={
|
||||||
<div className="flex items-center justify-end">
|
<div className="flex items-center justify-end">
|
||||||
<div className="flex items-center rounded-md px-2 sm:hover:bg-gray-100">
|
<div className="flex items-center rounded-md px-2 sm:hover:bg-gray-100">
|
||||||
<Label htmlFor="hiddenSwitch" className="mt-2 hidden cursor-pointer self-center pr-2 sm:inline">
|
<Skeleton
|
||||||
|
as={Label}
|
||||||
|
htmlFor="hiddenSwitch"
|
||||||
|
className="mt-2 hidden cursor-pointer self-center pr-2 sm:inline">
|
||||||
{t("hide_from_profile")}
|
{t("hide_from_profile")}
|
||||||
</Label>
|
</Skeleton>
|
||||||
<Switch
|
<Switch
|
||||||
id="hiddenSwitch"
|
id="hiddenSwitch"
|
||||||
defaultChecked={formMethods.getValues("hidden")}
|
defaultChecked={formMethods.getValues("hidden")}
|
||||||
@@ -208,6 +209,7 @@ function EventTypeSingleLayout({
|
|||||||
StartIcon={Icon.FiCode}
|
StartIcon={Icon.FiCode}
|
||||||
color="secondary"
|
color="secondary"
|
||||||
size="icon"
|
size="icon"
|
||||||
|
tooltip={t("embed")}
|
||||||
/>
|
/>
|
||||||
<Button
|
<Button
|
||||||
color="secondary"
|
color="secondary"
|
||||||
@@ -265,10 +267,15 @@ function EventTypeSingleLayout({
|
|||||||
<ClientSuspense fallback={<Loader />}>
|
<ClientSuspense fallback={<Loader />}>
|
||||||
<div className="-mt-2 flex flex-col xl:flex-row xl:space-x-8">
|
<div className="-mt-2 flex flex-col xl:flex-row xl:space-x-8">
|
||||||
<div className="hidden xl:block">
|
<div className="hidden xl:block">
|
||||||
<VerticalTabs className="primary-navigation" tabs={EventTypeTabs} sticky />
|
<VerticalTabs
|
||||||
|
className="primary-navigation"
|
||||||
|
tabs={EventTypeTabs}
|
||||||
|
sticky
|
||||||
|
linkProps={{ shallow: true }}
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div className="p-2 md:mx-0 md:p-0 xl:hidden">
|
<div className="p-2 md:mx-0 md:p-0 xl:hidden">
|
||||||
<HorizontalTabs tabNameKey="tabName" tabs={EventTypeTabs} />
|
<HorizontalTabs tabs={EventTypeTabs} linkProps={{ shallow: true }} />
|
||||||
</div>
|
</div>
|
||||||
<div className="w-full ltr:mr-2 rtl:ml-2">
|
<div className="w-full ltr:mr-2 rtl:ml-2">
|
||||||
<div
|
<div
|
||||||
@@ -292,7 +299,7 @@ function EventTypeSingleLayout({
|
|||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
deleteMutation.mutate({ id: eventType.id });
|
deleteMutation.mutate({ id: eventType.id });
|
||||||
}}>
|
}}>
|
||||||
{t("delete_event_type_description") as string}
|
{t("delete_event_type_description")}
|
||||||
</ConfirmationDialogContent>
|
</ConfirmationDialogContent>
|
||||||
</Dialog>
|
</Dialog>
|
||||||
<EmbedDialog />
|
<EmbedDialog />
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ function SkeletonLoader() {
|
|||||||
<SkeletonContainer>
|
<SkeletonContainer>
|
||||||
<div className="mb-4 flex items-center">
|
<div className="mb-4 flex items-center">
|
||||||
<SkeletonAvatar className="h-8 w-8" />
|
<SkeletonAvatar className="h-8 w-8" />
|
||||||
<div className="space-y-1">
|
<div className="flex flex-col space-y-1">
|
||||||
<SkeletonText className="h-4 w-16" />
|
<SkeletonText className="h-4 w-16" />
|
||||||
<SkeletonText className="h-4 w-24" />
|
<SkeletonText className="h-4 w-24" />
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { useMutation } from "react-query";
|
import { useMutation } from "@tanstack/react-query";
|
||||||
|
|
||||||
import { useLocale } from "@calcom/lib/hooks/useLocale";
|
import { useLocale } from "@calcom/lib/hooks/useLocale";
|
||||||
import { trpc } from "@calcom/trpc/react";
|
import { trpc } from "@calcom/trpc/react";
|
||||||
@@ -12,6 +12,7 @@ export function CalendarSwitch(props: {
|
|||||||
externalId: string;
|
externalId: string;
|
||||||
title: string;
|
title: string;
|
||||||
defaultSelected: boolean;
|
defaultSelected: boolean;
|
||||||
|
isSelected: boolean;
|
||||||
}) {
|
}) {
|
||||||
const { t } = useLocale();
|
const { t } = useLocale();
|
||||||
|
|
||||||
@@ -69,7 +70,7 @@ export function CalendarSwitch(props: {
|
|||||||
key={props.externalId}
|
key={props.externalId}
|
||||||
name="enabled"
|
name="enabled"
|
||||||
label={props.title}
|
label={props.title}
|
||||||
defaultChecked={props.defaultSelected}
|
defaultChecked={props.isSelected}
|
||||||
onCheckedChange={(isOn: boolean) => {
|
onCheckedChange={(isOn: boolean) => {
|
||||||
mutation.mutate({ isOn });
|
mutation.mutate({ isOn });
|
||||||
}}
|
}}
|
||||||
|
|||||||
@@ -1,16 +1,14 @@
|
|||||||
import { ReactNode } from "react";
|
|
||||||
import {
|
import {
|
||||||
QueryObserverIdleResult,
|
|
||||||
QueryObserverLoadingErrorResult,
|
QueryObserverLoadingErrorResult,
|
||||||
QueryObserverLoadingResult,
|
QueryObserverLoadingResult,
|
||||||
QueryObserverRefetchErrorResult,
|
QueryObserverRefetchErrorResult,
|
||||||
QueryObserverSuccessResult,
|
QueryObserverSuccessResult,
|
||||||
UseQueryResult,
|
UseQueryResult,
|
||||||
} from "react-query";
|
} from "@tanstack/react-query";
|
||||||
|
import { ReactNode } from "react";
|
||||||
|
|
||||||
import { useLocale } from "@calcom/lib/hooks/useLocale";
|
import { useLocale } from "@calcom/lib/hooks/useLocale";
|
||||||
import type { TRPCClientErrorLike } from "@calcom/trpc/client";
|
import type { TRPCClientErrorLike } from "@calcom/trpc/client";
|
||||||
import type { UseTRPCQueryOptions } from "@calcom/trpc/react";
|
|
||||||
import { trpc } from "@calcom/trpc/react";
|
import { trpc } from "@calcom/trpc/react";
|
||||||
import type {
|
import type {
|
||||||
inferHandlerInput,
|
inferHandlerInput,
|
||||||
@@ -22,6 +20,8 @@ import type { AppRouter } from "@calcom/trpc/server/routers/_app";
|
|||||||
import { Alert } from "@calcom/ui/Alert";
|
import { Alert } from "@calcom/ui/Alert";
|
||||||
import Loader from "@calcom/ui/Loader";
|
import Loader from "@calcom/ui/Loader";
|
||||||
|
|
||||||
|
import type { UseTRPCQueryOptions } from "@trpc/react/shared";
|
||||||
|
|
||||||
type ErrorLike = {
|
type ErrorLike = {
|
||||||
message: string;
|
message: string;
|
||||||
};
|
};
|
||||||
@@ -34,7 +34,6 @@ interface QueryCellOptionsBase<TData, TError extends ErrorLike> {
|
|||||||
query: QueryObserverLoadingErrorResult<TData, TError> | QueryObserverRefetchErrorResult<TData, TError>
|
query: QueryObserverLoadingErrorResult<TData, TError> | QueryObserverRefetchErrorResult<TData, TError>
|
||||||
) => JSXElementOrNull;
|
) => JSXElementOrNull;
|
||||||
loading?: (query: QueryObserverLoadingResult<TData, TError> | null) => JSXElementOrNull;
|
loading?: (query: QueryObserverLoadingResult<TData, TError> | null) => JSXElementOrNull;
|
||||||
idle?: (query: QueryObserverIdleResult<TData, TError>) => JSXElementOrNull;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
interface QueryCellOptionsNoEmpty<TData, TError extends ErrorLike>
|
interface QueryCellOptionsNoEmpty<TData, TError extends ErrorLike>
|
||||||
@@ -84,14 +83,11 @@ export function QueryCell<TData, TError extends ErrorLike>(
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (query.status === "idle") {
|
|
||||||
return opts.idle?.(query) ?? StatusLoader;
|
|
||||||
}
|
|
||||||
// impossible state
|
// impossible state
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
type inferProcedures<TObj extends ProcedureRecord<any, any, any, any, any, any>> = {
|
type inferProcedures<TObj extends ProcedureRecord> = {
|
||||||
[TPath in keyof TObj]: {
|
[TPath in keyof TObj]: {
|
||||||
input: inferProcedureInput<TObj[TPath]>;
|
input: inferProcedureInput<TObj[TPath]>;
|
||||||
output: inferProcedureOutput<TObj[TPath]>;
|
output: inferProcedureOutput<TObj[TPath]>;
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ import { ComponentProps, ReactNode } from "react";
|
|||||||
|
|
||||||
import DynamicHelpscoutProvider from "@calcom/features/ee/support/lib/helpscout/providerDynamic";
|
import DynamicHelpscoutProvider from "@calcom/features/ee/support/lib/helpscout/providerDynamic";
|
||||||
import DynamicIntercomProvider from "@calcom/features/ee/support/lib/intercom/providerDynamic";
|
import DynamicIntercomProvider from "@calcom/features/ee/support/lib/intercom/providerDynamic";
|
||||||
import { trpc } from "@calcom/trpc/react";
|
import { trpc, proxy } from "@calcom/trpc/react";
|
||||||
import { MetaProvider } from "@calcom/ui/v2/core/Meta";
|
import { MetaProvider } from "@calcom/ui/v2/core/Meta";
|
||||||
|
|
||||||
import usePublicPage from "@lib/hooks/usePublicPage";
|
import usePublicPage from "@lib/hooks/usePublicPage";
|
||||||
@@ -38,7 +38,8 @@ const CustomI18nextProvider = (props: AppPropsWithChildren) => {
|
|||||||
* i18n should never be clubbed with other queries, so that it's caching can be managed independently.
|
* i18n should never be clubbed with other queries, so that it's caching can be managed independently.
|
||||||
* We intend to not cache i18n query
|
* We intend to not cache i18n query
|
||||||
**/
|
**/
|
||||||
const { i18n, locale } = trpc.useQuery(["viewer.public.i18n"], { context: { skipBatch: true } }).data ?? {
|
const { i18n, locale } = trpc.useQuery(["viewer.public.i18n"], { trpc: { context: { skipBatch: true } } })
|
||||||
|
.data ?? {
|
||||||
locale: "en",
|
locale: "en",
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -54,7 +55,7 @@ const CustomI18nextProvider = (props: AppPropsWithChildren) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const AppProviders = (props: AppPropsWithChildren) => {
|
const AppProviders = (props: AppPropsWithChildren) => {
|
||||||
const session = trpc.useQuery(["viewer.public.session"]).data;
|
const session = proxy.public.session.useQuery().data;
|
||||||
// No need to have intercom on public pages - Good for Page Performance
|
// No need to have intercom on public pages - Good for Page Performance
|
||||||
const isPublicPage = usePublicPage();
|
const isPublicPage = usePublicPage();
|
||||||
const isThemeSupported =
|
const isThemeSupported =
|
||||||
|
|||||||
@@ -1,6 +1,10 @@
|
|||||||
// handles logic related to user clock display using 24h display / timeZone options.
|
// handles logic related to user clock display using 24h display / timeZone options.
|
||||||
import dayjs from "@calcom/dayjs";
|
import dayjs from "@calcom/dayjs";
|
||||||
import { isBrowserLocale24h } from "@calcom/lib/timeFormat";
|
import {
|
||||||
|
getIs24hClockFromLocalStorage,
|
||||||
|
isBrowserLocale24h,
|
||||||
|
setIs24hClockInLocalStorage,
|
||||||
|
} from "@calcom/lib/timeFormat";
|
||||||
import { localStorage } from "@calcom/lib/webstorage";
|
import { localStorage } from "@calcom/lib/webstorage";
|
||||||
|
|
||||||
interface TimeOptions {
|
interface TimeOptions {
|
||||||
@@ -20,8 +24,8 @@ const initClock = () => {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// This only sets browser locale if there's no preference on localStorage.
|
// This only sets browser locale if there's no preference on localStorage.
|
||||||
if (!localStorage.getItem("timeOption.is24hClock")) set24hClock(isBrowserLocale24h());
|
if (getIs24hClockFromLocalStorage() === null) set24hClock(isBrowserLocale24h());
|
||||||
timeOptions.is24hClock = localStorage.getItem("timeOption.is24hClock") === "true";
|
timeOptions.is24hClock = !!getIs24hClockFromLocalStorage();
|
||||||
timeOptions.inviteeTimeZone = localStorage.getItem("timeOption.preferredTimeZone") || dayjs.tz.guess();
|
timeOptions.inviteeTimeZone = localStorage.getItem("timeOption.preferredTimeZone") || dayjs.tz.guess();
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -32,7 +36,7 @@ const is24h = (is24hClock?: boolean) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const set24hClock = (is24hClock: boolean) => {
|
const set24hClock = (is24hClock: boolean) => {
|
||||||
localStorage.setItem("timeOption.is24hClock", is24hClock.toString());
|
setIs24hClockInLocalStorage(is24hClock);
|
||||||
timeOptions.is24hClock = is24hClock;
|
timeOptions.is24hClock = is24hClock;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -9,10 +9,10 @@ export const WEBHOOK_TRIGGER_EVENTS_GROUPED_BY_APP = {
|
|||||||
WebhookTriggerEvents.BOOKING_RESCHEDULED,
|
WebhookTriggerEvents.BOOKING_RESCHEDULED,
|
||||||
WebhookTriggerEvents.MEETING_ENDED,
|
WebhookTriggerEvents.MEETING_ENDED,
|
||||||
] as const,
|
] as const,
|
||||||
routing_forms: [WebhookTriggerEvents.FORM_SUBMITTED] as ["FORM_SUBMITTED"],
|
"routing-forms": [WebhookTriggerEvents.FORM_SUBMITTED] as ["FORM_SUBMITTED"],
|
||||||
};
|
};
|
||||||
|
|
||||||
export const WEBHOOK_TRIGGER_EVENTS = [
|
export const WEBHOOK_TRIGGER_EVENTS = [
|
||||||
...WEBHOOK_TRIGGER_EVENTS_GROUPED_BY_APP.core,
|
...WEBHOOK_TRIGGER_EVENTS_GROUPED_BY_APP.core,
|
||||||
...WEBHOOK_TRIGGER_EVENTS_GROUPED_BY_APP.routing_forms,
|
...WEBHOOK_TRIGGER_EVENTS_GROUPED_BY_APP["routing-forms"],
|
||||||
] as const;
|
] as const;
|
||||||
+12
-1
@@ -7,6 +7,7 @@ import { extendEventData, nextCollectBasicSettings } from "@calcom/lib/telemetry
|
|||||||
|
|
||||||
const V2_WHITELIST = [
|
const V2_WHITELIST = [
|
||||||
"/settings/admin",
|
"/settings/admin",
|
||||||
|
"/settings/billing",
|
||||||
"/settings/developer/webhooks",
|
"/settings/developer/webhooks",
|
||||||
"/settings/developer/api-keys",
|
"/settings/developer/api-keys",
|
||||||
"/settings/my-account",
|
"/settings/my-account",
|
||||||
@@ -17,13 +18,15 @@ const V2_WHITELIST = [
|
|||||||
"/event-types",
|
"/event-types",
|
||||||
"/workflows",
|
"/workflows",
|
||||||
"/apps",
|
"/apps",
|
||||||
|
"/teams",
|
||||||
"/success",
|
"/success",
|
||||||
"/auth/login",
|
"/auth/login",
|
||||||
];
|
];
|
||||||
|
|
||||||
// For pages
|
// For pages
|
||||||
// - which has V1 versions being modified as V2
|
// - which has V1 versions being modified as V2
|
||||||
const V2_BLACKLIST = ["/apps/routing_forms/"];
|
// - Add routing_forms to keep old links working
|
||||||
|
const V2_BLACKLIST = ["/apps/routing_forms/", "/apps/routing-forms/", "/apps/typeform/"];
|
||||||
|
|
||||||
const middleware: NextMiddleware = async (req) => {
|
const middleware: NextMiddleware = async (req) => {
|
||||||
const url = req.nextUrl;
|
const url = req.nextUrl;
|
||||||
@@ -42,6 +45,13 @@ const middleware: NextMiddleware = async (req) => {
|
|||||||
return NextResponse.redirect(req.nextUrl);
|
return NextResponse.redirect(req.nextUrl);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Don't 404 old routing_forms links
|
||||||
|
if (url.pathname.startsWith("/apps/routing_forms")) {
|
||||||
|
url.pathname = url.pathname.replace("/apps/routing_forms", "/apps/routing-forms");
|
||||||
|
return NextResponse.rewrite(url);
|
||||||
|
}
|
||||||
|
|
||||||
/** Display available V2 pages */
|
/** Display available V2 pages */
|
||||||
if (
|
if (
|
||||||
!V2_BLACKLIST.some((p) => url.pathname.startsWith(p)) &&
|
!V2_BLACKLIST.some((p) => url.pathname.startsWith(p)) &&
|
||||||
@@ -51,6 +61,7 @@ const middleware: NextMiddleware = async (req) => {
|
|||||||
url.pathname = `/v2${url.pathname}`;
|
url.pathname = `/v2${url.pathname}`;
|
||||||
return NextResponse.rewrite(url);
|
return NextResponse.rewrite(url);
|
||||||
}
|
}
|
||||||
|
|
||||||
return NextResponse.next();
|
return NextResponse.next();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -135,11 +135,11 @@ const nextConfig = {
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
source: "/forms/:formId",
|
source: "/forms/:formId",
|
||||||
destination: "/apps/routing_forms/routing-link/:formId",
|
destination: "/apps/routing-forms/routing-link/:formId",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
source: "/router",
|
source: "/router",
|
||||||
destination: "/apps/routing_forms/router",
|
destination: "/apps/routing-forms/router",
|
||||||
},
|
},
|
||||||
/* TODO: have these files being served from another deployment or CDN {
|
/* TODO: have these files being served from another deployment or CDN {
|
||||||
source: "/embed/embed.js",
|
source: "/embed/embed.js",
|
||||||
@@ -159,6 +159,11 @@ const nextConfig = {
|
|||||||
destination: "/settings/my-account/profile",
|
destination: "/settings/my-account/profile",
|
||||||
permanent: true,
|
permanent: true,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
source: "/settings/teams",
|
||||||
|
destination: "/teams",
|
||||||
|
permanent: true,
|
||||||
|
},
|
||||||
/* V2 testers get redirected to the new settings */
|
/* V2 testers get redirected to the new settings */
|
||||||
{
|
{
|
||||||
source: "/settings/profile",
|
source: "/settings/profile",
|
||||||
|
|||||||
+12
-11
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@calcom/web",
|
"name": "@calcom/web",
|
||||||
"version": "2.0.0",
|
"version": "2.0.4",
|
||||||
"private": true,
|
"private": true,
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"analyze": "ANALYZE=true next build",
|
"analyze": "ANALYZE=true next build",
|
||||||
@@ -45,18 +45,20 @@
|
|||||||
"@hookform/resolvers": "^2.9.7",
|
"@hookform/resolvers": "^2.9.7",
|
||||||
"@next-auth/prisma-adapter": "^1.0.4",
|
"@next-auth/prisma-adapter": "^1.0.4",
|
||||||
"@next/bundle-analyzer": "12.1.6",
|
"@next/bundle-analyzer": "12.1.6",
|
||||||
"@radix-ui/react-avatar": "^0.1.4",
|
"@radix-ui/react-avatar": "^1.0.0",
|
||||||
"@radix-ui/react-collapsible": "^0.1.0",
|
"@radix-ui/react-collapsible": "^1.0.0",
|
||||||
"@radix-ui/react-dialog": "^0.1.0",
|
"@radix-ui/react-dialog": "^1.0.0",
|
||||||
"@radix-ui/react-dropdown-menu": "^0.1.1",
|
"@radix-ui/react-dropdown-menu": "^1.0.0",
|
||||||
"@radix-ui/react-id": "^0.1.0",
|
"@radix-ui/react-id": "^1.0.0",
|
||||||
"@radix-ui/react-radio-group": "^0.1.1",
|
"@radix-ui/react-popover": "^1.0.0",
|
||||||
"@radix-ui/react-slider": "^0.1.1",
|
"@radix-ui/react-radio-group": "^1.0.0",
|
||||||
"@radix-ui/react-switch": "^0.1.1",
|
"@radix-ui/react-slider": "^1.0.0",
|
||||||
"@radix-ui/react-toggle-group": "^0.1.5",
|
"@radix-ui/react-switch": "^1.0.0",
|
||||||
|
"@radix-ui/react-toggle-group": "^1.0.0",
|
||||||
"@radix-ui/react-tooltip": "^1.0.0",
|
"@radix-ui/react-tooltip": "^1.0.0",
|
||||||
"@stripe/react-stripe-js": "^1.10.0",
|
"@stripe/react-stripe-js": "^1.10.0",
|
||||||
"@stripe/stripe-js": "^1.35.0",
|
"@stripe/stripe-js": "^1.35.0",
|
||||||
|
"@tanstack/react-query": "^4.3.9",
|
||||||
"@vercel/edge-functions-ui": "^0.2.1",
|
"@vercel/edge-functions-ui": "^0.2.1",
|
||||||
"@wojtekmaj/react-daterange-picker": "^3.3.1",
|
"@wojtekmaj/react-daterange-picker": "^3.3.1",
|
||||||
"accept-language-parser": "^1.5.0",
|
"accept-language-parser": "^1.5.0",
|
||||||
@@ -105,7 +107,6 @@
|
|||||||
"react-live-chat-loader": "^2.7.3",
|
"react-live-chat-loader": "^2.7.3",
|
||||||
"react-multi-email": "^0.5.3",
|
"react-multi-email": "^0.5.3",
|
||||||
"react-phone-number-input": "^3.2.7",
|
"react-phone-number-input": "^3.2.7",
|
||||||
"react-query": "^3.39.2",
|
|
||||||
"react-select": "^5.4.0",
|
"react-select": "^5.4.0",
|
||||||
"react-timezone-select": "^1.3.2",
|
"react-timezone-select": "^1.3.2",
|
||||||
"react-use-intercom": "1.5.1",
|
"react-use-intercom": "1.5.1",
|
||||||
|
|||||||
+8
-10
@@ -73,7 +73,7 @@ export default function Custom404() {
|
|||||||
<ul role="list" className="mt-4">
|
<ul role="list" className="mt-4">
|
||||||
<li className="border-2 border-green-500 px-4 py-2">
|
<li className="border-2 border-green-500 px-4 py-2">
|
||||||
<a
|
<a
|
||||||
href={`${WEBSITE_URL}/pricing?infra`}
|
href="https://console.cal.com"
|
||||||
className="relative flex items-start space-x-4 py-6 rtl:space-x-reverse">
|
className="relative flex items-start space-x-4 py-6 rtl:space-x-reverse">
|
||||||
<div className="flex-shrink-0">
|
<div className="flex-shrink-0">
|
||||||
<span className="flex h-12 w-12 items-center justify-center rounded-lg bg-green-50">
|
<span className="flex h-12 w-12 items-center justify-center rounded-lg bg-green-50">
|
||||||
@@ -190,12 +190,10 @@ export default function Custom404() {
|
|||||||
{t("check_spelling_mistakes_or_go_back")}
|
{t("check_spelling_mistakes_or_go_back")}
|
||||||
</span>
|
</span>
|
||||||
) : isCalcom ? (
|
) : isCalcom ? (
|
||||||
<Link href={url}>
|
<a target="_blank" href={url} className="mt-2 inline-block text-lg" rel="noreferrer">
|
||||||
<a className="mt-2 inline-block text-lg">
|
|
||||||
{t("the_username")} <strong className="text-blue-500">cal.com{username}</strong>{" "}
|
{t("the_username")} <strong className="text-blue-500">cal.com{username}</strong>{" "}
|
||||||
{t("is_still_available")} <span className="text-blue-500">{t("register_now")}</span>.
|
{t("is_still_available")} <span className="text-blue-500">{t("register_now")}</span>.
|
||||||
</a>
|
</a>
|
||||||
</Link>
|
|
||||||
) : (
|
) : (
|
||||||
<span className="mt-2 inline-block text-lg">
|
<span className="mt-2 inline-block text-lg">
|
||||||
{t("the_username")}{" "}
|
{t("the_username")}{" "}
|
||||||
@@ -211,8 +209,11 @@ export default function Custom404() {
|
|||||||
{!isSubpage && isCalcom && (
|
{!isSubpage && isCalcom && (
|
||||||
<ul role="list" className="mt-4">
|
<ul role="list" className="mt-4">
|
||||||
<li className="border-2 border-green-500 px-4 py-2">
|
<li className="border-2 border-green-500 px-4 py-2">
|
||||||
<Link href={url}>
|
<a
|
||||||
<a className="relative flex items-start space-x-4 py-6 rtl:space-x-reverse">
|
href={url}
|
||||||
|
target="_blank"
|
||||||
|
className="relative flex items-start space-x-4 py-6 rtl:space-x-reverse"
|
||||||
|
rel="noreferrer">
|
||||||
<div className="flex-shrink-0">
|
<div className="flex-shrink-0">
|
||||||
<span className="flex h-12 w-12 items-center justify-center rounded-lg bg-green-50">
|
<span className="flex h-12 w-12 items-center justify-center rounded-lg bg-green-50">
|
||||||
<Icon.FiCheck className="h-6 w-6 text-green-500" aria-hidden="true" />
|
<Icon.FiCheck className="h-6 w-6 text-green-500" aria-hidden="true" />
|
||||||
@@ -227,15 +228,12 @@ export default function Custom404() {
|
|||||||
</span>
|
</span>
|
||||||
</span>
|
</span>
|
||||||
</h3>
|
</h3>
|
||||||
<p className="text-base text-gray-500">
|
<p className="text-base text-gray-500">{t("claim_username_and_schedule_events")}</p>
|
||||||
{t("claim_username_and_schedule_events")}
|
|
||||||
</p>
|
|
||||||
</div>
|
</div>
|
||||||
<div className="flex-shrink-0 self-center">
|
<div className="flex-shrink-0 self-center">
|
||||||
<Icon.FiChevronRight className="h-5 w-5 text-gray-400" aria-hidden="true" />
|
<Icon.FiChevronRight className="h-5 w-5 text-gray-400" aria-hidden="true" />
|
||||||
</div>
|
</div>
|
||||||
</a>
|
</a>
|
||||||
</Link>
|
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
)}
|
)}
|
||||||
|
|||||||
@@ -115,7 +115,7 @@ const providers: Provider[] = [
|
|||||||
};
|
};
|
||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
// ImpersonationProvider,
|
ImpersonationProvider,
|
||||||
];
|
];
|
||||||
|
|
||||||
if (IS_GOOGLE_LOGIN_ENABLED) {
|
if (IS_GOOGLE_LOGIN_ENABLED) {
|
||||||
|
|||||||
@@ -76,7 +76,7 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse)
|
|||||||
});
|
});
|
||||||
|
|
||||||
// get user's credentials + their connected integrations
|
// get user's credentials + their connected integrations
|
||||||
const calendarCredentials = getCalendarCredentials(user.credentials, user.id);
|
const calendarCredentials = getCalendarCredentials(user.credentials);
|
||||||
// get all the connected integrations' calendars (from third party)
|
// get all the connected integrations' calendars (from third party)
|
||||||
const connectedCalendars = await getConnectedCalendars(calendarCredentials, user.selectedCalendars);
|
const connectedCalendars = await getConnectedCalendars(calendarCredentials, user.selectedCalendars);
|
||||||
const calendars = connectedCalendars.flatMap((c) => c.calendars).filter(notEmpty);
|
const calendars = connectedCalendars.flatMap((c) => c.calendars).filter(notEmpty);
|
||||||
|
|||||||
@@ -327,6 +327,7 @@ async function handler(req: NextApiRequest) {
|
|||||||
|
|
||||||
if (!users) throw new HttpError({ statusCode: 404, message: "eventTypeUser.notFound" });
|
if (!users) throw new HttpError({ statusCode: 404, message: "eventTypeUser.notFound" });
|
||||||
|
|
||||||
|
if (!eventType.seatsPerTimeSlot) {
|
||||||
const availableUsers = await ensureAvailableUsers(
|
const availableUsers = await ensureAvailableUsers(
|
||||||
{
|
{
|
||||||
...eventType,
|
...eventType,
|
||||||
@@ -338,6 +339,7 @@ async function handler(req: NextApiRequest) {
|
|||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// Add an if conditional if there are no seats on the event type
|
||||||
// Assign to only one user when ROUND_ROBIN
|
// Assign to only one user when ROUND_ROBIN
|
||||||
if (eventType.schedulingType === SchedulingType.ROUND_ROBIN) {
|
if (eventType.schedulingType === SchedulingType.ROUND_ROBIN) {
|
||||||
users = [await getLuckyUser("MAXIMIZE_AVAILABILITY", { availableUsers, eventTypeId: eventType.id })];
|
users = [await getLuckyUser("MAXIMIZE_AVAILABILITY", { availableUsers, eventTypeId: eventType.id })];
|
||||||
@@ -348,6 +350,7 @@ async function handler(req: NextApiRequest) {
|
|||||||
}
|
}
|
||||||
users = availableUsers;
|
users = availableUsers;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
console.log("available users", users);
|
console.log("available users", users);
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import { GetServerSidePropsContext } from "next";
|
import { GetServerSidePropsContext } from "next";
|
||||||
import { useRouter } from "next/router";
|
import { useRouter } from "next/router";
|
||||||
|
|
||||||
import RoutingFormsRoutingConfig from "@calcom/app-store/ee/routing_forms/pages/app-routing.config";
|
import RoutingFormsRoutingConfig from "@calcom/app-store/ee/routing-forms/pages/app-routing.config";
|
||||||
import TypeformRoutingConfig from "@calcom/app-store/typeform/pages/app-routing.config";
|
import TypeformRoutingConfig from "@calcom/app-store/typeform/pages/app-routing.config";
|
||||||
import prisma from "@calcom/prisma";
|
import prisma from "@calcom/prisma";
|
||||||
import { AppGetServerSideProps } from "@calcom/types/AppGetServerSideProps";
|
import { AppGetServerSideProps } from "@calcom/types/AppGetServerSideProps";
|
||||||
@@ -28,7 +28,7 @@ type NotFound = {
|
|||||||
|
|
||||||
// TODO: It is a candidate for apps.*.generated.*
|
// TODO: It is a candidate for apps.*.generated.*
|
||||||
const AppsRouting = {
|
const AppsRouting = {
|
||||||
routing_forms: RoutingFormsRoutingConfig,
|
"routing-forms": RoutingFormsRoutingConfig,
|
||||||
typeform: TypeformRoutingConfig,
|
typeform: TypeformRoutingConfig,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -1,17 +1,16 @@
|
|||||||
import { GetServerSidePropsContext } from "next";
|
import { GetServerSidePropsContext } from "next";
|
||||||
import { signOut, useSession } from "next-auth/react";
|
import { signOut, useSession } from "next-auth/react";
|
||||||
import Link from "next/link";
|
|
||||||
import { useRouter } from "next/router";
|
import { useRouter } from "next/router";
|
||||||
import { useEffect } from "react";
|
import { useEffect } from "react";
|
||||||
|
|
||||||
import { WEBSITE_URL } from "@calcom/lib/constants";
|
import { WEBSITE_URL } from "@calcom/lib/constants";
|
||||||
import { useLocale } from "@calcom/lib/hooks/useLocale";
|
import { useLocale } from "@calcom/lib/hooks/useLocale";
|
||||||
import Button from "@calcom/ui/Button";
|
|
||||||
import { Icon } from "@calcom/ui/Icon";
|
import { Icon } from "@calcom/ui/Icon";
|
||||||
|
import Button from "@calcom/ui/v2/core/Button";
|
||||||
|
|
||||||
import { inferSSRProps } from "@lib/types/inferSSRProps";
|
import { inferSSRProps } from "@lib/types/inferSSRProps";
|
||||||
|
|
||||||
import AuthContainer from "@components/ui/AuthContainer";
|
import AuthContainer from "@components/v2/ui/AuthContainer";
|
||||||
|
|
||||||
import { ssrInit } from "@server/lib/ssr";
|
import { ssrInit } from "@server/lib/ssr";
|
||||||
|
|
||||||
@@ -30,7 +29,7 @@ export default function Logout(props: Props) {
|
|||||||
const { t } = useLocale();
|
const { t } = useLocale();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<AuthContainer title={t("logged_out")} description={t("youve_been_logged_out")}>
|
<AuthContainer title={t("logged_out")} description={t("youve_been_logged_out")} showLogo>
|
||||||
<div className="mb-4">
|
<div className="mb-4">
|
||||||
<div className="mx-auto flex h-12 w-12 items-center justify-center rounded-full bg-green-100">
|
<div className="mx-auto flex h-12 w-12 items-center justify-center rounded-full bg-green-100">
|
||||||
<Icon.FiCheck className="h-6 w-6 text-green-600" />
|
<Icon.FiCheck className="h-6 w-6 text-green-600" />
|
||||||
@@ -44,9 +43,9 @@ export default function Logout(props: Props) {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<Link href="/auth/login" passHref>
|
<Button href="/auth/login" passHref className="flex w-full justify-center">
|
||||||
<Button className="flex w-full justify-center"> {t("go_back_login")}</Button>
|
{t("go_back_login")}
|
||||||
</Link>
|
</Button>
|
||||||
</AuthContainer>
|
</AuthContainer>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
import { CheckIcon } from "@heroicons/react/solid";
|
import { CheckIcon } from "@heroicons/react/solid";
|
||||||
import { zodResolver } from "@hookform/resolvers/zod";
|
import { zodResolver } from "@hookform/resolvers/zod";
|
||||||
|
import classNames from "classnames";
|
||||||
import { useRouter } from "next/router";
|
import { useRouter } from "next/router";
|
||||||
import { useState } from "react";
|
import { useState } from "react";
|
||||||
import { Controller, FormProvider, useForm } from "react-hook-form";
|
import { Controller, FormProvider, useForm } from "react-hook-form";
|
||||||
@@ -9,7 +10,7 @@ import { isPasswordValid } from "@calcom/lib/auth";
|
|||||||
import { useLocale } from "@calcom/lib/hooks/useLocale";
|
import { useLocale } from "@calcom/lib/hooks/useLocale";
|
||||||
import prisma from "@calcom/prisma";
|
import prisma from "@calcom/prisma";
|
||||||
import { inferSSRProps } from "@calcom/types/inferSSRProps";
|
import { inferSSRProps } from "@calcom/types/inferSSRProps";
|
||||||
import { TextField, EmailField, PasswordField } from "@calcom/ui/v2";
|
import { TextField, EmailField, PasswordField, Label } from "@calcom/ui/v2";
|
||||||
import WizardForm from "@calcom/ui/v2/core/WizardForm";
|
import WizardForm from "@calcom/ui/v2/core/WizardForm";
|
||||||
|
|
||||||
const StepDone = () => {
|
const StepDone = () => {
|
||||||
@@ -85,6 +86,8 @@ const SetupFormStep1 = (props: { setIsLoading: (val: boolean) => void }) => {
|
|||||||
}
|
}
|
||||||
}, onError);
|
}, onError);
|
||||||
|
|
||||||
|
const longWebsiteUrl = process.env.NEXT_PUBLIC_WEBSITE_URL.length > 30;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<FormProvider {...formMethods}>
|
<FormProvider {...formMethods}>
|
||||||
<form id="setup-step-1" name="setup-step-1" className="space-y-4" onSubmit={onSubmit}>
|
<form id="setup-step-1" name="setup-step-1" className="space-y-4" onSubmit={onSubmit}>
|
||||||
@@ -93,14 +96,27 @@ const SetupFormStep1 = (props: { setIsLoading: (val: boolean) => void }) => {
|
|||||||
name="username"
|
name="username"
|
||||||
control={formMethods.control}
|
control={formMethods.control}
|
||||||
render={({ field: { onBlur, onChange, value } }) => (
|
render={({ field: { onBlur, onChange, value } }) => (
|
||||||
|
<>
|
||||||
|
<Label htmlFor="username" className={classNames(longWebsiteUrl && "mb-0")}>
|
||||||
|
<span className="block">{t("username")}</span>
|
||||||
|
{longWebsiteUrl && (
|
||||||
|
<small className="items-centerpx-3 mt-2 inline-flex rounded-t-md border border-b-0 border-gray-300 bg-gray-100 py-1 px-3 text-gray-500">
|
||||||
|
{process.env.NEXT_PUBLIC_WEBSITE_URL}
|
||||||
|
</small>
|
||||||
|
)}
|
||||||
|
</Label>
|
||||||
<TextField
|
<TextField
|
||||||
addOnLeading={
|
addOnLeading={
|
||||||
|
!longWebsiteUrl && (
|
||||||
<span className="items-centerpx-3 inline-flex rounded-none text-sm text-gray-500">
|
<span className="items-centerpx-3 inline-flex rounded-none text-sm text-gray-500">
|
||||||
{process.env.NEXT_PUBLIC_WEBSITE_URL}/
|
{process.env.NEXT_PUBLIC_WEBSITE_URL}/
|
||||||
</span>
|
</span>
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
id="username"
|
||||||
|
labelSrOnly={true}
|
||||||
value={value || ""}
|
value={value || ""}
|
||||||
className="my-0"
|
className={classNames("my-0", longWebsiteUrl && "rounded-t-none")}
|
||||||
onBlur={onBlur}
|
onBlur={onBlur}
|
||||||
name="username"
|
name="username"
|
||||||
onChange={async (e) => {
|
onChange={async (e) => {
|
||||||
@@ -109,6 +125,7 @@ const SetupFormStep1 = (props: { setIsLoading: (val: boolean) => void }) => {
|
|||||||
await formMethods.trigger("username");
|
await formMethods.trigger("username");
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
|
</>
|
||||||
)}
|
)}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -2,6 +2,8 @@
|
|||||||
* @deprecated modifications to this file should be v2 only
|
* @deprecated modifications to this file should be v2 only
|
||||||
* Use `/apps/web/pages/v2/availability/[schedule].tsx` instead
|
* Use `/apps/web/pages/v2/availability/[schedule].tsx` instead
|
||||||
*/
|
*/
|
||||||
|
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
||||||
|
// @ts-nocheck
|
||||||
import { GetStaticPaths, GetStaticProps } from "next";
|
import { GetStaticPaths, GetStaticProps } from "next";
|
||||||
import { useRouter } from "next/router";
|
import { useRouter } from "next/router";
|
||||||
import { useState } from "react";
|
import { useState } from "react";
|
||||||
|
|||||||
@@ -51,7 +51,6 @@ export function AvailabilityList({ schedules }: inferQueryOutput<"viewer.availab
|
|||||||
key={schedule.id}
|
key={schedule.id}
|
||||||
schedule={schedule}
|
schedule={schedule}
|
||||||
deleteFunction={deleteMutation.mutate}
|
deleteFunction={deleteMutation.mutate}
|
||||||
isDeleting={deleteMutation.isLoading}
|
|
||||||
/>
|
/>
|
||||||
))}
|
))}
|
||||||
</ul>
|
</ul>
|
||||||
|
|||||||
@@ -28,6 +28,7 @@ const descriptionByStatus: Record<BookingListingStatus, string> = {
|
|||||||
recurring: "recurring_bookings",
|
recurring: "recurring_bookings",
|
||||||
past: "past_bookings",
|
past: "past_bookings",
|
||||||
cancelled: "cancelled_bookings",
|
cancelled: "cancelled_bookings",
|
||||||
|
unconfirmed: "unconfirmed_bookings",
|
||||||
};
|
};
|
||||||
|
|
||||||
const querySchema = z.object({
|
const querySchema = z.object({
|
||||||
@@ -91,7 +92,7 @@ export default function Bookings() {
|
|||||||
{query.status === "error" && (
|
{query.status === "error" && (
|
||||||
<Alert severity="error" title={t("something_went_wrong")} message={query.error.message} />
|
<Alert severity="error" title={t("something_went_wrong")} message={query.error.message} />
|
||||||
)}
|
)}
|
||||||
{(query.status === "loading" || query.status === "idle") && <SkeletonLoader />}
|
{(query.status === "loading" || query.isPaused) && <SkeletonLoader />}
|
||||||
{query.status === "success" && !isEmpty && (
|
{query.status === "success" && !isEmpty && (
|
||||||
<>
|
<>
|
||||||
<div className="mt-6 overflow-hidden rounded-sm border border-b border-gray-200">
|
<div className="mt-6 overflow-hidden rounded-sm border border-b border-gray-200">
|
||||||
|
|||||||
@@ -1,3 +1,9 @@
|
|||||||
|
/**
|
||||||
|
* @deprecated modifications to this file should be v2 only
|
||||||
|
* Use `apps/web/pages/v2/event-types/[type].tsx` instead
|
||||||
|
*/
|
||||||
|
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
||||||
|
// @ts-nocheck
|
||||||
import { zodResolver } from "@hookform/resolvers/zod";
|
import { zodResolver } from "@hookform/resolvers/zod";
|
||||||
import { EventTypeCustomInput, MembershipRole, PeriodType, Prisma, SchedulingType } from "@prisma/client";
|
import { EventTypeCustomInput, MembershipRole, PeriodType, Prisma, SchedulingType } from "@prisma/client";
|
||||||
import { Collapsible, CollapsibleContent, CollapsibleTrigger } from "@radix-ui/react-collapsible";
|
import { Collapsible, CollapsibleContent, CollapsibleTrigger } from "@radix-ui/react-collapsible";
|
||||||
@@ -16,15 +22,16 @@ import { v5 as uuidv5 } from "uuid";
|
|||||||
import { z } from "zod";
|
import { z } from "zod";
|
||||||
|
|
||||||
import { SelectGifInput } from "@calcom/app-store/giphy/components";
|
import { SelectGifInput } from "@calcom/app-store/giphy/components";
|
||||||
import { getEventLocationType, EventLocationType } from "@calcom/app-store/locations";
|
import { EventLocationType, getEventLocationType } from "@calcom/app-store/locations";
|
||||||
import { StripeData } from "@calcom/app-store/stripepayment/lib/server";
|
import { StripeData } from "@calcom/app-store/stripepayment/lib/server";
|
||||||
import getApps, { getLocationOptions } from "@calcom/app-store/utils";
|
import getApps, { getLocationOptions } from "@calcom/app-store/utils";
|
||||||
import { LocationObject, LocationType } from "@calcom/core/location";
|
import { LocationObject } from "@calcom/core/location";
|
||||||
import { parseRecurringEvent } from "@calcom/lib";
|
import { parseRecurringEvent } from "@calcom/lib";
|
||||||
import { CAL_URL, WEBAPP_URL } from "@calcom/lib/constants";
|
import { CAL_URL, WEBAPP_URL } from "@calcom/lib/constants";
|
||||||
import { useLocale } from "@calcom/lib/hooks/useLocale";
|
import { useLocale } from "@calcom/lib/hooks/useLocale";
|
||||||
import showToast from "@calcom/lib/notification";
|
import showToast from "@calcom/lib/notification";
|
||||||
import prisma from "@calcom/prisma";
|
import prisma from "@calcom/prisma";
|
||||||
|
import { TRPCClientError } from "@calcom/trpc/client";
|
||||||
import { trpc } from "@calcom/trpc/react";
|
import { trpc } from "@calcom/trpc/react";
|
||||||
import type { RecurringEvent } from "@calcom/types/Calendar";
|
import type { RecurringEvent } from "@calcom/types/Calendar";
|
||||||
import { Alert } from "@calcom/ui/Alert";
|
import { Alert } from "@calcom/ui/Alert";
|
||||||
@@ -64,7 +71,6 @@ import * as RadioArea from "@components/ui/form/radio-area";
|
|||||||
import WebhookListContainer from "@components/webhook/WebhookListContainer";
|
import WebhookListContainer from "@components/webhook/WebhookListContainer";
|
||||||
|
|
||||||
import { getTranslation } from "@server/lib/i18n";
|
import { getTranslation } from "@server/lib/i18n";
|
||||||
import { TRPCClientError } from "@trpc/client";
|
|
||||||
|
|
||||||
const RainbowInstallForm = dynamic(() => import("@calcom/rainbow/components/RainbowInstallForm"), {
|
const RainbowInstallForm = dynamic(() => import("@calcom/rainbow/components/RainbowInstallForm"), {
|
||||||
suspense: true,
|
suspense: true,
|
||||||
@@ -108,6 +114,7 @@ export type FormValues = {
|
|||||||
periodCountCalendarDays: "1" | "0";
|
periodCountCalendarDays: "1" | "0";
|
||||||
periodDates: { startDate: Date; endDate: Date };
|
periodDates: { startDate: Date; endDate: Date };
|
||||||
seatsPerTimeSlot: number | null;
|
seatsPerTimeSlot: number | null;
|
||||||
|
seatsPerTimeSlotEnabled: boolean;
|
||||||
minimumBookingNotice: number;
|
minimumBookingNotice: number;
|
||||||
beforeBufferTime: number;
|
beforeBufferTime: number;
|
||||||
afterBufferTime: number;
|
afterBufferTime: number;
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ import { CAL_URL, WEBAPP_URL } from "@calcom/lib/constants";
|
|||||||
import { useLocale } from "@calcom/lib/hooks/useLocale";
|
import { useLocale } from "@calcom/lib/hooks/useLocale";
|
||||||
import showToast from "@calcom/lib/notification";
|
import showToast from "@calcom/lib/notification";
|
||||||
import { inferQueryOutput, trpc } from "@calcom/trpc/react";
|
import { inferQueryOutput, trpc } from "@calcom/trpc/react";
|
||||||
|
import { TRPCClientError } from "@calcom/trpc/react";
|
||||||
import { Button } from "@calcom/ui";
|
import { Button } from "@calcom/ui";
|
||||||
import { Alert } from "@calcom/ui/Alert";
|
import { Alert } from "@calcom/ui/Alert";
|
||||||
import Badge from "@calcom/ui/Badge";
|
import Badge from "@calcom/ui/Badge";
|
||||||
@@ -23,6 +24,7 @@ import Dropdown, {
|
|||||||
DropdownMenuItem,
|
DropdownMenuItem,
|
||||||
DropdownMenuSeparator,
|
DropdownMenuSeparator,
|
||||||
DropdownMenuTrigger,
|
DropdownMenuTrigger,
|
||||||
|
DropdownMenuPortal,
|
||||||
} from "@calcom/ui/Dropdown";
|
} from "@calcom/ui/Dropdown";
|
||||||
import EmptyScreen from "@calcom/ui/EmptyScreen";
|
import EmptyScreen from "@calcom/ui/EmptyScreen";
|
||||||
import { Icon } from "@calcom/ui/Icon";
|
import { Icon } from "@calcom/ui/Icon";
|
||||||
@@ -42,8 +44,6 @@ import { LinkText } from "@components/ui/LinkText";
|
|||||||
import NoCalendarConnectedAlert from "@components/ui/NoCalendarConnectedAlert";
|
import NoCalendarConnectedAlert from "@components/ui/NoCalendarConnectedAlert";
|
||||||
import SkeletonLoader from "@components/v2/eventtype/SkeletonLoader";
|
import SkeletonLoader from "@components/v2/eventtype/SkeletonLoader";
|
||||||
|
|
||||||
import { TRPCClientError } from "@trpc/react";
|
|
||||||
|
|
||||||
type EventTypeGroups = inferQueryOutput<"viewer.eventTypes">["eventTypeGroups"];
|
type EventTypeGroups = inferQueryOutput<"viewer.eventTypes">["eventTypeGroups"];
|
||||||
type EventTypeGroupProfile = EventTypeGroups[number]["profile"];
|
type EventTypeGroupProfile = EventTypeGroups[number]["profile"];
|
||||||
interface EventTypeListHeadingProps {
|
interface EventTypeListHeadingProps {
|
||||||
@@ -346,7 +346,8 @@ export const EventTypeList = ({ group, groupIndex, readOnly, types }: EventTypeL
|
|||||||
<DropdownMenuTrigger asChild data-testid={"event-type-options-" + type.id}>
|
<DropdownMenuTrigger asChild data-testid={"event-type-options-" + type.id}>
|
||||||
<Button type="button" size="icon" color="minimal" StartIcon={Icon.FiMoreHorizontal} />
|
<Button type="button" size="icon" color="minimal" StartIcon={Icon.FiMoreHorizontal} />
|
||||||
</DropdownMenuTrigger>
|
</DropdownMenuTrigger>
|
||||||
<DropdownMenuContent portalled>
|
<DropdownMenuPortal>
|
||||||
|
<DropdownMenuContent>
|
||||||
<DropdownMenuItem className="outline-none">
|
<DropdownMenuItem className="outline-none">
|
||||||
<Link href={calLink}>
|
<Link href={calLink}>
|
||||||
<Button
|
<Button
|
||||||
@@ -436,6 +437,7 @@ export const EventTypeList = ({ group, groupIndex, readOnly, types }: EventTypeL
|
|||||||
</Button>
|
</Button>
|
||||||
</DropdownMenuItem>
|
</DropdownMenuItem>
|
||||||
</DropdownMenuContent>
|
</DropdownMenuContent>
|
||||||
|
</DropdownMenuPortal>
|
||||||
</Dropdown>
|
</Dropdown>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -540,6 +542,7 @@ const EventTypesPage = () => {
|
|||||||
<title>Home | Cal.com</title>
|
<title>Home | Cal.com</title>
|
||||||
<link rel="icon" href="/favicon.ico" />
|
<link rel="icon" href="/favicon.ico" />
|
||||||
</Head>
|
</Head>
|
||||||
|
|
||||||
<Shell
|
<Shell
|
||||||
heading={t("event_types_page_title") as string}
|
heading={t("event_types_page_title") as string}
|
||||||
subtitle={t("event_types_page_subtitle") as string}
|
subtitle={t("event_types_page_subtitle") as string}
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
import UserV2OptInBanner from "@calcom/features/users/components/UserV2OptInBanner";
|
|
||||||
import { useLocale } from "@calcom/lib/hooks/useLocale";
|
import { useLocale } from "@calcom/lib/hooks/useLocale";
|
||||||
import { MobileNavigationMoreItems } from "@calcom/ui/Shell";
|
import { MobileNavigationMoreItems } from "@calcom/ui/Shell";
|
||||||
import { Shell } from "@calcom/ui/v2";
|
import { Shell } from "@calcom/ui/v2";
|
||||||
|
|||||||
@@ -21,6 +21,7 @@ import { useLocale } from "@calcom/lib/hooks/useLocale";
|
|||||||
import showToast from "@calcom/lib/notification";
|
import showToast from "@calcom/lib/notification";
|
||||||
import { collectPageParameters, telemetryEventTypes, useTelemetry } from "@calcom/lib/telemetry";
|
import { collectPageParameters, telemetryEventTypes, useTelemetry } from "@calcom/lib/telemetry";
|
||||||
import prisma from "@calcom/prisma";
|
import prisma from "@calcom/prisma";
|
||||||
|
import { TRPCClientErrorLike } from "@calcom/trpc/client";
|
||||||
import { trpc } from "@calcom/trpc/react";
|
import { trpc } from "@calcom/trpc/react";
|
||||||
import type { AppRouter } from "@calcom/trpc/server/routers/_app";
|
import type { AppRouter } from "@calcom/trpc/server/routers/_app";
|
||||||
import { Alert } from "@calcom/ui/Alert";
|
import { Alert } from "@calcom/ui/Alert";
|
||||||
@@ -39,8 +40,6 @@ import Schedule from "@components/availability/Schedule";
|
|||||||
import { CalendarListContainer } from "@components/integrations/CalendarListContainer";
|
import { CalendarListContainer } from "@components/integrations/CalendarListContainer";
|
||||||
import { UsernameAvailability } from "@components/ui/UsernameAvailability";
|
import { UsernameAvailability } from "@components/ui/UsernameAvailability";
|
||||||
|
|
||||||
import { TRPCClientErrorLike } from "@trpc/client";
|
|
||||||
|
|
||||||
// Embed isn't applicable to onboarding, so ignore the rule
|
// Embed isn't applicable to onboarding, so ignore the rule
|
||||||
/* eslint-disable @calcom/eslint/avoid-web-storage */
|
/* eslint-disable @calcom/eslint/avoid-web-storage */
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
|
import { useQuery } from "@tanstack/react-query";
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import { useQuery } from "react-query";
|
|
||||||
|
|
||||||
import { HttpError } from "@lib/core/http/error";
|
import { HttpError } from "@lib/core/http/error";
|
||||||
|
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ export default function Settings() {
|
|||||||
const { data: routingForms } = trpc.useQuery([
|
const { data: routingForms } = trpc.useQuery([
|
||||||
"viewer.appById",
|
"viewer.appById",
|
||||||
{
|
{
|
||||||
appId: "routing_forms",
|
appId: "routing-forms",
|
||||||
},
|
},
|
||||||
]);
|
]);
|
||||||
|
|
||||||
@@ -19,7 +19,7 @@ export default function Settings() {
|
|||||||
<WebhookListContainer title="Event Webhooks" subtitle={t("receive_cal_meeting_data")} />
|
<WebhookListContainer title="Event Webhooks" subtitle={t("receive_cal_meeting_data")} />
|
||||||
{routingForms && (
|
{routingForms && (
|
||||||
<WebhookListContainer
|
<WebhookListContainer
|
||||||
appId="routing_forms"
|
appId="routing-forms"
|
||||||
title="Routing Webhooks"
|
title="Routing Webhooks"
|
||||||
subtitle="Receive Routing Form responses at a specified URL, in real-time, when a Routing Form is submitted"
|
subtitle="Receive Routing Form responses at a specified URL, in real-time, when a Routing Form is submitted"
|
||||||
/>
|
/>
|
||||||
|
|||||||
@@ -17,6 +17,7 @@ import TimezoneSelect, { ITimezone } from "react-timezone-select";
|
|||||||
|
|
||||||
import { useLocale } from "@calcom/lib/hooks/useLocale";
|
import { useLocale } from "@calcom/lib/hooks/useLocale";
|
||||||
import showToast from "@calcom/lib/notification";
|
import showToast from "@calcom/lib/notification";
|
||||||
|
import { setIs24hClockInLocalStorage } from "@calcom/lib/timeFormat";
|
||||||
import prisma from "@calcom/prisma";
|
import prisma from "@calcom/prisma";
|
||||||
import { TRPCClientErrorLike } from "@calcom/trpc/client";
|
import { TRPCClientErrorLike } from "@calcom/trpc/client";
|
||||||
import { trpc } from "@calcom/trpc/react";
|
import { trpc } from "@calcom/trpc/react";
|
||||||
@@ -229,7 +230,7 @@ function SettingsView(props: ComponentProps<typeof Settings> & { localeProp: str
|
|||||||
// Write time format to localStorage if available
|
// Write time format to localStorage if available
|
||||||
// Embed isn't applicable to profile pages. So ignore the rule
|
// Embed isn't applicable to profile pages. So ignore the rule
|
||||||
// eslint-disable-next-line @calcom/eslint/avoid-web-storage
|
// eslint-disable-next-line @calcom/eslint/avoid-web-storage
|
||||||
window.localStorage.setItem("timeOption.is24hClock", selectedTimeFormat.value === 12 ? "false" : "true");
|
setIs24hClockInLocalStorage(selectedTimeFormat.value === 24);
|
||||||
|
|
||||||
// TODO: Add validation
|
// TODO: Add validation
|
||||||
|
|
||||||
@@ -575,7 +576,7 @@ function SettingsView(props: ComponentProps<typeof Settings> & { localeProp: str
|
|||||||
* i18n should never be clubbed with other queries, so that it's caching can be managed independently.
|
* i18n should never be clubbed with other queries, so that it's caching can be managed independently.
|
||||||
* We intend to not cache i18n query
|
* We intend to not cache i18n query
|
||||||
**/
|
**/
|
||||||
const WithQuery = withQuery(["viewer.public.i18n"], { context: { skipBatch: true } });
|
const WithQuery = withQuery(["viewer.public.i18n"], { trpc: { context: { skipBatch: true } } });
|
||||||
|
|
||||||
export default function Settings(props: Props) {
|
export default function Settings(props: Props) {
|
||||||
const { t } = useLocale();
|
const { t } = useLocale();
|
||||||
|
|||||||
@@ -26,7 +26,7 @@ import { useLocale } from "@calcom/lib/hooks/useLocale";
|
|||||||
import useTheme from "@calcom/lib/hooks/useTheme";
|
import useTheme from "@calcom/lib/hooks/useTheme";
|
||||||
import { getEveryFreqFor } from "@calcom/lib/recurringStrings";
|
import { getEveryFreqFor } from "@calcom/lib/recurringStrings";
|
||||||
import { collectPageParameters, telemetryEventTypes, useTelemetry } from "@calcom/lib/telemetry";
|
import { collectPageParameters, telemetryEventTypes, useTelemetry } from "@calcom/lib/telemetry";
|
||||||
import { isBrowserLocale24h } from "@calcom/lib/timeFormat";
|
import { getIs24hClockFromLocalStorage, isBrowserLocale24h } from "@calcom/lib/timeFormat";
|
||||||
import { localStorage } from "@calcom/lib/webstorage";
|
import { localStorage } from "@calcom/lib/webstorage";
|
||||||
import prisma from "@calcom/prisma";
|
import prisma from "@calcom/prisma";
|
||||||
import Button from "@calcom/ui/Button";
|
import Button from "@calcom/ui/Button";
|
||||||
@@ -203,7 +203,7 @@ export default function Success(props: SuccessProps) {
|
|||||||
// TODO: Add payment details
|
// TODO: Add payment details
|
||||||
});
|
});
|
||||||
setDate(date.tz(localStorage.getItem("timeOption.preferredTimeZone") || dayjs.tz.guess()));
|
setDate(date.tz(localStorage.getItem("timeOption.preferredTimeZone") || dayjs.tz.guess()));
|
||||||
setIs24h(!!localStorage.getItem("timeOption.is24hClock"));
|
setIs24h(!!getIs24hClockFromLocalStorage());
|
||||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||||
}, [eventType, needsConfirmation]);
|
}, [eventType, needsConfirmation]);
|
||||||
|
|
||||||
|
|||||||
@@ -18,21 +18,25 @@ export default function Apps({ apps }: InferGetStaticPropsType<typeof getStaticP
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<Shell isPublic large>
|
<Shell
|
||||||
<div className="text-md flex items-center gap-1 px-4 pb-3 pt-3 font-semibold md:px-8 lg:px-0 lg:pt-0">
|
isPublic
|
||||||
|
backPath="/apps"
|
||||||
|
heading={
|
||||||
|
<>
|
||||||
<Link href="/apps">
|
<Link href="/apps">
|
||||||
<a className="inline-flex items-center justify-start gap-1 rounded-sm py-2 text-gray-900">
|
<a className="inline-flex items-center justify-start gap-1 rounded-sm py-2 text-gray-900">
|
||||||
<Icon.FiArrowLeft className="h-4 w-4" />
|
|
||||||
{isLocaleReady ? t("app_store") : <SkeletonText className="h-4 w-24" />}{" "}
|
{isLocaleReady ? t("app_store") : <SkeletonText className="h-4 w-24" />}{" "}
|
||||||
</a>
|
</a>
|
||||||
</Link>
|
</Link>
|
||||||
{category && (
|
{category && (
|
||||||
<span className="flex gap-1 text-gray-600">
|
<span className="gap-1 text-gray-600">
|
||||||
<span> / </span>
|
<span> / </span>
|
||||||
{t("category_apps", { category: category[0].toUpperCase() + category?.slice(1) })}
|
{t("category_apps", { category: category[0].toUpperCase() + category?.slice(1) })}
|
||||||
</span>
|
</span>
|
||||||
)}
|
)}
|
||||||
</div>
|
</>
|
||||||
|
}
|
||||||
|
large>
|
||||||
<div className="mb-16">
|
<div className="mb-16">
|
||||||
<div className="grid-col-1 grid grid-cols-1 gap-3 md:grid-cols-3">
|
<div className="grid-col-1 grid grid-cols-1 gap-3 md:grid-cols-3">
|
||||||
{apps.map((app) => {
|
{apps.map((app) => {
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { useRouter } from "next/router";
|
import { InferGetServerSidePropsType } from "next";
|
||||||
import z from "zod";
|
import z from "zod";
|
||||||
|
|
||||||
import { InstallAppButton } from "@calcom/app-store/components";
|
import { InstallAppButton } from "@calcom/app-store/components";
|
||||||
@@ -6,6 +6,7 @@ import { InstalledAppVariants } from "@calcom/app-store/utils";
|
|||||||
import { useLocale } from "@calcom/lib/hooks/useLocale";
|
import { useLocale } from "@calcom/lib/hooks/useLocale";
|
||||||
import { inferQueryOutput, trpc } from "@calcom/trpc/react";
|
import { inferQueryOutput, trpc } from "@calcom/trpc/react";
|
||||||
import { App } from "@calcom/types/App";
|
import { App } from "@calcom/types/App";
|
||||||
|
import { AppGetServerSidePropsContext } from "@calcom/types/AppGetServerSideProps";
|
||||||
import { Icon } from "@calcom/ui/Icon";
|
import { Icon } from "@calcom/ui/Icon";
|
||||||
import SkeletonLoader from "@calcom/ui/apps/SkeletonLoader";
|
import SkeletonLoader from "@calcom/ui/apps/SkeletonLoader";
|
||||||
import { Alert } from "@calcom/ui/v2/core/Alert";
|
import { Alert } from "@calcom/ui/v2/core/Alert";
|
||||||
@@ -90,7 +91,7 @@ interface IntegrationsContainerProps {
|
|||||||
|
|
||||||
const IntegrationsList = ({ data }: { data: inferQueryOutput<"viewer.integrations"> }) => {
|
const IntegrationsList = ({ data }: { data: inferQueryOutput<"viewer.integrations"> }) => {
|
||||||
return (
|
return (
|
||||||
<List>
|
<List noBorderTreatment>
|
||||||
{data.items.map((item) => (
|
{data.items.map((item) => (
|
||||||
<IntegrationListItem
|
<IntegrationListItem
|
||||||
name={item.name}
|
name={item.name}
|
||||||
@@ -100,7 +101,7 @@ const IntegrationsList = ({ data }: { data: inferQueryOutput<"viewer.integration
|
|||||||
logo={item.logo}
|
logo={item.logo}
|
||||||
description={item.description}
|
description={item.description}
|
||||||
actions={
|
actions={
|
||||||
<div className="flex w-32 justify-center">
|
<div className="flex w-32 justify-end">
|
||||||
<ConnectOrDisconnectIntegrationButton
|
<ConnectOrDisconnectIntegrationButton
|
||||||
credentialIds={item.credentialIds}
|
credentialIds={item.credentialIds}
|
||||||
type={item.type}
|
type={item.type}
|
||||||
@@ -177,12 +178,8 @@ const querySchema = z.object({
|
|||||||
category: z.nativeEnum(InstalledAppVariants),
|
category: z.nativeEnum(InstalledAppVariants),
|
||||||
});
|
});
|
||||||
|
|
||||||
export default function InstalledApps() {
|
export default function InstalledApps({ category }: InferGetServerSidePropsType<typeof getServerSideProps>) {
|
||||||
const { t } = useLocale();
|
const { t } = useLocale();
|
||||||
const router = useRouter();
|
|
||||||
const { category } = router.isReady
|
|
||||||
? querySchema.parse(router.query)
|
|
||||||
: { category: InstalledAppVariants.calendar as const };
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<InstalledAppsLayout heading={t("installed_apps")} subtitle={t("manage_your_connected_apps")}>
|
<InstalledAppsLayout heading={t("installed_apps")} subtitle={t("manage_your_connected_apps")}>
|
||||||
@@ -202,3 +199,30 @@ export default function InstalledApps() {
|
|||||||
</InstalledAppsLayout>
|
</InstalledAppsLayout>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Server side rendering
|
||||||
|
export async function getServerSideProps(ctx: AppGetServerSidePropsContext) {
|
||||||
|
// get return-to cookie and redirect if needed
|
||||||
|
const { cookies } = ctx.req;
|
||||||
|
if (cookies && cookies["return-to"]) {
|
||||||
|
const returnTo = cookies["return-to"];
|
||||||
|
if (returnTo) {
|
||||||
|
ctx.res.setHeader("Set-Cookie", "return-to=; path=/; expires=Thu, 01 Jan 1970 00:00:00 GMT");
|
||||||
|
return {
|
||||||
|
redirect: {
|
||||||
|
destination: `${returnTo}`,
|
||||||
|
permanent: false,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const params = querySchema.safeParse(ctx.params);
|
||||||
|
|
||||||
|
if (!params.success) return { notFound: true };
|
||||||
|
|
||||||
|
return {
|
||||||
|
props: {
|
||||||
|
category: params.data.category,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
@@ -78,7 +78,7 @@ export default function Login({
|
|||||||
|
|
||||||
const LoginFooter = (
|
const LoginFooter = (
|
||||||
<a href={`${WEBSITE_URL}/signup`} className="text-brand-500 font-medium">
|
<a href={`${WEBSITE_URL}/signup`} className="text-brand-500 font-medium">
|
||||||
{t("i_dont_have_an_account")}
|
{t("dont_have_an_account")}
|
||||||
</a>
|
</a>
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -140,7 +140,7 @@ export default function Login({
|
|||||||
{...form.register("email")}
|
{...form.register("email")}
|
||||||
/>
|
/>
|
||||||
<div className="relative">
|
<div className="relative">
|
||||||
<div className="absolute right-0 -top-[6px]">
|
<div className="absolute right-0 -top-[6px] z-10">
|
||||||
<Link href="/auth/forgot-password">
|
<Link href="/auth/forgot-password">
|
||||||
<a tabIndex={-1} className="text-sm font-medium text-gray-600">
|
<a tabIndex={-1} className="text-sm font-medium text-gray-600">
|
||||||
{t("forgot")}
|
{t("forgot")}
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ import { availabilityAsString } from "@calcom/lib/availability";
|
|||||||
import { useLocale } from "@calcom/lib/hooks/useLocale";
|
import { useLocale } from "@calcom/lib/hooks/useLocale";
|
||||||
import { stringOrNumber } from "@calcom/prisma/zod-utils";
|
import { stringOrNumber } from "@calcom/prisma/zod-utils";
|
||||||
import { trpc } from "@calcom/trpc/react";
|
import { trpc } from "@calcom/trpc/react";
|
||||||
|
import useMeQuery from "@calcom/trpc/react/hooks/useMeQuery";
|
||||||
import type { Schedule as ScheduleType } from "@calcom/types/schedule";
|
import type { Schedule as ScheduleType } from "@calcom/types/schedule";
|
||||||
import { Icon } from "@calcom/ui";
|
import { Icon } from "@calcom/ui";
|
||||||
import TimezoneSelect from "@calcom/ui/form/TimezoneSelect";
|
import TimezoneSelect from "@calcom/ui/form/TimezoneSelect";
|
||||||
@@ -18,11 +19,12 @@ import Switch from "@calcom/ui/v2/core/Switch";
|
|||||||
import VerticalDivider from "@calcom/ui/v2/core/VerticalDivider";
|
import VerticalDivider from "@calcom/ui/v2/core/VerticalDivider";
|
||||||
import { Form, Label } from "@calcom/ui/v2/core/form/fields";
|
import { Form, Label } from "@calcom/ui/v2/core/form/fields";
|
||||||
import showToast from "@calcom/ui/v2/core/notifications";
|
import showToast from "@calcom/ui/v2/core/notifications";
|
||||||
import { SkeletonText } from "@calcom/ui/v2/core/skeleton";
|
import { Skeleton, SkeletonText } from "@calcom/ui/v2/core/skeleton";
|
||||||
|
|
||||||
import { HttpError } from "@lib/core/http/error";
|
import { HttpError } from "@lib/core/http/error";
|
||||||
|
|
||||||
import EditableHeading from "@components/ui/EditableHeading";
|
import EditableHeading from "@components/ui/EditableHeading";
|
||||||
|
import { SelectSkeletonLoader } from "@components/v2/availability/SkeletonLoader";
|
||||||
|
|
||||||
const querySchema = z.object({
|
const querySchema = z.object({
|
||||||
schedule: stringOrNumber,
|
schedule: stringOrNumber,
|
||||||
@@ -39,11 +41,12 @@ export default function Availability({ schedule }: { schedule: number }) {
|
|||||||
const { t, i18n } = useLocale();
|
const { t, i18n } = useLocale();
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const utils = trpc.useContext();
|
const utils = trpc.useContext();
|
||||||
|
const me = useMeQuery();
|
||||||
|
|
||||||
const { data, isLoading } = trpc.useQuery(["viewer.availability.schedule", { scheduleId: schedule }]);
|
const { data, isLoading } = trpc.useQuery(["viewer.availability.schedule", { scheduleId: schedule }]);
|
||||||
|
|
||||||
const form = useForm<AvailabilityFormValues>();
|
const form = useForm<AvailabilityFormValues>();
|
||||||
const { control, reset, setValue } = form;
|
const { control, reset } = form;
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!isLoading && data) {
|
if (!isLoading && data) {
|
||||||
@@ -79,22 +82,35 @@ export default function Availability({ schedule }: { schedule: number }) {
|
|||||||
return (
|
return (
|
||||||
<Shell
|
<Shell
|
||||||
backPath="/availability"
|
backPath="/availability"
|
||||||
title={t("availability_title", { availabilityTitle: data?.schedule.name })}
|
title={data?.schedule.name && data.schedule.name + " | " + t("availability")}
|
||||||
heading={
|
heading={
|
||||||
<EditableHeading title={data?.schedule.name || ""} onChange={(name) => setValue("name", name)} />
|
<Controller
|
||||||
|
control={form.control}
|
||||||
|
name="name"
|
||||||
|
render={({ field }) => <EditableHeading isReady={!isLoading} {...field} />}
|
||||||
|
/>
|
||||||
}
|
}
|
||||||
subtitle={data?.schedule.availability.map((availability) => (
|
subtitle={
|
||||||
|
data ? (
|
||||||
|
data.schedule.availability.map((availability) => (
|
||||||
<span key={availability.id}>
|
<span key={availability.id}>
|
||||||
{availabilityAsString(availability, { locale: i18n.language })}
|
{availabilityAsString(availability, { locale: i18n.language })}
|
||||||
<br />
|
<br />
|
||||||
</span>
|
</span>
|
||||||
))}
|
))
|
||||||
|
) : (
|
||||||
|
<SkeletonText className="h-4 w-48" />
|
||||||
|
)
|
||||||
|
}
|
||||||
CTA={
|
CTA={
|
||||||
<div className="flex items-center justify-end">
|
<div className="flex items-center justify-end">
|
||||||
<div className="flex items-center rounded-md px-2 sm:hover:bg-gray-100">
|
<div className="flex items-center rounded-md px-2 sm:hover:bg-gray-100">
|
||||||
<Label htmlFor="hiddenSwitch" className="mt-2 hidden cursor-pointer self-center pr-2 sm:inline">
|
<Skeleton
|
||||||
|
as={Label}
|
||||||
|
htmlFor="hiddenSwitch"
|
||||||
|
className="mt-2 hidden cursor-pointer self-center pr-2 sm:inline">
|
||||||
{t("set_to_default")}
|
{t("set_to_default")}
|
||||||
</Label>
|
</Skeleton>
|
||||||
<Switch
|
<Switch
|
||||||
id="hiddenSwitch"
|
id="hiddenSwitch"
|
||||||
disabled={isLoading}
|
disabled={isLoading}
|
||||||
@@ -132,7 +148,17 @@ export default function Availability({ schedule }: { schedule: number }) {
|
|||||||
<h3 className="mb-5 text-base font-medium leading-6 text-gray-900">
|
<h3 className="mb-5 text-base font-medium leading-6 text-gray-900">
|
||||||
{t("change_start_end")}
|
{t("change_start_end")}
|
||||||
</h3>
|
</h3>
|
||||||
<Schedule control={control} name="schedule" />
|
{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>
|
||||||
</div>
|
</div>
|
||||||
<div className="min-w-40 col-span-3 space-y-2 lg:col-span-1">
|
<div className="min-w-40 col-span-3 space-y-2 lg:col-span-1">
|
||||||
@@ -147,11 +173,11 @@ export default function Availability({ schedule }: { schedule: number }) {
|
|||||||
value ? (
|
value ? (
|
||||||
<TimezoneSelect
|
<TimezoneSelect
|
||||||
value={value}
|
value={value}
|
||||||
className="focus:border-brand mt-1 block rounded-md border-gray-300 text-sm"
|
className="focus:border-brand mt-1 block w-72 rounded-md border-gray-300 text-sm"
|
||||||
onChange={(timezone) => onChange(timezone.value)}
|
onChange={(timezone) => onChange(timezone.value)}
|
||||||
/>
|
/>
|
||||||
) : (
|
) : (
|
||||||
<SkeletonText className="h-6 w-full" />
|
<SelectSkeletonLoader className="w-72" />
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
|
|||||||
@@ -21,16 +21,32 @@ export function AvailabilityList({ schedules }: inferQueryOutput<"viewer.availab
|
|||||||
const meQuery = trpc.useQuery(["viewer.me"]);
|
const meQuery = trpc.useQuery(["viewer.me"]);
|
||||||
|
|
||||||
const deleteMutation = trpc.useMutation("viewer.availability.schedule.delete", {
|
const deleteMutation = trpc.useMutation("viewer.availability.schedule.delete", {
|
||||||
onSuccess: async () => {
|
onMutate: async ({ scheduleId }) => {
|
||||||
await utils.invalidateQueries(["viewer.availability.list"]);
|
await utils.cancelQuery(["viewer.availability.list"]);
|
||||||
showToast(t("schedule_deleted_successfully"), "success");
|
const previousValue = utils.getQueryData(["viewer.availability.list"]);
|
||||||
|
if (previousValue) {
|
||||||
|
const filteredValue = previousValue.schedules.filter(({ id }) => id !== scheduleId);
|
||||||
|
utils.setQueryData(["viewer.availability.list"], { ...previousValue, schedules: filteredValue });
|
||||||
|
}
|
||||||
|
|
||||||
|
return { previousValue };
|
||||||
},
|
},
|
||||||
onError: (err) => {
|
|
||||||
|
onError: (err, variables, context) => {
|
||||||
|
if (context?.previousValue) {
|
||||||
|
utils.setQueryData(["viewer.availability.list"], context.previousValue);
|
||||||
|
}
|
||||||
if (err instanceof HttpError) {
|
if (err instanceof HttpError) {
|
||||||
const message = `${err.statusCode}: ${err.message}`;
|
const message = `${err.statusCode}: ${err.message}`;
|
||||||
showToast(message, "error");
|
showToast(message, "error");
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
onSettled: () => {
|
||||||
|
utils.invalidateQueries(["viewer.availability.list"]);
|
||||||
|
},
|
||||||
|
onSuccess: () => {
|
||||||
|
showToast(t("schedule_deleted_successfully"), "success");
|
||||||
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
// Adds smooth delete button - item fades and old item slides into place
|
// Adds smooth delete button - item fades and old item slides into place
|
||||||
@@ -61,7 +77,6 @@ export function AvailabilityList({ schedules }: inferQueryOutput<"viewer.availab
|
|||||||
key={schedule.id}
|
key={schedule.id}
|
||||||
schedule={schedule}
|
schedule={schedule}
|
||||||
deleteFunction={deleteMutation.mutate}
|
deleteFunction={deleteMutation.mutate}
|
||||||
isDeleting={deleteMutation.isLoading}
|
|
||||||
/>
|
/>
|
||||||
))}
|
))}
|
||||||
</ul>
|
</ul>
|
||||||
|
|||||||
@@ -20,13 +20,14 @@ import SkeletonLoader from "@components/v2/bookings/SkeletonLoader";
|
|||||||
type BookingListingStatus = inferQueryInput<"viewer.bookings">["status"];
|
type BookingListingStatus = inferQueryInput<"viewer.bookings">["status"];
|
||||||
type BookingOutput = inferQueryOutput<"viewer.bookings">["bookings"][0];
|
type BookingOutput = inferQueryOutput<"viewer.bookings">["bookings"][0];
|
||||||
|
|
||||||
const validStatuses = ["upcoming", "recurring", "past", "cancelled"] as const;
|
const validStatuses = ["upcoming", "recurring", "past", "cancelled", "unconfirmed"] as const;
|
||||||
|
|
||||||
const descriptionByStatus: Record<BookingListingStatus, string> = {
|
const descriptionByStatus: Record<BookingListingStatus, string> = {
|
||||||
upcoming: "upcoming_bookings",
|
upcoming: "upcoming_bookings",
|
||||||
recurring: "recurring_bookings",
|
recurring: "recurring_bookings",
|
||||||
past: "past_bookings",
|
past: "past_bookings",
|
||||||
cancelled: "cancelled_bookings",
|
cancelled: "cancelled_bookings",
|
||||||
|
unconfirmed: "unconfirmed_bookings",
|
||||||
};
|
};
|
||||||
|
|
||||||
const querySchema = z.object({
|
const querySchema = z.object({
|
||||||
@@ -89,11 +90,11 @@ export default function Bookings() {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<BookingLayout heading={t("bookings")} subtitle={t("bookings_description")}>
|
<BookingLayout heading={t("bookings")} subtitle={t("bookings_description")}>
|
||||||
<div className="flex w-full flex-1 flex-col" ref={animationParentRef}>
|
<div className="flex w-full flex-col" ref={animationParentRef}>
|
||||||
{query.status === "error" && (
|
{query.status === "error" && (
|
||||||
<Alert severity="error" title={t("something_went_wrong")} message={query.error.message} />
|
<Alert severity="error" title={t("something_went_wrong")} message={query.error.message} />
|
||||||
)}
|
)}
|
||||||
{(query.status === "loading" || query.status === "idle") && <SkeletonLoader />}
|
{(query.status === "loading" || query.isPaused) && <SkeletonLoader />}
|
||||||
{query.status === "success" && !isEmpty && (
|
{query.status === "success" && !isEmpty && (
|
||||||
<div className="pt-2 xl:pt-0">
|
<div className="pt-2 xl:pt-0">
|
||||||
<WipeMyCalActionButton bookingStatus={status} bookingsEmpty={isEmpty} />
|
<WipeMyCalActionButton bookingStatus={status} bookingsEmpty={isEmpty} />
|
||||||
@@ -102,7 +103,7 @@ export default function Bookings() {
|
|||||||
*/}
|
*/}
|
||||||
|
|
||||||
<div className="overflow-hidden rounded-md border border-gray-200">
|
<div className="overflow-hidden rounded-md border border-gray-200">
|
||||||
<table className="w-full">
|
<table className="w-full max-w-full table-fixed">
|
||||||
<tbody className="divide-y divide-gray-200 bg-white" data-testid="bookings">
|
<tbody className="divide-y divide-gray-200 bg-white" data-testid="bookings">
|
||||||
{query.data.pages.map((page, index) => (
|
{query.data.pages.map((page, index) => (
|
||||||
<Fragment key={index}>
|
<Fragment key={index}>
|
||||||
|
|||||||
@@ -70,6 +70,7 @@ export type FormValues = {
|
|||||||
periodCountCalendarDays: "1" | "0";
|
periodCountCalendarDays: "1" | "0";
|
||||||
periodDates: { startDate: Date; endDate: Date };
|
periodDates: { startDate: Date; endDate: Date };
|
||||||
seatsPerTimeSlot: number | null;
|
seatsPerTimeSlot: number | null;
|
||||||
|
seatsPerTimeSlotEnabled: boolean;
|
||||||
minimumBookingNotice: number;
|
minimumBookingNotice: number;
|
||||||
beforeBufferTime: number;
|
beforeBufferTime: number;
|
||||||
afterBufferTime: number;
|
afterBufferTime: number;
|
||||||
@@ -96,7 +97,8 @@ export type EventTypeSetupInfered = inferSSRProps<typeof getServerSideProps>;
|
|||||||
const EventTypePage = (props: inferSSRProps<typeof getServerSideProps>) => {
|
const EventTypePage = (props: inferSSRProps<typeof getServerSideProps>) => {
|
||||||
const { t } = useLocale();
|
const { t } = useLocale();
|
||||||
|
|
||||||
const { eventType, locationOptions, team, teamMembers } = props;
|
const { eventType: dbEventType, locationOptions, team, teamMembers } = props;
|
||||||
|
const [eventType, setEventType] = useState(dbEventType);
|
||||||
const animationParentRef = useRef(null);
|
const animationParentRef = useRef(null);
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const { tabName } = querySchema.parse(router.query);
|
const { tabName } = querySchema.parse(router.query);
|
||||||
@@ -106,7 +108,8 @@ const EventTypePage = (props: inferSSRProps<typeof getServerSideProps>) => {
|
|||||||
}, [animationParentRef]);
|
}, [animationParentRef]);
|
||||||
|
|
||||||
const updateMutation = trpc.useMutation("viewer.eventTypes.update", {
|
const updateMutation = trpc.useMutation("viewer.eventTypes.update", {
|
||||||
onSuccess: async ({ eventType }) => {
|
onSuccess: async ({ eventType: newEventType }) => {
|
||||||
|
setEventType({ ...eventType, slug: newEventType.slug });
|
||||||
showToast(
|
showToast(
|
||||||
t("event_type_updated_successfully", {
|
t("event_type_updated_successfully", {
|
||||||
eventTypeTitle: eventType.title,
|
eventTypeTitle: eventType.title,
|
||||||
@@ -153,6 +156,7 @@ const EventTypePage = (props: inferSSRProps<typeof getServerSideProps>) => {
|
|||||||
endDate: periodDates.endDate,
|
endDate: periodDates.endDate,
|
||||||
},
|
},
|
||||||
schedulingType: eventType.schedulingType,
|
schedulingType: eventType.schedulingType,
|
||||||
|
minimumBookingNotice: eventType.minimumBookingNotice,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -220,6 +224,9 @@ const EventTypePage = (props: inferSSRProps<typeof getServerSideProps>) => {
|
|||||||
locations,
|
locations,
|
||||||
blockchainId,
|
blockchainId,
|
||||||
smartContractAddress,
|
smartContractAddress,
|
||||||
|
// We don't need to send it to the backend
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||||
|
seatsPerTimeSlotEnabled,
|
||||||
...input
|
...input
|
||||||
} = values;
|
} = values;
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { UserPlan } from "@prisma/client";
|
import { useAutoAnimate } from "@formkit/auto-animate/react";
|
||||||
import Head from "next/head";
|
import Head from "next/head";
|
||||||
import Link from "next/link";
|
import Link from "next/link";
|
||||||
import { useRouter } from "next/router";
|
import { useRouter } from "next/router";
|
||||||
@@ -7,6 +7,7 @@ import React, { Fragment, useEffect, useState } from "react";
|
|||||||
import { CAL_URL, WEBAPP_URL } from "@calcom/lib/constants";
|
import { CAL_URL, WEBAPP_URL } from "@calcom/lib/constants";
|
||||||
import { useLocale } from "@calcom/lib/hooks/useLocale";
|
import { useLocale } from "@calcom/lib/hooks/useLocale";
|
||||||
import { inferQueryOutput, trpc } from "@calcom/trpc/react";
|
import { inferQueryOutput, trpc } from "@calcom/trpc/react";
|
||||||
|
import { TRPCClientError } from "@calcom/trpc/react";
|
||||||
import { Icon } from "@calcom/ui";
|
import { Icon } from "@calcom/ui";
|
||||||
import { Badge, Button, ButtonGroup, Dialog, EmptyScreen, showToast, Switch, Tooltip } from "@calcom/ui/v2";
|
import { Badge, Button, ButtonGroup, Dialog, EmptyScreen, showToast, Switch, Tooltip } from "@calcom/ui/v2";
|
||||||
import ConfirmationDialogContent from "@calcom/ui/v2/core/ConfirmationDialogContent";
|
import ConfirmationDialogContent from "@calcom/ui/v2/core/ConfirmationDialogContent";
|
||||||
@@ -16,6 +17,7 @@ import Dropdown, {
|
|||||||
DropdownMenuItem,
|
DropdownMenuItem,
|
||||||
DropdownMenuSeparator,
|
DropdownMenuSeparator,
|
||||||
DropdownMenuTrigger,
|
DropdownMenuTrigger,
|
||||||
|
DropdownMenuPortal,
|
||||||
} from "@calcom/ui/v2/core/Dropdown";
|
} from "@calcom/ui/v2/core/Dropdown";
|
||||||
import Shell from "@calcom/ui/v2/core/Shell";
|
import Shell from "@calcom/ui/v2/core/Shell";
|
||||||
import CreateEventTypeButton from "@calcom/ui/v2/modules/event-types/CreateEventType";
|
import CreateEventTypeButton from "@calcom/ui/v2/modules/event-types/CreateEventType";
|
||||||
@@ -29,8 +31,6 @@ import Avatar from "@components/ui/Avatar";
|
|||||||
import AvatarGroup from "@components/ui/AvatarGroup";
|
import AvatarGroup from "@components/ui/AvatarGroup";
|
||||||
import SkeletonLoader from "@components/v2/eventtype/SkeletonLoader";
|
import SkeletonLoader from "@components/v2/eventtype/SkeletonLoader";
|
||||||
|
|
||||||
import { TRPCClientError } from "@trpc/react";
|
|
||||||
|
|
||||||
type EventTypeGroups = inferQueryOutput<"viewer.eventTypes">["eventTypeGroups"];
|
type EventTypeGroups = inferQueryOutput<"viewer.eventTypes">["eventTypeGroups"];
|
||||||
type EventTypeGroupProfile = EventTypeGroups[number]["profile"];
|
type EventTypeGroupProfile = EventTypeGroups[number]["profile"];
|
||||||
|
|
||||||
@@ -52,7 +52,7 @@ const Item = ({ type, group, readOnly }: { type: EventType; group: EventTypeGrou
|
|||||||
const { t } = useLocale();
|
const { t } = useLocale();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Link href={`/event-types/${type.id}`}>
|
<Link href={`/event-types/${type.id}?tabName=setup`}>
|
||||||
<a
|
<a
|
||||||
className="flex-grow truncate text-sm"
|
className="flex-grow truncate text-sm"
|
||||||
title={`${type.title} ${type.description ? `– ${type.description}` : ""}`}>
|
title={`${type.title} ${type.description ? `– ${type.description}` : ""}`}>
|
||||||
@@ -82,6 +82,7 @@ const MemoizedItem = React.memo(Item);
|
|||||||
export const EventTypeList = ({ group, groupIndex, readOnly, types }: EventTypeListProps): JSX.Element => {
|
export const EventTypeList = ({ group, groupIndex, readOnly, types }: EventTypeListProps): JSX.Element => {
|
||||||
const { t } = useLocale();
|
const { t } = useLocale();
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
|
const [parent] = useAutoAnimate<HTMLUListElement>();
|
||||||
const [deleteDialogOpen, setDeleteDialogOpen] = useState(false);
|
const [deleteDialogOpen, setDeleteDialogOpen] = useState(false);
|
||||||
const [deleteDialogTypeId, setDeleteDialogTypeId] = useState(0);
|
const [deleteDialogTypeId, setDeleteDialogTypeId] = useState(0);
|
||||||
const utils = trpc.useContext();
|
const utils = trpc.useContext();
|
||||||
@@ -91,8 +92,8 @@ export const EventTypeList = ({ group, groupIndex, readOnly, types }: EventTypeL
|
|||||||
await utils.cancelQuery(["viewer.eventTypes"]);
|
await utils.cancelQuery(["viewer.eventTypes"]);
|
||||||
await utils.invalidateQueries(["viewer.eventTypes"]);
|
await utils.invalidateQueries(["viewer.eventTypes"]);
|
||||||
},
|
},
|
||||||
onSettled: async () => {
|
onSettled: () => {
|
||||||
await utils.invalidateQueries(["viewer.eventTypes"]);
|
utils.invalidateQueries(["viewer.eventTypes"]);
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -107,7 +108,7 @@ export const EventTypeList = ({ group, groupIndex, readOnly, types }: EventTypeL
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
function moveEventType(index: number, increment: 1 | -1) {
|
async function moveEventType(index: number, increment: 1 | -1) {
|
||||||
const newList = [...types];
|
const newList = [...types];
|
||||||
|
|
||||||
const type = types[index];
|
const type = types[index];
|
||||||
@@ -117,24 +118,19 @@ export const EventTypeList = ({ group, groupIndex, readOnly, types }: EventTypeL
|
|||||||
newList[index + increment] = type;
|
newList[index + increment] = type;
|
||||||
}
|
}
|
||||||
|
|
||||||
utils.cancelQuery(["viewer.eventTypes"]);
|
await utils.cancelQuery(["viewer.eventTypes"]);
|
||||||
utils.setQueryData(["viewer.eventTypes"], (data) => {
|
|
||||||
// tRPC is very strict with the return signature...
|
const previousValue = utils.getQueryData(["viewer.eventTypes"]);
|
||||||
if (!data)
|
if (previousValue) {
|
||||||
return {
|
utils.setQueryData(["viewer.eventTypes"], {
|
||||||
eventTypeGroups: [],
|
...previousValue,
|
||||||
profiles: [],
|
eventTypeGroups: [
|
||||||
viewer: { canAddEvents: true, plan: UserPlan.PRO },
|
...previousValue.eventTypeGroups.slice(0, groupIndex),
|
||||||
};
|
|
||||||
return {
|
|
||||||
...data,
|
|
||||||
eventTypesGroups: [
|
|
||||||
...data.eventTypeGroups.slice(0, groupIndex),
|
|
||||||
{ ...group, eventTypes: newList },
|
{ ...group, eventTypes: newList },
|
||||||
...data.eventTypeGroups.slice(groupIndex + 1),
|
...previousValue.eventTypeGroups.slice(groupIndex + 1),
|
||||||
],
|
],
|
||||||
};
|
|
||||||
});
|
});
|
||||||
|
}
|
||||||
|
|
||||||
mutation.mutate({
|
mutation.mutate({
|
||||||
ids: newList.map((type) => type.id),
|
ids: newList.map((type) => type.id),
|
||||||
@@ -201,7 +197,7 @@ export const EventTypeList = ({ group, groupIndex, readOnly, types }: EventTypeL
|
|||||||
const lastItem = types[types.length - 1];
|
const lastItem = types[types.length - 1];
|
||||||
return (
|
return (
|
||||||
<div className="mb-16 flex overflow-hidden rounded-md border border-gray-200 bg-white">
|
<div className="mb-16 flex overflow-hidden rounded-md border border-gray-200 bg-white">
|
||||||
<ul className="w-full divide-y divide-neutral-200" data-testid="event-types">
|
<ul ref={parent} className="!static w-full divide-y divide-neutral-200" data-testid="event-types">
|
||||||
{types.map((type, index) => {
|
{types.map((type, index) => {
|
||||||
const embedLink = `${group.profile.slug}/${type.slug}`;
|
const embedLink = `${group.profile.slug}/${type.slug}`;
|
||||||
const calLink = `${CAL_URL}/${embedLink}`;
|
const calLink = `${CAL_URL}/${embedLink}`;
|
||||||
@@ -296,8 +292,9 @@ export const EventTypeList = ({ group, groupIndex, readOnly, types }: EventTypeL
|
|||||||
<DropdownMenuItem>
|
<DropdownMenuItem>
|
||||||
<DropdownItem
|
<DropdownItem
|
||||||
type="button"
|
type="button"
|
||||||
href={"/event-types/" + type.id}
|
data-testid={"event-type-edit-" + type.id}
|
||||||
StartIcon={Icon.FiEdit2}>
|
StartIcon={Icon.FiEdit2}
|
||||||
|
onClick={() => router.push("/event-types/" + type.id)}>
|
||||||
{t("edit") as string}
|
{t("edit") as string}
|
||||||
</DropdownItem>
|
</DropdownItem>
|
||||||
</DropdownMenuItem>
|
</DropdownMenuItem>
|
||||||
@@ -347,7 +344,8 @@ export const EventTypeList = ({ group, groupIndex, readOnly, types }: EventTypeL
|
|||||||
<DropdownMenuTrigger asChild data-testid={"event-type-options-" + type.id}>
|
<DropdownMenuTrigger asChild data-testid={"event-type-options-" + type.id}>
|
||||||
<Button type="button" size="icon" color="secondary" StartIcon={Icon.FiMoreHorizontal} />
|
<Button type="button" size="icon" color="secondary" StartIcon={Icon.FiMoreHorizontal} />
|
||||||
</DropdownMenuTrigger>
|
</DropdownMenuTrigger>
|
||||||
<DropdownMenuContent portalled>
|
<DropdownMenuPortal>
|
||||||
|
<DropdownMenuContent>
|
||||||
<DropdownMenuItem className="outline-none">
|
<DropdownMenuItem className="outline-none">
|
||||||
<Link href={calLink}>
|
<Link href={calLink}>
|
||||||
<a target="_blank">
|
<a target="_blank">
|
||||||
@@ -399,9 +397,9 @@ export const EventTypeList = ({ group, groupIndex, readOnly, types }: EventTypeL
|
|||||||
<DropdownMenuItem className="outline-none">
|
<DropdownMenuItem className="outline-none">
|
||||||
<Button
|
<Button
|
||||||
type="button"
|
type="button"
|
||||||
href={"/event-types/" + type.id}
|
onClick={() => router.push("/event-types/" + type.id)}
|
||||||
color="minimal"
|
color="minimal"
|
||||||
className="w-full"
|
className="w-full rounded-none"
|
||||||
StartIcon={Icon.FiEdit}>
|
StartIcon={Icon.FiEdit}>
|
||||||
{t("edit") as string}
|
{t("edit") as string}
|
||||||
</Button>
|
</Button>
|
||||||
@@ -431,6 +429,7 @@ export const EventTypeList = ({ group, groupIndex, readOnly, types }: EventTypeL
|
|||||||
</Button>
|
</Button>
|
||||||
</DropdownMenuItem>
|
</DropdownMenuItem>
|
||||||
</DropdownMenuContent>
|
</DropdownMenuContent>
|
||||||
|
</DropdownMenuPortal>
|
||||||
</Dropdown>
|
</Dropdown>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -0,0 +1,86 @@
|
|||||||
|
import { useState } from "react";
|
||||||
|
import { HelpScout, useChat } from "react-live-chat-loader";
|
||||||
|
|
||||||
|
import { classNames } from "@calcom/lib";
|
||||||
|
import { useLocale } from "@calcom/lib/hooks/useLocale";
|
||||||
|
import { trpc } from "@calcom/trpc/react";
|
||||||
|
import { Icon } from "@calcom/ui";
|
||||||
|
import { Button } from "@calcom/ui/v2";
|
||||||
|
import Meta from "@calcom/ui/v2/core/Meta";
|
||||||
|
import { getLayout } from "@calcom/ui/v2/core/layouts/SettingsLayout";
|
||||||
|
|
||||||
|
interface CtaRowProps {
|
||||||
|
title: string;
|
||||||
|
description: string;
|
||||||
|
children: React.ReactNode;
|
||||||
|
className?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
const CtaRow = ({ title, description, className, children }: CtaRowProps) => {
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<section className={classNames("flex flex-col sm:flex-row", className)}>
|
||||||
|
<div>
|
||||||
|
<h2 className="font-medium">{title}</h2>
|
||||||
|
<p>{description}</p>
|
||||||
|
</div>
|
||||||
|
<div className="flex-shrink-0 pt-3 sm:ml-auto sm:pt-0 sm:pl-3">{children}</div>
|
||||||
|
</section>
|
||||||
|
<hr className="border-neutral-200" />
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
const BillingView = () => {
|
||||||
|
const { t } = useLocale();
|
||||||
|
const { data: user } = trpc.useQuery(["viewer.me"]);
|
||||||
|
const isPro = user?.plan === "PRO";
|
||||||
|
const [, loadChat] = useChat();
|
||||||
|
const [showChat, setShowChat] = useState(false);
|
||||||
|
|
||||||
|
const onContactSupportClick = () => {
|
||||||
|
setShowChat(true);
|
||||||
|
loadChat({ open: true });
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<Meta title={t("billing")} description={t("manage_billing_description")} />
|
||||||
|
<div className="space-y-6 text-sm sm:space-y-8">
|
||||||
|
{!isPro && (
|
||||||
|
<CtaRow title={t("billing_freeplan_title")} description={t("billing_freeplan_description")}>
|
||||||
|
<form target="_blank" method="POST" action="/api/upgrade">
|
||||||
|
<Button type="submit" EndIcon={Icon.FiExternalLink}>
|
||||||
|
{t("billing_freeplan_cta")}
|
||||||
|
</Button>
|
||||||
|
</form>
|
||||||
|
</CtaRow>
|
||||||
|
)}
|
||||||
|
|
||||||
|
<CtaRow
|
||||||
|
className={classNames(!isPro && "pointer-events-none opacity-30")}
|
||||||
|
title={t("billing_manage_details_title")}
|
||||||
|
description={t("billing_manage_details_description")}>
|
||||||
|
<Button
|
||||||
|
color={isPro ? "primary" : "secondary"}
|
||||||
|
href="/api/integrations/stripepayment/portal"
|
||||||
|
target="_blank"
|
||||||
|
EndIcon={Icon.FiExternalLink}>
|
||||||
|
{t("billing_portal")}
|
||||||
|
</Button>
|
||||||
|
</CtaRow>
|
||||||
|
|
||||||
|
<CtaRow title={t("billing_help_title")} description={t("billing_help_description")}>
|
||||||
|
<Button color="secondary" onClick={onContactSupportClick}>
|
||||||
|
{t("billing_help_cta")}
|
||||||
|
</Button>
|
||||||
|
</CtaRow>
|
||||||
|
{showChat && <HelpScout color="#292929" icon="message" horizontalPosition="right" zIndex="1" />}
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
BillingView.getLayout = getLayout;
|
||||||
|
|
||||||
|
export default BillingView;
|
||||||
@@ -39,16 +39,16 @@ const ApiKeysView = () => {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<Meta title="api_keys" description="webhooks_description" />
|
<Meta title="API Keys" description="API keys allow other apps to communicate with Cal.com" />
|
||||||
|
|
||||||
<LicenseRequired>
|
<LicenseRequired>
|
||||||
<>
|
<>
|
||||||
{isLoading && <SkeletonLoader />}
|
{isLoading && <SkeletonLoader />}
|
||||||
<div>
|
<div>
|
||||||
{data?.length ? (
|
{isLoading ? null : data?.length ? (
|
||||||
<>
|
<>
|
||||||
<div className="mt-6 mb-8 rounded-md border">
|
<div className="mt-6 mb-8 rounded-md border">
|
||||||
{data?.map((apiKey, index) => (
|
{data.map((apiKey, index) => (
|
||||||
<ApiKeyListItem
|
<ApiKeyListItem
|
||||||
key={apiKey.id}
|
key={apiKey.id}
|
||||||
apiKey={apiKey}
|
apiKey={apiKey}
|
||||||
|
|||||||
@@ -165,7 +165,7 @@ const AppearanceView = () => {
|
|||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
/>
|
/>
|
||||||
<Button color="primary" className="mt-8">
|
<Button type="submit" color="primary" className="mt-8">
|
||||||
{t("update")}
|
{t("update")}
|
||||||
</Button>
|
</Button>
|
||||||
</Form>
|
</Form>
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ import { WEBAPP_URL } from "@calcom/lib/constants";
|
|||||||
import { useLocale } from "@calcom/lib/hooks/useLocale";
|
import { useLocale } from "@calcom/lib/hooks/useLocale";
|
||||||
import { trpc } from "@calcom/trpc/react";
|
import { trpc } from "@calcom/trpc/react";
|
||||||
import { Icon } from "@calcom/ui";
|
import { Icon } from "@calcom/ui";
|
||||||
|
import { Alert } from "@calcom/ui/v2";
|
||||||
import Badge from "@calcom/ui/v2/core/Badge";
|
import Badge from "@calcom/ui/v2/core/Badge";
|
||||||
import EmptyScreen from "@calcom/ui/v2/core/EmptyScreen";
|
import EmptyScreen from "@calcom/ui/v2/core/EmptyScreen";
|
||||||
import Meta from "@calcom/ui/v2/core/Meta";
|
import Meta from "@calcom/ui/v2/core/Meta";
|
||||||
@@ -23,7 +24,7 @@ import { CalendarSwitch } from "@components/v2/settings/CalendarSwitch";
|
|||||||
const SkeletonLoader = () => {
|
const SkeletonLoader = () => {
|
||||||
return (
|
return (
|
||||||
<SkeletonContainer>
|
<SkeletonContainer>
|
||||||
<div className="mt-6 mb-8 space-y-6 divide-y">
|
<div className="mt-6 mb-8 space-y-6">
|
||||||
<SkeletonText className="h-8 w-full" />
|
<SkeletonText className="h-8 w-full" />
|
||||||
<SkeletonText className="h-8 w-full" />
|
<SkeletonText className="h-8 w-full" />
|
||||||
<SkeletonText className="h-8 w-full" />
|
<SkeletonText className="h-8 w-full" />
|
||||||
@@ -89,7 +90,30 @@ const CalendarsView = () => {
|
|||||||
<List>
|
<List>
|
||||||
{data.connectedCalendars.map((item) => (
|
{data.connectedCalendars.map((item) => (
|
||||||
<Fragment key={item.credentialId}>
|
<Fragment key={item.credentialId}>
|
||||||
{item.calendars && (
|
{item.error && item.error.message && (
|
||||||
|
<Alert
|
||||||
|
severity="warning"
|
||||||
|
key={item.credentialId}
|
||||||
|
title={t("calendar_connection_fail")}
|
||||||
|
message={item.error.message}
|
||||||
|
className="mb-4 mt-4"
|
||||||
|
actions={
|
||||||
|
<>
|
||||||
|
{/* @TODO: add a reconnect button, that calls add api and delete old credential */}
|
||||||
|
<DisconnectIntegration
|
||||||
|
credentialId={item.credentialId}
|
||||||
|
trashIcon
|
||||||
|
onSuccess={() => query.refetch()}
|
||||||
|
buttonProps={{
|
||||||
|
className: "border border-gray-300 py-[2px]",
|
||||||
|
color: "secondary",
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</>
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
{item?.error === undefined && item.calendars && (
|
||||||
<ListItem expanded className="flex-col">
|
<ListItem expanded className="flex-col">
|
||||||
<div className="flex w-full flex-1 items-center space-x-3 pb-5 pl-1 pt-1 rtl:space-x-reverse">
|
<div className="flex w-full flex-1 items-center space-x-3 pb-5 pl-1 pt-1 rtl:space-x-reverse">
|
||||||
{
|
{
|
||||||
@@ -132,6 +156,7 @@ const CalendarsView = () => {
|
|||||||
externalId={cal.externalId}
|
externalId={cal.externalId}
|
||||||
title={cal.name || "Nameless calendar"}
|
title={cal.name || "Nameless calendar"}
|
||||||
type={item.integration.type}
|
type={item.integration.type}
|
||||||
|
isSelected={cal.isSelected}
|
||||||
defaultSelected={cal.externalId === data?.destinationCalendar?.externalId}
|
defaultSelected={cal.externalId === data?.destinationCalendar?.externalId}
|
||||||
/>
|
/>
|
||||||
))}
|
))}
|
||||||
@@ -153,6 +178,22 @@ const CalendarsView = () => {
|
|||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
}}
|
}}
|
||||||
|
error={() => {
|
||||||
|
return (
|
||||||
|
<Alert
|
||||||
|
message={
|
||||||
|
<Trans i18nKey="fetching_calendars_error">
|
||||||
|
An error ocurred while fetching your Calendars.
|
||||||
|
<a className="cursor-pointer underline" onClick={() => query.refetch()}>
|
||||||
|
try again
|
||||||
|
</a>
|
||||||
|
.
|
||||||
|
</Trans>
|
||||||
|
}
|
||||||
|
severity="error"
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}}
|
||||||
/>
|
/>
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -51,7 +51,7 @@ const ConferencingLayout = () => {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="w-full bg-white sm:mx-0 xl:mt-0">
|
<div className="w-full bg-white sm:mx-0 xl:mt-0">
|
||||||
<Meta title="conferencing" description="conferencing_description" />
|
<Meta title="Conferencing" description="Add your favourite video conferencing apps for your meetings" />
|
||||||
<List roundContainer={true}>
|
<List roundContainer={true}>
|
||||||
{apps?.items &&
|
{apps?.items &&
|
||||||
apps.items
|
apps.items
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ import { useMemo } from "react";
|
|||||||
import { useForm, Controller } from "react-hook-form";
|
import { useForm, Controller } from "react-hook-form";
|
||||||
|
|
||||||
import { useLocale } from "@calcom/lib/hooks/useLocale";
|
import { useLocale } from "@calcom/lib/hooks/useLocale";
|
||||||
|
import { setIs24hClockInLocalStorage } from "@calcom/lib/timeFormat";
|
||||||
import { trpc } from "@calcom/trpc/react";
|
import { trpc } from "@calcom/trpc/react";
|
||||||
import { Button } from "@calcom/ui/v2/core/Button";
|
import { Button } from "@calcom/ui/v2/core/Button";
|
||||||
import Meta from "@calcom/ui/v2/core/Meta";
|
import Meta from "@calcom/ui/v2/core/Meta";
|
||||||
@@ -35,7 +36,7 @@ interface GeneralViewProps {
|
|||||||
localeProp: string;
|
localeProp: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
const WithQuery = withQuery(["viewer.public.i18n"], { context: { skipBatch: true } });
|
const WithQuery = withQuery(["viewer.public.i18n"], { trpc: { context: { skipBatch: true } } });
|
||||||
|
|
||||||
const GeneralQueryView = () => {
|
const GeneralQueryView = () => {
|
||||||
return (
|
return (
|
||||||
@@ -110,6 +111,8 @@ const GeneralView = ({ localeProp }: GeneralViewProps) => {
|
|||||||
<Form
|
<Form
|
||||||
form={formMethods}
|
form={formMethods}
|
||||||
handleSubmit={(values) => {
|
handleSubmit={(values) => {
|
||||||
|
setIs24hClockInLocalStorage(values.timeFormat.value === 24);
|
||||||
|
|
||||||
mutation.mutate({
|
mutation.mutate({
|
||||||
...values,
|
...values,
|
||||||
locale: values.locale.value,
|
locale: values.locale.value,
|
||||||
@@ -188,7 +191,7 @@ const GeneralView = ({ localeProp }: GeneralViewProps) => {
|
|||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
/>
|
/>
|
||||||
<Button color="primary" className="mt-8">
|
<Button color="primary" type="submit" className="mt-8">
|
||||||
<>{t("update")}</>
|
<>{t("update")}</>
|
||||||
</Button>
|
</Button>
|
||||||
</Form>
|
</Form>
|
||||||
|
|||||||
@@ -1,9 +1,10 @@
|
|||||||
import crypto from "crypto";
|
import crypto from "crypto";
|
||||||
import { signOut } from "next-auth/react";
|
import { signOut } from "next-auth/react";
|
||||||
import { useRef, useState, BaseSyntheticEvent } from "react";
|
import { useRef, useState, BaseSyntheticEvent, useEffect } from "react";
|
||||||
import { Controller, useForm } from "react-hook-form";
|
import { Controller, useForm } from "react-hook-form";
|
||||||
|
|
||||||
import { ErrorCode } from "@calcom/lib/auth";
|
import { ErrorCode } from "@calcom/lib/auth";
|
||||||
|
import { WEBSITE_URL } from "@calcom/lib/constants";
|
||||||
import { useLocale } from "@calcom/lib/hooks/useLocale";
|
import { useLocale } from "@calcom/lib/hooks/useLocale";
|
||||||
import { TRPCClientErrorLike } from "@calcom/trpc/client";
|
import { TRPCClientErrorLike } from "@calcom/trpc/client";
|
||||||
import { trpc } from "@calcom/trpc/react";
|
import { trpc } from "@calcom/trpc/react";
|
||||||
@@ -21,6 +22,7 @@ import showToast from "@calcom/ui/v2/core/notifications";
|
|||||||
import { SkeletonContainer, SkeletonText, SkeletonButton, SkeletonAvatar } from "@calcom/ui/v2/core/skeleton";
|
import { SkeletonContainer, SkeletonText, SkeletonButton, SkeletonAvatar } from "@calcom/ui/v2/core/skeleton";
|
||||||
|
|
||||||
import TwoFactor from "@components/auth/TwoFactor";
|
import TwoFactor from "@components/auth/TwoFactor";
|
||||||
|
import { UsernameAvailability } from "@components/ui/UsernameAvailability";
|
||||||
|
|
||||||
const SkeletonLoader = () => {
|
const SkeletonLoader = () => {
|
||||||
return (
|
return (
|
||||||
@@ -47,6 +49,7 @@ interface DeleteAccountValues {
|
|||||||
const ProfileView = () => {
|
const ProfileView = () => {
|
||||||
const { t } = useLocale();
|
const { t } = useLocale();
|
||||||
const utils = trpc.useContext();
|
const utils = trpc.useContext();
|
||||||
|
const usernameRef = useRef<HTMLInputElement>(null);
|
||||||
|
|
||||||
const { data: user, isLoading } = trpc.useQuery(["viewer.me"]);
|
const { data: user, isLoading } = trpc.useQuery(["viewer.me"]);
|
||||||
const mutation = trpc.useMutation("viewer.updateProfile", {
|
const mutation = trpc.useMutation("viewer.updateProfile", {
|
||||||
@@ -58,10 +61,16 @@ const ProfileView = () => {
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const [confirmPasswordOpen, setConfirmPasswordOpen] = useState(false);
|
||||||
|
const [confirmPasswordErrorMessage, setConfirmPasswordDeleteErrorMessage] = useState("");
|
||||||
const [deleteAccountOpen, setDeleteAccountOpen] = useState(false);
|
const [deleteAccountOpen, setDeleteAccountOpen] = useState(false);
|
||||||
const [hasDeleteErrors, setHasDeleteErrors] = useState(false);
|
const [hasDeleteErrors, setHasDeleteErrors] = useState(false);
|
||||||
const [deleteErrorMessage, setDeleteErrorMessage] = useState("");
|
const [deleteErrorMessage, setDeleteErrorMessage] = useState("");
|
||||||
|
const [currentUsername, setCurrentUsername] = useState<string | undefined>(user?.username || undefined);
|
||||||
|
const [inputUsernameValue, setInputUsernameValue] = useState(currentUsername);
|
||||||
|
useEffect(() => {
|
||||||
|
if (user?.username) setCurrentUsername(user?.username);
|
||||||
|
}, [user?.username]);
|
||||||
const form = useForm<DeleteAccountValues>();
|
const form = useForm<DeleteAccountValues>();
|
||||||
|
|
||||||
const emailMd5 = crypto
|
const emailMd5 = crypto
|
||||||
@@ -81,6 +90,16 @@ const ProfileView = () => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const confirmPasswordMutation = trpc.useMutation("viewer.auth.verifyPassword", {
|
||||||
|
onSuccess() {
|
||||||
|
mutation.mutate(formMethods.getValues());
|
||||||
|
setConfirmPasswordOpen(false);
|
||||||
|
},
|
||||||
|
onError() {
|
||||||
|
setConfirmPasswordDeleteErrorMessage(t("incorrect_password"));
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
const onDeleteMeErrorMutation = (error: TRPCClientErrorLike<AppRouter>) => {
|
const onDeleteMeErrorMutation = (error: TRPCClientErrorLike<AppRouter>) => {
|
||||||
setHasDeleteErrors(true);
|
setHasDeleteErrors(true);
|
||||||
setDeleteErrorMessage(errorMessages[error.message]);
|
setDeleteErrorMessage(errorMessages[error.message]);
|
||||||
@@ -93,6 +112,12 @@ const ProfileView = () => {
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const onConfirmPassword = (e: Event | React.MouseEvent<HTMLElement, MouseEvent>) => {
|
||||||
|
e.preventDefault();
|
||||||
|
const password = passwordRef.current.value;
|
||||||
|
confirmPasswordMutation.mutate({ passwordInput: password });
|
||||||
|
};
|
||||||
|
|
||||||
const onConfirmButton = (e: Event | React.MouseEvent<HTMLElement, MouseEvent>) => {
|
const onConfirmButton = (e: Event | React.MouseEvent<HTMLElement, MouseEvent>) => {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
const totpCode = form.getValues("totpCode");
|
const totpCode = form.getValues("totpCode");
|
||||||
@@ -105,15 +130,26 @@ const ProfileView = () => {
|
|||||||
deleteMeMutation.mutate({ password, totpCode });
|
deleteMeMutation.mutate({ password, totpCode });
|
||||||
};
|
};
|
||||||
|
|
||||||
const formMethods = useForm({
|
const formMethods = useForm<{
|
||||||
defaultValues: {
|
avatar?: string;
|
||||||
|
username?: string;
|
||||||
|
name?: string;
|
||||||
|
email?: string;
|
||||||
|
bio?: string;
|
||||||
|
}>();
|
||||||
|
|
||||||
|
const { reset } = formMethods;
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (user)
|
||||||
|
reset({
|
||||||
avatar: user?.avatar || "",
|
avatar: user?.avatar || "",
|
||||||
username: user?.username || "",
|
username: user?.username || "",
|
||||||
name: user?.name || "",
|
name: user?.name || "",
|
||||||
email: user?.email || "",
|
email: user?.email || "",
|
||||||
bio: user?.bio || "",
|
bio: user?.bio || "",
|
||||||
},
|
|
||||||
});
|
});
|
||||||
|
}, [reset, user]);
|
||||||
|
|
||||||
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
||||||
const passwordRef = useRef<HTMLInputElement>(null!);
|
const passwordRef = useRef<HTMLInputElement>(null!);
|
||||||
@@ -126,15 +162,27 @@ const ProfileView = () => {
|
|||||||
[ErrorCode.InternalServerError]: `${t("something_went_wrong")} ${t("please_try_again_and_contact_us")}`,
|
[ErrorCode.InternalServerError]: `${t("something_went_wrong")} ${t("please_try_again_and_contact_us")}`,
|
||||||
[ErrorCode.ThirdPartyIdentityProviderEnabled]: t("account_created_with_identity_provider"),
|
[ErrorCode.ThirdPartyIdentityProviderEnabled]: t("account_created_with_identity_provider"),
|
||||||
};
|
};
|
||||||
|
const onSuccessfulUsernameUpdate = async () => {
|
||||||
|
showToast(t("settings_updated_successfully"), "success");
|
||||||
|
await utils.invalidateQueries(["viewer.me"]);
|
||||||
|
};
|
||||||
|
|
||||||
if (isLoading) return <SkeletonLoader />;
|
const onErrorInUsernameUpdate = () => {
|
||||||
|
showToast(t("error_updating_settings"), "error");
|
||||||
|
};
|
||||||
|
|
||||||
|
if (isLoading || !user) return <SkeletonLoader />;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<Form
|
<Form
|
||||||
form={formMethods}
|
form={formMethods}
|
||||||
handleSubmit={(values) => {
|
handleSubmit={(values) => {
|
||||||
|
if (values.email !== user?.email) {
|
||||||
|
setConfirmPasswordOpen(true);
|
||||||
|
} else {
|
||||||
mutation.mutate(values);
|
mutation.mutate(values);
|
||||||
|
}
|
||||||
}}>
|
}}>
|
||||||
<Meta title="Profile" description="Manage settings for your cal profile" />
|
<Meta title="Profile" description="Manage settings for your cal profile" />
|
||||||
<div className="flex items-center">
|
<div className="flex items-center">
|
||||||
@@ -159,73 +207,28 @@ const ProfileView = () => {
|
|||||||
)}
|
)}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<Controller
|
|
||||||
control={formMethods.control}
|
|
||||||
name="username"
|
|
||||||
render={({ field: { value } }) => (
|
|
||||||
<div className="mt-8">
|
<div className="mt-8">
|
||||||
<TextField
|
<UsernameAvailability
|
||||||
data-testid="username-input"
|
currentUsername={currentUsername}
|
||||||
name="username"
|
setCurrentUsername={setCurrentUsername}
|
||||||
label={t("personal_cal_url")}
|
inputUsernameValue={inputUsernameValue}
|
||||||
addOnLeading="https://cal.com/"
|
usernameRef={usernameRef}
|
||||||
value={value}
|
setInputUsernameValue={setInputUsernameValue}
|
||||||
onChange={(e) => {
|
onSuccessMutation={onSuccessfulUsernameUpdate}
|
||||||
formMethods.setValue("username", e?.target.value);
|
onErrorMutation={onErrorInUsernameUpdate}
|
||||||
}}
|
user={user}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
)}
|
|
||||||
/>
|
|
||||||
<Controller
|
|
||||||
control={formMethods.control}
|
|
||||||
name="name"
|
|
||||||
render={({ field: { value, onChange } }) => (
|
|
||||||
<div className="mt-8">
|
<div className="mt-8">
|
||||||
<TextField
|
<TextField label={t("full_name")} {...formMethods.register("name")} />
|
||||||
label={t("full_name")}
|
|
||||||
value={value}
|
|
||||||
onChange={(e) => {
|
|
||||||
onChange(e?.target.value);
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
</div>
|
</div>
|
||||||
)}
|
|
||||||
/>
|
|
||||||
<Controller
|
|
||||||
control={formMethods.control}
|
|
||||||
name="email"
|
|
||||||
render={({ field: { value } }) => (
|
|
||||||
<div className="mt-8">
|
<div className="mt-8">
|
||||||
<TextField
|
<TextField label={t("email")} hint={t("change_email_hint")} {...formMethods.register("email")} />
|
||||||
name="email"
|
|
||||||
label={t("email")}
|
|
||||||
value={value}
|
|
||||||
hint={t("change_email_hint")}
|
|
||||||
onChange={(e) => {
|
|
||||||
formMethods.setValue("email", e?.target.value);
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
</div>
|
</div>
|
||||||
)}
|
|
||||||
/>
|
|
||||||
<Controller
|
|
||||||
control={formMethods.control}
|
|
||||||
name="bio"
|
|
||||||
render={({ field: { value } }) => (
|
|
||||||
<div className="mt-8">
|
<div className="mt-8">
|
||||||
<TextField
|
<TextField label={t("about")} hint={t("bio_hint")} {...formMethods.register("bio")} />
|
||||||
name="bio"
|
|
||||||
label={t("about")}
|
|
||||||
hint={t("bio_hint")}
|
|
||||||
value={value}
|
|
||||||
onChange={(e) => {
|
|
||||||
formMethods.setValue("bio", e?.target.value);
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
</div>
|
</div>
|
||||||
)}
|
|
||||||
/>
|
|
||||||
<Button color="primary" className="mt-8" type="submit" loading={mutation.isLoading}>
|
<Button color="primary" className="mt-8" type="submit" loading={mutation.isLoading}>
|
||||||
{t("update")}
|
{t("update")}
|
||||||
</Button>
|
</Button>
|
||||||
@@ -279,6 +282,32 @@ const ProfileView = () => {
|
|||||||
</DialogContent>
|
</DialogContent>
|
||||||
</Dialog>
|
</Dialog>
|
||||||
</Form>
|
</Form>
|
||||||
|
|
||||||
|
{/* If changing email, confirm password */}
|
||||||
|
<Dialog open={confirmPasswordOpen} onOpenChange={setConfirmPasswordOpen}>
|
||||||
|
<DialogContent
|
||||||
|
title={t("confirm_password")}
|
||||||
|
description={t("confirm_password_change_email")}
|
||||||
|
type="creation"
|
||||||
|
actionText={t("confirm")}
|
||||||
|
Icon={Icon.FiAlertTriangle}
|
||||||
|
actionOnClick={(e) => e && onConfirmPassword(e)}>
|
||||||
|
<>
|
||||||
|
<PasswordField
|
||||||
|
data-testid="password"
|
||||||
|
name="password"
|
||||||
|
id="password"
|
||||||
|
type="password"
|
||||||
|
autoComplete="current-password"
|
||||||
|
required
|
||||||
|
label="Password"
|
||||||
|
ref={passwordRef}
|
||||||
|
/>
|
||||||
|
|
||||||
|
{confirmPasswordErrorMessage && <Alert severity="error" title={confirmPasswordErrorMessage} />}
|
||||||
|
</>
|
||||||
|
</DialogContent>
|
||||||
|
</Dialog>
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ import { useLocale } from "@calcom/lib/hooks/useLocale";
|
|||||||
import { trpc } from "@calcom/trpc/react";
|
import { trpc } from "@calcom/trpc/react";
|
||||||
import Button from "@calcom/ui/v2/core/Button";
|
import Button from "@calcom/ui/v2/core/Button";
|
||||||
import Meta from "@calcom/ui/v2/core/Meta";
|
import Meta from "@calcom/ui/v2/core/Meta";
|
||||||
import { Form, TextField } from "@calcom/ui/v2/core/form/fields";
|
import { Form, PasswordField } from "@calcom/ui/v2/core/form/fields";
|
||||||
import { getLayout } from "@calcom/ui/v2/core/layouts/SettingsLayout";
|
import { getLayout } from "@calcom/ui/v2/core/layouts/SettingsLayout";
|
||||||
import showToast from "@calcom/ui/v2/core/notifications";
|
import showToast from "@calcom/ui/v2/core/notifications";
|
||||||
|
|
||||||
@@ -48,7 +48,7 @@ const PasswordView = () => {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<Meta title="Password" description="Manage settings for your account passwords" />
|
<Meta title={t("password")} description={t("password_description")} />
|
||||||
{user && user.identityProvider !== IdentityProvider.CAL ? (
|
{user && user.identityProvider !== IdentityProvider.CAL ? (
|
||||||
<div>
|
<div>
|
||||||
<div className="mt-6">
|
<div className="mt-6">
|
||||||
@@ -65,22 +65,17 @@ const PasswordView = () => {
|
|||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
) : (
|
) : (
|
||||||
<Form<ChangePasswordFormValues> form={formMethods} handleSubmit={handleSubmit}>
|
<Form form={formMethods} handleSubmit={handleSubmit}>
|
||||||
<div className="max-w-[38rem] sm:flex sm:space-x-4">
|
<div className="max-w-[38rem] sm:flex sm:space-x-4">
|
||||||
<div className="flex-grow">
|
<div className="flex-grow">
|
||||||
<TextField {...register("oldPassword")} label={t("old_password")} type="password" />
|
<PasswordField {...register("oldPassword")} label={t("old_password")} />
|
||||||
</div>
|
</div>
|
||||||
<div className="flex-grow">
|
<div className="flex-grow">
|
||||||
<TextField
|
<PasswordField {...register("newPassword")} label={t("new_password")} />
|
||||||
{...register("newPassword")}
|
|
||||||
label={t("new_password")}
|
|
||||||
type="password"
|
|
||||||
placeholder={t("secure_password")}
|
|
||||||
/>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<p className="text-sm text-gray-600">
|
<p className="text-sm text-gray-600">
|
||||||
<Trans i18nKey="valid_password">
|
<Trans i18nKey="invalid_password_hint">
|
||||||
Password must be at least at least 7 characters, mix of uppercase & lowercase letters, and
|
Password must be at least at least 7 characters, mix of uppercase & lowercase letters, and
|
||||||
contain at least 1 number
|
contain at least 1 number
|
||||||
</Trans>
|
</Trans>
|
||||||
@@ -89,8 +84,8 @@ const PasswordView = () => {
|
|||||||
<Button
|
<Button
|
||||||
color="primary"
|
color="primary"
|
||||||
className="mt-8"
|
className="mt-8"
|
||||||
disabled={isSubmitting || mutation.isLoading}
|
type="submit"
|
||||||
onClick={() => handleSubmit(formMethods.getValues())}>
|
disabled={isSubmitting || mutation.isLoading}>
|
||||||
{t("update")}
|
{t("update")}
|
||||||
</Button>
|
</Button>
|
||||||
</Form>
|
</Form>
|
||||||
|
|||||||
@@ -69,10 +69,9 @@ const CreateNewTeamPage = () => {
|
|||||||
data-testid="onboarding"
|
data-testid="onboarding"
|
||||||
key={router.asPath}>
|
key={router.asPath}>
|
||||||
<Head>
|
<Head>
|
||||||
<title>{t("create_new_team")}</title>
|
<title>Create a new Team</title>
|
||||||
<link rel="icon" href="/favicon.ico" />
|
<link rel="icon" href="/favicon.ico" />
|
||||||
</Head>
|
</Head>
|
||||||
|
|
||||||
<div className="mx-auto px-4 py-24">
|
<div className="mx-auto px-4 py-24">
|
||||||
<div className="relative">
|
<div className="relative">
|
||||||
<div className="sm:mx-auto sm:w-full sm:max-w-[600px]">
|
<div className="sm:mx-auto sm:w-full sm:max-w-[600px]">
|
||||||
|
|||||||
@@ -26,7 +26,7 @@ import { useLocale } from "@calcom/lib/hooks/useLocale";
|
|||||||
import useTheme from "@calcom/lib/hooks/useTheme";
|
import useTheme from "@calcom/lib/hooks/useTheme";
|
||||||
import { getEveryFreqFor } from "@calcom/lib/recurringStrings";
|
import { getEveryFreqFor } from "@calcom/lib/recurringStrings";
|
||||||
import { collectPageParameters, telemetryEventTypes, useTelemetry } from "@calcom/lib/telemetry";
|
import { collectPageParameters, telemetryEventTypes, useTelemetry } from "@calcom/lib/telemetry";
|
||||||
import { isBrowserLocale24h } from "@calcom/lib/timeFormat";
|
import { getIs24hClockFromLocalStorage, isBrowserLocale24h } from "@calcom/lib/timeFormat";
|
||||||
import { localStorage } from "@calcom/lib/webstorage";
|
import { localStorage } from "@calcom/lib/webstorage";
|
||||||
import prisma from "@calcom/prisma";
|
import prisma from "@calcom/prisma";
|
||||||
import Button from "@calcom/ui/Button";
|
import Button from "@calcom/ui/Button";
|
||||||
@@ -201,7 +201,7 @@ export default function Success(props: SuccessProps) {
|
|||||||
// TODO: Add payment details
|
// TODO: Add payment details
|
||||||
});
|
});
|
||||||
setDate(date.tz(localStorage.getItem("timeOption.preferredTimeZone") || dayjs.tz.guess()));
|
setDate(date.tz(localStorage.getItem("timeOption.preferredTimeZone") || dayjs.tz.guess()));
|
||||||
setIs24h(!!localStorage.getItem("timeOption.is24hClock"));
|
setIs24h(!!getIs24hClockFromLocalStorage());
|
||||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||||
}, [eventType, needsConfirmation]);
|
}, [eventType, needsConfirmation]);
|
||||||
|
|
||||||
@@ -263,7 +263,7 @@ export default function Success(props: SuccessProps) {
|
|||||||
{userIsOwner && !isEmbed && (
|
{userIsOwner && !isEmbed && (
|
||||||
<div className="mt-2 ml-4 -mb-4">
|
<div className="mt-2 ml-4 -mb-4">
|
||||||
<Link href={eventType.recurringEvent?.count ? "/bookings/recurring" : "/bookings/upcoming"}>
|
<Link href={eventType.recurringEvent?.count ? "/bookings/recurring" : "/bookings/upcoming"}>
|
||||||
<a className="mt-2 inline-flex px-1 py-2 text-sm text-gray-500 hover:bg-gray-100 hover:text-gray-800">
|
<a className="mt-2 inline-flex px-1 py-2 text-sm text-gray-500 hover:bg-gray-100 hover:text-gray-800 dark:hover:bg-transparent dark:hover:text-white">
|
||||||
<Icon.FiChevronLeft className="h-5 w-5" /> {t("back_to_bookings")}
|
<Icon.FiChevronLeft className="h-5 w-5" /> {t("back_to_bookings")}
|
||||||
</a>
|
</a>
|
||||||
</Link>
|
</Link>
|
||||||
@@ -411,7 +411,7 @@ export default function Success(props: SuccessProps) {
|
|||||||
!isCancelled &&
|
!isCancelled &&
|
||||||
(!isCancellationMode ? (
|
(!isCancellationMode ? (
|
||||||
<>
|
<>
|
||||||
<hr className="border-bookinglightest" />
|
<hr className="border-bookinglightest dark:border-darkgray-300" />
|
||||||
<div className="py-8 text-center last:pb-0">
|
<div className="py-8 text-center last:pb-0">
|
||||||
<span className="text-gray-900 ltr:mr-2 rtl:ml-2 dark:text-gray-50">
|
<span className="text-gray-900 ltr:mr-2 rtl:ml-2 dark:text-gray-50">
|
||||||
{t("need_to_make_a_change")}
|
{t("need_to_make_a_change")}
|
||||||
@@ -448,7 +448,7 @@ export default function Success(props: SuccessProps) {
|
|||||||
))}
|
))}
|
||||||
{userIsOwner && !needsConfirmation && !isCancellationMode && !isCancelled && (
|
{userIsOwner && !needsConfirmation && !isCancellationMode && !isCancelled && (
|
||||||
<>
|
<>
|
||||||
<hr className="border-bookinglightest" />
|
<hr className="border-bookinglightest dark:border-darkgray-300" />
|
||||||
<div className="text-bookingdark align-center flex flex-row justify-center pt-8">
|
<div className="text-bookingdark align-center flex flex-row justify-center pt-8">
|
||||||
<span className="flex self-center font-medium text-gray-700 ltr:mr-2 rtl:ml-2 dark:text-gray-50">
|
<span className="flex self-center font-medium text-gray-700 ltr:mr-2 rtl:ml-2 dark:text-gray-50">
|
||||||
{t("add_to_calendar")}
|
{t("add_to_calendar")}
|
||||||
|
|||||||
@@ -0,0 +1,72 @@
|
|||||||
|
import { useState } from "react";
|
||||||
|
|
||||||
|
import { useLocale } from "@calcom/lib/hooks/useLocale";
|
||||||
|
import { trpc } from "@calcom/trpc/react";
|
||||||
|
import { Icon } from "@calcom/ui/Icon";
|
||||||
|
import { Shell } from "@calcom/ui/v2";
|
||||||
|
import { Alert } from "@calcom/ui/v2/core/Alert";
|
||||||
|
import Button from "@calcom/ui/v2/core/Button";
|
||||||
|
import EmptyScreen from "@calcom/ui/v2/core/EmptyScreen";
|
||||||
|
|
||||||
|
import SkeletonLoaderTeamList from "@components/team/SkeletonloaderTeamList";
|
||||||
|
import TeamCreateModal from "@components/team/TeamCreateModal";
|
||||||
|
import TeamList from "@components/team/TeamList";
|
||||||
|
|
||||||
|
function Teams() {
|
||||||
|
const { t } = useLocale();
|
||||||
|
const [showCreateTeamModal, setShowCreateTeamModal] = useState(false);
|
||||||
|
const [errorMessage, setErrorMessage] = useState("");
|
||||||
|
|
||||||
|
const { data, isLoading } = trpc.useQuery(["viewer.teams.list"], {
|
||||||
|
onError: (e) => {
|
||||||
|
setErrorMessage(e.message);
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
const teams = data?.filter((m) => m.accepted) || [];
|
||||||
|
const invites = data?.filter((m) => !m.accepted) || [];
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Shell
|
||||||
|
heading={t("teams")}
|
||||||
|
subtitle={t("create_manage_teams_collaborative")}
|
||||||
|
CTA={
|
||||||
|
<Button type="button" onClick={() => setShowCreateTeamModal(true)}>
|
||||||
|
<Icon.FiPlus className="inline-block h-3.5 w-3.5 text-white group-hover:text-black ltr:mr-2 rtl:ml-2" />
|
||||||
|
{t("new")}
|
||||||
|
</Button>
|
||||||
|
}>
|
||||||
|
<>
|
||||||
|
{!!errorMessage && <Alert severity="error" title={errorMessage} />}
|
||||||
|
{showCreateTeamModal && (
|
||||||
|
<TeamCreateModal isOpen={showCreateTeamModal} onClose={() => setShowCreateTeamModal(false)} />
|
||||||
|
)}
|
||||||
|
{invites.length > 0 && (
|
||||||
|
<div className="mb-4">
|
||||||
|
<h1 className="mb-2 text-lg font-medium">{t("open_invitations")}</h1>
|
||||||
|
<TeamList teams={invites} />
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
{isLoading && <SkeletonLoaderTeamList />}
|
||||||
|
{!teams.length && !isLoading && (
|
||||||
|
<EmptyScreen
|
||||||
|
Icon={Icon.FiUsers}
|
||||||
|
headline={t("no_teams")}
|
||||||
|
description={t("no_teams_description")}
|
||||||
|
buttonRaw={
|
||||||
|
<Button color="secondary" onClick={() => setShowCreateTeamModal(true)}>
|
||||||
|
{t("create_team")}
|
||||||
|
</Button>
|
||||||
|
}
|
||||||
|
buttonOnClick={() => setShowCreateTeamModal(true)}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
{teams.length > 0 && <TeamList teams={teams} />}
|
||||||
|
</>
|
||||||
|
</Shell>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Teams.requiresLicense = false;
|
||||||
|
|
||||||
|
export default Teams;
|
||||||
@@ -35,10 +35,10 @@ test.describe("Change username on settings", () => {
|
|||||||
const usernameInput = page.locator("[data-testid=username-input]");
|
const usernameInput = page.locator("[data-testid=username-input]");
|
||||||
|
|
||||||
await usernameInput.fill("demousernamex");
|
await usernameInput.fill("demousernamex");
|
||||||
|
await page.click("[data-testid=update-username-btn]");
|
||||||
await Promise.all([
|
await Promise.all([
|
||||||
|
page.click("[data-testid=save-username]"),
|
||||||
page.waitForResponse("**/viewer.updateProfile*"),
|
page.waitForResponse("**/viewer.updateProfile*"),
|
||||||
page.click('button[type="submit"]'),
|
|
||||||
]);
|
]);
|
||||||
|
|
||||||
const newUpdatedUser = await prisma.user.findUniqueOrThrow({
|
const newUpdatedUser = await prisma.user.findUniqueOrThrow({
|
||||||
|
|||||||
@@ -2,13 +2,8 @@ import { expect, Page } from "@playwright/test";
|
|||||||
|
|
||||||
import { test } from "./lib/fixtures";
|
import { test } from "./lib/fixtures";
|
||||||
|
|
||||||
// these tests need rewrite
|
function chooseEmbedType(page: Page, embedType: string) {
|
||||||
// eslint-disable-next-line playwright/no-skipped-test
|
page.locator(`[data-testid=${embedType}]`).click();
|
||||||
test.skip();
|
|
||||||
|
|
||||||
async function chooseEmbedType(page: Page, embedType: string) {
|
|
||||||
const $embedTypeSelector = await page.locator(`[data-testid=${embedType}]`);
|
|
||||||
$embedTypeSelector.click();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async function gotToPreviewTab(page: Page) {
|
async function gotToPreviewTab(page: Page) {
|
||||||
@@ -111,7 +106,7 @@ test.describe("Embed Code Generator Tests", () => {
|
|||||||
basePage: "/event-types",
|
basePage: "/event-types",
|
||||||
});
|
});
|
||||||
|
|
||||||
await chooseEmbedType(page, "inline");
|
chooseEmbedType(page, "inline");
|
||||||
|
|
||||||
await expectToBeNavigatingToEmbedCodeAndPreviewDialog(page, {
|
await expectToBeNavigatingToEmbedCodeAndPreviewDialog(page, {
|
||||||
embedUrl,
|
embedUrl,
|
||||||
@@ -119,19 +114,18 @@ test.describe("Embed Code Generator Tests", () => {
|
|||||||
basePage: "/event-types",
|
basePage: "/event-types",
|
||||||
});
|
});
|
||||||
|
|
||||||
/*await expectToContainValidCode(page, { embedType: "inline" });
|
await expectToContainValidCode(page, { embedType: "inline" });
|
||||||
|
|
||||||
await gotToPreviewTab(page);
|
await gotToPreviewTab(page);
|
||||||
|
|
||||||
await expectToContainValidPreviewIframe(page, {
|
await expectToContainValidPreviewIframe(page, {
|
||||||
embedType: "inline",
|
embedType: "inline",
|
||||||
calLink: `${pro.username}/30-min`,
|
calLink: `${pro.username}/30-min`,
|
||||||
});*/
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
test("open Embed Dialog and choose floating-popup for First Event Type", async ({ page, users }) => {
|
test("open Embed Dialog and choose floating-popup for First Event Type", async ({ page, users }) => {
|
||||||
const [pro] = users.get();
|
const [pro] = users.get();
|
||||||
|
|
||||||
const embedUrl = await clickFirstEventTypeEmbedButton(page);
|
const embedUrl = await clickFirstEventTypeEmbedButton(page);
|
||||||
|
|
||||||
await expectToBeNavigatingToEmbedTypesDialog(page, {
|
await expectToBeNavigatingToEmbedTypesDialog(page, {
|
||||||
@@ -139,20 +133,20 @@ test.describe("Embed Code Generator Tests", () => {
|
|||||||
basePage: "/event-types",
|
basePage: "/event-types",
|
||||||
});
|
});
|
||||||
|
|
||||||
await chooseEmbedType(page, "floating-popup");
|
chooseEmbedType(page, "floating-popup");
|
||||||
|
|
||||||
await expectToBeNavigatingToEmbedCodeAndPreviewDialog(page, {
|
await expectToBeNavigatingToEmbedCodeAndPreviewDialog(page, {
|
||||||
embedUrl,
|
embedUrl,
|
||||||
embedType: "floating-popup",
|
embedType: "floating-popup",
|
||||||
basePage: "/event-types",
|
basePage: "/event-types",
|
||||||
});
|
});
|
||||||
/*await expectToContainValidCode(page, { embedType: "floating-popup" });
|
await expectToContainValidCode(page, { embedType: "floating-popup" });
|
||||||
|
|
||||||
await gotToPreviewTab(page);
|
await gotToPreviewTab(page);
|
||||||
await expectToContainValidPreviewIframe(page, {
|
await expectToContainValidPreviewIframe(page, {
|
||||||
embedType: "floating-popup",
|
embedType: "floating-popup",
|
||||||
calLink: `${pro.username}/30-min`,
|
calLink: `${pro.username}/30-min`,
|
||||||
});*/
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
test("open Embed Dialog and choose element-click for First Event Type", async ({ page, users }) => {
|
test("open Embed Dialog and choose element-click for First Event Type", async ({ page, users }) => {
|
||||||
@@ -164,20 +158,20 @@ test.describe("Embed Code Generator Tests", () => {
|
|||||||
basePage: "/event-types",
|
basePage: "/event-types",
|
||||||
});
|
});
|
||||||
|
|
||||||
await chooseEmbedType(page, "element-click");
|
chooseEmbedType(page, "element-click");
|
||||||
|
|
||||||
await expectToBeNavigatingToEmbedCodeAndPreviewDialog(page, {
|
await expectToBeNavigatingToEmbedCodeAndPreviewDialog(page, {
|
||||||
embedUrl,
|
embedUrl,
|
||||||
embedType: "element-click",
|
embedType: "element-click",
|
||||||
basePage: "/event-types",
|
basePage: "/event-types",
|
||||||
});
|
});
|
||||||
/*await expectToContainValidCode(page, { embedType: "element-click" });
|
await expectToContainValidCode(page, { embedType: "element-click" });
|
||||||
|
|
||||||
await gotToPreviewTab(page);
|
await gotToPreviewTab(page);
|
||||||
await expectToContainValidPreviewIframe(page, {
|
await expectToContainValidPreviewIframe(page, {
|
||||||
embedType: "element-click",
|
embedType: "element-click",
|
||||||
calLink: `${pro.username}/30-min`,
|
calLink: `${pro.username}/30-min`,
|
||||||
});*/
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -200,7 +194,7 @@ test.describe("Embed Code Generator Tests", () => {
|
|||||||
basePage,
|
basePage,
|
||||||
});
|
});
|
||||||
|
|
||||||
await chooseEmbedType(page, "inline");
|
chooseEmbedType(page, "inline");
|
||||||
|
|
||||||
await expectToBeNavigatingToEmbedCodeAndPreviewDialog(page, {
|
await expectToBeNavigatingToEmbedCodeAndPreviewDialog(page, {
|
||||||
embedUrl,
|
embedUrl,
|
||||||
@@ -208,7 +202,7 @@ test.describe("Embed Code Generator Tests", () => {
|
|||||||
embedType: "inline",
|
embedType: "inline",
|
||||||
});
|
});
|
||||||
|
|
||||||
/*await expectToContainValidCode(page, {
|
await expectToContainValidCode(page, {
|
||||||
embedType: "inline",
|
embedType: "inline",
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -217,7 +211,7 @@ test.describe("Embed Code Generator Tests", () => {
|
|||||||
await expectToContainValidPreviewIframe(page, {
|
await expectToContainValidPreviewIframe(page, {
|
||||||
embedType: "inline",
|
embedType: "inline",
|
||||||
calLink: decodeURIComponent(embedUrl),
|
calLink: decodeURIComponent(embedUrl),
|
||||||
});*/
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@@ -1,5 +1,7 @@
|
|||||||
import { expect } from "@playwright/test";
|
import { expect } from "@playwright/test";
|
||||||
|
|
||||||
|
import { WEBAPP_URL } from "@calcom/lib/constants";
|
||||||
|
|
||||||
import { randomString } from "../lib/random";
|
import { randomString } from "../lib/random";
|
||||||
import { test } from "./lib/fixtures";
|
import { test } from "./lib/fixtures";
|
||||||
|
|
||||||
@@ -87,7 +89,7 @@ test.describe("Event Types tests", () => {
|
|||||||
);
|
);
|
||||||
const href = await firstElement.getAttribute("href");
|
const href = await firstElement.getAttribute("href");
|
||||||
if (!href) throw new Error("No href found for event type");
|
if (!href) throw new Error("No href found for event type");
|
||||||
const [eventTypeId] = href.split("/").reverse();
|
const [eventTypeId] = new URL(WEBAPP_URL + href).pathname.split("/").reverse();
|
||||||
const firstTitle = await page.locator(`[data-testid=event-type-title-${eventTypeId}]`).innerText();
|
const firstTitle = await page.locator(`[data-testid=event-type-title-${eventTypeId}]`).innerText();
|
||||||
const firstFullSlug = await page.locator(`[data-testid=event-type-slug-${eventTypeId}]`).innerText();
|
const firstFullSlug = await page.locator(`[data-testid=event-type-slug-${eventTypeId}]`).innerText();
|
||||||
const firstSlug = firstFullSlug.split("/")[2];
|
const firstSlug = firstFullSlug.split("/")[2];
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ import type Prisma from "@prisma/client";
|
|||||||
import { Prisma as PrismaType, UserPlan } from "@prisma/client";
|
import { Prisma as PrismaType, UserPlan } from "@prisma/client";
|
||||||
import { hash } from "bcryptjs";
|
import { hash } from "bcryptjs";
|
||||||
|
|
||||||
|
import dayjs from "@calcom/dayjs";
|
||||||
import { DEFAULT_SCHEDULE, getAvailabilityFromSchedule } from "@calcom/lib/availability";
|
import { DEFAULT_SCHEDULE, getAvailabilityFromSchedule } from "@calcom/lib/availability";
|
||||||
import { prisma } from "@calcom/prisma";
|
import { prisma } from "@calcom/prisma";
|
||||||
|
|
||||||
@@ -257,7 +258,7 @@ const createUser = async (
|
|||||||
password: await hashPassword(uname),
|
password: await hashPassword(uname),
|
||||||
emailVerified: new Date(),
|
emailVerified: new Date(),
|
||||||
completedOnboarding: opts?.completedOnboarding ?? true,
|
completedOnboarding: opts?.completedOnboarding ?? true,
|
||||||
timeZone: opts?.timeZone ?? TimeZoneEnum.UK,
|
timeZone: opts?.timeZone ?? dayjs.tz.guess(),
|
||||||
locale: opts?.locale ?? "en",
|
locale: opts?.locale ?? "en",
|
||||||
schedules:
|
schedules:
|
||||||
opts?.completedOnboarding ?? true
|
opts?.completedOnboarding ?? true
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ import { v4 as uuidv4 } from "uuid";
|
|||||||
import { prisma } from "@calcom/prisma";
|
import { prisma } from "@calcom/prisma";
|
||||||
|
|
||||||
import { test } from "./lib/fixtures";
|
import { test } from "./lib/fixtures";
|
||||||
import { createHttpServer, selectFirstAvailableTimeSlotNextMonth, todo, waitFor } from "./lib/testUtils";
|
import { todo } from "./lib/testUtils";
|
||||||
|
|
||||||
declare let global: {
|
declare let global: {
|
||||||
E2E_EMAILS?: ({ text: string } | Record<string, unknown>)[];
|
E2E_EMAILS?: ({ text: string } | Record<string, unknown>)[];
|
||||||
@@ -182,7 +182,7 @@ test.fixme("Integrations", () => {
|
|||||||
},
|
},
|
||||||
token: {
|
token: {
|
||||||
url: "https://zoom.us/oauth/token",
|
url: "https://zoom.us/oauth/token",
|
||||||
verify({ requestHeaders, code }) {
|
verify({ requestHeaders }) {
|
||||||
const authorization = requestHeaders.get("authorization").replace("Basic ", "");
|
const authorization = requestHeaders.get("authorization").replace("Basic ", "");
|
||||||
const clientPair = Buffer.from(authorization, "base64").toString();
|
const clientPair = Buffer.from(authorization, "base64").toString();
|
||||||
const [clientId, clientSecret] = clientPair.split(":");
|
const [clientId, clientSecret] = clientPair.split(":");
|
||||||
@@ -361,75 +361,4 @@ test.fixme("Integrations", () => {
|
|||||||
todo("Can add CalDav Calendar");
|
todo("Can add CalDav Calendar");
|
||||||
|
|
||||||
todo("Can add Apple Calendar");
|
todo("Can add Apple Calendar");
|
||||||
|
|
||||||
test("add webhook & test that creating an event triggers a webhook call", async ({
|
|
||||||
page,
|
|
||||||
users,
|
|
||||||
}, testInfo) => {
|
|
||||||
const webhookReceiver = createHttpServer();
|
|
||||||
const user = await users.create();
|
|
||||||
const [eventType] = user.eventTypes;
|
|
||||||
await user.login();
|
|
||||||
await page.goto(`/settings/developer`);
|
|
||||||
|
|
||||||
// --- add webhook
|
|
||||||
await page.click('[data-testid="new_webhook"]');
|
|
||||||
|
|
||||||
await expect(page.locator(`[data-testid='WebhookDialogForm']`)).toBeVisible();
|
|
||||||
|
|
||||||
await page.fill('[name="subscriberUrl"]', webhookReceiver.url);
|
|
||||||
|
|
||||||
await page.fill('[name="secret"]', "secret");
|
|
||||||
|
|
||||||
await page.click("[type=submit]");
|
|
||||||
|
|
||||||
// dialog is closed
|
|
||||||
await expect(page.locator(`[data-testid='WebhookDialogForm']`)).not.toBeVisible();
|
|
||||||
// page contains the url
|
|
||||||
expect(page.locator(`text='${webhookReceiver.url}'`)).toBeDefined();
|
|
||||||
|
|
||||||
// --- Book the first available day next month in the pro user's "30min"-event
|
|
||||||
await page.goto(`/${user.username}/${eventType.slug}`);
|
|
||||||
await selectFirstAvailableTimeSlotNextMonth(page);
|
|
||||||
|
|
||||||
// --- fill form
|
|
||||||
await page.fill('[name="name"]', "Test Testson");
|
|
||||||
await page.fill('[name="email"]', "test@example.com");
|
|
||||||
await page.press('[name="email"]', "Enter");
|
|
||||||
|
|
||||||
// --- check that webhook was called
|
|
||||||
await waitFor(() => {
|
|
||||||
expect(webhookReceiver.requestList.length).toBe(1);
|
|
||||||
});
|
|
||||||
|
|
||||||
const [request] = webhookReceiver.requestList;
|
|
||||||
const body = request.body as any;
|
|
||||||
|
|
||||||
// remove dynamic properties that differs depending on where you run the tests
|
|
||||||
const dynamic = "[redacted/dynamic]";
|
|
||||||
body.createdAt = dynamic;
|
|
||||||
body.payload.startTime = dynamic;
|
|
||||||
body.payload.endTime = dynamic;
|
|
||||||
body.payload.location = dynamic;
|
|
||||||
for (const attendee of body.payload.attendees) {
|
|
||||||
attendee.timeZone = dynamic;
|
|
||||||
attendee.language = dynamic;
|
|
||||||
}
|
|
||||||
body.payload.organizer.email = dynamic;
|
|
||||||
body.payload.organizer.timeZone = dynamic;
|
|
||||||
body.payload.organizer.language = dynamic;
|
|
||||||
body.payload.uid = dynamic;
|
|
||||||
body.payload.bookingId = dynamic;
|
|
||||||
body.payload.additionalInformation = dynamic;
|
|
||||||
body.payload.requiresConfirmation = dynamic;
|
|
||||||
body.payload.eventTypeId = dynamic;
|
|
||||||
|
|
||||||
// if we change the shape of our webhooks, we can simply update this by clicking `u`
|
|
||||||
// console.log("BODY", body);
|
|
||||||
// Text files shouldn't have platform specific suffixes
|
|
||||||
testInfo.snapshotSuffix = "";
|
|
||||||
expect(JSON.stringify(body)).toMatchSnapshot(`webhookResponse.txt`);
|
|
||||||
|
|
||||||
webhookReceiver.close();
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
@@ -0,0 +1,76 @@
|
|||||||
|
import { expect } from "@playwright/test";
|
||||||
|
|
||||||
|
import { test } from "./lib/fixtures";
|
||||||
|
import { createHttpServer, selectFirstAvailableTimeSlotNextMonth, waitFor } from "./lib/testUtils";
|
||||||
|
|
||||||
|
test("add webhook & test that creating an event triggers a webhook call", async ({
|
||||||
|
page,
|
||||||
|
users,
|
||||||
|
}, testInfo) => {
|
||||||
|
const webhookReceiver = createHttpServer();
|
||||||
|
const user = await users.create();
|
||||||
|
const [eventType] = user.eventTypes;
|
||||||
|
await user.login();
|
||||||
|
await page.goto(`/settings/developer/webhooks`);
|
||||||
|
|
||||||
|
// --- add webhook
|
||||||
|
await page.click('[data-testid="new_webhook"]');
|
||||||
|
|
||||||
|
await page.fill('[name="subscriberUrl"]', webhookReceiver.url);
|
||||||
|
|
||||||
|
await page.fill('[name="secret"]', "secret");
|
||||||
|
|
||||||
|
await Promise.all([
|
||||||
|
page.click("[type=submit]"),
|
||||||
|
page.waitForNavigation({
|
||||||
|
url: (url) => url.pathname.endsWith("/settings/developer/webhooks"),
|
||||||
|
}),
|
||||||
|
]);
|
||||||
|
|
||||||
|
// page contains the url
|
||||||
|
expect(page.locator(`text='${webhookReceiver.url}'`)).toBeDefined();
|
||||||
|
|
||||||
|
// --- Book the first available day next month in the pro user's "30min"-event
|
||||||
|
await page.goto(`/${user.username}/${eventType.slug}`);
|
||||||
|
await selectFirstAvailableTimeSlotNextMonth(page);
|
||||||
|
|
||||||
|
// --- fill form
|
||||||
|
await page.fill('[name="name"]', "Test Testson");
|
||||||
|
await page.fill('[name="email"]', "test@example.com");
|
||||||
|
await page.press('[name="email"]', "Enter");
|
||||||
|
|
||||||
|
// --- check that webhook was called
|
||||||
|
await waitFor(() => {
|
||||||
|
expect(webhookReceiver.requestList.length).toBe(1);
|
||||||
|
});
|
||||||
|
|
||||||
|
const [request] = webhookReceiver.requestList;
|
||||||
|
const body = request.body as any;
|
||||||
|
|
||||||
|
// remove dynamic properties that differs depending on where you run the tests
|
||||||
|
const dynamic = "[redacted/dynamic]";
|
||||||
|
body.createdAt = dynamic;
|
||||||
|
body.payload.startTime = dynamic;
|
||||||
|
body.payload.endTime = dynamic;
|
||||||
|
body.payload.location = dynamic;
|
||||||
|
for (const attendee of body.payload.attendees) {
|
||||||
|
attendee.timeZone = dynamic;
|
||||||
|
attendee.language = dynamic;
|
||||||
|
}
|
||||||
|
body.payload.organizer.email = dynamic;
|
||||||
|
body.payload.organizer.timeZone = dynamic;
|
||||||
|
body.payload.organizer.language = dynamic;
|
||||||
|
body.payload.uid = dynamic;
|
||||||
|
body.payload.bookingId = dynamic;
|
||||||
|
body.payload.additionalInformation = dynamic;
|
||||||
|
body.payload.requiresConfirmation = dynamic;
|
||||||
|
body.payload.eventTypeId = dynamic;
|
||||||
|
|
||||||
|
// if we change the shape of our webhooks, we can simply update this by clicking `u`
|
||||||
|
// console.log("BODY", body);
|
||||||
|
// Text files shouldn't have platform specific suffixes
|
||||||
|
testInfo.snapshotSuffix = "";
|
||||||
|
expect(JSON.stringify(body)).toMatchSnapshot(`webhookResponse.txt`);
|
||||||
|
|
||||||
|
webhookReceiver.close();
|
||||||
|
});
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
{"triggerEvent":"BOOKING_CREATED","createdAt":"[redacted/dynamic]","payload":{"type":"30 min","title":"30 min between PRO and Test Testson","description":"","additionalNotes":"","customInputs":{},"startTime":"[redacted/dynamic]","endTime":"[redacted/dynamic]","organizer":{"name":"PRO","email":"[redacted/dynamic]","timeZone":"[redacted/dynamic]","language":"[redacted/dynamic]"},"attendees":[{"email":"test@example.com","name":"Test Testson","timeZone":"[redacted/dynamic]","language":"[redacted/dynamic]"}],"location":"[redacted/dynamic]","destinationCalendar":null,"hideCalendarNotes":false,"requiresConfirmation":"[redacted/dynamic]","eventTypeId":"[redacted/dynamic]","uid":"[redacted/dynamic]","eventTitle":"30 min","eventDescription":null,"price":0,"currency":"usd","length":30,"bookingId":"[redacted/dynamic]","metadata":{},"status":"ACCEPTED","additionalInformation":"[redacted/dynamic]"}}
|
||||||
@@ -112,7 +112,6 @@
|
|||||||
"use_link_to_reset_password": "استخدم الرابط أدناه لإعادة تعيين كلمة المرور",
|
"use_link_to_reset_password": "استخدم الرابط أدناه لإعادة تعيين كلمة المرور",
|
||||||
"hey_there": "مرحبًا،",
|
"hey_there": "مرحبًا،",
|
||||||
"forgot_your_password_calcom": "نسيت كلمة المرور الخاصة بك؟ - Cal.com",
|
"forgot_your_password_calcom": "نسيت كلمة المرور الخاصة بك؟ - Cal.com",
|
||||||
"event_type_title": "{{eventTypeTitle}} | نوع الحدث",
|
|
||||||
"delete_webhook_confirmation_message": "هل أنت متأكد أنك تريد حذف الويب هوك هذا؟ لن تتلقى بعد الآن بيانات اجتماعات Cal.com على عنوان URL محدد، وفي الوقت الفعلي، عندما تتم جدولة حدث أو يتم إلغاؤه.",
|
"delete_webhook_confirmation_message": "هل أنت متأكد أنك تريد حذف الويب هوك هذا؟ لن تتلقى بعد الآن بيانات اجتماعات Cal.com على عنوان URL محدد، وفي الوقت الفعلي، عندما تتم جدولة حدث أو يتم إلغاؤه.",
|
||||||
"confirm_delete_webhook": "نعم، قم بحذف الويبهوك",
|
"confirm_delete_webhook": "نعم، قم بحذف الويبهوك",
|
||||||
"edit_webhook": "تعديل الويبهوك",
|
"edit_webhook": "تعديل الويبهوك",
|
||||||
@@ -143,6 +142,7 @@
|
|||||||
"view_public_page": "عرض الصفحة العامة",
|
"view_public_page": "عرض الصفحة العامة",
|
||||||
"sign_out": "تسجيل الخروج",
|
"sign_out": "تسجيل الخروج",
|
||||||
"add_another": "أضف واحدًا آخر",
|
"add_another": "أضف واحدًا آخر",
|
||||||
|
"install_another": "تثبيت آخر",
|
||||||
"until": "حتى",
|
"until": "حتى",
|
||||||
"powered_by": "مدعوم بواسطة",
|
"powered_by": "مدعوم بواسطة",
|
||||||
"unavailable": "غير متاح",
|
"unavailable": "غير متاح",
|
||||||
@@ -157,6 +157,7 @@
|
|||||||
"checkbox": "مربع الاختيار",
|
"checkbox": "مربع الاختيار",
|
||||||
"is_required": "مطلوب",
|
"is_required": "مطلوب",
|
||||||
"required": "مطلوب",
|
"required": "مطلوب",
|
||||||
|
"optional": "اختياري",
|
||||||
"input_type": "نوع الإدخال",
|
"input_type": "نوع الإدخال",
|
||||||
"rejected": "مرفوض",
|
"rejected": "مرفوض",
|
||||||
"unconfirmed": "غير مؤكد",
|
"unconfirmed": "غير مؤكد",
|
||||||
@@ -227,7 +228,9 @@
|
|||||||
"connect_your_calendar_instructions": "اربط التقويم لديك للتحقق تلقائيًا من الأوقات المشغولة والأحداث الجديدة أثناء جدولتها.",
|
"connect_your_calendar_instructions": "اربط التقويم لديك للتحقق تلقائيًا من الأوقات المشغولة والأحداث الجديدة أثناء جدولتها.",
|
||||||
"set_up_later": "الإعداد لاحقًا",
|
"set_up_later": "الإعداد لاحقًا",
|
||||||
"current_time": "الوقت الحالي",
|
"current_time": "الوقت الحالي",
|
||||||
|
"details": "التفاصيل",
|
||||||
"welcome": "مرحبًا",
|
"welcome": "مرحبًا",
|
||||||
|
"welcome_back": "أهلاً بك من جديد",
|
||||||
"welcome_to_calcom": "مرحبًا بك في Cal.com",
|
"welcome_to_calcom": "مرحبًا بك في Cal.com",
|
||||||
"welcome_instructions": "أخبرنا باسمك وبالمنطقة الزمنية التي توجد فيها. ستتمكن لاحقًا من تعديل هذا.",
|
"welcome_instructions": "أخبرنا باسمك وبالمنطقة الزمنية التي توجد فيها. ستتمكن لاحقًا من تعديل هذا.",
|
||||||
"connect_caldav": "الاتصال بخادم CalDav",
|
"connect_caldav": "الاتصال بخادم CalDav",
|
||||||
@@ -240,6 +243,7 @@
|
|||||||
"when": "متى",
|
"when": "متى",
|
||||||
"where": "أين",
|
"where": "أين",
|
||||||
"add_to_calendar": "إضافة إلى التقويم",
|
"add_to_calendar": "إضافة إلى التقويم",
|
||||||
|
"add_another_calendar": "إضافة رزنامة أخرى",
|
||||||
"other": "آخر",
|
"other": "آخر",
|
||||||
"emailed_you_and_attendees": "لقد أرسلنا إليك وإلى الحضور الآخرين دعوة للتقويم عبر البريد الإلكتروني تتضمن كل التفاصيل.",
|
"emailed_you_and_attendees": "لقد أرسلنا إليك وإلى الحضور الآخرين دعوة للتقويم عبر البريد الإلكتروني تتضمن كل التفاصيل.",
|
||||||
"emailed_you_and_attendees_recurring": "لقد أرسلنا إليك وإلى الحضور الآخرين دعوة تقويم عبر البريد الإلكتروني لأول هذه الأحداث المتكررة.",
|
"emailed_you_and_attendees_recurring": "لقد أرسلنا إليك وإلى الحضور الآخرين دعوة تقويم عبر البريد الإلكتروني لأول هذه الأحداث المتكررة.",
|
||||||
@@ -261,6 +265,8 @@
|
|||||||
"enter_new_password": "أدخل كلمة المرور الجديدة التي ترغب في تعيينها لحسابك.",
|
"enter_new_password": "أدخل كلمة المرور الجديدة التي ترغب في تعيينها لحسابك.",
|
||||||
"reset_password": "إعادة تعيين كلمة المرور",
|
"reset_password": "إعادة تعيين كلمة المرور",
|
||||||
"change_your_password": "تغيير كلمة المرور",
|
"change_your_password": "تغيير كلمة المرور",
|
||||||
|
"show_password": "عرض كلمة المرور",
|
||||||
|
"hide_password": "إخفاء كلمة المرور",
|
||||||
"try_again": "حاول مجددًا",
|
"try_again": "حاول مجددًا",
|
||||||
"request_is_expired": "انتهت صلاحية ذلك الطلب.",
|
"request_is_expired": "انتهت صلاحية ذلك الطلب.",
|
||||||
"reset_instructions": "أدخل عنوان البريد الإلكتروني المرتبط بحسابك وسنرسل إليك رابطًا لإعادة تعيين كلمة المرور.",
|
"reset_instructions": "أدخل عنوان البريد الإلكتروني المرتبط بحسابك وسنرسل إليك رابطًا لإعادة تعيين كلمة المرور.",
|
||||||
@@ -289,7 +295,7 @@
|
|||||||
"reschedule_instead": "بدلًا من ذلك، يمكنك إعادة جدولته.",
|
"reschedule_instead": "بدلًا من ذلك، يمكنك إعادة جدولته.",
|
||||||
"event_is_in_the_past": "الحدث في الماضي",
|
"event_is_in_the_past": "الحدث في الماضي",
|
||||||
"cancelling_event_recurring": "إن هذا الحدث أحد الأمثلة على حدث متكرر.",
|
"cancelling_event_recurring": "إن هذا الحدث أحد الأمثلة على حدث متكرر.",
|
||||||
"cancelling_all_recurring": "هذه هي الحالات المتبقية في الحدث المتكرر.",
|
"cancelling_all_recurring": "هذه هي كل الأمثلة المتبقية في الحدث المتكرر.",
|
||||||
"error_with_status_code_occured": "حدث خطأ برمز الحالة {{status}}.",
|
"error_with_status_code_occured": "حدث خطأ برمز الحالة {{status}}.",
|
||||||
"booking_already_cancelled": "تم إلغاء هذا الحجز بالفعل",
|
"booking_already_cancelled": "تم إلغاء هذا الحجز بالفعل",
|
||||||
"go_back_home": "العودة إلى الشاشة الرئيسية",
|
"go_back_home": "العودة إلى الشاشة الرئيسية",
|
||||||
@@ -306,6 +312,7 @@
|
|||||||
"recurring_bookings": "بمجرد أن يحجز شخص ما اجتماعًا متكررًا معك، سيظهر هنا.",
|
"recurring_bookings": "بمجرد أن يحجز شخص ما اجتماعًا متكررًا معك، سيظهر هنا.",
|
||||||
"past_bookings": "ستظهر هنا عمليات حجزك السابقة.",
|
"past_bookings": "ستظهر هنا عمليات حجزك السابقة.",
|
||||||
"cancelled_bookings": "ستظهر هنا عمليات حجزك التي تم إلغاؤها.",
|
"cancelled_bookings": "ستظهر هنا عمليات حجزك التي تم إلغاؤها.",
|
||||||
|
"unconfirmed_bookings": "ستظهر هنا كل حجوزات غير المؤكدة بعد.",
|
||||||
"on": "في",
|
"on": "في",
|
||||||
"and": "و",
|
"and": "و",
|
||||||
"calendar_shows_busy_between": "يظهر التقويم أنك مشغول بين",
|
"calendar_shows_busy_between": "يظهر التقويم أنك مشغول بين",
|
||||||
@@ -346,6 +353,7 @@
|
|||||||
"booking_cancelled": "تم إلغاء الحجز",
|
"booking_cancelled": "تم إلغاء الحجز",
|
||||||
"booking_rescheduled": "تمت إعادة جدولة الحجز",
|
"booking_rescheduled": "تمت إعادة جدولة الحجز",
|
||||||
"booking_created": "تم إنشاء الحجز",
|
"booking_created": "تم إنشاء الحجز",
|
||||||
|
"meeting_ended": "انتهى الاجتماع",
|
||||||
"form_submitted": "تم إرسال النموذج",
|
"form_submitted": "تم إرسال النموذج",
|
||||||
"event_triggers": "مشغلات الحدث",
|
"event_triggers": "مشغلات الحدث",
|
||||||
"subscriber_url": "عنوان URL للمشترك",
|
"subscriber_url": "عنوان URL للمشترك",
|
||||||
@@ -488,6 +496,9 @@
|
|||||||
"lets_create_first_administrator_user": "لنقم بإنشاء المستخدم المسؤول الأول.",
|
"lets_create_first_administrator_user": "لنقم بإنشاء المستخدم المسؤول الأول.",
|
||||||
"new_member": "العضو الجديد",
|
"new_member": "العضو الجديد",
|
||||||
"invite": "دعوة",
|
"invite": "دعوة",
|
||||||
|
"add_team_members": "إضافة أعضاء الفريق",
|
||||||
|
"add_team_members_description": "قم بدعوة الآخرين للانضمام إلى فريقك",
|
||||||
|
"add_team_member": "إضافة عضو فريق",
|
||||||
"invite_new_member": "دعوة عضو جديد",
|
"invite_new_member": "دعوة عضو جديد",
|
||||||
"invite_new_team_member": "دعوة شخص ما إلى فريقك.",
|
"invite_new_team_member": "دعوة شخص ما إلى فريقك.",
|
||||||
"change_member_role": "تغيير دور العضو في الفريق",
|
"change_member_role": "تغيير دور العضو في الفريق",
|
||||||
@@ -600,6 +611,7 @@
|
|||||||
"create_first_team_and_invite_others": "قم بإنشاء فريقك الأول ودعوة المستخدمين الآخرين للعمل معك.",
|
"create_first_team_and_invite_others": "قم بإنشاء فريقك الأول ودعوة المستخدمين الآخرين للعمل معك.",
|
||||||
"create_team_to_get_started": "قم بإنشاء فريق للبدء",
|
"create_team_to_get_started": "قم بإنشاء فريق للبدء",
|
||||||
"teams": "الفرق",
|
"teams": "الفرق",
|
||||||
|
"team": "فريق",
|
||||||
"team_billing": "الفوترة الخاصة بالفريق",
|
"team_billing": "الفوترة الخاصة بالفريق",
|
||||||
"upgrade_to_flexible_pro_title": "لقد قمنا بتغيير الفوترة الخاصة بالفرق",
|
"upgrade_to_flexible_pro_title": "لقد قمنا بتغيير الفوترة الخاصة بالفرق",
|
||||||
"upgrade_to_flexible_pro_message": "يوجد أعضاء في فريقك من دون مقاعد. قم بترقية خطة Pro خاصتك لتوفير المقاعد الناقصة.",
|
"upgrade_to_flexible_pro_message": "يوجد أعضاء في فريقك من دون مقاعد. قم بترقية خطة Pro خاصتك لتوفير المقاعد الناقصة.",
|
||||||
@@ -620,7 +632,9 @@
|
|||||||
"billing": "الفوترة",
|
"billing": "الفوترة",
|
||||||
"manage_your_billing_info": "قم بإدارة معلومات الفوترة لديك وإلغاء اشتراكك.",
|
"manage_your_billing_info": "قم بإدارة معلومات الفوترة لديك وإلغاء اشتراكك.",
|
||||||
"availability": "الأوقات المتاحة",
|
"availability": "الأوقات المتاحة",
|
||||||
|
"edit_availability": "تعديل التوفر",
|
||||||
"configure_availability": "اضبط الأوقات التي تكون متاحًا فيها للحجز.",
|
"configure_availability": "اضبط الأوقات التي تكون متاحًا فيها للحجز.",
|
||||||
|
"copy_times_to": "نسخ الأوقات إلى",
|
||||||
"change_weekly_schedule": "تغيير جدولك الأسبوعي",
|
"change_weekly_schedule": "تغيير جدولك الأسبوعي",
|
||||||
"logo": "الشعار",
|
"logo": "الشعار",
|
||||||
"error": "خطأ",
|
"error": "خطأ",
|
||||||
@@ -635,6 +649,7 @@
|
|||||||
"event_name_tooltip": "الاسم الذي سيظهر في التقاويم",
|
"event_name_tooltip": "الاسم الذي سيظهر في التقاويم",
|
||||||
"meeting_with_user": "الاجتماع مع {ATTENDEE}",
|
"meeting_with_user": "الاجتماع مع {ATTENDEE}",
|
||||||
"additional_inputs": "مدخلات إضافية",
|
"additional_inputs": "مدخلات إضافية",
|
||||||
|
"additional_input_description": "يتطلب من المجدول إدخال مدخلات إضافية قبل تأكيد الحجز",
|
||||||
"label": "العلامة",
|
"label": "العلامة",
|
||||||
"placeholder": "العنصر النائب",
|
"placeholder": "العنصر النائب",
|
||||||
"type": "النوع",
|
"type": "النوع",
|
||||||
@@ -649,6 +664,8 @@
|
|||||||
"disable_guests": "تعطيل خاصية الضيوف",
|
"disable_guests": "تعطيل خاصية الضيوف",
|
||||||
"disable_guests_description": "قم بتعطيل إضافة مزيد من الضيوف أثناء الحجز.",
|
"disable_guests_description": "قم بتعطيل إضافة مزيد من الضيوف أثناء الحجز.",
|
||||||
"private_link": "إنشاء رابط خاص",
|
"private_link": "إنشاء رابط خاص",
|
||||||
|
"private_link_label": "رابط خاص",
|
||||||
|
"private_link_hint": "سيتم إعادة توليد الرابط الخاص بك بعد كل استخدام",
|
||||||
"copy_private_link": "نسخ الرابط الخاص",
|
"copy_private_link": "نسخ الرابط الخاص",
|
||||||
"private_link_description": "إنشاء عنوان URL خاص لمشاركته دون الكشف عن اسم المستخدم الخاص بك في Cal",
|
"private_link_description": "إنشاء عنوان URL خاص لمشاركته دون الكشف عن اسم المستخدم الخاص بك في Cal",
|
||||||
"invitees_can_schedule": "يمكن للمدعوين الجدولة",
|
"invitees_can_schedule": "يمكن للمدعوين الجدولة",
|
||||||
@@ -690,16 +707,21 @@
|
|||||||
"delete_account_confirmation_message": "هل تريد بالتأكيد حذف حسابك على Cal.com؟ أي شخص شاركت رابط حسابك معه لن يستطيع بعد الآن الحجز باستخدامه، وستفقد أي تفضيلات حفظتها.",
|
"delete_account_confirmation_message": "هل تريد بالتأكيد حذف حسابك على Cal.com؟ أي شخص شاركت رابط حسابك معه لن يستطيع بعد الآن الحجز باستخدامه، وستفقد أي تفضيلات حفظتها.",
|
||||||
"integrations": "التكاملات",
|
"integrations": "التكاملات",
|
||||||
"apps": "التطبيقات",
|
"apps": "التطبيقات",
|
||||||
|
"category_apps": "تطبيقات {{category}}",
|
||||||
"app_store": "متجر التطبيقات",
|
"app_store": "متجر التطبيقات",
|
||||||
"app_store_description": "الربط بين الناس، والتكنولوجيا، ومكان العمل.",
|
"app_store_description": "الربط بين الناس، والتكنولوجيا، ومكان العمل.",
|
||||||
"settings": "الإعدادات",
|
"settings": "الإعدادات",
|
||||||
"event_type_moved_successfully": "تم نقل نوع الحدث بنجاح",
|
"event_type_moved_successfully": "تم نقل نوع الحدث بنجاح",
|
||||||
|
"next_step_text": "الخطوة التالية",
|
||||||
"next_step": "تخطي الخطوة",
|
"next_step": "تخطي الخطوة",
|
||||||
"prev_step": "الخطوة السابقة",
|
"prev_step": "الخطوة السابقة",
|
||||||
|
"install": "تثبيت",
|
||||||
"installed": "تم التثبيت",
|
"installed": "تم التثبيت",
|
||||||
"active_install_one": "{{count}} تثبيت نشط",
|
"active_install_one": "{{count}} تثبيت نشط",
|
||||||
"active_install_other": "{{count}} تثبيت نشط",
|
"active_install_other": "{{count}} تثبيت نشط",
|
||||||
"globally_install": "تم تثبيته حول العالم",
|
"globally_install": "تم تثبيته حول العالم",
|
||||||
|
"app_successfully_installed": "تم تثبيت التطبيق بنجاح",
|
||||||
|
"app_could_not_be_installed": "تعذر تثبيت التطبيق",
|
||||||
"disconnect": "فصل",
|
"disconnect": "فصل",
|
||||||
"embed_your_calendar": "تضمين تقويمك في صفحة الويب لديك",
|
"embed_your_calendar": "تضمين تقويمك في صفحة الويب لديك",
|
||||||
"connect_your_favourite_apps": "الربط مع تطبيقاتك المفضلة.",
|
"connect_your_favourite_apps": "الربط مع تطبيقاتك المفضلة.",
|
||||||
@@ -710,6 +732,7 @@
|
|||||||
"connect_additional_calendar": "ربط رزنامة إضافية",
|
"connect_additional_calendar": "ربط رزنامة إضافية",
|
||||||
"conferencing": "المؤتمرات عبر الفيديو",
|
"conferencing": "المؤتمرات عبر الفيديو",
|
||||||
"calendar": "التقويم",
|
"calendar": "التقويم",
|
||||||
|
"payments": "الدفعات",
|
||||||
"not_installed": "لم يتم التثبيت",
|
"not_installed": "لم يتم التثبيت",
|
||||||
"error_password_mismatch": "كلمات المرور غير متطابقة.",
|
"error_password_mismatch": "كلمات المرور غير متطابقة.",
|
||||||
"error_required_field": "هذا الحقل مطلوب.",
|
"error_required_field": "هذا الحقل مطلوب.",
|
||||||
@@ -743,9 +766,22 @@
|
|||||||
"import_from": "الاستيراد من",
|
"import_from": "الاستيراد من",
|
||||||
"access_token": "Access token",
|
"access_token": "Access token",
|
||||||
"visit_roadmap": "المخطط",
|
"visit_roadmap": "المخطط",
|
||||||
|
"featured_categories": "الفئات البارزة",
|
||||||
"popular_categories": "الفئات الشائعة",
|
"popular_categories": "الفئات الشائعة",
|
||||||
|
"number_apps_one": "تطبيق {{count}}",
|
||||||
|
"number_apps_other": "تطبيقات {{count}}",
|
||||||
"trending_apps": "التطبيقات الرائجة",
|
"trending_apps": "التطبيقات الرائجة",
|
||||||
|
"explore_apps": "تطبيقات {{category}}",
|
||||||
"installed_apps": "التطبيقات المثبتة",
|
"installed_apps": "التطبيقات المثبتة",
|
||||||
|
"no_category_apps": "لا تطبيقات {{category}}",
|
||||||
|
"no_category_apps_description_calendar": "أضف تطبيق رزنامة للتحقق من أي تضارب لمنع أي حجوزات مزدوجة",
|
||||||
|
"no_category_apps_description_conferencing": "حاول إضافة تطبيق مؤتمرات لدمج مكالمة الفيديو مع عملائك",
|
||||||
|
"no_category_apps_description_payment": "أضف تطبيق دفع لتسهيل التعاملات المالية بينك وبين عملائك",
|
||||||
|
"no_category_apps_description_other": "أضف أي نوع آخر من التطبيقات للقيام بأي شيء",
|
||||||
|
"installed_app_calendar_description": "اضبط الرزنامة (الرزنامات) للتحقق من أي تضارب لمنع الحجوزات المزدوجة.",
|
||||||
|
"installed_app_conferencing_description": "أضف تطبيقات مؤتمرات الفيديو المفضلة لديك لاجتماعاتك",
|
||||||
|
"installed_app_payment_description": "قم بإعداد أي خدمات معالجة دفع تود استخدامها عند طلب النقود من العملاء.",
|
||||||
|
"installed_app_other_description": "جميع تطبيقاتك المثبتة من الفئات الأخرى.",
|
||||||
"empty_installed_apps_headline": "لم يتم تثبيت أي تطبيق",
|
"empty_installed_apps_headline": "لم يتم تثبيت أي تطبيق",
|
||||||
"empty_installed_apps_description": "تعطيك التطبيقات القدرة على تعزيز سير عملك وتحسين الجدولة في حياتك بشدة.",
|
"empty_installed_apps_description": "تعطيك التطبيقات القدرة على تعزيز سير عملك وتحسين الجدولة في حياتك بشدة.",
|
||||||
"empty_installed_apps_button": "استكشف متجر التطبيقات (App Store)",
|
"empty_installed_apps_button": "استكشف متجر التطبيقات (App Store)",
|
||||||
@@ -766,6 +802,7 @@
|
|||||||
"remove": "إزالة",
|
"remove": "إزالة",
|
||||||
"add": "إضافة",
|
"add": "إضافة",
|
||||||
"installed_one": "تم التثبيت",
|
"installed_one": "تم التثبيت",
|
||||||
|
"installed_other": "{{count}} مثبت",
|
||||||
"verify_wallet": "تأكيد المحفظة",
|
"verify_wallet": "تأكيد المحفظة",
|
||||||
"connect_metamask": "توصيل Metamask",
|
"connect_metamask": "توصيل Metamask",
|
||||||
"create_events_on": "إنشاء أحداث في:",
|
"create_events_on": "إنشاء أحداث في:",
|
||||||
@@ -783,6 +820,8 @@
|
|||||||
"set_to_default": "تعيين إلى الافتراضي",
|
"set_to_default": "تعيين إلى الافتراضي",
|
||||||
"new_schedule_btn": "جدول جديد",
|
"new_schedule_btn": "جدول جديد",
|
||||||
"add_new_schedule": "إضافة جدول جديد",
|
"add_new_schedule": "إضافة جدول جديد",
|
||||||
|
"add_new_calendar": "إضافة رزنامة جديدة",
|
||||||
|
"set_calendar": "حدد أين سيتم إضافة الأحداث الجديدة عند الحجز.",
|
||||||
"delete_schedule": "حذف الجدول",
|
"delete_schedule": "حذف الجدول",
|
||||||
"schedule_created_successfully": "تم إنشاء جدول {{scheduleName}} بنجاح",
|
"schedule_created_successfully": "تم إنشاء جدول {{scheduleName}} بنجاح",
|
||||||
"availability_updated_successfully": "تم تحديث الأوقات المتاحة بنجاح",
|
"availability_updated_successfully": "تم تحديث الأوقات المتاحة بنجاح",
|
||||||
@@ -877,7 +916,7 @@
|
|||||||
"choose_ways_put_cal_site": "اختر واحدة من الطرق التالية لوضع Cal على موقعك الإلكتروني.",
|
"choose_ways_put_cal_site": "اختر واحدة من الطرق التالية لوضع Cal على موقعك الإلكتروني.",
|
||||||
"setting_up_zapier": "إعداد دمج Zapier الخاص بك",
|
"setting_up_zapier": "إعداد دمج Zapier الخاص بك",
|
||||||
"generate_api_key": "إنشاء مفتاح API",
|
"generate_api_key": "إنشاء مفتاح API",
|
||||||
"generate_api_key_description": "إنشاء مفتاح API لاستخدامه مع Cal.com في",
|
"generate_api_key_description": "إنشاء مفتاح API لاستخدامه مع Cal.com على",
|
||||||
"your_unique_api_key": "مفتاح API الفريد الخاص بك",
|
"your_unique_api_key": "مفتاح API الفريد الخاص بك",
|
||||||
"copy_safe_api_key": "انسخ مفتاح API هذا واحفظه في مكان آمن. إذا فقدت هذا المفتاح، يتوجب عليك إنشاء مفتاح جديد.",
|
"copy_safe_api_key": "انسخ مفتاح API هذا واحفظه في مكان آمن. إذا فقدت هذا المفتاح، يتوجب عليك إنشاء مفتاح جديد.",
|
||||||
"zapier_setup_instructions": "<0>سجل الدخول إلى حساب Zapier الخاص بك وأنشئ Zap جديد.</0><1>حدد Cal.com كتطبيق Trigger لديك. اختر أيضًا حدث Trigger.</1><2>اختر حسابك ثم أدخل مفتاح API الفريد الخاص بك.</2><3>اختبر Trigger الخاص بك.</3><4>أنت جاهز!</4>",
|
"zapier_setup_instructions": "<0>سجل الدخول إلى حساب Zapier الخاص بك وأنشئ Zap جديد.</0><1>حدد Cal.com كتطبيق Trigger لديك. اختر أيضًا حدث Trigger.</1><2>اختر حسابك ثم أدخل مفتاح API الفريد الخاص بك.</2><3>اختبر Trigger الخاص بك.</3><4>أنت جاهز!</4>",
|
||||||
@@ -936,6 +975,7 @@
|
|||||||
"workflows": "سير العمل",
|
"workflows": "سير العمل",
|
||||||
"new_workflow_btn": "سير عمل جديد",
|
"new_workflow_btn": "سير عمل جديد",
|
||||||
"add_new_workflow": "إضافة سير عمل جديد",
|
"add_new_workflow": "إضافة سير عمل جديد",
|
||||||
|
"reschedule_event_trigger": "متى يتم إعادة جدولة الحدث",
|
||||||
"trigger": "مشغل",
|
"trigger": "مشغل",
|
||||||
"triggers": "مشغلين",
|
"triggers": "مشغلين",
|
||||||
"action": "إجراء",
|
"action": "إجراء",
|
||||||
@@ -963,10 +1003,13 @@
|
|||||||
"change_username_standard_to_premium": "عند التغيير من اسم مستخدم قياسي إلى اسم مستخدم مميز، سيتم نقلك إلى الدفع للترقية.",
|
"change_username_standard_to_premium": "عند التغيير من اسم مستخدم قياسي إلى اسم مستخدم مميز، سيتم نقلك إلى الدفع للترقية.",
|
||||||
"change_username_premium_to_standard": "عند التغيير من اسم مستخدم مميز إلى اسم مستخدم قياسي، سيتم نقلك إلى الدفع لخفض المستوى.",
|
"change_username_premium_to_standard": "عند التغيير من اسم مستخدم مميز إلى اسم مستخدم قياسي، سيتم نقلك إلى الدفع لخفض المستوى.",
|
||||||
"go_to_stripe_billing": "الذهاب إلى الفوترة",
|
"go_to_stripe_billing": "الذهاب إلى الفوترة",
|
||||||
|
"stripe_description": "يتطلب الدفع للحجز (0.5% + 0.10 يورو عمولة لكل معاملة)",
|
||||||
"trial_expired": "انتهت صلاحية الفترة التجريبية الخاصة بك",
|
"trial_expired": "انتهت صلاحية الفترة التجريبية الخاصة بك",
|
||||||
"remove_app": "إزالة التطبيق",
|
"remove_app": "إزالة التطبيق",
|
||||||
"yes_remove_app": "نعم، قم بإزالة التطبيق",
|
"yes_remove_app": "نعم، قم بإزالة التطبيق",
|
||||||
"are_you_sure_you_want_to_remove_this_app": "هل أنت متأكد من أنك تريد إزالة هذا التطبيق؟",
|
"are_you_sure_you_want_to_remove_this_app": "هل أنت متأكد من أنك تريد إزالة هذا التطبيق؟",
|
||||||
|
"app_removed_successfully": "تمت إزالة التطبيق بنجاح",
|
||||||
|
"error_removing_app": "خطأ في إزالة التطبيق",
|
||||||
"web_conference": "مؤتمر عبر الإنترنت",
|
"web_conference": "مؤتمر عبر الإنترنت",
|
||||||
"number_for_sms_reminders": "رقم الهاتف (لتذكير الرسائل القصيرة)",
|
"number_for_sms_reminders": "رقم الهاتف (لتذكير الرسائل القصيرة)",
|
||||||
"requires_confirmation": "يتطلب التأكيد",
|
"requires_confirmation": "يتطلب التأكيد",
|
||||||
@@ -1022,20 +1065,205 @@
|
|||||||
"navigate": "تنقّل",
|
"navigate": "تنقّل",
|
||||||
"open": "فتح",
|
"open": "فتح",
|
||||||
"close": "إغلاق",
|
"close": "إغلاق",
|
||||||
"embed": "مُضمَن",
|
"team_feature_teams": "هذه ميزة في Team. قم بالترقية إلى Team لرؤية توفر فريقك.",
|
||||||
|
"team_feature_workflows": "هذه ميزة في Team. قم بالترقية إلى Team لأتمتة إشعارات الحدث والتذكير مع سير العمل.",
|
||||||
|
"show_eventtype_on_profile": "إظهار على الملف الشخصي",
|
||||||
|
"embed": "تضمين",
|
||||||
"new_username": "اسم مستخدم جديد",
|
"new_username": "اسم مستخدم جديد",
|
||||||
"current_username": "اسم المستخدم الحالي",
|
"current_username": "اسم المستخدم الحالي",
|
||||||
"example_1": "مثال 1",
|
"example_1": "مثال 1",
|
||||||
"example_2": "مثال 2",
|
"example_2": "مثال 2",
|
||||||
|
"additional_input_label": "تسمية الإدخال الاضافي",
|
||||||
"company_size": "حجم الشركة",
|
"company_size": "حجم الشركة",
|
||||||
"what_help_needed": "ما الذي تحتاج إلى مساعدة بشأنه؟",
|
"what_help_needed": "ما الذي تحتاج إلى مساعدة بشأنه؟",
|
||||||
"variable_format": "تنسيق المتغير",
|
"variable_format": "تنسيق المتغير",
|
||||||
|
"webhook_subscriber_url_reserved": "رابط مشترك Webhook معرّف بالفعل",
|
||||||
"custom_input_as_variable_info": "تجاهل جميع الأحرف الخاصة من تسمية الإدخال الإضافي (استخدم الأحرف والأرقام فقط)، واستخدم الحروف الكبيرة لجميع الأحرف واستبدل المساحات البيضاء بالشرط.",
|
"custom_input_as_variable_info": "تجاهل جميع الأحرف الخاصة من تسمية الإدخال الإضافي (استخدم الأحرف والأرقام فقط)، واستخدم الحروف الكبيرة لجميع الأحرف واستبدل المساحات البيضاء بالشرط.",
|
||||||
"using_additional_inputs_as_variables": "كيف أستخدم مدخلات إضافية كمتغيرات؟",
|
"using_additional_inputs_as_variables": "كيف أستخدم مدخلات إضافية كمتغيرات؟",
|
||||||
"download_desktop_app": "تحميل تطبيق سطح المكتب",
|
"download_desktop_app": "تحميل تطبيق سطح المكتب",
|
||||||
"set_ping_link": "تعيين رابط Ping",
|
"set_ping_link": "تعيين رابط Ping",
|
||||||
|
"rate_limit_exceeded": "تم تجاوز حد السعر",
|
||||||
|
"when_something_happens": "عندما يحدث شيء ما",
|
||||||
|
"action_is_performed": "يتم تنفيذ إجراء",
|
||||||
|
"test_action": "إجراء الاختبار",
|
||||||
|
"notification_sent": "تم إرسال الإشعار",
|
||||||
|
"no_input": "لا مدخلات",
|
||||||
|
"test_workflow_action": "اختبار إجراء سير العمل",
|
||||||
|
"send_sms": "إرسال رسالة نصية",
|
||||||
|
"send_sms_to_number": "هل أنت متأكد من رغبتك في إرسال رسالة قصيرة إلى {{number}}؟",
|
||||||
"missing_connected_calendar": "لا يوجد تقويم افتراضي متصل",
|
"missing_connected_calendar": "لا يوجد تقويم افتراضي متصل",
|
||||||
|
"connect_your_calendar_and_link": "يمكنك ربط رزنامتك من <1>هنا</1>.",
|
||||||
|
"default_calendar_selected": "الرزنامة الافتراضية",
|
||||||
|
"hide_from_profile": "إخفاء من الملف الشخصي",
|
||||||
|
"event_setup_tab_title": "إعداد الحدث",
|
||||||
|
"event_limit_tab_title": "الحدود",
|
||||||
|
"event_limit_tab_description": "ما تواتر مرات الحجز",
|
||||||
|
"event_advanced_tab_description": "إعدادات الرزنامة والمزيد...",
|
||||||
|
"event_advanced_tab_title": "متقدم",
|
||||||
|
"select_which_cal": "اختر أي رزنامة تريد إضافة الحجز إليها",
|
||||||
|
"custom_event_name": "اسم حدث مخصص",
|
||||||
|
"custom_event_name_description": "إنشاء أسماء أحداث مخصصة لعرضها في حدث الرزنامة",
|
||||||
|
"2fa_required": "ثمة حاجة إلى المصادقة الثنائية",
|
||||||
|
"incorrect_2fa": "رمز المصادقة الثنائية غير صحيح",
|
||||||
|
"which_event_type_apply": "ما نوع الحدث الذي سينطبق عليه هذا؟",
|
||||||
|
"no_workflows_description": "تعمل سير العمل على تمكين أتمتة إرسال الإشعارات والتذكيرات التي تمكنك من بناء عمليات حول الأحداث الخاصة بك.",
|
||||||
|
"create_workflow": "إنشاء سير عمل",
|
||||||
|
"do_this": "افعل هذا",
|
||||||
|
"turn_off": "إيقاف التشغيل",
|
||||||
|
"settings_updated_successfully": "تم تحديث الإعدادات بنجاح",
|
||||||
|
"error_updating_settings": "خطأ في تحديث الإعدادات",
|
||||||
|
"personal_cal_url": "عنوان Cal URL الخاص بي",
|
||||||
|
"bio_hint": "اكتب بضع جمل عن نفسك، والتي ستظهر على صفحة عنوان Url الشخصية لديك.",
|
||||||
|
"delete_account_modal_title": "حذف الحساب",
|
||||||
|
"confirm_delete_account_modal": "هل أنت متأكد من أنك تريد حذف حساب Cal.com الخاص بك؟",
|
||||||
|
"delete_my_account": "حذف حسابي",
|
||||||
|
"start_of_week": "بداية الأسبوع",
|
||||||
|
"select_calendars": "حدد الرزنامات التي تريد التحقق منها بحثًا عن تضاربات لمنع الحجوزات المزدوجة.",
|
||||||
|
"check_for_conflicts": "التحقق من وجود تضاربات",
|
||||||
|
"adding_events_to": "إضافة أحداث إلى",
|
||||||
|
"follow_system_preferences": "اتبع تفضيلات النظام",
|
||||||
|
"custom_brand_colors": "ألوان العلامة التجارية المخصصة",
|
||||||
|
"customize_your_brand_colors": "تخصيص لون العلامة التجارية الخاصة بك في صفحة الحجز.",
|
||||||
|
"pro": "Pro",
|
||||||
|
"removes_cal_branding": "إزالة أي علامات تجارية ذات صلة بـCal ، أي 'تم تشغيلها من قبل Cal.'",
|
||||||
|
"profile_picture": "صورة الملف الشخصي",
|
||||||
|
"upload": "تحميل",
|
||||||
|
"web3": "الويب 3",
|
||||||
|
"rainbow_token_gated": "هذا النوع من الأحداث موجود وراء بوابة رمز.",
|
||||||
|
"rainbow_connect_wallet_gate": "قم بتوصيل محفظتك إذا كنت تملك <1>{{name}}</1> (<3>{{symbol}}</3>).",
|
||||||
|
"rainbow_insufficient_balance": "لا تحتوي محفظتك المتصلة على ما يكفي من 1>{{symbol}}</1>.",
|
||||||
|
"rainbow_sign_message_request": "قم بتوقيع طلب الرسالة على محفظتك.",
|
||||||
|
"rainbow_signature_error": "خطأ في طلب التوقيع من محفظتك.",
|
||||||
|
"token_address": "عنوان الرمز المميز",
|
||||||
|
"blockchain": "البلوكشين",
|
||||||
|
"old_password": "كلمة مرور قديمة",
|
||||||
|
"secure_password": "كلمة المرور الجديدة الآمنة كلياً",
|
||||||
|
"error_updating_password": "خطأ في تحديث كلمة المرور",
|
||||||
|
"two_factor_auth": "المصادقة الثنائية",
|
||||||
|
"recurring_event_tab_description": "إعداد جدول تكرار",
|
||||||
|
"today": "اليوم",
|
||||||
|
"appearance": "المظهر",
|
||||||
|
"appearance_subtitle": "إدارة إعدادات مظهر الحجز الخاص بك",
|
||||||
|
"my_account": "حسابي",
|
||||||
|
"general": "عام",
|
||||||
|
"calendars": "الرزنامات",
|
||||||
|
"2fa_auth": "المصادقة الثنائية",
|
||||||
|
"invoices": "الفواتير",
|
||||||
|
"embeds": "التضمينات",
|
||||||
|
"impersonation": "التقمّص",
|
||||||
|
"users": "المستخدمون",
|
||||||
|
"profile_description": "إدارة الإعدادات لملفك الرزنامة الشخصي لديك",
|
||||||
|
"general_description": "إدارة الإعدادات للغة والمنطقة الزمنية الخاصة بك",
|
||||||
|
"calendars_description": "اضبط كيفية تفاعل أنواع الأحداث لديك مع رزناماتك",
|
||||||
|
"appearance_description": "إدارة إعدادات مظهر الحجز الخاص بك",
|
||||||
|
"conferencing_description": "إدارة تطبيقات مؤتمرات الفيديو لديك لاجتماعاتك",
|
||||||
|
"password_description": "إدارة إعدادات كلمات مرور حسابك",
|
||||||
|
"2fa_description": "إدارة إعدادات كلمات مرور حسابك",
|
||||||
|
"we_just_need_basic_info": "نحتاج فقط إلى بعض المعلومات الأساسية لإعداد ملفك الشخصي.",
|
||||||
|
"skip": "تخطي",
|
||||||
|
"do_this_later": "القيام بهذا لاحقاً",
|
||||||
|
"set_availability_getting_started_subtitle_1": "تحديد الفترات الزمنية التي أنت فيها متاح",
|
||||||
|
"set_availability_getting_started_subtitle_2": "يمكنك تخصيص كل هذا في وقت لاحق في صفحة التوفر.",
|
||||||
|
"connect_calendars_from_app_store": "يمكنك إضافة المزيد من الرزنامات من متجر التطبيقات",
|
||||||
|
"connect_conference_apps": "ربط تطبيقات المؤتمرات",
|
||||||
|
"connect_calendar_apps": "ربط تطبيقات الرزنامة",
|
||||||
|
"connect_payment_apps": "ربط تطبيقات الدفع",
|
||||||
|
"connect_other_apps": "ربط تطبيقات أخرى",
|
||||||
|
"current_step_of_total": "الخطوة {{currentStep}} من {{maxSteps}}",
|
||||||
|
"add_variable": "إضافة متغير",
|
||||||
|
"custom_phone_number": "رقم هاتف مخصص",
|
||||||
|
"message_template": "نموذج رسالة",
|
||||||
|
"email_subject": "موضوع الرسالة الإلكترونية",
|
||||||
|
"add_dynamic_variables": "أضف متغيرات نص ديناميكية",
|
||||||
|
"event_name_info": "اسم نوع الحدث",
|
||||||
|
"event_date_info": "تاريخ الحدث",
|
||||||
|
"event_time_info": "وقت بدء الحدث",
|
||||||
|
"location_info": "موقع الحدث",
|
||||||
"organizer_name_info": "اسمك",
|
"organizer_name_info": "اسمك",
|
||||||
|
"additional_notes_info": "ملاحظات إضافية للحجز",
|
||||||
|
"attendee_name_info": "اسم الشخص صاحب الحجز",
|
||||||
|
"to": "إلى",
|
||||||
|
"attendee_required_enter_number": "سيتطلب هذا من الحضور إدخال رقم هاتف عند الحجز",
|
||||||
|
"workflow_turned_on_successfully": "تم تحديث سير العمل {{workflowName}} بنجاح {{offOn}}",
|
||||||
|
"download_responses": "تحميل الردود",
|
||||||
|
"create_your_first_form": "إنشاء أول استمارة",
|
||||||
|
"create_your_first_form_description": "يمكنك من خلال استمارات التوجيه طرح أسئلة التأهيل والتوجيه إلى الشخص/نوع الحدث المناسب.",
|
||||||
|
"create_your_first_webhook": "إنشاء أول Webhook",
|
||||||
|
"create_your_first_webhook_description": "يمكنك باستخدام Webhooks تلقي بيانات الاجتماع في الوقت الفعلي عندما يحدث شيء ما في Cal.com.",
|
||||||
|
"for_a_maximum_of": "كحد أقصى لـ",
|
||||||
|
"event_one": "حدث",
|
||||||
|
"event_other": "أحداث",
|
||||||
|
"profile_team_description": "إدارة إعدادات الملف الشخصي لفريقك",
|
||||||
|
"members_team_description": "المستخدمين الذين هم في المجموعة",
|
||||||
|
"team_url": "عنوان URL للفريق",
|
||||||
|
"delete_team": "حذف الفريق",
|
||||||
|
"team_members": "أعضاء الفريق",
|
||||||
|
"more": "المزيد",
|
||||||
|
"more_page_footer": "نعتبر تطبيق الهاتف المحمول امتداداً لتطبيق الويب، لكن يرجعى العودة لتطبيق الويب إذا كنت تقوم بأي إجراءات معقدة.",
|
||||||
|
"workflow_example_1": "إرسال رسائل نصية للحضور للتذكير قبل 24 ساعة من بدء الحدث",
|
||||||
|
"workflow_example_2": "إرسال رسالة نصية مخصصة عند إعادة جدولة الحدث للحضور",
|
||||||
|
"workflow_example_3": "إرسال بريد إلكتروني مخصص عندما يتم حجز حدث جديد للاستضافة",
|
||||||
|
"workflow_example_4": "إرسال رسائل نصية للحضور للتذكير قبل 1 ساعة من بدء الحدث",
|
||||||
|
"workflow_example_5": "إرسال رسالة نصية مخصصة عند إعادة جدولة الحدث للحضور",
|
||||||
|
"workflow_example_6": "إرسال بريد إلكتروني مخصص عندما يتم حجز حدث جديد للاستضافة",
|
||||||
|
"welcome_to_cal_header": "مرحبًا بك في Cal.com!",
|
||||||
|
"edit_form_later_subtitle": "سوف تكون قادراً على تعديل هذا لاحقاً.",
|
||||||
|
"connect_calendar_later": "سأقوم بتوصيل التقويم في وقت لاحق",
|
||||||
|
"set_my_availability_later": "سأحدد متى أكون متوفراً لاحقاً",
|
||||||
|
"problem_saving_user_profile": "حدثت مشكلة أثناء حفظ بياناتك. الرجاء المحاولة من جديد أو التواصل مع دعم العملاء.",
|
||||||
|
"purchase_missing_seats": "شراء المقاعد الناقصة",
|
||||||
|
"slot_length": "طول الفتحة",
|
||||||
|
"booking_appearance": "مظهر الحجز",
|
||||||
|
"appearance_team_description": "إدارة إعدادات مظهر الحجز الخاص بك",
|
||||||
|
"only_owner_change": "يمكن فقط لمالك هذا الفريق إجراء تغييرات على حجز الفريق ",
|
||||||
|
"team_disable_cal_branding_description": "إزالة أي علامات تجارية ذات صلة بـCal ، أي 'تم تشغيلها من قبل Cal'",
|
||||||
|
"invited_by_team": "دعاك {{teamName}} للانضمام إلى فريقهم كـ{{role}}",
|
||||||
|
"token_invalid_expired": "الرمز المميز إما غير صالح أو انتهت صلاحيته.",
|
||||||
|
"exchange_add": "الربط مع Microsoft Exchange",
|
||||||
|
"exchange_authentication": "طريقة المصادقة",
|
||||||
|
"exchange_authentication_standard": "المصادقة الأساسية",
|
||||||
|
"exchange_authentication_ntlm": "مصادقة NTLM",
|
||||||
|
"exchange_compression": "ضغط وفق Gzip",
|
||||||
|
"routing_forms_description": "يمكنك هنا رؤية جميع النماذج والمسارات التي أنشأتها.",
|
||||||
|
"add_new_form": "إضافة استمارة جديدة",
|
||||||
|
"form_description": "إنشاء استمارتك لتوجيه طالب حجز",
|
||||||
|
"copy_link_to_form": "نسخ رابط إلى الاستمارة",
|
||||||
|
"theme": "السمة",
|
||||||
|
"theme_applies_note": "ينطبق هذا فقط على صفحات الحجز العامة الخاصة بك",
|
||||||
"theme_light": "فاتح",
|
"theme_light": "فاتح",
|
||||||
"theme_dark": "داكن"
|
"theme_dark": "داكن",
|
||||||
|
"theme_system": "النظام الافتراضي",
|
||||||
|
"add_a_team": "إضافة فريق",
|
||||||
|
"saml_config": "إعدادات SAML",
|
||||||
|
"add_webhook_description": "تلقي بيانات الاجتماع في الوقت الحقيقي حالما يحدث شيء ما في Cal.com",
|
||||||
|
"triggers_when": "المشغلات عندما",
|
||||||
|
"test_webhook": "الرجاء إجراء اختبار ping قبل الإنشاء.",
|
||||||
|
"enable_webhook": "تمكين Webhook",
|
||||||
|
"add_webhook": "إضافة Webhook",
|
||||||
|
"webhook_edited_successfully": "تم حفظ Webhook",
|
||||||
|
"webhooks_description": "تلقي بيانات الاجتماع في الوقت الحقيقي عندما يحدث شيء ما في Cal.com",
|
||||||
|
"api_keys_description": "إنشاء مفاتيح API لاستخدامها للوصول إلى حسابك الخاص",
|
||||||
|
"new_api_key": "مفتاح API جديد",
|
||||||
|
"active": "نشط",
|
||||||
|
"api_key_updated": "تم تحديث اسم مفتاح API",
|
||||||
|
"api_key_update_failed": "خطأ في تحديث اسم مفتاح API",
|
||||||
|
"embeds_title": "تضمين HTML iframe",
|
||||||
|
"embeds_description": "تضمين جميع أنواع الأحداث لديك على موقعك على الإنترنت",
|
||||||
|
"create_first_api_key": "إنشاء أول مفتاح API لك",
|
||||||
|
"create_first_api_key_description": "تسمح مفاتيح API بتواصل التطبيقات الأخرى مع Cal.com",
|
||||||
|
"back_to_signin": "العودة لتسجيل الدخول",
|
||||||
|
"reset_link_sent": "تم إرسال رابط إعادة الضبط",
|
||||||
|
"password_reset_email": "ثمة بريد إلكتروني في طريقه إلى {{email}} مع تعليمات لإعادة تعيين كلمة المرور الخاصة بك.",
|
||||||
|
"password_updated": "تم تحديث كلمة المرور!",
|
||||||
|
"pending_payment": "في انتظار الدفع",
|
||||||
|
"confirmation_page_rainbow": "رمز بوابة الحدث الخاص بك مع الرموز أو NFTs على Ethereum وPolygon وغيرها.",
|
||||||
|
"not_on_cal": "ليس على Cal.com",
|
||||||
|
"no_calendar_installed": "لا يوجد رزنامة مثبتة",
|
||||||
|
"no_calendar_installed_description": "لم تقم بعد بالاتصال بأي من التقويمات الخاصة بك",
|
||||||
|
"add_a_calendar": "إضافة رزنامة",
|
||||||
|
"change_email_hint": "قد تحتاج إلى تسجيل الخروج والعودة مجددًا لرؤية التغييرات التي تم تنفيذها",
|
||||||
|
"confirm_password_change_email": "الرجاء تأكيد كلمة المرور الخاصة بك قبل تغيير عنوان بريدك الإلكتروني",
|
||||||
|
"seats": "مقاعد",
|
||||||
|
"every_app_published": "كل تطبيق منشور على متجر تطبيقات Cal.com هو مصدر مفتوح ويتم اختباره بشكل شامل عن طريق مراجعات الأقران. لا يدعم Cal.com أو يصادق على هذه التطبيقات ما لم يتم نشرها بواسطة Cal.com. إذا واجهت محتوى أو سلوك غير مناسب يرجى الإبلاغ عن ذلك.",
|
||||||
|
"report_app": "الإبلاغ عن التطبيق"
|
||||||
}
|
}
|
||||||
@@ -112,7 +112,6 @@
|
|||||||
"use_link_to_reset_password": "Pro obnovení hesla použijte odkaz níž",
|
"use_link_to_reset_password": "Pro obnovení hesla použijte odkaz níž",
|
||||||
"hey_there": "Zdravíme,",
|
"hey_there": "Zdravíme,",
|
||||||
"forgot_your_password_calcom": "Zapomněli jste heslo? - Cal.com",
|
"forgot_your_password_calcom": "Zapomněli jste heslo? - Cal.com",
|
||||||
"event_type_title": "{{eventTypeTitle}} | Typ události",
|
|
||||||
"delete_webhook_confirmation_message": "Opravdu chcete smazat tento webhook? Přestanete v reálném čase dostávat Cal.com data o schůzce na dané URL, pokud bude událost naplánována nebo zrušena.",
|
"delete_webhook_confirmation_message": "Opravdu chcete smazat tento webhook? Přestanete v reálném čase dostávat Cal.com data o schůzce na dané URL, pokud bude událost naplánována nebo zrušena.",
|
||||||
"confirm_delete_webhook": "Ano, smazat webhook",
|
"confirm_delete_webhook": "Ano, smazat webhook",
|
||||||
"edit_webhook": "Upravit webhook",
|
"edit_webhook": "Upravit webhook",
|
||||||
@@ -143,6 +142,7 @@
|
|||||||
"view_public_page": "Zobrazit veřejnou stránku",
|
"view_public_page": "Zobrazit veřejnou stránku",
|
||||||
"sign_out": "Odhlásit se",
|
"sign_out": "Odhlásit se",
|
||||||
"add_another": "Přidat další",
|
"add_another": "Přidat další",
|
||||||
|
"install_another": "Nainstalovat další",
|
||||||
"until": "do",
|
"until": "do",
|
||||||
"powered_by": "běží na",
|
"powered_by": "běží na",
|
||||||
"unavailable": "Nedostupný",
|
"unavailable": "Nedostupný",
|
||||||
@@ -157,6 +157,7 @@
|
|||||||
"checkbox": "Zaškrtávací pole",
|
"checkbox": "Zaškrtávací pole",
|
||||||
"is_required": "Je vyžadováno",
|
"is_required": "Je vyžadováno",
|
||||||
"required": "Vyžadováno",
|
"required": "Vyžadováno",
|
||||||
|
"optional": "Nepovinné",
|
||||||
"input_type": "Typ pole",
|
"input_type": "Typ pole",
|
||||||
"rejected": "Zamítnuto",
|
"rejected": "Zamítnuto",
|
||||||
"unconfirmed": "Nepotvrzeno",
|
"unconfirmed": "Nepotvrzeno",
|
||||||
@@ -227,10 +228,12 @@
|
|||||||
"connect_your_calendar_instructions": "Připojit kalendář pro automatickou kontrolu časů, kdy nejste dostupní, a nově naplánovaných událostí.",
|
"connect_your_calendar_instructions": "Připojit kalendář pro automatickou kontrolu časů, kdy nejste dostupní, a nově naplánovaných událostí.",
|
||||||
"set_up_later": "Zprovoznit později",
|
"set_up_later": "Zprovoznit později",
|
||||||
"current_time": "Aktuální čas",
|
"current_time": "Aktuální čas",
|
||||||
|
"details": "Podrobnosti",
|
||||||
"welcome": "Vítejte",
|
"welcome": "Vítejte",
|
||||||
|
"welcome_back": "Vítejte zpět",
|
||||||
"welcome_to_calcom": "Vítejte na webu Cal.com",
|
"welcome_to_calcom": "Vítejte na webu Cal.com",
|
||||||
"welcome_instructions": "Řekněte nám vaše jméno a v jaké časové zóně se pohybujete. Později můžete tyto informace změnit.",
|
"welcome_instructions": "Řekněte nám vaše jméno a v jaké časové zóně se pohybujete. Později můžete tyto informace změnit.",
|
||||||
"connect_caldav": "Připojit se k CalDav serveru",
|
"connect_caldav": "Připojit se k CalDav (Beta)u",
|
||||||
"credentials_stored_and_encrypted": "Vaše přihlašovací údaje budou uloženy a zašifrovány.",
|
"credentials_stored_and_encrypted": "Vaše přihlašovací údaje budou uloženy a zašifrovány.",
|
||||||
"connect": "Připojit",
|
"connect": "Připojit",
|
||||||
"try_for_free": "Vyzkoušet zdarma",
|
"try_for_free": "Vyzkoušet zdarma",
|
||||||
@@ -240,6 +243,7 @@
|
|||||||
"when": "Kdy",
|
"when": "Kdy",
|
||||||
"where": "Kde",
|
"where": "Kde",
|
||||||
"add_to_calendar": "Přidat do kalendáře",
|
"add_to_calendar": "Přidat do kalendáře",
|
||||||
|
"add_another_calendar": "Přidat další kalendář",
|
||||||
"other": "Ostatní",
|
"other": "Ostatní",
|
||||||
"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": "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_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.",
|
||||||
@@ -261,6 +265,8 @@
|
|||||||
"enter_new_password": "Zadejte nové heslo, které chcete u účtu používat.",
|
"enter_new_password": "Zadejte nové heslo, které chcete u účtu používat.",
|
||||||
"reset_password": "Obnovit heslo",
|
"reset_password": "Obnovit heslo",
|
||||||
"change_your_password": "Změnit heslo",
|
"change_your_password": "Změnit heslo",
|
||||||
|
"show_password": "Zobrazit heslo",
|
||||||
|
"hide_password": "Skrýt heslo",
|
||||||
"try_again": "Zkusit znovu",
|
"try_again": "Zkusit znovu",
|
||||||
"request_is_expired": "Platnost tohoto požadavku vypršela.",
|
"request_is_expired": "Platnost tohoto požadavku vypršela.",
|
||||||
"reset_instructions": "Zadejte e-mailovou adresu přiřazenou k vašemu účtu. Pošleme vám na ni odkaz pro obnovení vašeho hesla.",
|
"reset_instructions": "Zadejte e-mailovou adresu přiřazenou k vašemu účtu. Pošleme vám na ni odkaz pro obnovení vašeho hesla.",
|
||||||
@@ -306,6 +312,7 @@
|
|||||||
"recurring_bookings": "Jakmile si někdo s vámi zarezervuje opakovanou schůzku, zobrazí se to zde.",
|
"recurring_bookings": "Jakmile si někdo s vámi zarezervuje opakovanou schůzku, zobrazí se to zde.",
|
||||||
"past_bookings": "Vaše proběhlé rezervace se zobrazí zde.",
|
"past_bookings": "Vaše proběhlé rezervace se zobrazí zde.",
|
||||||
"cancelled_bookings": "Vaše zrušené rezervace se zobrazí zde.",
|
"cancelled_bookings": "Vaše zrušené rezervace se zobrazí zde.",
|
||||||
|
"unconfirmed_bookings": "Vaše nepotvrzené rezervace se zobrazí zde.",
|
||||||
"on": "dne",
|
"on": "dne",
|
||||||
"and": "a",
|
"and": "a",
|
||||||
"calendar_shows_busy_between": "Kalendář vás zobrazuje jako nedostupného mezi",
|
"calendar_shows_busy_between": "Kalendář vás zobrazuje jako nedostupného mezi",
|
||||||
@@ -346,6 +353,7 @@
|
|||||||
"booking_cancelled": "Rezervace zrušena",
|
"booking_cancelled": "Rezervace zrušena",
|
||||||
"booking_rescheduled": "Rezervace přesunuta",
|
"booking_rescheduled": "Rezervace přesunuta",
|
||||||
"booking_created": "Rezervace vytvořena",
|
"booking_created": "Rezervace vytvořena",
|
||||||
|
"meeting_ended": "Schůzka skončila",
|
||||||
"form_submitted": "Formulář byl odeslán",
|
"form_submitted": "Formulář byl odeslán",
|
||||||
"event_triggers": "Eventy na základě akce",
|
"event_triggers": "Eventy na základě akce",
|
||||||
"subscriber_url": "URL pro odběry",
|
"subscriber_url": "URL pro odběry",
|
||||||
@@ -488,6 +496,9 @@
|
|||||||
"lets_create_first_administrator_user": "Pojďme vytvořit prvního uživatele administrátora.",
|
"lets_create_first_administrator_user": "Pojďme vytvořit prvního uživatele administrátora.",
|
||||||
"new_member": "Nový člen",
|
"new_member": "Nový člen",
|
||||||
"invite": "Pozvat",
|
"invite": "Pozvat",
|
||||||
|
"add_team_members": "Přidat členy týmu",
|
||||||
|
"add_team_members_description": "Pozvěte další, aby se připojili k vašemu týmu",
|
||||||
|
"add_team_member": "Přidat člena týmu",
|
||||||
"invite_new_member": "Pozvat nového člena",
|
"invite_new_member": "Pozvat nového člena",
|
||||||
"invite_new_team_member": "Pozvat někoho do týmu.",
|
"invite_new_team_member": "Pozvat někoho do týmu.",
|
||||||
"change_member_role": "Změnit roli člena týmu",
|
"change_member_role": "Změnit roli člena týmu",
|
||||||
@@ -600,6 +611,7 @@
|
|||||||
"create_first_team_and_invite_others": "Vytvořte svůj první tým a pozvěte další uživatele, aby s vámi spolupracovali.",
|
"create_first_team_and_invite_others": "Vytvořte svůj první tým a pozvěte další uživatele, aby s vámi spolupracovali.",
|
||||||
"create_team_to_get_started": "Začněte vytvořením týmu",
|
"create_team_to_get_started": "Začněte vytvořením týmu",
|
||||||
"teams": "Týmy",
|
"teams": "Týmy",
|
||||||
|
"team": "Tým",
|
||||||
"team_billing": "Fakturace týmů",
|
"team_billing": "Fakturace týmů",
|
||||||
"upgrade_to_flexible_pro_title": "Změnili jsme fakturaci pro týmy",
|
"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.",
|
"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.",
|
||||||
@@ -620,7 +632,9 @@
|
|||||||
"billing": "Fakturace",
|
"billing": "Fakturace",
|
||||||
"manage_your_billing_info": "Spravujte své fakturační údaje a zrušte své předplatné.",
|
"manage_your_billing_info": "Spravujte své fakturační údaje a zrušte své předplatné.",
|
||||||
"availability": "Dostupnost",
|
"availability": "Dostupnost",
|
||||||
|
"edit_availability": "Upravit dostupnost",
|
||||||
"configure_availability": "Nastavit časy, kdy jste dostupní pro rezervace.",
|
"configure_availability": "Nastavit časy, kdy jste dostupní pro rezervace.",
|
||||||
|
"copy_times_to": "Kopírovat časy do",
|
||||||
"change_weekly_schedule": "Změnit týdenní pracovní dobu",
|
"change_weekly_schedule": "Změnit týdenní pracovní dobu",
|
||||||
"logo": "Logo",
|
"logo": "Logo",
|
||||||
"error": "Chyba",
|
"error": "Chyba",
|
||||||
@@ -635,6 +649,7 @@
|
|||||||
"event_name_tooltip": "Název, který se zobrazí v kalendářích",
|
"event_name_tooltip": "Název, který se zobrazí v kalendářích",
|
||||||
"meeting_with_user": "Schůzka s {ATTENDEE}",
|
"meeting_with_user": "Schůzka s {ATTENDEE}",
|
||||||
"additional_inputs": "Další pole",
|
"additional_inputs": "Další pole",
|
||||||
|
"additional_input_description": "Před potvrzením rezervace vyžadovat od plánující osoby zadání dalších vstupů",
|
||||||
"label": "Popisek",
|
"label": "Popisek",
|
||||||
"placeholder": "Placeholder",
|
"placeholder": "Placeholder",
|
||||||
"type": "Typ",
|
"type": "Typ",
|
||||||
@@ -649,6 +664,8 @@
|
|||||||
"disable_guests": "Zakázat hosty",
|
"disable_guests": "Zakázat hosty",
|
||||||
"disable_guests_description": "Zakázat přidávání dalších hostů během rezervace.",
|
"disable_guests_description": "Zakázat přidávání dalších hostů během rezervace.",
|
||||||
"private_link": "Vygenerovat soukromou adresu URL",
|
"private_link": "Vygenerovat soukromou adresu URL",
|
||||||
|
"private_link_label": "Soukromý odkaz",
|
||||||
|
"private_link_hint": "Váš soukromý odkaz se po každém použití obnoví",
|
||||||
"copy_private_link": "Zkopírovat soukromý odkaz",
|
"copy_private_link": "Zkopírovat soukromý odkaz",
|
||||||
"private_link_description": "Vygenerujte soukromou adresu URL, kterou budete sdílet, aniž byste odhalili své uživatelské jméno ve službě Cal",
|
"private_link_description": "Vygenerujte soukromou adresu URL, kterou budete sdílet, aniž byste odhalili své uživatelské jméno ve službě Cal",
|
||||||
"invitees_can_schedule": "Pozvaní mohou plánovat",
|
"invitees_can_schedule": "Pozvaní mohou plánovat",
|
||||||
@@ -679,7 +696,7 @@
|
|||||||
"add_new_event_type": "Přidat nový typ události",
|
"add_new_event_type": "Přidat nový typ události",
|
||||||
"new_event_type_to_book_description": "Vytvořit nový typ události, ve které si lidé mohou rezervovat časy.",
|
"new_event_type_to_book_description": "Vytvořit nový typ události, ve které si lidé mohou rezervovat časy.",
|
||||||
"length": "Doba trvání",
|
"length": "Doba trvání",
|
||||||
"minimum_booking_notice": "Minimální upozornění na rezervaci",
|
"minimum_booking_notice": "Minimální potřebná doba",
|
||||||
"slot_interval": "Časové intervaly",
|
"slot_interval": "Časové intervaly",
|
||||||
"slot_interval_default": "Použít délku události (výchozí)",
|
"slot_interval_default": "Použít délku události (výchozí)",
|
||||||
"delete_event_type_description": "Opravdu chcete smazat tento typ události? Všichni, se kterými jsme tento odkaz sdíleli, ho nebudou moct používat pro rezervování.",
|
"delete_event_type_description": "Opravdu chcete smazat tento typ události? Všichni, se kterými jsme tento odkaz sdíleli, ho nebudou moct používat pro rezervování.",
|
||||||
@@ -690,16 +707,21 @@
|
|||||||
"delete_account_confirmation_message": "Opravdu chcete odstranit svůj účet na Cal.com? 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.",
|
"delete_account_confirmation_message": "Opravdu chcete odstranit svůj účet na Cal.com? 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",
|
"integrations": "Integrace",
|
||||||
"apps": "Aplikace",
|
"apps": "Aplikace",
|
||||||
|
"category_apps": "Aplikace ({{category}})",
|
||||||
"app_store": "App Store",
|
"app_store": "App Store",
|
||||||
"app_store_description": "Propojování lidí, technologií a pracoviště.",
|
"app_store_description": "Propojování lidí, technologií a pracoviště.",
|
||||||
"settings": "Nastavení",
|
"settings": "Nastavení",
|
||||||
"event_type_moved_successfully": "Typ události byl úspěšně přesunut",
|
"event_type_moved_successfully": "Typ události byl úspěšně přesunut",
|
||||||
|
"next_step_text": "Další krok",
|
||||||
"next_step": "Přeskočit krok",
|
"next_step": "Přeskočit krok",
|
||||||
"prev_step": "Předchozí krok",
|
"prev_step": "Předchozí krok",
|
||||||
|
"install": "Nainstalovat",
|
||||||
"installed": "Nainstalováno",
|
"installed": "Nainstalováno",
|
||||||
"active_install_one": "Aktivní instalace: {{count}}",
|
"active_install_one": "Aktivní instalace: {{count}}",
|
||||||
"active_install_other": "Aktivní instalace: {{count}}",
|
"active_install_other": "Aktivní instalace: {{count}}",
|
||||||
"globally_install": "Nainstalováno globálně",
|
"globally_install": "Nainstalováno globálně",
|
||||||
|
"app_successfully_installed": "Aplikace byla nainstalována",
|
||||||
|
"app_could_not_be_installed": "Aplikaci se nepodařilo nainstalovat",
|
||||||
"disconnect": "Odpojit",
|
"disconnect": "Odpojit",
|
||||||
"embed_your_calendar": "Vložte kalendář do vaší webové stránky",
|
"embed_your_calendar": "Vložte kalendář do vaší webové stránky",
|
||||||
"connect_your_favourite_apps": "Připojte své oblíbené aplikace.",
|
"connect_your_favourite_apps": "Připojte své oblíbené aplikace.",
|
||||||
@@ -710,6 +732,7 @@
|
|||||||
"connect_additional_calendar": "Připojit další kalendář",
|
"connect_additional_calendar": "Připojit další kalendář",
|
||||||
"conferencing": "Konference",
|
"conferencing": "Konference",
|
||||||
"calendar": "Kalendář",
|
"calendar": "Kalendář",
|
||||||
|
"payments": "Platby",
|
||||||
"not_installed": "Nenainstalováno",
|
"not_installed": "Nenainstalováno",
|
||||||
"error_password_mismatch": "Hesla se neshodují.",
|
"error_password_mismatch": "Hesla se neshodují.",
|
||||||
"error_required_field": "Toto pole je povinné.",
|
"error_required_field": "Toto pole je povinné.",
|
||||||
@@ -743,9 +766,22 @@
|
|||||||
"import_from": "Importovat z",
|
"import_from": "Importovat z",
|
||||||
"access_token": "Access token",
|
"access_token": "Access token",
|
||||||
"visit_roadmap": "Roadmapa",
|
"visit_roadmap": "Roadmapa",
|
||||||
|
"featured_categories": "Doporučené kategorie",
|
||||||
"popular_categories": "Oblíbené kategorie",
|
"popular_categories": "Oblíbené kategorie",
|
||||||
|
"number_apps_one": "Aplikace: {{count}}",
|
||||||
|
"number_apps_other": "Aplikace: {{count}}",
|
||||||
"trending_apps": "Populární aplikace",
|
"trending_apps": "Populární aplikace",
|
||||||
|
"explore_apps": "Aplikace ({{category}})",
|
||||||
"installed_apps": "Nainstalované aplikace",
|
"installed_apps": "Nainstalované aplikace",
|
||||||
|
"no_category_apps": "Žádné aplikace ({{kategorie}})",
|
||||||
|
"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",
|
||||||
|
"no_category_apps_description_payment": "Přidejte platební aplikaci, která usnadní provádění transakcí mezi vámi a vašimi klienty",
|
||||||
|
"no_category_apps_description_other": "Přidejte jakýkoli jiný typ aplikace pro nejrůznější činnosti",
|
||||||
|
"installed_app_calendar_description": "Nastavte si kalendáře, ať můžete kontrolovat konflikty a zabránit tak dvojím rezervacím.",
|
||||||
|
"installed_app_conferencing_description": "Přidejte své oblíbené aplikace pro videokonference pro vaše schůzky",
|
||||||
|
"installed_app_payment_description": "Nakonfigurujte služby zpracování plateb, které se mají používat při strhávání plateb z klientů.",
|
||||||
|
"installed_app_other_description": "Všechny vaše nainstalované aplikace z ostatních kategorií.",
|
||||||
"empty_installed_apps_headline": "Nenainstalovány žádné aplikace",
|
"empty_installed_apps_headline": "Nenainstalovány žádné aplikace",
|
||||||
"empty_installed_apps_description": "Aplikace vám umožní zlepšit pracovní postupy a výrazně zkvalitnit plánování.",
|
"empty_installed_apps_description": "Aplikace vám umožní zlepšit pracovní postupy a výrazně zkvalitnit plánování.",
|
||||||
"empty_installed_apps_button": "Prozkoumejte App Store",
|
"empty_installed_apps_button": "Prozkoumejte App Store",
|
||||||
@@ -766,6 +802,7 @@
|
|||||||
"remove": "Odebrat",
|
"remove": "Odebrat",
|
||||||
"add": "Přidat",
|
"add": "Přidat",
|
||||||
"installed_one": "Nainstalováno",
|
"installed_one": "Nainstalováno",
|
||||||
|
"installed_other": "Nainstalováno: {{count}}",
|
||||||
"verify_wallet": "Ověřit peněženku",
|
"verify_wallet": "Ověřit peněženku",
|
||||||
"connect_metamask": "Připojit Metamask",
|
"connect_metamask": "Připojit Metamask",
|
||||||
"create_events_on": "Vytvořit události v:",
|
"create_events_on": "Vytvořit události v:",
|
||||||
@@ -783,6 +820,8 @@
|
|||||||
"set_to_default": "Nastavit jako výchozí",
|
"set_to_default": "Nastavit jako výchozí",
|
||||||
"new_schedule_btn": "Nový plán",
|
"new_schedule_btn": "Nový plán",
|
||||||
"add_new_schedule": "Přidat nový plán",
|
"add_new_schedule": "Přidat nový plán",
|
||||||
|
"add_new_calendar": "Přidání nového kalendáře",
|
||||||
|
"set_calendar": "Nastavte, kam se mají při rezervaci přidávat nové události.",
|
||||||
"delete_schedule": "Odstranit plán",
|
"delete_schedule": "Odstranit plán",
|
||||||
"schedule_created_successfully": "Plán {{scheduleName}} byl úspěšně vytvořen",
|
"schedule_created_successfully": "Plán {{scheduleName}} byl úspěšně vytvořen",
|
||||||
"availability_updated_successfully": "Dostupnost byla úspěšně aktualizována",
|
"availability_updated_successfully": "Dostupnost byla úspěšně aktualizována",
|
||||||
@@ -809,7 +848,7 @@
|
|||||||
"booking_full": "Nejsou k dispozici žádná další místa",
|
"booking_full": "Nejsou k dispozici žádná další místa",
|
||||||
"api_keys": "Klíče API",
|
"api_keys": "Klíče API",
|
||||||
"api_key": "Klíč API",
|
"api_key": "Klíč API",
|
||||||
"test_api_key": "Testovací klíč API",
|
"test_api_key": "Otestovat klíč API",
|
||||||
"test_passed": "Test se zdařil!",
|
"test_passed": "Test se zdařil!",
|
||||||
"test_failed": "Test se nezdařil",
|
"test_failed": "Test se nezdařil",
|
||||||
"provide_api_key": "Zadejte klíč API",
|
"provide_api_key": "Zadejte klíč API",
|
||||||
@@ -883,7 +922,7 @@
|
|||||||
"zapier_setup_instructions": "<0>Přihlaste se ke svému účtu Zapier a vytvořte nový Zap.</0><1>Vyberte Cal.com jako svoji aplikaci Trigger. Také vyberte událost Trigger.</1><2>Vyberte si svůj účet a pak zadejte svůj unikátní klíč API.</2><3>Otestujte aplikaci Trigger.</3><4>Vše máte nastaveno!</4>",
|
"zapier_setup_instructions": "<0>Přihlaste se ke svému účtu Zapier a vytvořte nový Zap.</0><1>Vyberte Cal.com jako svoji aplikaci Trigger. Také vyberte událost Trigger.</1><2>Vyberte si svůj účet a pak zadejte svůj unikátní klíč API.</2><3>Otestujte aplikaci Trigger.</3><4>Vše máte nastaveno!</4>",
|
||||||
"install_zapier_app": "Nejdřív si z App Store nainstalujte aplikaci Zapier.",
|
"install_zapier_app": "Nejdřív si z App Store nainstalujte aplikaci Zapier.",
|
||||||
"connect_apple_server": "Připojit se k serveru Apple",
|
"connect_apple_server": "Připojit se k serveru Apple",
|
||||||
"connect_caldav_server": "Připojit se k CalDav serveru",
|
"connect_caldav_server": "Připojit se k CalDav (Beta)u",
|
||||||
"calendar_url": "URL kalendáře",
|
"calendar_url": "URL kalendáře",
|
||||||
"apple_server_generate_password": "Vygenerujte si specifické heslo pro aplikaci Cal.com na",
|
"apple_server_generate_password": "Vygenerujte si specifické heslo pro aplikaci Cal.com na",
|
||||||
"credentials_stored_encrypted": "Vaše přihlašovací údaje budou uloženy a zašifrovány.",
|
"credentials_stored_encrypted": "Vaše přihlašovací údaje budou uloženy a zašifrovány.",
|
||||||
@@ -936,6 +975,7 @@
|
|||||||
"workflows": "Pracovní postupy",
|
"workflows": "Pracovní postupy",
|
||||||
"new_workflow_btn": "Nový pracovní postup",
|
"new_workflow_btn": "Nový pracovní postup",
|
||||||
"add_new_workflow": "Přidat nový pracovní postup",
|
"add_new_workflow": "Přidat nový pracovní postup",
|
||||||
|
"reschedule_event_trigger": "pokud je událost přeložena na jiný termín",
|
||||||
"trigger": "Spouštěč",
|
"trigger": "Spouštěč",
|
||||||
"triggers": "Spouštěče",
|
"triggers": "Spouštěče",
|
||||||
"action": "Akce",
|
"action": "Akce",
|
||||||
@@ -949,7 +989,7 @@
|
|||||||
"workflow_deleted_successfully": "Pracovní postup byl odstraněn",
|
"workflow_deleted_successfully": "Pracovní postup byl odstraněn",
|
||||||
"how_long_before": "Za jak dlouho začne událost?",
|
"how_long_before": "Za jak dlouho začne událost?",
|
||||||
"day_timeUnit": "dny",
|
"day_timeUnit": "dny",
|
||||||
"hour_timeUnit": "hodiny",
|
"hour_timeUnit": "h",
|
||||||
"minute_timeUnit": "min",
|
"minute_timeUnit": "min",
|
||||||
"new_workflow_heading": "Vytvořte svůj první pracovní postup",
|
"new_workflow_heading": "Vytvořte svůj první pracovní postup",
|
||||||
"new_workflow_description": "Pracovní postupy umožňují automatizovat zasílání upomínek a oznámení.",
|
"new_workflow_description": "Pracovní postupy umožňují automatizovat zasílání upomínek a oznámení.",
|
||||||
@@ -963,10 +1003,13 @@
|
|||||||
"change_username_standard_to_premium": "Při změně uživatelského jména ze standardního na prémiové budete přesměrováni k platbě, po které přejdete na vyšší verzi.",
|
"change_username_standard_to_premium": "Při změně uživatelského jména ze standardního na prémiové budete přesměrováni k platbě, po které přejdete na vyšší verzi.",
|
||||||
"change_username_premium_to_standard": "Při změně uživatelského jména z prémiového na standardní budete přesměrováni k platbě, po které přejdete na nižší verzi.",
|
"change_username_premium_to_standard": "Při změně uživatelského jména z prémiového na standardní budete přesměrováni k platbě, po které přejdete na nižší verzi.",
|
||||||
"go_to_stripe_billing": "Přejít k fakturaci",
|
"go_to_stripe_billing": "Přejít k fakturaci",
|
||||||
|
"stripe_description": "Vyžadovat poplatek za rezervace (0,5 % + 0,10 € provize za transakci)",
|
||||||
"trial_expired": "Vaše zkušební verze vypršela",
|
"trial_expired": "Vaše zkušební verze vypršela",
|
||||||
"remove_app": "Odstranit aplikaci",
|
"remove_app": "Odstranit aplikaci",
|
||||||
"yes_remove_app": "Ano, odstranit aplikaci",
|
"yes_remove_app": "Ano, odstranit aplikaci",
|
||||||
"are_you_sure_you_want_to_remove_this_app": "Opravdu chcete odstranit tuto aplikaci?",
|
"are_you_sure_you_want_to_remove_this_app": "Opravdu chcete odstranit tuto aplikaci?",
|
||||||
|
"app_removed_successfully": "Aplikace odstraněna",
|
||||||
|
"error_removing_app": "Chyba při odstraňování aplikace",
|
||||||
"web_conference": "Webová konference",
|
"web_conference": "Webová konference",
|
||||||
"number_for_sms_reminders": "Telefonní číslo (pro upomínky přes SMS)",
|
"number_for_sms_reminders": "Telefonní číslo (pro upomínky přes SMS)",
|
||||||
"requires_confirmation": "Vyžaduje potvrzení",
|
"requires_confirmation": "Vyžaduje potvrzení",
|
||||||
@@ -1022,18 +1065,205 @@
|
|||||||
"navigate": "Navigace",
|
"navigate": "Navigace",
|
||||||
"open": "Otevřít",
|
"open": "Otevřít",
|
||||||
"close": "Zavřít",
|
"close": "Zavřít",
|
||||||
|
"team_feature_teams": "Toto je funkce Team. Pokud chcete zobrazit dostupnost svého týmu, upgradujte na verzi Team.",
|
||||||
|
"team_feature_workflows": "Jedná se o funkci Team. Upgradujte na verzi Team, abyste mohli automatizovat upozornění na události a upomínky pomocí pracovních postupů.",
|
||||||
|
"show_eventtype_on_profile": "Zobrazit na profilu",
|
||||||
"embed": "Vložit",
|
"embed": "Vložit",
|
||||||
"new_username": "Nové uživatelské jméno",
|
"new_username": "Nové uživatelské jméno",
|
||||||
"current_username": "Současné uživatelské jméno",
|
"current_username": "Současné uživatelské jméno",
|
||||||
"example_1": "Příklad 1",
|
"example_1": "Příklad 1",
|
||||||
"example_2": "Příklad 2",
|
"example_2": "Příklad 2",
|
||||||
|
"additional_input_label": "Další vstupní štítek",
|
||||||
"company_size": "Velikost společnosti",
|
"company_size": "Velikost společnosti",
|
||||||
"what_help_needed": "S čím potřebujete pomoci?",
|
"what_help_needed": "S čím potřebujete pomoci?",
|
||||||
"variable_format": "Formát proměnné",
|
"variable_format": "Formát proměnné",
|
||||||
|
"webhook_subscriber_url_reserved": "Adresa URL odběratele webhooku je již definována",
|
||||||
|
"custom_input_as_variable_info": "Ignorujte všechny speciální znaky doplňkového vstupního štítku (používejte pouze písmena a číslice), používejte velká písmena a bílé znaky nahraďte podtržítky.",
|
||||||
"using_additional_inputs_as_variables": "Jak používat doplňkové vstupy jako proměnné?",
|
"using_additional_inputs_as_variables": "Jak používat doplňkové vstupy jako proměnné?",
|
||||||
"download_desktop_app": "Stáhněte si aplikaci pro stolní počítače",
|
"download_desktop_app": "Stáhněte si aplikaci pro stolní počítače",
|
||||||
"set_ping_link": "Nastavení odkazu Ping",
|
"set_ping_link": "Nastavení odkazu Ping",
|
||||||
|
"rate_limit_exceeded": "Byl překročen limit rychlosti",
|
||||||
|
"when_something_happens": "Pokud se něco stane",
|
||||||
|
"action_is_performed": "Provede se akce",
|
||||||
|
"test_action": "Testovací akce",
|
||||||
|
"notification_sent": "Oznámení odesláno",
|
||||||
|
"no_input": "Žádný vstup",
|
||||||
|
"test_workflow_action": "Testovací akce pracovního postupu",
|
||||||
|
"send_sms": "Odeslat SMS",
|
||||||
|
"send_sms_to_number": "Opravdu chcete odeslat SMS na číslo {{number}}?",
|
||||||
|
"missing_connected_calendar": "Není připojen žádný výchozí kalendář",
|
||||||
|
"connect_your_calendar_and_link": "Svůj kalendář můžete připojit <1>zde</1>.",
|
||||||
|
"default_calendar_selected": "Výchozí kalendář",
|
||||||
|
"hide_from_profile": "Nezobrazovat v profilu",
|
||||||
|
"event_setup_tab_title": "Nastavení události",
|
||||||
|
"event_limit_tab_title": "Omezení",
|
||||||
|
"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",
|
||||||
|
"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í",
|
||||||
|
"2fa_required": "Vyžadováno dvoufázové ověření",
|
||||||
|
"incorrect_2fa": "Nesprávný kód dvoufázového ověření",
|
||||||
|
"which_event_type_apply": "Na jaký typ události se to bude vztahovat?",
|
||||||
|
"no_workflows_description": "Pracovní postupy umožňují jednoduchou automatizaci zasílání oznámení a připomínek, což vám umožní vytvářet procesy v souvislosti s vašimi událostmi.",
|
||||||
|
"create_workflow": "Vytvoření pracovního postupu",
|
||||||
|
"do_this": "Provést",
|
||||||
|
"turn_off": "Vypnout",
|
||||||
|
"settings_updated_successfully": "Nastavení aktualizováno",
|
||||||
|
"error_updating_settings": "Chyba při aktualizaci nastavení",
|
||||||
|
"personal_cal_url": "Moje osobní adresa URL Cal",
|
||||||
|
"bio_hint": "Několik vět o vás. Obsah se zobrazí se na vaší osobní stránce URL.",
|
||||||
|
"delete_account_modal_title": "Odstranit účet",
|
||||||
|
"confirm_delete_account_modal": "Opravdu chcete odstranit svůj účet Cal.com?",
|
||||||
|
"delete_my_account": "Odstranit můj účet",
|
||||||
|
"start_of_week": "Začátek týdne",
|
||||||
|
"select_calendars": "Vyberte kalendáře, u kterých chcete kontrolovat konflikty v zájmu prevence dvojích rezervací.",
|
||||||
|
"check_for_conflicts": "Zkontrolovat konflikty",
|
||||||
|
"adding_events_to": "Přidání událostí do:",
|
||||||
|
"follow_system_preferences": "Řídit se předvolbami systému",
|
||||||
|
"custom_brand_colors": "Vlastní barvy značky",
|
||||||
|
"customize_your_brand_colors": "Vytvořte si rezervační stránku na míru v barvách své značky.",
|
||||||
|
"pro": "Pro",
|
||||||
|
"removes_cal_branding": "Odstraní všechny značky související s Cal, tj. „Běží na platformě Cal.“",
|
||||||
|
"profile_picture": "Profilový obrázek",
|
||||||
|
"upload": "Nahrát",
|
||||||
|
"web3": "Web3",
|
||||||
|
"rainbow_token_gated": "Tento typ události je uzamčený tokenem.",
|
||||||
|
"rainbow_connect_wallet_gate": "Propojte svoji peněženku, pokud vlastníte <1>{{name}}</1> (<3>{{symbol}}</3>).",
|
||||||
|
"rainbow_insufficient_balance": "Vaše propojená peněženka neobsahuje dostatek <1>{{symbol}}</1>.",
|
||||||
|
"rainbow_sign_message_request": "Podepište zprávu s žádostí ve své peněžence.",
|
||||||
|
"rainbow_signature_error": "Chyba při vyžádání podpisu z vaší peněženky.",
|
||||||
|
"token_address": "Adresa tokenu",
|
||||||
|
"blockchain": "Blockchain",
|
||||||
|
"old_password": "Staré heslo",
|
||||||
|
"secure_password": "Vaše nové heslo se super zabezpečením",
|
||||||
|
"error_updating_password": "Chyba při aktualizaci hesla",
|
||||||
|
"two_factor_auth": "Dvoufázové ověření",
|
||||||
|
"recurring_event_tab_description": "Nastavení opakujícího se plánu",
|
||||||
|
"today": "dnes",
|
||||||
|
"appearance": "Vzhled",
|
||||||
|
"appearance_subtitle": "Správa nastavení vzhledu rezervace",
|
||||||
|
"my_account": "Můj účet",
|
||||||
|
"general": "Obecné",
|
||||||
|
"calendars": "Kalendáře",
|
||||||
|
"2fa_auth": "Dvoufázové ověření",
|
||||||
|
"invoices": "Faktury",
|
||||||
|
"embeds": "Vložení",
|
||||||
|
"impersonation": "Ztotožnění",
|
||||||
|
"users": "Uživatelé",
|
||||||
|
"profile_description": "Správa nastavení profilu Cal",
|
||||||
|
"general_description": "Správa nastavení jazyka a časového pásma",
|
||||||
|
"calendars_description": "Konfigurace způsobu interkace typů událostí s kalendáři",
|
||||||
|
"appearance_description": "Správa nastavení vzhledu rezervace",
|
||||||
|
"conferencing_description": "Správa videokonferenčních aplikací pro vaše schůzky",
|
||||||
|
"password_description": "Správa nastavení pro hesla vašich účtů",
|
||||||
|
"2fa_description": "Správa nastavení pro hesla vašich účtů",
|
||||||
|
"we_just_need_basic_info": "K nastavení vašeho profilu potřebujeme jen několik základních informací.",
|
||||||
|
"skip": "Přeskočit",
|
||||||
|
"do_this_later": "Provést později",
|
||||||
|
"set_availability_getting_started_subtitle_1": "Definujte časová rozpětí, kdy budete k dispozici",
|
||||||
|
"set_availability_getting_started_subtitle_2": "To vše si můžete přizpůsobit později na stránce dostupnosti.",
|
||||||
|
"connect_calendars_from_app_store": "Další kalendáře můžete přidat přes obchod s aplikacemi",
|
||||||
|
"connect_conference_apps": "Propojit konferenční aplikace",
|
||||||
|
"connect_calendar_apps": "Propojit kalendářové aplikace",
|
||||||
|
"connect_payment_apps": "Připojit platební aplikace",
|
||||||
|
"connect_other_apps": "Připojit další aplikace",
|
||||||
|
"current_step_of_total": "Krok {{currentStep}} / {{maxSteps}}",
|
||||||
|
"add_variable": "Přidat proměnnou",
|
||||||
|
"custom_phone_number": "Vlastní telefonní číslo",
|
||||||
|
"message_template": "Šablona zprávy",
|
||||||
|
"email_subject": "Předmět e-mailu",
|
||||||
|
"add_dynamic_variables": "Přidání dynamických textových proměnných",
|
||||||
|
"event_name_info": "Název typu události",
|
||||||
|
"event_date_info": "Datum události",
|
||||||
|
"event_time_info": "Čas začátku události",
|
||||||
|
"location_info": "Místo události",
|
||||||
"organizer_name_info": "Vaše jméno",
|
"organizer_name_info": "Vaše jméno",
|
||||||
|
"additional_notes_info": "Další poznámky k rezervaci",
|
||||||
|
"attendee_name_info": "Jméno osoby provádějící rezervaci",
|
||||||
|
"to": "Komu",
|
||||||
|
"attendee_required_enter_number": "Při rezervaci je nutné, aby účastník zadal telefonní číslo",
|
||||||
|
"workflow_turned_on_successfully": "Pracovní postup {{workflowName}} byl {{offOn}}",
|
||||||
|
"download_responses": "Stáhnout odpovědi",
|
||||||
|
"create_your_first_form": "Vytvořte svůj první formulář",
|
||||||
|
"create_your_first_form_description": "Pomocí adresných formulářů můžete klást kvalifikační otázky a adresovat je správné osobě nebo typu události.",
|
||||||
|
"create_your_first_webhook": "Vytvořte svůj první webhook",
|
||||||
|
"create_your_first_webhook_description": "Pomocí webhooků můžete přijímat data o schůzkách v reálném čase, pokud v Cal.com dojde k nějaké akci.",
|
||||||
|
"for_a_maximum_of": "Max. pro",
|
||||||
|
"event_one": "událost",
|
||||||
|
"event_other": "událostí",
|
||||||
|
"profile_team_description": "Správa nastavení profilu vašeho týmu",
|
||||||
|
"members_team_description": "Uživatelé, kteří jsou ve skupině",
|
||||||
|
"team_url": "Adresa URL týmu",
|
||||||
|
"delete_team": "Odstranit tým",
|
||||||
|
"team_members": "Členové týmu",
|
||||||
|
"more": "Více",
|
||||||
|
"more_page_footer": "Mobilní aplikaci považujeme za rozšíření webové aplikace. Pokud provádíte složitější akce, vraťte se prosím k webové aplikaci.",
|
||||||
|
"workflow_example_1": "Odeslat účastníkovi SMS upomínku 24 hodin před začátkem akce",
|
||||||
|
"workflow_example_2": "Odeslat účastníkovi vlastní SMS, pokud je událost přeložena na jiný termín",
|
||||||
|
"workflow_example_3": "Odeslat hostiteli vlastní e-mail, pokud je rezervována nová událost",
|
||||||
|
"workflow_example_4": "Odeslat účastníkovi upomínku 1 hodinu před začátkem akce",
|
||||||
|
"workflow_example_5": "Odeslat hostiteli vlastní e-mail, pokud je událost přeložena na jiný termín",
|
||||||
|
"workflow_example_6": "Odeslat hostiteli vlastní SMS, pokud je rezervována nová událost",
|
||||||
|
"welcome_to_cal_header": "Vítá vás Cal.com!",
|
||||||
|
"edit_form_later_subtitle": "Toto budete moci upravit později.",
|
||||||
|
"connect_calendar_later": "Připojím svůj kalendář později",
|
||||||
|
"set_my_availability_later": "Svou dostupnost nastavím později",
|
||||||
|
"problem_saving_user_profile": "Při ukládání vašich údajů došlo k problému. Zkuste to prosím znovu, případně se obraťte na zákaznickou podporu.",
|
||||||
|
"purchase_missing_seats": "Koupit chybějící místa",
|
||||||
|
"slot_length": "Délka slotu",
|
||||||
|
"booking_appearance": "Vzhled rezervace",
|
||||||
|
"appearance_team_description": "Správa nastavení vzhledu rezervace vašeho týmu",
|
||||||
|
"only_owner_change": "Změny v rezervaci týmu může provádět pouze jeho vlastník ",
|
||||||
|
"team_disable_cal_branding_description": "Odstraní všechny značky související s Cal, tj. „Běží na platformě Cal.“",
|
||||||
|
"invited_by_team": "Tým {{teamName}} vás pozval do svého týmu na pozici {{role}}",
|
||||||
|
"token_invalid_expired": "Token je buď neplatný, nebo jeho platnost vypršela.",
|
||||||
|
"exchange_add": "Propojit s Microsoft Exchange",
|
||||||
|
"exchange_authentication": "Metoda ověřování",
|
||||||
|
"exchange_authentication_standard": "Základní ověření",
|
||||||
|
"exchange_authentication_ntlm": "Ověřování NTLM",
|
||||||
|
"exchange_compression": "Komprese GZip",
|
||||||
|
"routing_forms_description": "Zde si můžete prohlédnout všechny vytvořené formuláře a trasy.",
|
||||||
|
"add_new_form": "Přidat nový formulář",
|
||||||
|
"form_description": "Vytvořte formulář, který adresujete rezervující osobě",
|
||||||
|
"copy_link_to_form": "Kopírovat odkaz na formulář",
|
||||||
|
"theme": "Motiv",
|
||||||
|
"theme_applies_note": "Toto se týká pouze vašich veřejných stránek s rezervacemi",
|
||||||
"theme_light": "Světlý",
|
"theme_light": "Světlý",
|
||||||
"theme_dark": "Tmavý"
|
"theme_dark": "Tmavý",
|
||||||
|
"theme_system": "Výchozí nastavení systému",
|
||||||
|
"add_a_team": "Přidat tým",
|
||||||
|
"saml_config": "Konfig. SAML",
|
||||||
|
"add_webhook_description": "Přijímejte data o schůzkách v reálném čase, pokud v Cal.com dojde k nějaké akci",
|
||||||
|
"triggers_when": "Spustí se, pokud:",
|
||||||
|
"test_webhook": "Před vytvořením proveďte test ping.",
|
||||||
|
"enable_webhook": "Povolit webhook",
|
||||||
|
"add_webhook": "Přidat webhook",
|
||||||
|
"webhook_edited_successfully": "Webhook uložen",
|
||||||
|
"webhooks_description": "Přijímejte data o schůzkách v reálném čase, pokud v Cal.com dojde k nějaké akci",
|
||||||
|
"api_keys_description": "Vygenerujte klíče API pro přístup k vlastnímu účtu",
|
||||||
|
"new_api_key": "Nový klíč API",
|
||||||
|
"active": "Aktivní",
|
||||||
|
"api_key_updated": "Aktualizace názvu klíče API",
|
||||||
|
"api_key_update_failed": "Chyba při aktualizaci názvu klíče API",
|
||||||
|
"embeds_title": "Vložení rámce HTML iframe",
|
||||||
|
"embeds_description": "Vložte všechny typy událostí na vaši webovou stránku",
|
||||||
|
"create_first_api_key": "Vytvořte svůj první klíč API",
|
||||||
|
"create_first_api_key_description": "Klíče API umožňují ostatním aplikacím komunikovat se službou Cal.com",
|
||||||
|
"back_to_signin": "Zpět na přihlášení",
|
||||||
|
"reset_link_sent": "Odkaz pro obnovení odeslán",
|
||||||
|
"password_reset_email": "Na adresu {{email}} je na cestě e-mail s pokyny k obnovení hesla.",
|
||||||
|
"password_updated": "Heslo aktualizováno!",
|
||||||
|
"pending_payment": "Čeká se na platbu",
|
||||||
|
"confirmation_page_rainbow": "Zamkněte svoji událost pomocí tokenů nebo NFT na platformách Ethereum, Polygon a dalších.",
|
||||||
|
"not_on_cal": "Nenachází se na Cal.com",
|
||||||
|
"no_calendar_installed": "Není nainstalován kalendář",
|
||||||
|
"no_calendar_installed_description": "Ještě jste nepropojili žádný ze svých kalendářů",
|
||||||
|
"add_a_calendar": "Přidejte kalendář",
|
||||||
|
"change_email_hint": "Možná se budete muset odhlásit a znovu přihlásit, aby se změny projevily",
|
||||||
|
"confirm_password_change_email": "Před změnou e-mailové adresy potvrďte své heslo",
|
||||||
|
"seats": "míst",
|
||||||
|
"every_app_published": "Každá aplikace zveřejněná v obchodě s aplikacemi na Cal.com má otevřený zdrojový kód a je důkladně testována prostřednictvím vzájemného hodnocení. Společnost Cal.com, Inc. nicméně tyto aplikace neschvaluje ani necertifikuje, pokud nejsou zveřejněny přímo společností Cal.com. Pokud se setkáte s nevhodným obsahem nebo chováním, nahlaste to.",
|
||||||
|
"report_app": "Nahlásit aplikaci"
|
||||||
}
|
}
|
||||||
@@ -112,7 +112,6 @@
|
|||||||
"use_link_to_reset_password": "Benutzen Sie den Link, um Ihr Passwort zurückzusetzen",
|
"use_link_to_reset_password": "Benutzen Sie den Link, um Ihr Passwort zurückzusetzen",
|
||||||
"hey_there": "Hallo,",
|
"hey_there": "Hallo,",
|
||||||
"forgot_your_password_calcom": "Passwort vergessen? - Cal.com",
|
"forgot_your_password_calcom": "Passwort vergessen? - Cal.com",
|
||||||
"event_type_title": "{{eventTypeTitle}} | Event-Typ",
|
|
||||||
"delete_webhook_confirmation_message": "Sind Sie sicher, dass Sie diesen Webhook löschen möchten? Sie werden keine Cal.com Termindaten mehr erhalten.",
|
"delete_webhook_confirmation_message": "Sind Sie sicher, dass Sie diesen Webhook löschen möchten? Sie werden keine Cal.com Termindaten mehr erhalten.",
|
||||||
"confirm_delete_webhook": "Ja, Webhook löschen",
|
"confirm_delete_webhook": "Ja, Webhook löschen",
|
||||||
"edit_webhook": "Webhook bearbeiten",
|
"edit_webhook": "Webhook bearbeiten",
|
||||||
@@ -255,7 +254,7 @@
|
|||||||
"user_needs_to_confirm_or_reject_booking_recurring": "{{user}} muss noch die Terminreihe des wiederkehrenden Termins bestätigen oder ablehnen.",
|
"user_needs_to_confirm_or_reject_booking_recurring": "{{user}} muss noch die Terminreihe des wiederkehrenden Termins bestätigen oder ablehnen.",
|
||||||
"meeting_is_scheduled": "Dieser Termin ist geplant",
|
"meeting_is_scheduled": "Dieser Termin ist geplant",
|
||||||
"meeting_is_scheduled_recurring": "Ihr wiederkehrender Termin wurde geplant",
|
"meeting_is_scheduled_recurring": "Ihr wiederkehrender Termin wurde geplant",
|
||||||
"submitted": "Ihr Termin wurde gebuhct",
|
"submitted": "Ihr Termin wurde gebucht",
|
||||||
"submitted_recurring": "Ihr wiederkehrender Termin wurde gebucht",
|
"submitted_recurring": "Ihr wiederkehrender Termin wurde gebucht",
|
||||||
"booking_submitted": "Ihre Buchung wurde versandt",
|
"booking_submitted": "Ihre Buchung wurde versandt",
|
||||||
"booking_submitted_recurring": "Ihre wiederkehrende Buchung wurde versandt",
|
"booking_submitted_recurring": "Ihre wiederkehrende Buchung wurde versandt",
|
||||||
@@ -266,6 +265,8 @@
|
|||||||
"enter_new_password": "Geben Sie das neue Passwort ein.",
|
"enter_new_password": "Geben Sie das neue Passwort ein.",
|
||||||
"reset_password": "Passwort zurücksetzen",
|
"reset_password": "Passwort zurücksetzen",
|
||||||
"change_your_password": "Passwort ändern",
|
"change_your_password": "Passwort ändern",
|
||||||
|
"show_password": "Passwort anzeigen",
|
||||||
|
"hide_password": "Passwort verbergen",
|
||||||
"try_again": "Erneut versuchen",
|
"try_again": "Erneut versuchen",
|
||||||
"request_is_expired": "Diese Anfrage ist abgelaufen.",
|
"request_is_expired": "Diese Anfrage ist abgelaufen.",
|
||||||
"reset_instructions": "Geben Sie die E-Mail-Adresse Ihres Kontos ein und wir senden Ihnen einen Link zum Zurücksetzen Ihres Passworts.",
|
"reset_instructions": "Geben Sie die E-Mail-Adresse Ihres Kontos ein und wir senden Ihnen einen Link zum Zurücksetzen Ihres Passworts.",
|
||||||
@@ -355,6 +356,7 @@
|
|||||||
"meeting_ended": "Meeting beendet",
|
"meeting_ended": "Meeting beendet",
|
||||||
"form_submitted": "Formular gesendet",
|
"form_submitted": "Formular gesendet",
|
||||||
"event_triggers": "Ereignis-Auslöser",
|
"event_triggers": "Ereignis-Auslöser",
|
||||||
|
"subscriber_url": "Subscriber-URL",
|
||||||
"create_new_webhook": "Einen neuen Webhook erstellen",
|
"create_new_webhook": "Einen neuen Webhook erstellen",
|
||||||
"webhooks": "Webhooks",
|
"webhooks": "Webhooks",
|
||||||
"team_webhooks": "Team Webhooks",
|
"team_webhooks": "Team Webhooks",
|
||||||
@@ -465,7 +467,7 @@
|
|||||||
"host_phone_number": "Ihre Telefonnummer",
|
"host_phone_number": "Ihre Telefonnummer",
|
||||||
"enter_phone_number": "Telefonnummer eingeben",
|
"enter_phone_number": "Telefonnummer eingeben",
|
||||||
"reschedule": "Neuplanen",
|
"reschedule": "Neuplanen",
|
||||||
"reschedule_this": "Stattdessen verschie",
|
"reschedule_this": "Stattdessen verschieben",
|
||||||
"book_a_team_member": "Teammitglied stattdessen buchen",
|
"book_a_team_member": "Teammitglied stattdessen buchen",
|
||||||
"or": "ODER",
|
"or": "ODER",
|
||||||
"go_back": "Zurück",
|
"go_back": "Zurück",
|
||||||
@@ -494,6 +496,9 @@
|
|||||||
"lets_create_first_administrator_user": "Lass uns als erstes den Administrator Benutzer anlegen.",
|
"lets_create_first_administrator_user": "Lass uns als erstes den Administrator Benutzer anlegen.",
|
||||||
"new_member": "Neues Mitglied",
|
"new_member": "Neues Mitglied",
|
||||||
"invite": "Einladen",
|
"invite": "Einladen",
|
||||||
|
"add_team_members": "Teammitglieder hinzufügen",
|
||||||
|
"add_team_members_description": "Lade andere ein, deinem Team beizutreten",
|
||||||
|
"add_team_member": "Teammitglied hinzufügen",
|
||||||
"invite_new_member": "Ein neues Mitglied einladen",
|
"invite_new_member": "Ein neues Mitglied einladen",
|
||||||
"invite_new_team_member": "Laden Sie jemanden in Ihr Team ein.",
|
"invite_new_team_member": "Laden Sie jemanden in Ihr Team ein.",
|
||||||
"change_member_role": "Rolle des Teammitglieds ändern",
|
"change_member_role": "Rolle des Teammitglieds ändern",
|
||||||
@@ -629,6 +634,7 @@
|
|||||||
"availability": "Verfügbarkeit",
|
"availability": "Verfügbarkeit",
|
||||||
"edit_availability": "Verfügbarkeit editieren",
|
"edit_availability": "Verfügbarkeit editieren",
|
||||||
"configure_availability": "Konfigurieren Sie die Zeiten, in denen Sie für Buchungen zur Verfügung stehen.",
|
"configure_availability": "Konfigurieren Sie die Zeiten, in denen Sie für Buchungen zur Verfügung stehen.",
|
||||||
|
"copy_times_to": "Zeiten kopieren in",
|
||||||
"change_weekly_schedule": "Wöchentliche Termine ändern",
|
"change_weekly_schedule": "Wöchentliche Termine ändern",
|
||||||
"logo": "Logo",
|
"logo": "Logo",
|
||||||
"error": "Fehler",
|
"error": "Fehler",
|
||||||
@@ -643,6 +649,7 @@
|
|||||||
"event_name_tooltip": "Der Name, der in Kalendern angezeigt wird",
|
"event_name_tooltip": "Der Name, der in Kalendern angezeigt wird",
|
||||||
"meeting_with_user": "Meeting mit {ATTENDEE}",
|
"meeting_with_user": "Meeting mit {ATTENDEE}",
|
||||||
"additional_inputs": "Zusätzliche Notizen",
|
"additional_inputs": "Zusätzliche Notizen",
|
||||||
|
"additional_input_description": "Erfordert die Eingabe zusätzlicher Eingaben durch den Zeitplaner vor der Buchungsbestätigung",
|
||||||
"label": "Bezeichnung",
|
"label": "Bezeichnung",
|
||||||
"placeholder": "Placeholder",
|
"placeholder": "Placeholder",
|
||||||
"type": "Typ",
|
"type": "Typ",
|
||||||
@@ -725,6 +732,7 @@
|
|||||||
"connect_additional_calendar": "Zusätzlichen Kalender verbinden",
|
"connect_additional_calendar": "Zusätzlichen Kalender verbinden",
|
||||||
"conferencing": "Videokonferenzen",
|
"conferencing": "Videokonferenzen",
|
||||||
"calendar": "Kalender",
|
"calendar": "Kalender",
|
||||||
|
"payments": "Zahlungen",
|
||||||
"not_installed": "Nicht installiert",
|
"not_installed": "Nicht installiert",
|
||||||
"error_password_mismatch": "Passwörter stimmen nicht überein.",
|
"error_password_mismatch": "Passwörter stimmen nicht überein.",
|
||||||
"error_required_field": "Dieses Feld ist erforderlich.",
|
"error_required_field": "Dieses Feld ist erforderlich.",
|
||||||
@@ -765,6 +773,15 @@
|
|||||||
"trending_apps": "Angesagte Apps",
|
"trending_apps": "Angesagte Apps",
|
||||||
"explore_apps": "{{category}} Apps",
|
"explore_apps": "{{category}} Apps",
|
||||||
"installed_apps": "Installierte Apps",
|
"installed_apps": "Installierte Apps",
|
||||||
|
"no_category_apps": "Keine {{category}} Apps",
|
||||||
|
"no_category_apps_description_calendar": "Fügen Sie eine Kalender-App hinzu, in der nach Konflikten gesucht werden soll, um Doppelbuchungen zu vermeiden",
|
||||||
|
"no_category_apps_description_conferencing": "Versuchen Sie, eine Konferenz-App hinzuzufügen, um Videoanrufe mit Ihren Kunden zu integrieren",
|
||||||
|
"no_category_apps_description_payment": "Fügen Sie eine Zahlungs-App hinzu, um die Transaktion zwischen Ihnen und Ihren Kunden zu erleichtern",
|
||||||
|
"no_category_apps_description_other": "Füge jede beliebige andere Art von App hinzu, um alle möglichen Dinge zu tun",
|
||||||
|
"installed_app_calendar_description": "Legen Sie den/die Kalender in denen nach Konflikten gesucht werden sollen fest, um Doppelbuchungen zu vermeiden.",
|
||||||
|
"installed_app_conferencing_description": "Fügen Sie Ihre liebsten Videokonferenz-Apps für Ihre Meetings hinzu",
|
||||||
|
"installed_app_payment_description": "Konfigurieren Sie die Zahlungsdienstleister, welcher bei der Belastung Ihrer Kunden verwendet werden sollen.",
|
||||||
|
"installed_app_other_description": "Alle von Ihnen installierten Apps aus anderen Kategorien.",
|
||||||
"empty_installed_apps_headline": "Keine Apps installiert",
|
"empty_installed_apps_headline": "Keine Apps installiert",
|
||||||
"empty_installed_apps_description": "Apps erlauben es Ihnen, Ihren Arbeitsfluss zu verbessern und Ihre Planung viel besser zu gestalten.",
|
"empty_installed_apps_description": "Apps erlauben es Ihnen, Ihren Arbeitsfluss zu verbessern und Ihre Planung viel besser zu gestalten.",
|
||||||
"empty_installed_apps_button": "Entdecken Sie den App Store",
|
"empty_installed_apps_button": "Entdecken Sie den App Store",
|
||||||
@@ -803,6 +820,8 @@
|
|||||||
"set_to_default": "Auf Standard setzen",
|
"set_to_default": "Auf Standard setzen",
|
||||||
"new_schedule_btn": "Neuer Verfügbarkeitsplan",
|
"new_schedule_btn": "Neuer Verfügbarkeitsplan",
|
||||||
"add_new_schedule": "Neuen Verfügbarkeitsplan hinzufügen",
|
"add_new_schedule": "Neuen Verfügbarkeitsplan hinzufügen",
|
||||||
|
"add_new_calendar": "Neuen Kalender hinzufügen",
|
||||||
|
"set_calendar": "Legen Sie fest, wo neue Events hinzugefügt werden sollen, wenn Sie gebucht werden.",
|
||||||
"delete_schedule": "Verfügbarkeitsplan löschen",
|
"delete_schedule": "Verfügbarkeitsplan löschen",
|
||||||
"schedule_created_successfully": "{{scheduleName}} -Verfügbarkeitsplan erfolgreich erstellt",
|
"schedule_created_successfully": "{{scheduleName}} -Verfügbarkeitsplan erfolgreich erstellt",
|
||||||
"availability_updated_successfully": "Verfügbarkeit erfolgreich aktualisiert",
|
"availability_updated_successfully": "Verfügbarkeit erfolgreich aktualisiert",
|
||||||
@@ -984,10 +1003,13 @@
|
|||||||
"change_username_standard_to_premium": "Da Sie von einem Standard- zu einem Premium-Benutzernamen wechseln, werden Sie zum Upgrade zur Kasse gebracht.",
|
"change_username_standard_to_premium": "Da Sie von einem Standard- zu einem Premium-Benutzernamen wechseln, werden Sie zum Upgrade zur Kasse gebracht.",
|
||||||
"change_username_premium_to_standard": "Da Sie von einem Premium- zu einem Standard-Benutzernamen wechseln, werden Sie zum Downgrade zur Kasse gebracht.",
|
"change_username_premium_to_standard": "Da Sie von einem Premium- zu einem Standard-Benutzernamen wechseln, werden Sie zum Downgrade zur Kasse gebracht.",
|
||||||
"go_to_stripe_billing": "Zur Abrechnung",
|
"go_to_stripe_billing": "Zur Abrechnung",
|
||||||
|
"stripe_description": "Zahlung für Buchungen (0,5 % + 0,10 € Provision pro Transaktion)",
|
||||||
"trial_expired": "Ihre Testversion ist abgelaufen",
|
"trial_expired": "Ihre Testversion ist abgelaufen",
|
||||||
"remove_app": "App entfernen",
|
"remove_app": "App entfernen",
|
||||||
"yes_remove_app": "Ja, App entfernen",
|
"yes_remove_app": "Ja, App entfernen",
|
||||||
"are_you_sure_you_want_to_remove_this_app": "Sind Sie sicher, dass Sie diese App entfernen möchten?",
|
"are_you_sure_you_want_to_remove_this_app": "Sind Sie sicher, dass Sie diese App entfernen möchten?",
|
||||||
|
"app_removed_successfully": "App erfolgreich entfernt",
|
||||||
|
"error_removing_app": "Fehler beim Entfernen der App",
|
||||||
"web_conference": "Webkonferenz",
|
"web_conference": "Webkonferenz",
|
||||||
"number_for_sms_reminders": "Telefonnummer (für SMS-Erinnerungen)",
|
"number_for_sms_reminders": "Telefonnummer (für SMS-Erinnerungen)",
|
||||||
"requires_confirmation": "Erfordert Bestätigung",
|
"requires_confirmation": "Erfordert Bestätigung",
|
||||||
@@ -1043,6 +1065,8 @@
|
|||||||
"navigate": "Navigieren",
|
"navigate": "Navigieren",
|
||||||
"open": "Öffnen",
|
"open": "Öffnen",
|
||||||
"close": "Schließen",
|
"close": "Schließen",
|
||||||
|
"team_feature_teams": "Dies ist eine Team-Funktion. Sie müssen auf die Team-Version upgraden, um die Verfügbarkeit Ihres Teams zu sehen.",
|
||||||
|
"team_feature_workflows": "Dies ist eine Team-Funktion. Sie müssen auf die Team-Version upgraden, um Ihre Termin-Benachrichtigungen und Erinnerungen mit Workflows zu automatisieren.",
|
||||||
"show_eventtype_on_profile": "Im Profil anzeigen",
|
"show_eventtype_on_profile": "Im Profil anzeigen",
|
||||||
"embed": "Einbetten",
|
"embed": "Einbetten",
|
||||||
"new_username": "Neuer Benutzername",
|
"new_username": "Neuer Benutzername",
|
||||||
@@ -1076,10 +1100,13 @@
|
|||||||
"event_limit_tab_description": "Wie oft können Sie gebucht werden",
|
"event_limit_tab_description": "Wie oft können Sie gebucht werden",
|
||||||
"event_advanced_tab_description": "Kalendereinstellungen & mehr...",
|
"event_advanced_tab_description": "Kalendereinstellungen & mehr...",
|
||||||
"event_advanced_tab_title": "Erweitert",
|
"event_advanced_tab_title": "Erweitert",
|
||||||
|
"select_which_cal": "Wählen Sie den Kalender aus, zu dem Buchungen hinzugefügt werden sollen",
|
||||||
"custom_event_name": "Eigener Ereignisname",
|
"custom_event_name": "Eigener Ereignisname",
|
||||||
|
"custom_event_name_description": "Erstellen Sie benutzerdefinierte Ereignisnamen, die im Kalenderereignis angezeigt werden sollen",
|
||||||
"2fa_required": "Zwei-Faktor-Authentifizierung erforderlich",
|
"2fa_required": "Zwei-Faktor-Authentifizierung erforderlich",
|
||||||
"incorrect_2fa": "Falscher Zwei-Faktor-Authentifizierungscode",
|
"incorrect_2fa": "Falscher Zwei-Faktor-Authentifizierungscode",
|
||||||
"which_event_type_apply": "Auf welchen Ereignistyp wird dies angewandt?",
|
"which_event_type_apply": "Auf welchen Ereignistyp wird dies angewandt?",
|
||||||
|
"no_workflows_description": "Workflows ermöglichen die einfache Automatisierung des Versands von Benachrichtigungen und Erinnerungen, so dass Sie Prozesse rund um Ihre Ereignisse erstellen können.",
|
||||||
"create_workflow": "Einen Workflow erstellen",
|
"create_workflow": "Einen Workflow erstellen",
|
||||||
"do_this": "Mache dies",
|
"do_this": "Mache dies",
|
||||||
"turn_off": "Abschalten",
|
"turn_off": "Abschalten",
|
||||||
@@ -1088,8 +1115,10 @@
|
|||||||
"personal_cal_url": "Meine persönliche Cal. com URL",
|
"personal_cal_url": "Meine persönliche Cal. com URL",
|
||||||
"bio_hint": "Schreiben Sie eine kurze Beschreibung, welche auf Ihrer persönlichen Url-Seite erscheinen wird.",
|
"bio_hint": "Schreiben Sie eine kurze Beschreibung, welche auf Ihrer persönlichen Url-Seite erscheinen wird.",
|
||||||
"delete_account_modal_title": "Account löschen",
|
"delete_account_modal_title": "Account löschen",
|
||||||
|
"confirm_delete_account_modal": "Sind Sie sicher, dass Sie Ihr Cal.com-Konto löschen möchten?",
|
||||||
"delete_my_account": "Meinen Account löschen",
|
"delete_my_account": "Meinen Account löschen",
|
||||||
"start_of_week": "Wochenstart",
|
"start_of_week": "Wochenstart",
|
||||||
|
"select_calendars": "Wählen Sie aus, in welchen Kalendern Sie nach Konflikten suchen wollen, um Doppelbuchungen zu vermeiden.",
|
||||||
"check_for_conflicts": "Auf Konflikte prüfen",
|
"check_for_conflicts": "Auf Konflikte prüfen",
|
||||||
"adding_events_to": "Ereignisse hinzufügen zu",
|
"adding_events_to": "Ereignisse hinzufügen zu",
|
||||||
"follow_system_preferences": "Systemeinstellungen folgen",
|
"follow_system_preferences": "Systemeinstellungen folgen",
|
||||||
@@ -1101,32 +1130,46 @@
|
|||||||
"upload": "Upload",
|
"upload": "Upload",
|
||||||
"web3": "Web3",
|
"web3": "Web3",
|
||||||
"rainbow_token_gated": "Dieser Ereignistyp ist durch einen Token geschützt.",
|
"rainbow_token_gated": "Dieser Ereignistyp ist durch einen Token geschützt.",
|
||||||
|
"rainbow_connect_wallet_gate": "Verbinden Sie Ihre Wallet, falls Sie <1>{{name}}</1> (<3>{{symbol}}</3>) besitzen.",
|
||||||
|
"rainbow_insufficient_balance": "Ihre verbundene Wallet enthält nicht genug <1>{{symbol}}</1>.",
|
||||||
|
"rainbow_sign_message_request": "Unterschreiben Sie die Nachrichtenanfrage in Ihrer Wallet.",
|
||||||
|
"rainbow_signature_error": "Fehler beim Anfordern der Signatur von Ihrer Wallet.",
|
||||||
"token_address": "Adresse des Token",
|
"token_address": "Adresse des Token",
|
||||||
"blockchain": "Blockchain",
|
"blockchain": "Blockchain",
|
||||||
"old_password": "Altes Passwort",
|
"old_password": "Altes Passwort",
|
||||||
"secure_password": "Ihr sicheres neues Passwort",
|
"secure_password": "Ihr sicheres neues Passwort",
|
||||||
"error_updating_password": "Fehler beim aktualisieren des Passworts",
|
"error_updating_password": "Fehler beim aktualisieren des Passworts",
|
||||||
"two_factor_auth": "Zwei-Faktor-Authentifizierung",
|
"two_factor_auth": "Zwei-Faktor-Authentifizierung",
|
||||||
|
"recurring_event_tab_description": "Einen wiederholenden Zeitplan einrichten",
|
||||||
"today": "heute",
|
"today": "heute",
|
||||||
"appearance": "Aussehen",
|
"appearance": "Aussehen",
|
||||||
|
"appearance_subtitle": "Einstellungen für Ihre Buchungsdarstellung verwalten",
|
||||||
"my_account": "Mein Account",
|
"my_account": "Mein Account",
|
||||||
"general": "Allgemein",
|
"general": "Allgemein",
|
||||||
"calendars": "Kalender",
|
"calendars": "Kalender",
|
||||||
"2fa_auth": "2 Faktor-Authentifizierung",
|
"2fa_auth": "2 Faktor-Authentifizierung",
|
||||||
"invoices": "Rechnungen",
|
"invoices": "Rechnungen",
|
||||||
|
"embeds": "Embeds",
|
||||||
"impersonation": "Benutzeridentitätswechsel",
|
"impersonation": "Benutzeridentitätswechsel",
|
||||||
"users": "Benutzer",
|
"users": "Benutzer",
|
||||||
"profile_description": "Einstellungen für Ihr Cal.com Profil verwalten",
|
"profile_description": "Einstellungen für Ihr Cal.com Profil verwalten",
|
||||||
"general_description": "Einstellungen für Ihre Sprache und Zeitzone verwalten",
|
"general_description": "Einstellungen für Ihre Sprache und Zeitzone verwalten",
|
||||||
"calendars_description": "Konfigurieren Sie, wie Ihre Event-Typen mit Ihren Kalendern interagieren sollen",
|
"calendars_description": "Konfigurieren Sie, wie Ihre Event-Typen mit Ihren Kalendern interagieren sollen",
|
||||||
|
"appearance_description": "Einstellungen für Ihre Buchungsdarstellung verwalten",
|
||||||
"conferencing_description": "Verwalten Sie Ihre Video-Konferenz-Apps für Ihre Meetings",
|
"conferencing_description": "Verwalten Sie Ihre Video-Konferenz-Apps für Ihre Meetings",
|
||||||
"password_description": "Einstellungen für Ihre Konto-Passwörter verwalten",
|
"password_description": "Einstellungen für Ihre Konto-Passwörter verwalten",
|
||||||
|
"2fa_description": "Einstellungen für Ihre Konto-Passwörter verwalten",
|
||||||
"we_just_need_basic_info": "Wir benötigen nur ein paar grundlegende Informationen, um Ihr Profil einzurichten.",
|
"we_just_need_basic_info": "Wir benötigen nur ein paar grundlegende Informationen, um Ihr Profil einzurichten.",
|
||||||
"skip": "Überspringen",
|
"skip": "Überspringen",
|
||||||
"do_this_later": "Später machen",
|
"do_this_later": "Später machen",
|
||||||
"set_availability_getting_started_subtitle_1": "Zeiträume definieren, in denen Sie verfügbar sind",
|
"set_availability_getting_started_subtitle_1": "Zeiträume definieren, in denen Sie verfügbar sind",
|
||||||
"set_availability_getting_started_subtitle_2": "Sie können dies alles später auf der Verfügbarkeitsseite anpassen.",
|
"set_availability_getting_started_subtitle_2": "Sie können dies alles später auf der Verfügbarkeitsseite anpassen.",
|
||||||
"connect_calendars_from_app_store": "Sie können weitere Kalender aus dem App-Store hinzufügen",
|
"connect_calendars_from_app_store": "Sie können weitere Kalender aus dem App-Store hinzufügen",
|
||||||
|
"connect_conference_apps": "Konferenz-Apps verbinden",
|
||||||
|
"connect_calendar_apps": "Kalender-Apps verbinden",
|
||||||
|
"connect_payment_apps": "Zahlungs-Apps verbinden",
|
||||||
|
"connect_other_apps": "Andere Apps verbinden",
|
||||||
|
"current_step_of_total": "Schritt {{currentStep}} von {{maxSteps}}",
|
||||||
"add_variable": "Variable hinzufügen",
|
"add_variable": "Variable hinzufügen",
|
||||||
"custom_phone_number": "Benutzerdefinierte Telefonnummer",
|
"custom_phone_number": "Benutzerdefinierte Telefonnummer",
|
||||||
"message_template": "Nachrichtenvorlage",
|
"message_template": "Nachrichtenvorlage",
|
||||||
@@ -1141,10 +1184,22 @@
|
|||||||
"attendee_name_info": "Der Name der Buchenden",
|
"attendee_name_info": "Der Name der Buchenden",
|
||||||
"to": "An",
|
"to": "An",
|
||||||
"attendee_required_enter_number": "Hier muss der Teilnehmer bei der Buchung eine Telefonnummer eingeben",
|
"attendee_required_enter_number": "Hier muss der Teilnehmer bei der Buchung eine Telefonnummer eingeben",
|
||||||
|
"workflow_turned_on_successfully": "{{workflowName}} Workflow erfolgreich {{offOn}}geschaltet",
|
||||||
"download_responses": "Antworten herunterladen",
|
"download_responses": "Antworten herunterladen",
|
||||||
"create_your_first_form": "Erstellen Sie Ihr erstes Formular",
|
"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 auf Cal.com passiert.",
|
||||||
"for_a_maximum_of": "Für maximal",
|
"for_a_maximum_of": "Für maximal",
|
||||||
|
"event_one": "Ereignis",
|
||||||
|
"event_other": "Ereignisse",
|
||||||
|
"profile_team_description": "Einstellungen für Ihr Teamprofil verwalten",
|
||||||
|
"members_team_description": "Benutzer in der Gruppe",
|
||||||
|
"team_url": "Team-URL",
|
||||||
|
"delete_team": "Team löschen",
|
||||||
|
"team_members": "Teammitglieder",
|
||||||
"more": "Mehr",
|
"more": "Mehr",
|
||||||
|
"more_page_footer": "Wir betrachten die mobile Anwendung als Erweiterung der Web-Anwendung. Wenn Sie komplizierte Aktionen durchführen, verwenden Sie bitte die Web-Anwendung.",
|
||||||
"workflow_example_1": "Eine Erinnerung per Mail an die Teilnehmer verschicken, 24 Stunden bevor das Event startet",
|
"workflow_example_1": "Eine Erinnerung per Mail an die Teilnehmer verschicken, 24 Stunden bevor das Event startet",
|
||||||
"workflow_example_2": "Eine Erinnerung per SMS an die Teilnehmer verschicken, eine Stunde bevor das Event startet",
|
"workflow_example_2": "Eine Erinnerung per SMS an die Teilnehmer verschicken, eine Stunde bevor das Event startet",
|
||||||
"workflow_example_3": "Sende eine E-Mail an den Veranstalter, wenn das Ereignis abgebrochen wird",
|
"workflow_example_3": "Sende eine E-Mail an den Veranstalter, wenn das Ereignis abgebrochen wird",
|
||||||
@@ -1156,15 +1211,59 @@
|
|||||||
"connect_calendar_later": "Ich verbinde meinen Kalender später",
|
"connect_calendar_later": "Ich verbinde meinen Kalender später",
|
||||||
"set_my_availability_later": "Ich werde meine Verfügbarkeit später festlegen",
|
"set_my_availability_later": "Ich werde meine Verfügbarkeit später festlegen",
|
||||||
"problem_saving_user_profile": "Beim Speichern Ihrer Daten ist ein Problem aufgetreten. Bitte versuchen Sie es erneut oder wenden Sie sich an den Support.",
|
"problem_saving_user_profile": "Beim Speichern Ihrer Daten ist ein Problem aufgetreten. Bitte versuchen Sie es erneut oder wenden Sie sich an den Support.",
|
||||||
|
"purchase_missing_seats": "Fehlende Plätze kaufen",
|
||||||
|
"slot_length": "Zeitfensterlänge",
|
||||||
|
"booking_appearance": "Buchungsdarstellung",
|
||||||
|
"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 Cal-bezogenen Markenzeichen, z.B. 'Powered by Cal.'",
|
||||||
|
"invited_by_team": "{{teamName}} hat Sie eingeladen, dem Team als {{role}} beizutreten",
|
||||||
"token_invalid_expired": "Token ist entweder ungültig oder abgelaufen.",
|
"token_invalid_expired": "Token ist entweder ungültig oder abgelaufen.",
|
||||||
"exchange_add": "Mit Microsoft Exchange verbinden",
|
"exchange_add": "Mit Microsoft Exchange verbinden",
|
||||||
"exchange_authentication": "Authentifizierungsmethode",
|
"exchange_authentication": "Authentifizierungsmethode",
|
||||||
"exchange_authentication_standard": "Basisauthentifizierung",
|
"exchange_authentication_standard": "Basisauthentifizierung",
|
||||||
"exchange_authentication_ntlm": "NTLM-Authentifizierung",
|
"exchange_authentication_ntlm": "NTLM-Authentifizierung",
|
||||||
"exchange_compression": "GZip-Kompression",
|
"exchange_compression": "GZip-Kompression",
|
||||||
|
"routing_forms_description": "Hier sehen Sie alle Formulare und Weiterleitungen, die Sie erstellt haben.",
|
||||||
|
"add_new_form": "Neues Formular hinzufügen",
|
||||||
|
"form_description": "Erstellen Sie Ihr Formular, um einen Bucher zu anzuleiten",
|
||||||
|
"copy_link_to_form": "Link in Formular kopieren",
|
||||||
|
"theme": "Theme",
|
||||||
|
"theme_applies_note": "Dies gilt nur für Ihre öffentlichen Buchungsseiten",
|
||||||
"theme_light": "Hell",
|
"theme_light": "Hell",
|
||||||
"theme_dark": "Dunkel",
|
"theme_dark": "Dunkel",
|
||||||
|
"theme_system": "Systemstandard",
|
||||||
|
"add_a_team": "Team hinzufügen",
|
||||||
|
"saml_config": "SAML-Konfiguration",
|
||||||
|
"add_webhook_description": "Erhalten Sie Meetingdaten in Echtzeit, wenn etwas auf Cal.com 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 auf Cal.com 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",
|
||||||
|
"api_key_updated": "API-Schlüsselname aktualisiert",
|
||||||
|
"api_key_update_failed": "Fehler beim Aktualisieren des API-Schlüsselnamens",
|
||||||
|
"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 Cal.com zu kommunizieren",
|
||||||
"back_to_signin": "Zurück zur Anmeldung",
|
"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}}.",
|
||||||
"password_updated": "Passwort aktualisiert!",
|
"password_updated": "Passwort aktualisiert!",
|
||||||
"pending_payment": "Zahlung ausstehend"
|
"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 Cal.com",
|
||||||
|
"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 Cal.com App Store veröffentlicht wird, ist Open Source und gründlich durch Peer Reviews getestet. Cal.com, Inc. unterstützt oder zertifiziert diese Apps jedoch nicht, es sei denn, sie werden von Cal.com veröffentlicht. Wenn Sie auf unangemessene Inhalte oder Verhaltensweisen stoßen, melden Sie diese bitte.",
|
||||||
|
"report_app": "App melden"
|
||||||
}
|
}
|
||||||
@@ -112,7 +112,6 @@
|
|||||||
"use_link_to_reset_password": "Use the link below to reset your password",
|
"use_link_to_reset_password": "Use the link below to reset your password",
|
||||||
"hey_there": "Hey there,",
|
"hey_there": "Hey there,",
|
||||||
"forgot_your_password_calcom": "Forgot your password? - Cal.com",
|
"forgot_your_password_calcom": "Forgot your password? - Cal.com",
|
||||||
"event_type_title": "{{eventTypeTitle}} | Event Type",
|
|
||||||
"delete_webhook_confirmation_message": "Are you sure you want to delete this webhook? You will no longer receive Cal.com meeting data at a specified URL, in real-time, when an event is scheduled or canceled.",
|
"delete_webhook_confirmation_message": "Are you sure you want to delete this webhook? You will no longer receive Cal.com meeting data at a specified URL, in real-time, when an event is scheduled or canceled.",
|
||||||
"confirm_delete_webhook": "Yes, delete webhook",
|
"confirm_delete_webhook": "Yes, delete webhook",
|
||||||
"edit_webhook": "Edit Webhook",
|
"edit_webhook": "Edit Webhook",
|
||||||
@@ -206,7 +205,6 @@
|
|||||||
"2fa_enter_six_digit_code": "Enter the six-digit code from your authenticator app below.",
|
"2fa_enter_six_digit_code": "Enter the six-digit code from your authenticator app below.",
|
||||||
"create_an_account": "Create an account",
|
"create_an_account": "Create an account",
|
||||||
"dont_have_an_account": "Don't have an account?",
|
"dont_have_an_account": "Don't have an account?",
|
||||||
"i_dont_have_an_account": "I don't have an account",
|
|
||||||
"2fa_code": "Two-Factor Code",
|
"2fa_code": "Two-Factor Code",
|
||||||
"sign_in_account": "Sign in to your account",
|
"sign_in_account": "Sign in to your account",
|
||||||
"sign_in": "Sign in",
|
"sign_in": "Sign in",
|
||||||
@@ -235,7 +233,7 @@
|
|||||||
"welcome_back": "Welcome back",
|
"welcome_back": "Welcome back",
|
||||||
"welcome_to_calcom": "Welcome to Cal.com",
|
"welcome_to_calcom": "Welcome to Cal.com",
|
||||||
"welcome_instructions": "Tell us what to call you and let us know what timezone you’re in. You’ll be able to edit this later.",
|
"welcome_instructions": "Tell us what to call you and let us know what timezone you’re in. You’ll be able to edit this later.",
|
||||||
"connect_caldav": "Connect to CalDav Server",
|
"connect_caldav": "Connect to CalDav (Beta)",
|
||||||
"credentials_stored_and_encrypted": "Your credentials will be stored and encrypted.",
|
"credentials_stored_and_encrypted": "Your credentials will be stored and encrypted.",
|
||||||
"connect": "Connect",
|
"connect": "Connect",
|
||||||
"try_for_free": "Try it for free",
|
"try_for_free": "Try it for free",
|
||||||
@@ -447,7 +445,7 @@
|
|||||||
"sunday": "Sunday",
|
"sunday": "Sunday",
|
||||||
"all_booked_today": "All booked today.",
|
"all_booked_today": "All booked today.",
|
||||||
"slots_load_fail": "Could not load the available time slots.",
|
"slots_load_fail": "Could not load the available time slots.",
|
||||||
"additional_guests": "Add guest",
|
"additional_guests": "Add guests",
|
||||||
"your_name": "Your name",
|
"your_name": "Your name",
|
||||||
"email_address": "Email address",
|
"email_address": "Email address",
|
||||||
"enter_valid_email": "Please enter a valid email",
|
"enter_valid_email": "Please enter a valid email",
|
||||||
@@ -634,7 +632,6 @@
|
|||||||
"billing": "Billing",
|
"billing": "Billing",
|
||||||
"manage_your_billing_info": "Manage your billing information and cancel your subscription.",
|
"manage_your_billing_info": "Manage your billing information and cancel your subscription.",
|
||||||
"availability": "Availability",
|
"availability": "Availability",
|
||||||
"availability_title": "{{availabilityTitle}} | Availability",
|
|
||||||
"edit_availability": "Edit availability",
|
"edit_availability": "Edit availability",
|
||||||
"configure_availability": "Configure times when you are available for bookings.",
|
"configure_availability": "Configure times when you are available for bookings.",
|
||||||
"copy_times_to": "Copy times to",
|
"copy_times_to": "Copy times to",
|
||||||
@@ -843,7 +840,7 @@
|
|||||||
"redirect_url_upgrade_description": "In order to use this feature, you need to upgrade to a Pro account.",
|
"redirect_url_upgrade_description": "In order to use this feature, you need to upgrade to a Pro account.",
|
||||||
"duplicate": "Duplicate",
|
"duplicate": "Duplicate",
|
||||||
"offer_seats": "Offer seats",
|
"offer_seats": "Offer seats",
|
||||||
"offer_seats_description": "Offer seats to bookings (This disables guests & opt in bookings)",
|
"offer_seats_description": "Offer seats for booking. This automatically disables guest & opt-in bookings.",
|
||||||
"seats_available": "Seats available",
|
"seats_available": "Seats available",
|
||||||
"number_of_seats": "Number of seats per booking",
|
"number_of_seats": "Number of seats per booking",
|
||||||
"enter_number_of_seats": "Enter number of seats",
|
"enter_number_of_seats": "Enter number of seats",
|
||||||
@@ -925,13 +922,13 @@
|
|||||||
"zapier_setup_instructions": "<0>Log into your Zapier account and create a new Zap.</0><1>Select Cal.com as your Trigger app. Also choose a Trigger event.</1><2>Choose your account and then enter your Unique API Key.</2><3>Test your Trigger.</3><4>You're set!</4>",
|
"zapier_setup_instructions": "<0>Log into your Zapier account and create a new Zap.</0><1>Select Cal.com as your Trigger app. Also choose a Trigger event.</1><2>Choose your account and then enter your Unique API Key.</2><3>Test your Trigger.</3><4>You're set!</4>",
|
||||||
"install_zapier_app": "Please first install the Zapier App in the app store.",
|
"install_zapier_app": "Please first install the Zapier App in the app store.",
|
||||||
"connect_apple_server": "Connect to Apple Server",
|
"connect_apple_server": "Connect to Apple Server",
|
||||||
"connect_caldav_server": "Connect to CalDav Server",
|
"connect_caldav_server": "Connect to CalDav (Beta)",
|
||||||
"calendar_url": "Calendar URL",
|
"calendar_url": "Calendar URL",
|
||||||
"apple_server_generate_password": "Generate an app specific password to use with Cal.com at",
|
"apple_server_generate_password": "Generate an app specific password to use with Cal.com at",
|
||||||
"credentials_stored_encrypted": "Your credentials will be stored and encrypted.",
|
"credentials_stored_encrypted": "Your credentials will be stored and encrypted.",
|
||||||
"it_stored_encrypted": "It will be stored and encrypted.",
|
"it_stored_encrypted": "It will be stored and encrypted.",
|
||||||
"go_to_app_store": "Go to App Store",
|
"go_to_app_store": "Go to App Store",
|
||||||
"calendar_error": "Something went wrong, try reconnecting your calendar with all necessary permissions",
|
"calendar_error": "Try reconnecting your calendar with all necessary permissions",
|
||||||
"set_your_phone_number": "Set a phone number for the meeting",
|
"set_your_phone_number": "Set a phone number for the meeting",
|
||||||
"calendar_no_busy_slots": "There are no busy slots",
|
"calendar_no_busy_slots": "There are no busy slots",
|
||||||
"display_location_label": "Display on booking page",
|
"display_location_label": "Display on booking page",
|
||||||
@@ -1197,12 +1194,12 @@
|
|||||||
"event_one": "event",
|
"event_one": "event",
|
||||||
"event_other": "events",
|
"event_other": "events",
|
||||||
"profile_team_description": "Manage settings for your team profile",
|
"profile_team_description": "Manage settings for your team profile",
|
||||||
"members_team_description": "Users that are in the group. Apes together strong!",
|
"members_team_description": "Users that are in the group",
|
||||||
"team_url": "Team URL",
|
"team_url": "Team URL",
|
||||||
"delete_team": "Delete Team",
|
"delete_team": "Delete Team",
|
||||||
"team_members": "Team members",
|
"team_members": "Team members",
|
||||||
"more": "More",
|
"more": "More",
|
||||||
"more_page_footer": "We view the mobile application as an extension of the web application. If you are performing any complication actions, please refer back to the web application.",
|
"more_page_footer": "We view the mobile application as an extension of the web application. If you are performing any complicated actions, please refer back to the web application.",
|
||||||
"workflow_example_1": "Send SMS reminder 24 hours before event starts to attendee",
|
"workflow_example_1": "Send SMS reminder 24 hours before event starts to attendee",
|
||||||
"workflow_example_2": "Send custom SMS when event is rescheduled to attendee",
|
"workflow_example_2": "Send custom SMS when event is rescheduled to attendee",
|
||||||
"workflow_example_3": "Send custom email when new event is booked to host",
|
"workflow_example_3": "Send custom email when new event is booked to host",
|
||||||
@@ -1256,14 +1253,47 @@
|
|||||||
"create_first_api_key_description": "API keys allow other apps to communicate with Cal.com",
|
"create_first_api_key_description": "API keys allow other apps to communicate with Cal.com",
|
||||||
"back_to_signin": "Back to sign in",
|
"back_to_signin": "Back to sign in",
|
||||||
"reset_link_sent": "Reset link sent",
|
"reset_link_sent": "Reset link sent",
|
||||||
"password_reset_email":"An email is on it’s way to {{email}} with instructions to reset your password.",
|
"password_reset_email": "An email is on it’s way to {{email}} with instructions to reset your password.",
|
||||||
"password_reset_leading":"If you did not receive the email soon, check that the email address you entered is correct, check your spam folder or reach out to support if the issue persists.",
|
"password_reset_leading": "If you don't receive an email soon, check that the email address you entered is correct, check your spam folder or reach out to support if the issue persists.",
|
||||||
"password_updated":"Password updated!",
|
"password_updated": "Password updated!",
|
||||||
"pending_payment": "Pending payment",
|
"pending_payment": "Pending payment",
|
||||||
"confirmation_page_rainbow": "Token gate your event with tokens or NFTs on Ethereum, Polygon, and more.",
|
"confirmation_page_rainbow": "Token gate your event with tokens or NFTs on Ethereum, Polygon, and more.",
|
||||||
"not_on_cal": "Not on Cal.com",
|
"not_on_cal": "Not on Cal.com",
|
||||||
"no_calendar_installed": "No calendar installed",
|
"no_calendar_installed": "No calendar installed",
|
||||||
"no_calendar_installed_description": "You have not yet connected any of your calendars",
|
"no_calendar_installed_description": "You have not yet connected any of your calendars",
|
||||||
"add_a_calendar": "Add a calendar",
|
"add_a_calendar": "Add a calendar",
|
||||||
"change_email_hint": "You may need to log out and back in to see any change take effect"
|
"change_email_hint": "You may need to log out and back in to see any change take effect",
|
||||||
|
"confirm_password_change_email": "Please confirm your password before changing your email address",
|
||||||
|
"seats": "seats",
|
||||||
|
"every_app_published": "Every app published on the Cal.com App Store is open source and thoroughly tested via peer reviews. Nevertheless, Cal.com, Inc. does not endorse or certify these apps unless they are published by Cal.com. If you encounter inappropriate content or behaviour please report it.",
|
||||||
|
"report_app": "Report app",
|
||||||
|
"team_name_required": "Team name required",
|
||||||
|
"how_additional_inputs_as_variables": "How to use Additional Inputs as Variables",
|
||||||
|
"format": "Format",
|
||||||
|
"uppercase_for_letters": "Use uppercase for all letters",
|
||||||
|
"replace_whitespaces_underscores": "Replace whitespaces with underscores",
|
||||||
|
"manage_billing": "Manage billing",
|
||||||
|
"manage_billing_description": "Manage all things billing",
|
||||||
|
"billing_freeplan_title": "You're currently on the FREE plan",
|
||||||
|
"billing_freeplan_description": "We work better in teams. Extend your workflows with round-robin and collective events and make advanced routing forms",
|
||||||
|
"billing_freeplan_cta": "Try now",
|
||||||
|
"billing_manage_details_title": "View and manage your billing details",
|
||||||
|
"billing_manage_details_description": "View and edit your billing details, as well as cancel your subscription.",
|
||||||
|
"billing_portal": "Billing portal",
|
||||||
|
"billing_help_title": "Need anything else?",
|
||||||
|
"billing_help_description": "If you need any further help with billing, our support team are here to help.",
|
||||||
|
"billing_help_cta": "Contact support",
|
||||||
|
"ignore_special_characters": "Ignore special characters in your Additional Input label. Use only letters and numbers",
|
||||||
|
"retry": "Retry",
|
||||||
|
"fetching_calendars_error": "There was a problem fetching your calendars. Please <1>try again</1> or reach out to customer support.",
|
||||||
|
"calendar_connection_fail": "Calendar connection failed",
|
||||||
|
"booking_confirmation_success": "Booking confirmation succeeded",
|
||||||
|
"booking_confirmation_fail": "Booking confirmation failed",
|
||||||
|
"we_wont_show_again": "We won't show this again",
|
||||||
|
"couldnt_update_timezone": "We couldn't update the timezone",
|
||||||
|
"updated_timezone_to": "Updated timezone to {{formattedCurrentTz}}",
|
||||||
|
"update_timezone": "Update timezone",
|
||||||
|
"update_timezone_question": "Update Timezone?",
|
||||||
|
"update_timezone_description": "It seems like your local timezone has changed to {{formattedCurrentTz}}. It's very important to have the correct timezone to prevent bookings at undesired times. Do you want to update it?",
|
||||||
|
"dont_update": "Don't update"
|
||||||
}
|
}
|
||||||
@@ -112,7 +112,6 @@
|
|||||||
"use_link_to_reset_password": "Utilice el enlace de abajo para restablecer su contraseña",
|
"use_link_to_reset_password": "Utilice el enlace de abajo para restablecer su contraseña",
|
||||||
"hey_there": "Hola,",
|
"hey_there": "Hola,",
|
||||||
"forgot_your_password_calcom": "¿Has olvidado tu contraseña? - Cal.com",
|
"forgot_your_password_calcom": "¿Has olvidado tu contraseña? - Cal.com",
|
||||||
"event_type_title": "{{eventTypeTitle}} | Tipo de Evento",
|
|
||||||
"delete_webhook_confirmation_message": "¿Está seguro de que desea eliminar este webhook? Ya no recibirá datos de reuniones de Cal.com en una URL específica, en tiempo real, cuando se programe o cancele un evento.",
|
"delete_webhook_confirmation_message": "¿Está seguro de que desea eliminar este webhook? Ya no recibirá datos de reuniones de Cal.com en una URL específica, en tiempo real, cuando se programe o cancele un evento.",
|
||||||
"confirm_delete_webhook": "Sí, elimina este webhook",
|
"confirm_delete_webhook": "Sí, elimina este webhook",
|
||||||
"edit_webhook": "Editar Webhook",
|
"edit_webhook": "Editar Webhook",
|
||||||
@@ -143,6 +142,7 @@
|
|||||||
"view_public_page": "Ver página pública",
|
"view_public_page": "Ver página pública",
|
||||||
"sign_out": "Cerrar sesión",
|
"sign_out": "Cerrar sesión",
|
||||||
"add_another": "Añadir otro",
|
"add_another": "Añadir otro",
|
||||||
|
"install_another": "Instalar otro",
|
||||||
"until": "hasta el",
|
"until": "hasta el",
|
||||||
"powered_by": "con tecnología de",
|
"powered_by": "con tecnología de",
|
||||||
"unavailable": "Indisponible",
|
"unavailable": "Indisponible",
|
||||||
@@ -157,6 +157,7 @@
|
|||||||
"checkbox": "Casilla",
|
"checkbox": "Casilla",
|
||||||
"is_required": "Es requerido",
|
"is_required": "Es requerido",
|
||||||
"required": "Requerido",
|
"required": "Requerido",
|
||||||
|
"optional": "Opcional",
|
||||||
"input_type": "Tipo de entrada",
|
"input_type": "Tipo de entrada",
|
||||||
"rejected": "Rechazado",
|
"rejected": "Rechazado",
|
||||||
"unconfirmed": "Sin confirmar",
|
"unconfirmed": "Sin confirmar",
|
||||||
@@ -227,7 +228,9 @@
|
|||||||
"connect_your_calendar_instructions": "Conecta tu calendario para comprobar automáticamente los horarios ocupados y los nuevos eventos a medida que se programan.",
|
"connect_your_calendar_instructions": "Conecta tu calendario para comprobar automáticamente los horarios ocupados y los nuevos eventos a medida que se programan.",
|
||||||
"set_up_later": "Configurar más tarde",
|
"set_up_later": "Configurar más tarde",
|
||||||
"current_time": "Hora Actual",
|
"current_time": "Hora Actual",
|
||||||
|
"details": "Detalles",
|
||||||
"welcome": "Bienvenido",
|
"welcome": "Bienvenido",
|
||||||
|
"welcome_back": "Bienvenido de nuevo",
|
||||||
"welcome_to_calcom": "Bienvenido a Cal.com",
|
"welcome_to_calcom": "Bienvenido a Cal.com",
|
||||||
"welcome_instructions": "Cuéntanos cómo llamarte y dinos la zona horaria en la que estás. Podrás editarla más tarde.",
|
"welcome_instructions": "Cuéntanos cómo llamarte y dinos la zona horaria en la que estás. Podrás editarla más tarde.",
|
||||||
"connect_caldav": "Conectar con el servidor de CalDav",
|
"connect_caldav": "Conectar con el servidor de CalDav",
|
||||||
@@ -240,6 +243,7 @@
|
|||||||
"when": "Cuándo",
|
"when": "Cuándo",
|
||||||
"where": "Donde",
|
"where": "Donde",
|
||||||
"add_to_calendar": "Añadir al Calendario",
|
"add_to_calendar": "Añadir al Calendario",
|
||||||
|
"add_another_calendar": "Añadir otro calendario",
|
||||||
"other": "Otro",
|
"other": "Otro",
|
||||||
"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": "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_attendees_recurring": "Le enviamos a usted y a los demás asistentes una invitación al calendario para el primero de estos eventos recurrentes.",
|
||||||
@@ -261,6 +265,8 @@
|
|||||||
"enter_new_password": "Introduce la nueva contraseña que te gustaría para tu cuenta.",
|
"enter_new_password": "Introduce la nueva contraseña que te gustaría para tu cuenta.",
|
||||||
"reset_password": "Restablecer Contraseña",
|
"reset_password": "Restablecer Contraseña",
|
||||||
"change_your_password": "Cambiar Contraseña",
|
"change_your_password": "Cambiar Contraseña",
|
||||||
|
"show_password": "Mostrar contraseña",
|
||||||
|
"hide_password": "Ocultar contraseña",
|
||||||
"try_again": "Volver a Intentarlo",
|
"try_again": "Volver a Intentarlo",
|
||||||
"request_is_expired": "Esta solicitud ha caducado.",
|
"request_is_expired": "Esta solicitud ha caducado.",
|
||||||
"reset_instructions": "Introduzca el email asociado a su cuenta y le enviaremos un enlace para restablecer su contraseña.",
|
"reset_instructions": "Introduzca el email asociado a su cuenta y le enviaremos un enlace para restablecer su contraseña.",
|
||||||
@@ -288,7 +294,7 @@
|
|||||||
"cannot_cancel_booking": "No puedes cancelar esta reserva",
|
"cannot_cancel_booking": "No puedes cancelar esta reserva",
|
||||||
"reschedule_instead": "En su lugar, también puedes reprogramarlo.",
|
"reschedule_instead": "En su lugar, también puedes reprogramarlo.",
|
||||||
"event_is_in_the_past": "El evento es en el pasado",
|
"event_is_in_the_past": "El evento es en el pasado",
|
||||||
"cancelling_event_recurring": "El evento es una instancia de un evento recurrente.",
|
"cancelling_event_recurring": "El evento es un caso de un evento recurrente.",
|
||||||
"cancelling_all_recurring": "Todas estas son instancias restantes en el evento recurrente.",
|
"cancelling_all_recurring": "Todas estas son instancias restantes en el evento recurrente.",
|
||||||
"error_with_status_code_occured": "Se produjo un error con el código de estado {{status}}.",
|
"error_with_status_code_occured": "Se produjo un error con el código de estado {{status}}.",
|
||||||
"booking_already_cancelled": "Esta reserva ya fue cancelada",
|
"booking_already_cancelled": "Esta reserva ya fue cancelada",
|
||||||
@@ -306,6 +312,7 @@
|
|||||||
"recurring_bookings": "Tan pronto como alguien reserve una reunión recurrente con usted, aparecerá aquí.",
|
"recurring_bookings": "Tan pronto como alguien reserve una reunión recurrente con usted, aparecerá aquí.",
|
||||||
"past_bookings": "Sus reservas pasadas aparecerán aquí.",
|
"past_bookings": "Sus reservas pasadas aparecerán aquí.",
|
||||||
"cancelled_bookings": "Las reservas canceladas aparecerán aquí.",
|
"cancelled_bookings": "Las reservas canceladas aparecerán aquí.",
|
||||||
|
"unconfirmed_bookings": "Las reservas sin confirmar aparecerán aquí.",
|
||||||
"on": "en",
|
"on": "en",
|
||||||
"and": "y",
|
"and": "y",
|
||||||
"calendar_shows_busy_between": "Tu calendario te muestra como ocupado entre",
|
"calendar_shows_busy_between": "Tu calendario te muestra como ocupado entre",
|
||||||
@@ -346,6 +353,7 @@
|
|||||||
"booking_cancelled": "Reserva Cancelada",
|
"booking_cancelled": "Reserva Cancelada",
|
||||||
"booking_rescheduled": "Reserva habilitada",
|
"booking_rescheduled": "Reserva habilitada",
|
||||||
"booking_created": "Reserva Creada",
|
"booking_created": "Reserva Creada",
|
||||||
|
"meeting_ended": "Reunión finalizada",
|
||||||
"form_submitted": "Formulario enviado",
|
"form_submitted": "Formulario enviado",
|
||||||
"event_triggers": "Activadores de Eventos",
|
"event_triggers": "Activadores de Eventos",
|
||||||
"subscriber_url": "Url del suscriptor",
|
"subscriber_url": "Url del suscriptor",
|
||||||
@@ -488,6 +496,9 @@
|
|||||||
"lets_create_first_administrator_user": "Vamos a crear el primer usuario administrador.",
|
"lets_create_first_administrator_user": "Vamos a crear el primer usuario administrador.",
|
||||||
"new_member": "Nuevo Miembro",
|
"new_member": "Nuevo Miembro",
|
||||||
"invite": "Invitación",
|
"invite": "Invitación",
|
||||||
|
"add_team_members": "Añadir miembros del equipo",
|
||||||
|
"add_team_members_description": "Invite a otros para unirse a su equipo",
|
||||||
|
"add_team_member": "Añadir miembro del equipo",
|
||||||
"invite_new_member": "Invita a un Nuevo Miembro",
|
"invite_new_member": "Invita a un Nuevo Miembro",
|
||||||
"invite_new_team_member": "Invita a alguien a tu equipo.",
|
"invite_new_team_member": "Invita a alguien a tu equipo.",
|
||||||
"change_member_role": "Cambiar rol del miembro del equipo",
|
"change_member_role": "Cambiar rol del miembro del equipo",
|
||||||
@@ -600,6 +611,7 @@
|
|||||||
"create_first_team_and_invite_others": "Crea tu primer equipo e invita a otros usuarios a trabajar contigo.",
|
"create_first_team_and_invite_others": "Crea tu primer equipo e invita a otros usuarios a trabajar contigo.",
|
||||||
"create_team_to_get_started": "Crea un equipo para empezar",
|
"create_team_to_get_started": "Crea un equipo para empezar",
|
||||||
"teams": "Equipos",
|
"teams": "Equipos",
|
||||||
|
"team": "Equipo",
|
||||||
"team_billing": "Facturación del equipo",
|
"team_billing": "Facturación del equipo",
|
||||||
"upgrade_to_flexible_pro_title": "Hemos cambiado la facturación de los equipos",
|
"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.",
|
"upgrade_to_flexible_pro_message": "Hay miembros en tu equipo sin asiento. Actualiza al plan Pro para cubrir los asientos restantes.",
|
||||||
@@ -620,7 +632,9 @@
|
|||||||
"billing": "Facturación",
|
"billing": "Facturación",
|
||||||
"manage_your_billing_info": "Gestione su información de facturación y cancele su suscripción.",
|
"manage_your_billing_info": "Gestione su información de facturación y cancele su suscripción.",
|
||||||
"availability": "Disponibilidad",
|
"availability": "Disponibilidad",
|
||||||
|
"edit_availability": "Editar disponibilidad",
|
||||||
"configure_availability": "Configure los horarios en los que está disponible para realizar reservas.",
|
"configure_availability": "Configure los horarios en los que está disponible para realizar reservas.",
|
||||||
|
"copy_times_to": "Copiar tiempos en",
|
||||||
"change_weekly_schedule": "Cambia tu Horario Semanal",
|
"change_weekly_schedule": "Cambia tu Horario Semanal",
|
||||||
"logo": "Logotipo",
|
"logo": "Logotipo",
|
||||||
"error": "Error",
|
"error": "Error",
|
||||||
@@ -635,6 +649,7 @@
|
|||||||
"event_name_tooltip": "Nombre que aparecerá en los calendarios",
|
"event_name_tooltip": "Nombre que aparecerá en los calendarios",
|
||||||
"meeting_with_user": "Reunión con {ATTENDEE}",
|
"meeting_with_user": "Reunión con {ATTENDEE}",
|
||||||
"additional_inputs": "Campos Adicionales",
|
"additional_inputs": "Campos Adicionales",
|
||||||
|
"additional_input_description": "Requerir que el planificador introduzca entradas adicionales antes de confirmar la reserva",
|
||||||
"label": "Etiqueta",
|
"label": "Etiqueta",
|
||||||
"placeholder": "Marcador de posición",
|
"placeholder": "Marcador de posición",
|
||||||
"type": "Tipo",
|
"type": "Tipo",
|
||||||
@@ -649,6 +664,8 @@
|
|||||||
"disable_guests": "Desactivar Invitados",
|
"disable_guests": "Desactivar Invitados",
|
||||||
"disable_guests_description": "Desactiva agregar invitados adicionales al hacer la reserva.",
|
"disable_guests_description": "Desactiva agregar invitados adicionales al hacer la reserva.",
|
||||||
"private_link": "Generar una URL privada",
|
"private_link": "Generar una URL privada",
|
||||||
|
"private_link_label": "Enlace privado",
|
||||||
|
"private_link_hint": "Su enlace privado se regenera después de cada uso",
|
||||||
"copy_private_link": "Copiar enlace privado",
|
"copy_private_link": "Copiar enlace privado",
|
||||||
"private_link_description": "Generar una URL privada para compartir sin exponer su nombre de usuario de Cal",
|
"private_link_description": "Generar una URL privada para compartir sin exponer su nombre de usuario de Cal",
|
||||||
"invitees_can_schedule": "Los invitados pueden programar",
|
"invitees_can_schedule": "Los invitados pueden programar",
|
||||||
@@ -690,16 +707,21 @@
|
|||||||
"delete_account_confirmation_message": "¿Estás seguro de que quieres eliminar tu cuenta de Cal.com? 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á.",
|
"delete_account_confirmation_message": "¿Estás seguro de que quieres eliminar tu cuenta de Cal.com? 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",
|
"integrations": "Integraciones",
|
||||||
"apps": "Aplicaciones",
|
"apps": "Aplicaciones",
|
||||||
|
"category_apps": "Aplicaciones {{category}}",
|
||||||
"app_store": "App Store",
|
"app_store": "App Store",
|
||||||
"app_store_description": "Conectar personas, tecnología y lugar de trabajo.",
|
"app_store_description": "Conectar personas, tecnología y lugar de trabajo.",
|
||||||
"settings": "Ajustes",
|
"settings": "Ajustes",
|
||||||
"event_type_moved_successfully": "El tipo de evento se ha movido correctamente",
|
"event_type_moved_successfully": "El tipo de evento se ha movido correctamente",
|
||||||
|
"next_step_text": "Siguiente paso",
|
||||||
"next_step": "Saltar paso",
|
"next_step": "Saltar paso",
|
||||||
"prev_step": "Paso anterior",
|
"prev_step": "Paso anterior",
|
||||||
|
"install": "Instalar",
|
||||||
"installed": "Instalado",
|
"installed": "Instalado",
|
||||||
"active_install_one": "{{count}} instalación activa",
|
"active_install_one": "{{count}} instalación activa",
|
||||||
"active_install_other": "{{count}} instalaciones activas",
|
"active_install_other": "{{count}} instalaciones activas",
|
||||||
"globally_install": "Instalada globalmente",
|
"globally_install": "Instalada globalmente",
|
||||||
|
"app_successfully_installed": "Aplicación instalada correctamente",
|
||||||
|
"app_could_not_be_installed": "No se ha podido instalar la aplicación",
|
||||||
"disconnect": "Desconectar",
|
"disconnect": "Desconectar",
|
||||||
"embed_your_calendar": "Incorpora tu calendario en tu página web",
|
"embed_your_calendar": "Incorpora tu calendario en tu página web",
|
||||||
"connect_your_favourite_apps": "Conecta tus aplicaciones favoritas.",
|
"connect_your_favourite_apps": "Conecta tus aplicaciones favoritas.",
|
||||||
@@ -710,6 +732,7 @@
|
|||||||
"connect_additional_calendar": "Conectar calendario adicional",
|
"connect_additional_calendar": "Conectar calendario adicional",
|
||||||
"conferencing": "Conferencias",
|
"conferencing": "Conferencias",
|
||||||
"calendar": "Calendario",
|
"calendar": "Calendario",
|
||||||
|
"payments": "Pagos",
|
||||||
"not_installed": "No instalado",
|
"not_installed": "No instalado",
|
||||||
"error_password_mismatch": "Las contraseñas no coinciden.",
|
"error_password_mismatch": "Las contraseñas no coinciden.",
|
||||||
"error_required_field": "Este campo es requerido.",
|
"error_required_field": "Este campo es requerido.",
|
||||||
@@ -743,9 +766,22 @@
|
|||||||
"import_from": "Importar desde",
|
"import_from": "Importar desde",
|
||||||
"access_token": "Token de acceso",
|
"access_token": "Token de acceso",
|
||||||
"visit_roadmap": "Hoja de ruta",
|
"visit_roadmap": "Hoja de ruta",
|
||||||
|
"featured_categories": "Categorías destacadas",
|
||||||
"popular_categories": "Categorías populares",
|
"popular_categories": "Categorías populares",
|
||||||
|
"number_apps_one": "{{count}} aplicación",
|
||||||
|
"number_apps_other": "{{count}} aplicaciones",
|
||||||
"trending_apps": "Aplicaciones populares",
|
"trending_apps": "Aplicaciones populares",
|
||||||
|
"explore_apps": "Aplicaciones {{category}}",
|
||||||
"installed_apps": "Aplicaciones instaladas",
|
"installed_apps": "Aplicaciones instaladas",
|
||||||
|
"no_category_apps": "No hay aplicaciones {{category}}",
|
||||||
|
"no_category_apps_description_calendar": "Añada una aplicación de calendario para comprobar si hay conflictos y evitar reservas dobles",
|
||||||
|
"no_category_apps_description_conferencing": "Intente añadir una aplicación de conferencias para integrar las videollamadas con sus clientes",
|
||||||
|
"no_category_apps_description_payment": "Añada una aplicación de pagos para facilitar las transacciones con sus clientes",
|
||||||
|
"no_category_apps_description_other": "Añada cualquier otro tipo de aplicación para hacer todo tipo de tareas",
|
||||||
|
"installed_app_calendar_description": "Configure los calendarios para comprobar conflictos y evitar reservas dobles.",
|
||||||
|
"installed_app_conferencing_description": "Añada sus aplicaciones de videoconferencia favoritas para sus reuniones",
|
||||||
|
"installed_app_payment_description": "Configure qué servicios de procesamiento de pagos se van a usar al cobrarles a sus clientes.",
|
||||||
|
"installed_app_other_description": "Todas sus aplicaciones instaladas de otras categorías.",
|
||||||
"empty_installed_apps_headline": "No hay aplicaciones instaladas",
|
"empty_installed_apps_headline": "No hay aplicaciones instaladas",
|
||||||
"empty_installed_apps_description": "Las aplicaciones le permiten mejorar su flujo de trabajo y mejorar su tiempo calendario de forma significativa.",
|
"empty_installed_apps_description": "Las aplicaciones le permiten mejorar su flujo de trabajo y mejorar su tiempo calendario de forma significativa.",
|
||||||
"empty_installed_apps_button": "Explore la tienda de aplicaciones",
|
"empty_installed_apps_button": "Explore la tienda de aplicaciones",
|
||||||
@@ -766,6 +802,7 @@
|
|||||||
"remove": "Eliminar",
|
"remove": "Eliminar",
|
||||||
"add": "Añadir",
|
"add": "Añadir",
|
||||||
"installed_one": "Instalado",
|
"installed_one": "Instalado",
|
||||||
|
"installed_other": "{{count}} instaladas",
|
||||||
"verify_wallet": "Verificar billetera",
|
"verify_wallet": "Verificar billetera",
|
||||||
"connect_metamask": "Conectar Metamask",
|
"connect_metamask": "Conectar Metamask",
|
||||||
"create_events_on": "Crear eventos en:",
|
"create_events_on": "Crear eventos en:",
|
||||||
@@ -783,6 +820,8 @@
|
|||||||
"set_to_default": "Establecer como predeterminado",
|
"set_to_default": "Establecer como predeterminado",
|
||||||
"new_schedule_btn": "Nuevo horario",
|
"new_schedule_btn": "Nuevo horario",
|
||||||
"add_new_schedule": "Añadir un nuevo horario",
|
"add_new_schedule": "Añadir un nuevo horario",
|
||||||
|
"add_new_calendar": "Añadir un calendario nuevo",
|
||||||
|
"set_calendar": "Especifique dónde se añadirán los eventos nuevos cuando haya reservado.",
|
||||||
"delete_schedule": "Eliminar horario",
|
"delete_schedule": "Eliminar horario",
|
||||||
"schedule_created_successfully": "Horario {{scheduleName}} creado con éxito",
|
"schedule_created_successfully": "Horario {{scheduleName}} creado con éxito",
|
||||||
"availability_updated_successfully": "Disponibilidad actualizada correctamente",
|
"availability_updated_successfully": "Disponibilidad actualizada correctamente",
|
||||||
@@ -883,7 +922,7 @@
|
|||||||
"zapier_setup_instructions": "<0>Inicie sesión en su cuenta de Zapier y cree un nuevo Zap.</0><1>Seleccione Cal.com cómo su aplicación Trigger. También elija su evento Trigger.</1><2>Seleccione su cuenta e ingrese su Clave API única.</2><3>Pruebe su Trigger.</3><4>¡Listo!</4>",
|
"zapier_setup_instructions": "<0>Inicie sesión en su cuenta de Zapier y cree un nuevo Zap.</0><1>Seleccione Cal.com cómo su aplicación Trigger. También elija su evento Trigger.</1><2>Seleccione su cuenta e ingrese su Clave API única.</2><3>Pruebe su Trigger.</3><4>¡Listo!</4>",
|
||||||
"install_zapier_app": "Instale primero la aplicación Zapier desde la App Store.",
|
"install_zapier_app": "Instale primero la aplicación Zapier desde la App Store.",
|
||||||
"connect_apple_server": "Conectar con Apple Server",
|
"connect_apple_server": "Conectar con Apple Server",
|
||||||
"connect_caldav_server": "Conectar con CalDav Server",
|
"connect_caldav_server": "Conectar con CalDav (Beta)",
|
||||||
"calendar_url": "URL del calendario",
|
"calendar_url": "URL del calendario",
|
||||||
"apple_server_generate_password": "Genere una contraseña específica de la aplicación para utilizarla con Cal.com en",
|
"apple_server_generate_password": "Genere una contraseña específica de la aplicación para utilizarla con Cal.com en",
|
||||||
"credentials_stored_encrypted": "Sus credenciales serán almacenadas y cifradas.",
|
"credentials_stored_encrypted": "Sus credenciales serán almacenadas y cifradas.",
|
||||||
@@ -936,6 +975,7 @@
|
|||||||
"workflows": "Flujos de trabajo",
|
"workflows": "Flujos de trabajo",
|
||||||
"new_workflow_btn": "Flujo de trabajo nuevo",
|
"new_workflow_btn": "Flujo de trabajo nuevo",
|
||||||
"add_new_workflow": "Agregar un flujo de trabajo nuevo",
|
"add_new_workflow": "Agregar un flujo de trabajo nuevo",
|
||||||
|
"reschedule_event_trigger": "cuando el evento se vuelva a programar",
|
||||||
"trigger": "Desencadenante",
|
"trigger": "Desencadenante",
|
||||||
"triggers": "Desencadenantes",
|
"triggers": "Desencadenantes",
|
||||||
"action": "Acción",
|
"action": "Acción",
|
||||||
@@ -963,10 +1003,13 @@
|
|||||||
"change_username_standard_to_premium": "Como estás cambiando de un nombre de usuario estándar a un nombre de usuario premium, se te llevará al pago para actualizarlo.",
|
"change_username_standard_to_premium": "Como estás cambiando de un nombre de usuario estándar a un nombre de usuario premium, se te llevará al pago para actualizarlo.",
|
||||||
"change_username_premium_to_standard": "Como estás cambiando de un nombre de usuario premium a un nombre de usuario estándar, se te llevará al pago para bajar de categoría.",
|
"change_username_premium_to_standard": "Como estás cambiando de un nombre de usuario premium a un nombre de usuario estándar, se te llevará al pago para bajar de categoría.",
|
||||||
"go_to_stripe_billing": "Ir a facturación",
|
"go_to_stripe_billing": "Ir a facturación",
|
||||||
|
"stripe_description": "Se requiere un pago para las reservas (0,5 % + 0,10 € de comisión por transacción)",
|
||||||
"trial_expired": "Tu prueba ha caducado",
|
"trial_expired": "Tu prueba ha caducado",
|
||||||
"remove_app": "Eliminar aplicación",
|
"remove_app": "Eliminar aplicación",
|
||||||
"yes_remove_app": "Sí, eliminar aplicación",
|
"yes_remove_app": "Sí, eliminar aplicación",
|
||||||
"are_you_sure_you_want_to_remove_this_app": "¿Está seguro de que desea eliminar esta aplicación?",
|
"are_you_sure_you_want_to_remove_this_app": "¿Está seguro de que desea eliminar esta aplicación?",
|
||||||
|
"app_removed_successfully": "Aplicación eliminada correctamente",
|
||||||
|
"error_removing_app": "Error al eliminar la aplicación",
|
||||||
"web_conference": "Conferencia web",
|
"web_conference": "Conferencia web",
|
||||||
"number_for_sms_reminders": "Número de teléfono (para recordatorios de SMS)",
|
"number_for_sms_reminders": "Número de teléfono (para recordatorios de SMS)",
|
||||||
"requires_confirmation": "Requiere confirmación",
|
"requires_confirmation": "Requiere confirmación",
|
||||||
@@ -1022,18 +1065,205 @@
|
|||||||
"navigate": "Navegar",
|
"navigate": "Navegar",
|
||||||
"open": "Abrir",
|
"open": "Abrir",
|
||||||
"close": "Cerrar",
|
"close": "Cerrar",
|
||||||
|
"team_feature_teams": "Esta es una función Team. Actualice a Team para ver la disponibilidad de su equipo.",
|
||||||
|
"team_feature_workflows": "Esta es una función Team. Actualice a Team para automatizar los recordadorios y las notificaciones de eventos con flujos de trabajo.",
|
||||||
|
"show_eventtype_on_profile": "Mostrar en perfil",
|
||||||
"embed": "Insertar",
|
"embed": "Insertar",
|
||||||
"new_username": "Nombre de usuario nuevo",
|
"new_username": "Nombre de usuario nuevo",
|
||||||
"current_username": "Nombre de usuario actual",
|
"current_username": "Nombre de usuario actual",
|
||||||
"example_1": "Ejemplo 1",
|
"example_1": "Ejemplo 1",
|
||||||
"example_2": "Ejemplo 2",
|
"example_2": "Ejemplo 2",
|
||||||
|
"additional_input_label": "Etiqueta de entrada adicional",
|
||||||
"company_size": "Tamaño de la empresa",
|
"company_size": "Tamaño de la empresa",
|
||||||
"what_help_needed": "¿Con qué necesitas ayuda?",
|
"what_help_needed": "¿Con qué necesitas ayuda?",
|
||||||
"variable_format": "Formato variable",
|
"variable_format": "Formato variable",
|
||||||
|
"webhook_subscriber_url_reserved": "La URL del suscriptor de Webhook ya está definida",
|
||||||
|
"custom_input_as_variable_info": "Ignore todos los caracteres especiales de la etiqueta de entrada adicional (utilice solo letras y números), utilice mayúsculas para todas las letras y sustituya los espacios en blanco por guiones bajos.",
|
||||||
"using_additional_inputs_as_variables": "¿Cómo usar entradas adicionales como variables?",
|
"using_additional_inputs_as_variables": "¿Cómo usar entradas adicionales como variables?",
|
||||||
"download_desktop_app": "Descargar la aplicación de escritorio",
|
"download_desktop_app": "Descargar la aplicación de escritorio",
|
||||||
"set_ping_link": "Establecer enlace Ping",
|
"set_ping_link": "Establecer enlace Ping",
|
||||||
|
"rate_limit_exceeded": "Límite de tasa excedido",
|
||||||
|
"when_something_happens": "Cuando algo sucede",
|
||||||
|
"action_is_performed": "Se realiza una acción",
|
||||||
|
"test_action": "Probar acción",
|
||||||
|
"notification_sent": "Notificación enviada",
|
||||||
|
"no_input": "No hay entrada",
|
||||||
|
"test_workflow_action": "Probar acción de flujo de trabajo",
|
||||||
|
"send_sms": "Enviar SMS",
|
||||||
|
"send_sms_to_number": "¿Está seguro de que desea enviar un SMS al {{number}}?",
|
||||||
|
"missing_connected_calendar": "No hay ningún calendario predeterminado conectado",
|
||||||
|
"connect_your_calendar_and_link": "Puede conectar su calendario desde <1>aquí</1>.",
|
||||||
|
"default_calendar_selected": "Calendario predeterminado",
|
||||||
|
"hide_from_profile": "Ocultar del perfil",
|
||||||
|
"event_setup_tab_title": "Configuración del evento",
|
||||||
|
"event_limit_tab_title": "Límites",
|
||||||
|
"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",
|
||||||
|
"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",
|
||||||
|
"2fa_required": "Se requiere autenticación de dos factores",
|
||||||
|
"incorrect_2fa": "Código de autenticación de dos factores incorrecto",
|
||||||
|
"which_event_type_apply": "¿A qué tipo de evento se aplicará esto?",
|
||||||
|
"no_workflows_description": "Los flujos de trabajo permiten una automatización simple para enviar notificaciones y recordatorios que le permiten crear procesos para sus eventos.",
|
||||||
|
"create_workflow": "Crear un flujo de trabajo",
|
||||||
|
"do_this": "Hacer esto",
|
||||||
|
"turn_off": "Apagar",
|
||||||
|
"settings_updated_successfully": "Configuración actualizada correctamente",
|
||||||
|
"error_updating_settings": "Error al actualizar la configuración",
|
||||||
|
"personal_cal_url": "Mi URL personal de Cal",
|
||||||
|
"bio_hint": "Algunas frases sobre usted, esta información aparecerá en la página de su URL personal.",
|
||||||
|
"delete_account_modal_title": "Eliminar cuenta",
|
||||||
|
"confirm_delete_account_modal": "¿Está seguro que desea eliminar su cuenta de Cal.com?",
|
||||||
|
"delete_my_account": "Eliminar mi cuenta",
|
||||||
|
"start_of_week": "Inicio de la semana",
|
||||||
|
"select_calendars": "Seleccione los calendarios en los que desee comprobar conflictos para evitar reservas dobles.",
|
||||||
|
"check_for_conflicts": "Comprobar conflictos",
|
||||||
|
"adding_events_to": "Agregando eventos a",
|
||||||
|
"follow_system_preferences": "Siga las preferencias del sistema",
|
||||||
|
"custom_brand_colors": "Colores de marca personalizados",
|
||||||
|
"customize_your_brand_colors": "Personalice el color de su propia marca en su página de reservas.",
|
||||||
|
"pro": "Pro",
|
||||||
|
"removes_cal_branding": "Elimina cualquier marca relacionada con Cal, p. ej., \"Powered by Cal\".",
|
||||||
|
"profile_picture": "Imagen de perfil",
|
||||||
|
"upload": "Cargar",
|
||||||
|
"web3": "Web3",
|
||||||
|
"rainbow_token_gated": "Este tipo de evento tiene acceso cerrado por token.",
|
||||||
|
"rainbow_connect_wallet_gate": "Conecte su billetera si posee <1>{{name}}</1> (<3>{{symbol}}</3>).",
|
||||||
|
"rainbow_insufficient_balance": "Su billetera conectada no contiene suficiente <1>{{symbol}}</1>.",
|
||||||
|
"rainbow_sign_message_request": "Firme la solicitud de mensaje en su billetera.",
|
||||||
|
"rainbow_signature_error": "Error al solicitar la firma desde su billetera.",
|
||||||
|
"token_address": "Dirección del token",
|
||||||
|
"blockchain": "Blockchain",
|
||||||
|
"old_password": "Contraseña anterior",
|
||||||
|
"secure_password": "Su contraseña nueva supersegura",
|
||||||
|
"error_updating_password": "Error al actualizar la contraseña",
|
||||||
|
"two_factor_auth": "Autenticación de dos factores",
|
||||||
|
"recurring_event_tab_description": "Configurar un calendario repetitivo",
|
||||||
|
"today": "hoy",
|
||||||
|
"appearance": "Aspecto",
|
||||||
|
"appearance_subtitle": "Administre los ajustes para el aspecto de su reserva",
|
||||||
|
"my_account": "Mi cuenta",
|
||||||
|
"general": "General",
|
||||||
|
"calendars": "Calendarios",
|
||||||
|
"2fa_auth": "Autenticación de dos factores",
|
||||||
|
"invoices": "Facturas",
|
||||||
|
"embeds": "Inserciones",
|
||||||
|
"impersonation": "Suplantación",
|
||||||
|
"users": "Usuarios",
|
||||||
|
"profile_description": "Administre los ajustes para su perfil de Cal",
|
||||||
|
"general_description": "Administre los ajustes para su idioma y zona horaria",
|
||||||
|
"calendars_description": "Configure cómo deben interactuar sus tipos de eventos con sus calendarios",
|
||||||
|
"appearance_description": "Administre los ajustes para el aspecto de su reserva",
|
||||||
|
"conferencing_description": "Administre sus aplicaciones de videoconferencia para sus reuniones",
|
||||||
|
"password_description": "Administre los ajustes para las contraseñas de su cuenta",
|
||||||
|
"2fa_description": "Administre los ajustes para las contraseñas de su cuenta",
|
||||||
|
"we_just_need_basic_info": "Solo necesitamos información básica para configurar su perfil.",
|
||||||
|
"skip": "Omitir",
|
||||||
|
"do_this_later": "Hacerlo más tarde",
|
||||||
|
"set_availability_getting_started_subtitle_1": "Defina los intervalos de tiempo en los que esté disponible",
|
||||||
|
"set_availability_getting_started_subtitle_2": "Puede personalizar todo esto más tarde en la página de disponibilidad.",
|
||||||
|
"connect_calendars_from_app_store": "Puede añadir más calendarios desde la tienda de aplicaciones",
|
||||||
|
"connect_conference_apps": "Conectar aplicaciones de conferencia",
|
||||||
|
"connect_calendar_apps": "Conectar aplicaciones de calendario",
|
||||||
|
"connect_payment_apps": "Conectar aplicaciones de pago",
|
||||||
|
"connect_other_apps": "Conectar otras aplicaciones",
|
||||||
|
"current_step_of_total": "Paso {{currentStep}} de {{maxSteps}}",
|
||||||
|
"add_variable": "Añadir variable",
|
||||||
|
"custom_phone_number": "Número de teléfono personalizado",
|
||||||
|
"message_template": "Plantilla de mensaje",
|
||||||
|
"email_subject": "Asunto del correo electrónico",
|
||||||
|
"add_dynamic_variables": "Añadir variables de texto dinámico",
|
||||||
|
"event_name_info": "El nombre del tipo de evento",
|
||||||
|
"event_date_info": "La fecha del evento",
|
||||||
|
"event_time_info": "La hora de inicio del evento",
|
||||||
|
"location_info": "La ubicación del evento",
|
||||||
"organizer_name_info": "Tu Nombre",
|
"organizer_name_info": "Tu Nombre",
|
||||||
|
"additional_notes_info": "Las notas adicionales de la reserva",
|
||||||
|
"attendee_name_info": "El nombre de la persona que reserva",
|
||||||
|
"to": "Para",
|
||||||
|
"attendee_required_enter_number": "Será necesario que el asistente introduzca un número de teléfono al reservar",
|
||||||
|
"workflow_turned_on_successfully": "El flujo de trabajo {{workflowName}} se ajustó como {{offOn}} correctamente",
|
||||||
|
"download_responses": "Descargar respuestas",
|
||||||
|
"create_your_first_form": "Cree su primer formulario",
|
||||||
|
"create_your_first_form_description": "Con los formularios de orientación puede hacer preguntas de cualificación y llegar a la persona o tipo de evento correctos.",
|
||||||
|
"create_your_first_webhook": "Cree su primer Webhook",
|
||||||
|
"create_your_first_webhook_description": "Con Webhooks puede recibir datos de reuniones en tiempo real cuando suceda algo en Cal.com.",
|
||||||
|
"for_a_maximum_of": "Para un máximo de",
|
||||||
|
"event_one": "evento",
|
||||||
|
"event_other": "eventos",
|
||||||
|
"profile_team_description": "Administre ajustes para el perfil de su equipo",
|
||||||
|
"members_team_description": "Usuarios que están en el grupo",
|
||||||
|
"team_url": "URL del equipo",
|
||||||
|
"delete_team": "Eliminar equipo",
|
||||||
|
"team_members": "Miembros del equipo",
|
||||||
|
"more": "Más",
|
||||||
|
"more_page_footer": "Vemos la aplicación móvil como una extensión de la aplicación web. Si está realizando acciones complicadas, consulte la aplicación web.",
|
||||||
|
"workflow_example_1": "Enviar recordatorio por SMS al asistente 24 horas antes de que el evento comience",
|
||||||
|
"workflow_example_2": "Enviar SMS personalizado al asistente cuando se cambie la planificación del evento",
|
||||||
|
"workflow_example_3": "Enviar correo electrónico personalizado al anfitrión cuando se reserve un evento nuevo",
|
||||||
|
"workflow_example_4": "Enviar recordatorio por correo electrónico al asistente 1 hora antes de que el evento comience",
|
||||||
|
"workflow_example_5": "Enviar correo electrónico personalizado al anfitrión cuando se cambie la planificación del evento",
|
||||||
|
"workflow_example_6": "Enviar SMS personalizado al anfitrión cuando se reserve un evento nuevo",
|
||||||
|
"welcome_to_cal_header": "¡Bienvenido a Cal.com!",
|
||||||
|
"edit_form_later_subtitle": "Podrá editarlo más tarde.",
|
||||||
|
"connect_calendar_later": "Conectaré mi calendario más tarde",
|
||||||
|
"set_my_availability_later": "Indicaré mi disponibilidad más tarde",
|
||||||
|
"problem_saving_user_profile": "Se produjo un problema al guardar sus datos. Inténtelo de nuevo o póngase en contacto con el servicio de atención al cliente.",
|
||||||
|
"purchase_missing_seats": "Comprar licencias que faltan",
|
||||||
|
"slot_length": "Duración de franja",
|
||||||
|
"booking_appearance": "Aspecto de la reserva",
|
||||||
|
"appearance_team_description": "Administre los ajustes para el aspecto de la reserva de su equipo",
|
||||||
|
"only_owner_change": "Solo el propietario de este equipo puede hacer cambios en la reserva del equipo ",
|
||||||
|
"team_disable_cal_branding_description": "Elimina cualquier marca relacionada con Cal, p. ej., \"Powered by Cal\"",
|
||||||
|
"invited_by_team": "{{teamName}} le invitó a unirse a su equipo como {{role}}",
|
||||||
|
"token_invalid_expired": "El token no es válido o ha caducado.",
|
||||||
|
"exchange_add": "Conectar a Microsoft Exchange",
|
||||||
|
"exchange_authentication": "Método de autenticación",
|
||||||
|
"exchange_authentication_standard": "Autenticación básica",
|
||||||
|
"exchange_authentication_ntlm": "Autenticación NTLM",
|
||||||
|
"exchange_compression": "Compresión GZip",
|
||||||
|
"routing_forms_description": "Puede ver todos los formularios y rutas que ha creado aquí.",
|
||||||
|
"add_new_form": "Añadir formulario nuevo",
|
||||||
|
"form_description": "Cree su formulario para dirigirlo a un agente de reservas",
|
||||||
|
"copy_link_to_form": "Copiar enlace al formulario",
|
||||||
|
"theme": "Tema",
|
||||||
|
"theme_applies_note": "Solo se aplica a sus páginas de reservas públicas",
|
||||||
"theme_light": "Claro",
|
"theme_light": "Claro",
|
||||||
"theme_dark": "Oscuro"
|
"theme_dark": "Oscuro",
|
||||||
|
"theme_system": "Predeterminado del sistema",
|
||||||
|
"add_a_team": "Añadir un equipo",
|
||||||
|
"saml_config": "Configuración de SAML",
|
||||||
|
"add_webhook_description": "Reciba datos de reuniones en tiempo real cuando suceda algo en Cal.com",
|
||||||
|
"triggers_when": "Se activa cuando",
|
||||||
|
"test_webhook": "Antes de crear, ejecute una prueba de ping.",
|
||||||
|
"enable_webhook": "Activar Webhook",
|
||||||
|
"add_webhook": "Añadir Webhook",
|
||||||
|
"webhook_edited_successfully": "Webhook guardado",
|
||||||
|
"webhooks_description": "Reciba datos de reuniones en tiempo real cuando suceda algo en Cal.com",
|
||||||
|
"api_keys_description": "Genere claves API para acceder a su propia cuenta",
|
||||||
|
"new_api_key": "Clave API nueva",
|
||||||
|
"active": "Activo",
|
||||||
|
"api_key_updated": "Nombre de clave API actualizado",
|
||||||
|
"api_key_update_failed": "Error al actualizar el nombre de la clave API",
|
||||||
|
"embeds_title": "Inserción de iframe HTML",
|
||||||
|
"embeds_description": "Inserte todos sus tipos de eventos en su sitio web",
|
||||||
|
"create_first_api_key": "Cree su primera clave API",
|
||||||
|
"create_first_api_key_description": "Las claves API permiten a otras aplicaciones comunicarse con Cal.com",
|
||||||
|
"back_to_signin": "Volver a iniciar sesión",
|
||||||
|
"reset_link_sent": "Enlace de restablecimiento enviado",
|
||||||
|
"password_reset_email": "Se ha enviado un correo electrónico a {{email}} con instrucciones para restablecer su contraseña.",
|
||||||
|
"password_updated": "¡Contraseña actualizada!",
|
||||||
|
"pending_payment": "Pago pendiente",
|
||||||
|
"confirmation_page_rainbow": "Cierre el acceso a su evento con tokens o NFT en Ethereum, Polygon, etc.",
|
||||||
|
"not_on_cal": "No está en Cal.com",
|
||||||
|
"no_calendar_installed": "No hay ningún calendario instalado",
|
||||||
|
"no_calendar_installed_description": "Aún no ha conectado ninguno de sus calendarios",
|
||||||
|
"add_a_calendar": "Añadir un calendario",
|
||||||
|
"change_email_hint": "Quizá necesite cerrar sesión y volver a entrar para ver que el cambio surta efecto",
|
||||||
|
"confirm_password_change_email": "Confirme su contraseña antes de cambiar su dirección de correo electrónico",
|
||||||
|
"seats": "asientos",
|
||||||
|
"every_app_published": "Las aplicaciones publicadas en la tienda de aplicaciones de Cal.com son de código abierto y se han sometido a pruebas exhaustivas con las reseñas de pares. Sin embargo, Cal.com, Inc. no avala ni certifica estas aplicaciones a menos que Cal.com las haya publicado expresamente. Si encuentra contenido o comportamiento inapropiados, informe de ello.",
|
||||||
|
"report_app": "Denunciar aplicación"
|
||||||
}
|
}
|
||||||
@@ -112,7 +112,6 @@
|
|||||||
"use_link_to_reset_password": "Utilisez le lien ci-dessous pour réinitialiser votre mot de passe",
|
"use_link_to_reset_password": "Utilisez le lien ci-dessous pour réinitialiser votre mot de passe",
|
||||||
"hey_there": "Salut,",
|
"hey_there": "Salut,",
|
||||||
"forgot_your_password_calcom": "Mot de passe oublié ? - Cal.com",
|
"forgot_your_password_calcom": "Mot de passe oublié ? - Cal.com",
|
||||||
"event_type_title": "{{eventTypeTitle}} | Type d'événement",
|
|
||||||
"delete_webhook_confirmation_message": "Êtes-vous sûr de vouloir supprimer ce webhook ? Vous ne recevrez plus les données de réunion de Cal.com à une URL spécifiée, en temps réel, lorsqu'un événement est programmé ou annulé.",
|
"delete_webhook_confirmation_message": "Êtes-vous sûr de vouloir supprimer ce webhook ? Vous ne recevrez plus les données de réunion de Cal.com à une URL spécifiée, en temps réel, lorsqu'un événement est programmé ou annulé.",
|
||||||
"confirm_delete_webhook": "Oui, supprimer le webhook",
|
"confirm_delete_webhook": "Oui, supprimer le webhook",
|
||||||
"edit_webhook": "Modifier le webhook",
|
"edit_webhook": "Modifier le webhook",
|
||||||
@@ -143,6 +142,7 @@
|
|||||||
"view_public_page": "Voir la page publique",
|
"view_public_page": "Voir la page publique",
|
||||||
"sign_out": "Se déconnecter",
|
"sign_out": "Se déconnecter",
|
||||||
"add_another": "Ajouter un autre",
|
"add_another": "Ajouter un autre",
|
||||||
|
"install_another": "Installer un(e) autre",
|
||||||
"until": "jusqu'au",
|
"until": "jusqu'au",
|
||||||
"powered_by": "alimenté par",
|
"powered_by": "alimenté par",
|
||||||
"unavailable": "Indisponible",
|
"unavailable": "Indisponible",
|
||||||
@@ -157,6 +157,7 @@
|
|||||||
"checkbox": "Case à cocher",
|
"checkbox": "Case à cocher",
|
||||||
"is_required": "Est obligatoire",
|
"is_required": "Est obligatoire",
|
||||||
"required": "Obligatoire",
|
"required": "Obligatoire",
|
||||||
|
"optional": "Facultatif",
|
||||||
"input_type": "Type d'entrée",
|
"input_type": "Type d'entrée",
|
||||||
"rejected": "Refusé",
|
"rejected": "Refusé",
|
||||||
"unconfirmed": "Non confirmé",
|
"unconfirmed": "Non confirmé",
|
||||||
@@ -227,7 +228,9 @@
|
|||||||
"connect_your_calendar_instructions": "Connectez votre calendrier pour vérifier automatiquement vos disponibilités au fur et à mesure qu'elles évoluent.",
|
"connect_your_calendar_instructions": "Connectez votre calendrier pour vérifier automatiquement vos disponibilités au fur et à mesure qu'elles évoluent.",
|
||||||
"set_up_later": "Configurer plus tard",
|
"set_up_later": "Configurer plus tard",
|
||||||
"current_time": "Heure actuelle",
|
"current_time": "Heure actuelle",
|
||||||
|
"details": "Détails",
|
||||||
"welcome": "Bienvenue",
|
"welcome": "Bienvenue",
|
||||||
|
"welcome_back": "Bienvenue de nouveau",
|
||||||
"welcome_to_calcom": "Bienvenue sur Cal.com",
|
"welcome_to_calcom": "Bienvenue sur Cal.com",
|
||||||
"welcome_instructions": "Dites-nous comment nous devons vous appeler et votre fuseau horaire. Vous pourrez modifier ceci plus tard.",
|
"welcome_instructions": "Dites-nous comment nous devons vous appeler et votre fuseau horaire. Vous pourrez modifier ceci plus tard.",
|
||||||
"connect_caldav": "Se connecter au serveur CalDav",
|
"connect_caldav": "Se connecter au serveur CalDav",
|
||||||
@@ -240,6 +243,7 @@
|
|||||||
"when": "Quand",
|
"when": "Quand",
|
||||||
"where": "Où",
|
"where": "Où",
|
||||||
"add_to_calendar": "Ajouter au calendrier",
|
"add_to_calendar": "Ajouter au calendrier",
|
||||||
|
"add_another_calendar": "Ajouter un autre calendrier",
|
||||||
"other": "Autre",
|
"other": "Autre",
|
||||||
"emailed_you_and_attendees": "Nous vous avons envoyé, à vous et aux autres participants, une invitation par e-mail avec tous les détails.",
|
"emailed_you_and_attendees": "Nous vous avons envoyé, à vous et aux autres participants, une invitation par e-mail avec tous les détails.",
|
||||||
"emailed_you_and_attendees_recurring": "Nous vous avons envoyé, à vous et aux autres participants, une invitation au calendrier pour le premier de ces événements récurrents.",
|
"emailed_you_and_attendees_recurring": "Nous vous avons envoyé, à vous et aux autres participants, une invitation au calendrier pour le premier de ces événements récurrents.",
|
||||||
@@ -261,6 +265,8 @@
|
|||||||
"enter_new_password": "Entrez le nouveau mot de passe que vous souhaitez pour votre compte.",
|
"enter_new_password": "Entrez le nouveau mot de passe que vous souhaitez pour votre compte.",
|
||||||
"reset_password": "Réinitialiser le mot de passe",
|
"reset_password": "Réinitialiser le mot de passe",
|
||||||
"change_your_password": "Modifiez votre mot de passe",
|
"change_your_password": "Modifiez votre mot de passe",
|
||||||
|
"show_password": "Afficher le mot de passe",
|
||||||
|
"hide_password": "Masquer le mot de passe",
|
||||||
"try_again": "Réessayer",
|
"try_again": "Réessayer",
|
||||||
"request_is_expired": "Cette requête est expirée.",
|
"request_is_expired": "Cette requête est expirée.",
|
||||||
"reset_instructions": "Saisissez l'adresse e-mail associée à votre compte et nous vous enverrons un lien pour réinitialiser votre mot de passe.",
|
"reset_instructions": "Saisissez l'adresse e-mail associée à votre compte et nous vous enverrons un lien pour réinitialiser votre mot de passe.",
|
||||||
@@ -306,6 +312,7 @@
|
|||||||
"recurring_bookings": "Dès que quelqu'un réserve une réunion récurrente avec vous, elle apparaît ici.",
|
"recurring_bookings": "Dès que quelqu'un réserve une réunion récurrente avec vous, elle apparaît ici.",
|
||||||
"past_bookings": "Vos réservations passées apparaîtront ici.",
|
"past_bookings": "Vos réservations passées apparaîtront ici.",
|
||||||
"cancelled_bookings": "Vos réservations annulées apparaîtront ici.",
|
"cancelled_bookings": "Vos réservations annulées apparaîtront ici.",
|
||||||
|
"unconfirmed_bookings": "Vos réservations non confirmées apparaîtront ici.",
|
||||||
"on": "le",
|
"on": "le",
|
||||||
"and": "et",
|
"and": "et",
|
||||||
"calendar_shows_busy_between": "Votre calendrier vous montre comme étant occupé entre",
|
"calendar_shows_busy_between": "Votre calendrier vous montre comme étant occupé entre",
|
||||||
@@ -346,6 +353,7 @@
|
|||||||
"booking_cancelled": "Réservation Annulée",
|
"booking_cancelled": "Réservation Annulée",
|
||||||
"booking_rescheduled": "Réservation Modifiée",
|
"booking_rescheduled": "Réservation Modifiée",
|
||||||
"booking_created": "Réservation Créée",
|
"booking_created": "Réservation Créée",
|
||||||
|
"meeting_ended": "Réunion terminée",
|
||||||
"form_submitted": "Formulaire envoyé",
|
"form_submitted": "Formulaire envoyé",
|
||||||
"event_triggers": "Déclencheurs d'événements",
|
"event_triggers": "Déclencheurs d'événements",
|
||||||
"subscriber_url": "URL de l'abonné",
|
"subscriber_url": "URL de l'abonné",
|
||||||
@@ -488,6 +496,9 @@
|
|||||||
"lets_create_first_administrator_user": "Nous allons créer le premier utilisateur administrateur.",
|
"lets_create_first_administrator_user": "Nous allons créer le premier utilisateur administrateur.",
|
||||||
"new_member": "Nouveau membre",
|
"new_member": "Nouveau membre",
|
||||||
"invite": "Inviter",
|
"invite": "Inviter",
|
||||||
|
"add_team_members": "Ajouter des membres de l'équipe",
|
||||||
|
"add_team_members_description": "Invitez d'autres personnes à rejoindre votre équipe",
|
||||||
|
"add_team_member": "Ajouter un membre de l'équipe",
|
||||||
"invite_new_member": "Inviter un nouveau membre",
|
"invite_new_member": "Inviter un nouveau membre",
|
||||||
"invite_new_team_member": "Invitez quelqu'un à rejoindre votre équipe.",
|
"invite_new_team_member": "Invitez quelqu'un à rejoindre votre équipe.",
|
||||||
"change_member_role": "Changer le rôle du membre de l'équipe",
|
"change_member_role": "Changer le rôle du membre de l'équipe",
|
||||||
@@ -600,6 +611,7 @@
|
|||||||
"create_first_team_and_invite_others": "Créez votre première équipe et invitez d'autres utilisateurs à travailler avec vous.",
|
"create_first_team_and_invite_others": "Créez votre première équipe et invitez d'autres utilisateurs à travailler avec vous.",
|
||||||
"create_team_to_get_started": "Créer une équipe pour commencer",
|
"create_team_to_get_started": "Créer une équipe pour commencer",
|
||||||
"teams": "Équipes",
|
"teams": "Équipes",
|
||||||
|
"team": "Equipe",
|
||||||
"team_billing": "Facturation d'équipe",
|
"team_billing": "Facturation d'équipe",
|
||||||
"upgrade_to_flexible_pro_title": "Nous avons modifié la facturation pour les équipes",
|
"upgrade_to_flexible_pro_title": "Nous avons modifié la facturation pour les équipes",
|
||||||
"upgrade_to_flexible_pro_message": "Des membres dans votre équipe n'ont pas de place. Mettez à niveau votre offre pro pour couvrir les places manquantes.",
|
"upgrade_to_flexible_pro_message": "Des membres dans votre équipe n'ont pas de place. Mettez à niveau votre offre pro pour couvrir les places manquantes.",
|
||||||
@@ -620,7 +632,9 @@
|
|||||||
"billing": "Facturation",
|
"billing": "Facturation",
|
||||||
"manage_your_billing_info": "Gérez vos informations de facturation et annulez votre abonnement.",
|
"manage_your_billing_info": "Gérez vos informations de facturation et annulez votre abonnement.",
|
||||||
"availability": "Disponibilité",
|
"availability": "Disponibilité",
|
||||||
|
"edit_availability": "Modifier la disponibilité",
|
||||||
"configure_availability": "Déclarez les moments où vous êtes disponible pour un rendez-vous.",
|
"configure_availability": "Déclarez les moments où vous êtes disponible pour un rendez-vous.",
|
||||||
|
"copy_times_to": "Copier les heures vers",
|
||||||
"change_weekly_schedule": "Modifier votre planning hebdomadaire",
|
"change_weekly_schedule": "Modifier votre planning hebdomadaire",
|
||||||
"logo": "Logo",
|
"logo": "Logo",
|
||||||
"error": "Erreur",
|
"error": "Erreur",
|
||||||
@@ -635,6 +649,7 @@
|
|||||||
"event_name_tooltip": "Le nom qui apparaîtra dans les calendriers",
|
"event_name_tooltip": "Le nom qui apparaîtra dans les calendriers",
|
||||||
"meeting_with_user": "Rendez-vous avec {ATTENDEE}",
|
"meeting_with_user": "Rendez-vous avec {ATTENDEE}",
|
||||||
"additional_inputs": "Entrées additionnelles",
|
"additional_inputs": "Entrées additionnelles",
|
||||||
|
"additional_input_description": "Exiger que le planificateur saisisse des entrées supplémentaires avant que la réservation soit confirmée",
|
||||||
"label": "Libellé",
|
"label": "Libellé",
|
||||||
"placeholder": "Placeholder",
|
"placeholder": "Placeholder",
|
||||||
"type": "Type",
|
"type": "Type",
|
||||||
@@ -649,6 +664,8 @@
|
|||||||
"disable_guests": "Désactiver les invité. es",
|
"disable_guests": "Désactiver les invité. es",
|
||||||
"disable_guests_description": "Désactiver l'ajout d'invité·es supplémentaires lors de la réservation.",
|
"disable_guests_description": "Désactiver l'ajout d'invité·es supplémentaires lors de la réservation.",
|
||||||
"private_link": "Générer une URL privée",
|
"private_link": "Générer une URL privée",
|
||||||
|
"private_link_label": "Lien privé",
|
||||||
|
"private_link_hint": "Votre lien privé sera régénéré après chaque utilisation",
|
||||||
"copy_private_link": "Copier le lien privé",
|
"copy_private_link": "Copier le lien privé",
|
||||||
"private_link_description": "Générer une URL privée à partager sans exposer votre nom d'utilisateur Cal",
|
"private_link_description": "Générer une URL privée à partager sans exposer votre nom d'utilisateur Cal",
|
||||||
"invitees_can_schedule": "Les invité·es peuvent réserver",
|
"invitees_can_schedule": "Les invité·es peuvent réserver",
|
||||||
@@ -690,16 +707,21 @@
|
|||||||
"delete_account_confirmation_message": "Êtes-vous sûr de vouloir supprimer votre compte Cal.com ? Toute personne avec qui vous avez partagé le lien de votre compte ne pourra plus réserver en utilisant ce lien et toutes les préférences que vous avez enregistrées seront perdues.",
|
"delete_account_confirmation_message": "Êtes-vous sûr de vouloir supprimer votre compte Cal.com ? Toute personne avec qui vous avez partagé le lien de votre compte ne pourra plus réserver en utilisant ce lien et toutes les préférences que vous avez enregistrées seront perdues.",
|
||||||
"integrations": "Intégrations",
|
"integrations": "Intégrations",
|
||||||
"apps": "Applications",
|
"apps": "Applications",
|
||||||
|
"category_apps": "{{category}} applications",
|
||||||
"app_store": "App Store",
|
"app_store": "App Store",
|
||||||
"app_store_description": "Connecter les personnes, la technologie et l'espace de travail.",
|
"app_store_description": "Connecter les personnes, la technologie et l'espace de travail.",
|
||||||
"settings": "Paramètres",
|
"settings": "Paramètres",
|
||||||
"event_type_moved_successfully": "Le type d'évènement a bien été déplacé",
|
"event_type_moved_successfully": "Le type d'évènement a bien été déplacé",
|
||||||
|
"next_step_text": "Prochaine étape",
|
||||||
"next_step": "Passer l'étape",
|
"next_step": "Passer l'étape",
|
||||||
"prev_step": "Étape précédente",
|
"prev_step": "Étape précédente",
|
||||||
|
"install": "Installer",
|
||||||
"installed": "Installé",
|
"installed": "Installé",
|
||||||
"active_install_one": "{{count}} installation active",
|
"active_install_one": "{{count}} installation active",
|
||||||
"active_install_other": "{{count}} installations actives",
|
"active_install_other": "{{count}} installations actives",
|
||||||
"globally_install": "Installation globale",
|
"globally_install": "Installation globale",
|
||||||
|
"app_successfully_installed": "Application installée avec succès",
|
||||||
|
"app_could_not_be_installed": "Impossible d'installer l'application",
|
||||||
"disconnect": "Déconnecter",
|
"disconnect": "Déconnecter",
|
||||||
"embed_your_calendar": "Intégrez votre calendrier dans votre page web",
|
"embed_your_calendar": "Intégrez votre calendrier dans votre page web",
|
||||||
"connect_your_favourite_apps": "Connectez vos applications favorites.",
|
"connect_your_favourite_apps": "Connectez vos applications favorites.",
|
||||||
@@ -710,6 +732,7 @@
|
|||||||
"connect_additional_calendar": "Connecter un calendrier supplémentaire",
|
"connect_additional_calendar": "Connecter un calendrier supplémentaire",
|
||||||
"conferencing": "Conférence",
|
"conferencing": "Conférence",
|
||||||
"calendar": "Calendrier",
|
"calendar": "Calendrier",
|
||||||
|
"payments": "Paiements",
|
||||||
"not_installed": "Non installé",
|
"not_installed": "Non installé",
|
||||||
"error_password_mismatch": "Les mots de passe ne correspondent pas.",
|
"error_password_mismatch": "Les mots de passe ne correspondent pas.",
|
||||||
"error_required_field": "Ce champ est requis.",
|
"error_required_field": "Ce champ est requis.",
|
||||||
@@ -743,9 +766,22 @@
|
|||||||
"import_from": "Importer depuis",
|
"import_from": "Importer depuis",
|
||||||
"access_token": "Jeton d'accès",
|
"access_token": "Jeton d'accès",
|
||||||
"visit_roadmap": "Feuille de route",
|
"visit_roadmap": "Feuille de route",
|
||||||
|
"featured_categories": "Catégories en vedette",
|
||||||
"popular_categories": "Catégories populaires",
|
"popular_categories": "Catégories populaires",
|
||||||
|
"number_apps_one": "{{count}} Application",
|
||||||
|
"number_apps_other": "{{count}} Applications",
|
||||||
"trending_apps": "Applications populaires",
|
"trending_apps": "Applications populaires",
|
||||||
|
"explore_apps": "{{category}} applications",
|
||||||
"installed_apps": "Applications installées",
|
"installed_apps": "Applications installées",
|
||||||
|
"no_category_apps": "Aucune application {{category}}",
|
||||||
|
"no_category_apps_description_calendar": "Ajouter une application de calendrier pour vérifier les conflits et éviter les doubles réservations",
|
||||||
|
"no_category_apps_description_conferencing": "Essayez d'ajouter une application de conférence pour interconnecter les appels vidéo avec vos clients",
|
||||||
|
"no_category_apps_description_payment": "Ajouter une application de paiement pour faciliter les transactions entre vous et vos clients",
|
||||||
|
"no_category_apps_description_other": "Ajouter n'importe quel autre type d'application pour faire toutes sortes de choses",
|
||||||
|
"installed_app_calendar_description": "Définir le(s) calendrier(s) pour vérifier les conflits pour éviter les doubles réservations.",
|
||||||
|
"installed_app_conferencing_description": "Ajoutez vos applications de vidéoconférence préférées pour vos réunions",
|
||||||
|
"installed_app_payment_description": "Configurez les services de traitement de paiement à utiliser lors de la facturation de vos clients.",
|
||||||
|
"installed_app_other_description": "Toutes vos applications installées à partir d'autres catégories.",
|
||||||
"empty_installed_apps_headline": "Aucune application installée",
|
"empty_installed_apps_headline": "Aucune application installée",
|
||||||
"empty_installed_apps_description": "Les applications vous permettent d'améliorer votre flux de travail et votre processus de planification de façon significative.",
|
"empty_installed_apps_description": "Les applications vous permettent d'améliorer votre flux de travail et votre processus de planification de façon significative.",
|
||||||
"empty_installed_apps_button": "Explorer l'App Store",
|
"empty_installed_apps_button": "Explorer l'App Store",
|
||||||
@@ -766,6 +802,7 @@
|
|||||||
"remove": "Supprimer",
|
"remove": "Supprimer",
|
||||||
"add": "Ajouter",
|
"add": "Ajouter",
|
||||||
"installed_one": "Installé",
|
"installed_one": "Installé",
|
||||||
|
"installed_other": "{{count}} installé(e)(s)",
|
||||||
"verify_wallet": "Vérifier le portefeuille",
|
"verify_wallet": "Vérifier le portefeuille",
|
||||||
"connect_metamask": "Connecter Metamask",
|
"connect_metamask": "Connecter Metamask",
|
||||||
"create_events_on": "Créer des événements le :",
|
"create_events_on": "Créer des événements le :",
|
||||||
@@ -783,6 +820,8 @@
|
|||||||
"set_to_default": "Définir par défaut",
|
"set_to_default": "Définir par défaut",
|
||||||
"new_schedule_btn": "Nouveau programme",
|
"new_schedule_btn": "Nouveau programme",
|
||||||
"add_new_schedule": "Ajouter un nouveau programme",
|
"add_new_schedule": "Ajouter un nouveau programme",
|
||||||
|
"add_new_calendar": "Ajouter un nouveau calendrier",
|
||||||
|
"set_calendar": "Définir où ajouter de nouveaux événements lors de la réservation.",
|
||||||
"delete_schedule": "Supprimer le programme",
|
"delete_schedule": "Supprimer le programme",
|
||||||
"schedule_created_successfully": "{{scheduleName}} programme créé",
|
"schedule_created_successfully": "{{scheduleName}} programme créé",
|
||||||
"availability_updated_successfully": "{{scheduleName}} programme mis à jour",
|
"availability_updated_successfully": "{{scheduleName}} programme mis à jour",
|
||||||
@@ -850,7 +889,7 @@
|
|||||||
"edit_booking": "Modifier la réservation",
|
"edit_booking": "Modifier la réservation",
|
||||||
"reschedule_booking": "Reporter la réservation",
|
"reschedule_booking": "Reporter la réservation",
|
||||||
"former_time": "Ancienne heure",
|
"former_time": "Ancienne heure",
|
||||||
"confirmation_page_gif": "Gif pour la page de confirmation",
|
"confirmation_page_gif": "Ajouter un GIF à la page de confirmation",
|
||||||
"search": "Rechercher",
|
"search": "Rechercher",
|
||||||
"impersonate": "Connexion autre",
|
"impersonate": "Connexion autre",
|
||||||
"user_impersonation_heading": "Connexion en tant qu'autre utilisateur",
|
"user_impersonation_heading": "Connexion en tant qu'autre utilisateur",
|
||||||
@@ -877,7 +916,7 @@
|
|||||||
"choose_ways_put_cal_site": "Choisissez une des façons suivantes de mettre Cal sur votre site.",
|
"choose_ways_put_cal_site": "Choisissez une des façons suivantes de mettre Cal sur votre site.",
|
||||||
"setting_up_zapier": "Configuration de votre intégration Zapier",
|
"setting_up_zapier": "Configuration de votre intégration Zapier",
|
||||||
"generate_api_key": "Générer une clé Api",
|
"generate_api_key": "Générer une clé Api",
|
||||||
"generate_api_key_description": "Générer une clé API à utiliser avec Cal.com à",
|
"generate_api_key_description": "Générer une clé API à utiliser avec Cal.com sur",
|
||||||
"your_unique_api_key": "Votre clé API unique",
|
"your_unique_api_key": "Votre clé API unique",
|
||||||
"copy_safe_api_key": "Copiez cette clé API et conservez-la dans un endroit sûr. Si vous perdez cette clé, vous devrez en générer une nouvelle.",
|
"copy_safe_api_key": "Copiez cette clé API et conservez-la dans un endroit sûr. Si vous perdez cette clé, vous devrez en générer une nouvelle.",
|
||||||
"zapier_setup_instructions": "<0>Connectez-vous à votre compte Zapier et créez un nouveau Zap.</0><1>Sélectionnez Cal.com comme application Trigger. Choisissez également un événement Trigger. </1><2>Choisissez votre compte, puis saisissez votre clé API unique.</2><3>Testez votre Trigger.</3><4>Vous pouvez vous lancer !</4>",
|
"zapier_setup_instructions": "<0>Connectez-vous à votre compte Zapier et créez un nouveau Zap.</0><1>Sélectionnez Cal.com comme application Trigger. Choisissez également un événement Trigger. </1><2>Choisissez votre compte, puis saisissez votre clé API unique.</2><3>Testez votre Trigger.</3><4>Vous pouvez vous lancer !</4>",
|
||||||
@@ -936,6 +975,7 @@
|
|||||||
"workflows": "Workflows",
|
"workflows": "Workflows",
|
||||||
"new_workflow_btn": "Nouveau workflow",
|
"new_workflow_btn": "Nouveau workflow",
|
||||||
"add_new_workflow": "Ajouter un nouveau workflow",
|
"add_new_workflow": "Ajouter un nouveau workflow",
|
||||||
|
"reschedule_event_trigger": "lorsque l'événement est reprogrammé",
|
||||||
"trigger": "Déclencheur",
|
"trigger": "Déclencheur",
|
||||||
"triggers": "Déclencheurs",
|
"triggers": "Déclencheurs",
|
||||||
"action": "Action",
|
"action": "Action",
|
||||||
@@ -963,10 +1003,13 @@
|
|||||||
"change_username_standard_to_premium": "Puisque vous passez d'un nom d'utilisateur standard à un premium, vous allez être envoyé au paiement pour valider le changement.",
|
"change_username_standard_to_premium": "Puisque vous passez d'un nom d'utilisateur standard à un premium, vous allez être envoyé au paiement pour valider le changement.",
|
||||||
"change_username_premium_to_standard": "Puisque vous passez d'un nom d'utilisateur premium à un standard, vous allez être envoyé au paiement pour valider la rétrogradation.",
|
"change_username_premium_to_standard": "Puisque vous passez d'un nom d'utilisateur premium à un standard, vous allez être envoyé au paiement pour valider la rétrogradation.",
|
||||||
"go_to_stripe_billing": "Accéder à la facturation",
|
"go_to_stripe_billing": "Accéder à la facturation",
|
||||||
|
"stripe_description": "Nécessite un paiement pour les réservations (0,5% + 0,10 € de commission par transaction)",
|
||||||
"trial_expired": "Votre période d'essai a expiré",
|
"trial_expired": "Votre période d'essai a expiré",
|
||||||
"remove_app": "Supprimer l'application",
|
"remove_app": "Supprimer l'application",
|
||||||
"yes_remove_app": "Oui, supprimer l'application",
|
"yes_remove_app": "Oui, supprimer l'application",
|
||||||
"are_you_sure_you_want_to_remove_this_app": "Voulez-vous vraiment supprimer cette application ?",
|
"are_you_sure_you_want_to_remove_this_app": "Voulez-vous vraiment supprimer cette application ?",
|
||||||
|
"app_removed_successfully": "Application supprimée avec succès",
|
||||||
|
"error_removing_app": "Erreur lors de la suppression de l'application",
|
||||||
"web_conference": "Conférence en ligne",
|
"web_conference": "Conférence en ligne",
|
||||||
"number_for_sms_reminders": "Numéro de téléphone (pour les rappels par SMS)",
|
"number_for_sms_reminders": "Numéro de téléphone (pour les rappels par SMS)",
|
||||||
"requires_confirmation": "Nécessite une confirmation",
|
"requires_confirmation": "Nécessite une confirmation",
|
||||||
@@ -1022,18 +1065,201 @@
|
|||||||
"navigate": "Naviguer",
|
"navigate": "Naviguer",
|
||||||
"open": "Ouvrir",
|
"open": "Ouvrir",
|
||||||
"close": "Fermer",
|
"close": "Fermer",
|
||||||
|
"team_feature_teams": "Ceci est une fonctionnalité d'équipe. Mettez à niveau vers l'équipe pour voir la disponibilité de votre équipe.",
|
||||||
|
"team_feature_workflows": "Ceci est une fonctionnalité d'équipe. Mettez à niveau vers l'équipe pour automatiser vos notifications et rappels d'événements avec les flux de travail.",
|
||||||
|
"show_eventtype_on_profile": "Afficher sur le profil",
|
||||||
"embed": "Intégré",
|
"embed": "Intégré",
|
||||||
"new_username": "Nouveau nom d'utilisateur",
|
"new_username": "Nouveau nom d'utilisateur",
|
||||||
"current_username": "Nom d'utilisateur actuel",
|
"current_username": "Nom d'utilisateur actuel",
|
||||||
"example_1": "Exemple 1",
|
"example_1": "Exemple 1",
|
||||||
"example_2": "Exemple 2",
|
"example_2": "Exemple 2",
|
||||||
|
"additional_input_label": "Libellé de saisie supplémentaire",
|
||||||
"company_size": "Taille de l'entreprise",
|
"company_size": "Taille de l'entreprise",
|
||||||
"what_help_needed": "Pour quoi avez-vous besoin d'aide ?",
|
"what_help_needed": "Pour quoi avez-vous besoin d'aide ?",
|
||||||
"variable_format": "Format des variables",
|
"variable_format": "Format des variables",
|
||||||
|
"webhook_subscriber_url_reserved": "L'url d'abonné au Webhook est déjà définie",
|
||||||
|
"custom_input_as_variable_info": "Ignorer tous les caractères spéciaux du libellé de saisie supplémentaire (utiliser uniquement des lettres et des chiffres), utiliser des majuscules pour toutes les lettres et remplacer les espaces par des tirets bas.",
|
||||||
"using_additional_inputs_as_variables": "Comment utiliser des entrées supplémentaires en tant que variables ?",
|
"using_additional_inputs_as_variables": "Comment utiliser des entrées supplémentaires en tant que variables ?",
|
||||||
"download_desktop_app": "Télécharger l'application de bureau",
|
"download_desktop_app": "Télécharger l'application de bureau",
|
||||||
"set_ping_link": "Définir le lien Ping",
|
"set_ping_link": "Définir le lien Ping",
|
||||||
|
"rate_limit_exceeded": "Limite dépassée",
|
||||||
|
"when_something_happens": "Quand quelque chose se passe",
|
||||||
|
"action_is_performed": "Une action est effectuée",
|
||||||
|
"test_action": "Tester l'action",
|
||||||
|
"notification_sent": "Notification envoyée",
|
||||||
|
"no_input": "Aucune entrée",
|
||||||
|
"test_workflow_action": "Tester l'effet du workflow",
|
||||||
|
"send_sms": "Envoyer un SMS",
|
||||||
|
"send_sms_to_number": "Êtes-vous sûr de vouloir envoyer un SMS au {{number}}?",
|
||||||
|
"missing_connected_calendar": "Aucun calendrier par défaut connecté",
|
||||||
|
"connect_your_calendar_and_link": "Vous pouvez connecter votre calendrier depuis <1>ici</1>.",
|
||||||
|
"default_calendar_selected": "Calendrier par défaut",
|
||||||
|
"hide_from_profile": "Masquer du profil",
|
||||||
|
"event_setup_tab_title": "Configuration de l'événement",
|
||||||
|
"event_limit_tab_title": "Limites",
|
||||||
|
"event_limit_tab_description": "Fréquence de réservation",
|
||||||
|
"event_advanced_tab_description": "Paramètres du calendrier & plus...",
|
||||||
|
"event_advanced_tab_title": "Avancé",
|
||||||
|
"select_which_cal": "Sélectionnez le calendrier auquel ajouter des réservations",
|
||||||
|
"custom_event_name": "Nom de l'événement personnalisé",
|
||||||
|
"custom_event_name_description": "Créer des noms d'événements personnalisés à afficher sur l'événement du calendrier",
|
||||||
|
"2fa_required": "Authentification en deux étapes requise",
|
||||||
|
"incorrect_2fa": "Code d'authentification à deux facteurs incorrect",
|
||||||
|
"which_event_type_apply": "À quel type d'événement s'appliquera-t-il ?",
|
||||||
|
"no_workflows_description": "Les workflows permettent une automatisation simple pour envoyer des notifications et des rappels vous permettant de construire des processus autour de vos événements.",
|
||||||
|
"create_workflow": "Créer un workflow",
|
||||||
|
"do_this": "Effectuer ceci",
|
||||||
|
"turn_off": "Désactiver",
|
||||||
|
"settings_updated_successfully": "Paramètres mis à jour avec succès",
|
||||||
|
"error_updating_settings": "Erreur lors de la mise à jour des paramètres",
|
||||||
|
"personal_cal_url": "Mon URL Cal personnelle",
|
||||||
|
"bio_hint": "Quelques phrases à propos de vous. Ces informations apparaîtront sur votre page d'url personnelle.",
|
||||||
|
"delete_account_modal_title": "Supprimer le compte",
|
||||||
|
"confirm_delete_account_modal": "Êtes-vous sûr de vouloir supprimer votre compte Cal.com ?",
|
||||||
|
"delete_my_account": "Supprimer mon compte",
|
||||||
|
"start_of_week": "Début de la semaine",
|
||||||
|
"select_calendars": "Sélectionnez quels calendriers vous voulez vérifier les conflits pour éviter les doubles réservations.",
|
||||||
|
"check_for_conflicts": "Vérifier les conflits",
|
||||||
|
"adding_events_to": "Ajout d'événements à",
|
||||||
|
"follow_system_preferences": "Suivre les préférences système",
|
||||||
|
"custom_brand_colors": "Couleurs de marque personnalisées",
|
||||||
|
"customize_your_brand_colors": "Personnalisez votre propre couleur de marque dans votre page de réservation.",
|
||||||
|
"pro": "Pro",
|
||||||
|
"removes_cal_branding": "Supprime les marques associées à Cal, c'est-à-dire \"Powered by Cal.\"",
|
||||||
|
"profile_picture": "Photo de profil",
|
||||||
|
"upload": "Télécharger",
|
||||||
|
"web3": "Web3",
|
||||||
|
"rainbow_token_gated": "Ce type d'événement nécessite un jeton d'authentification.",
|
||||||
|
"rainbow_connect_wallet_gate": "Connectez votre portefeuille si vous possédez <1>{{name}}</1> (<3>{{symbol}}</3>).",
|
||||||
|
"rainbow_insufficient_balance": "Votre portefeuille connecté ne contient pas assez de <1>{{symbol}}</1>.",
|
||||||
|
"rainbow_sign_message_request": "Signez la demande de message sur votre portefeuille.",
|
||||||
|
"rainbow_signature_error": "Erreur lors de la demande de signature de votre portefeuille.",
|
||||||
|
"token_address": "Adresse du jeton",
|
||||||
|
"blockchain": "Blockchain",
|
||||||
|
"old_password": "Ancien mot de passe",
|
||||||
|
"secure_password": "Votre nouveau mot de passe super sécurisé",
|
||||||
|
"error_updating_password": "Erreur lors de la mise à jour du mot de passe",
|
||||||
|
"two_factor_auth": "Authentification en deux étapes",
|
||||||
|
"recurring_event_tab_description": "Configurez un calendrier récurrent",
|
||||||
|
"today": "aujourd'hui",
|
||||||
|
"appearance": "Apparence",
|
||||||
|
"appearance_subtitle": "Gérer les paramètres pour votre apparence de réservation",
|
||||||
|
"my_account": "Mon compte",
|
||||||
|
"general": "Général",
|
||||||
|
"calendars": "Calendriers",
|
||||||
|
"2fa_auth": "Authentification à deux facteurs",
|
||||||
|
"invoices": "Factures",
|
||||||
|
"embeds": "Intègre",
|
||||||
|
"impersonation": "Identification",
|
||||||
|
"users": "Utilisateurs",
|
||||||
|
"profile_description": "Gérer les paramètres de votre profil cal",
|
||||||
|
"general_description": "Gérer les paramètres pour votre langue et votre fuseau horaire",
|
||||||
|
"calendars_description": "Configurez la manière dont vos types d'événements interagissent avec vos calendriers",
|
||||||
|
"appearance_description": "Gérer les paramètres pour votre apparence de réservation",
|
||||||
|
"conferencing_description": "Gérez vos applications de vidéoconférence pour vos réunions",
|
||||||
|
"password_description": "Gérer les paramètres pour les mots de passe de votre compte",
|
||||||
|
"2fa_description": "Gérer les paramètres pour les mots de passe de votre compte",
|
||||||
|
"we_just_need_basic_info": "Nous avons juste besoin de quelques informations de base pour configurer votre profil.",
|
||||||
|
"skip": "Ignorer",
|
||||||
|
"do_this_later": "Effectuer ceci plus tard",
|
||||||
|
"set_availability_getting_started_subtitle_1": "Définir les plages de temps lorsque vous êtes disponible",
|
||||||
|
"set_availability_getting_started_subtitle_2": "Vous pouvez personnaliser tout cela plus tard dans la page de disponibilité.",
|
||||||
|
"connect_calendars_from_app_store": "Vous pouvez ajouter plus de calendriers depuis l'App Store",
|
||||||
|
"connect_conference_apps": "Connecter les applications de conférence",
|
||||||
|
"connect_calendar_apps": "Connecter les applications de calendrier",
|
||||||
|
"connect_payment_apps": "Connecter les applications de paiement",
|
||||||
|
"connect_other_apps": "Connecter d'autres applications",
|
||||||
|
"current_step_of_total": "Étape {{currentStep}} sur {{maxSteps}}",
|
||||||
|
"add_variable": "Ajouter une variable",
|
||||||
|
"custom_phone_number": "Numéro de téléphone personnalisé",
|
||||||
|
"message_template": "Modèle de message",
|
||||||
|
"email_subject": "Objet",
|
||||||
|
"add_dynamic_variables": "Ajouter des variables de texte dynamiques",
|
||||||
|
"event_name_info": "Nom du type d'événement",
|
||||||
|
"event_date_info": "Date de l'évènement",
|
||||||
|
"event_time_info": "Heure de début de l'événement",
|
||||||
|
"location_info": "Lieu de l'événement",
|
||||||
"organizer_name_info": "Votre nom",
|
"organizer_name_info": "Votre nom",
|
||||||
|
"additional_notes_info": "Notes supplémentaires de réservation",
|
||||||
|
"attendee_name_info": "Nom de la personne réservant",
|
||||||
|
"to": "À/vers",
|
||||||
|
"attendee_required_enter_number": "Le participant devra entrer un numéro de téléphone lors de la réservation",
|
||||||
|
"workflow_turned_on_successfully": "Le workflow {{workflowName}} a été {{offOn}} avec succès",
|
||||||
|
"download_responses": "Télécharger les réponses",
|
||||||
|
"create_your_first_form": "Créer votre premier formulaire",
|
||||||
|
"create_your_first_form_description": "Grâce aux formulaires d'acheminement, vous pouvez poser des questions de qualification et vous diriger vers la personne ou le type d'événement appropriés.",
|
||||||
|
"create_your_first_webhook": "Créez votre premier Webhook",
|
||||||
|
"create_your_first_webhook_description": "Avec les Webhooks, vous pouvez recevoir des données de réunion en temps réel lorsque quelque chose se passe sur Cal.com.",
|
||||||
|
"for_a_maximum_of": "Pour un maximum de",
|
||||||
|
"event_one": "événement",
|
||||||
|
"event_other": "événements",
|
||||||
|
"profile_team_description": "Gérer les paramètres de votre profil d'équipe",
|
||||||
|
"members_team_description": "Utilisateurs membres du groupe",
|
||||||
|
"team_url": "URL de l'équipe",
|
||||||
|
"delete_team": "Supprimer l'équipe",
|
||||||
|
"team_members": "Membres de l'équipe",
|
||||||
|
"more": "En savoir plus",
|
||||||
|
"more_page_footer": "Nous considérons l'application mobile comme une extension de l'application web. Si vous effectuez des actions complexes, veuillez vous référer à l'application Web.",
|
||||||
|
"workflow_example_1": "Envoyer un rappel SMS 24 heures avant le début de l'événement",
|
||||||
|
"workflow_example_2": "Envoyer un SMS personnalisé lorsque l'événement est reprogrammé au participant",
|
||||||
|
"workflow_example_3": "Envoyer un email personnalisé quand un nouvel événement est réservé à un hôte",
|
||||||
|
"workflow_example_4": "Envoyer un rappel par e-mail 1 heure avant le début des événements",
|
||||||
|
"workflow_example_5": "Envoyer un email personnalisé lorsque l'événement est reprogrammé à l'hôte",
|
||||||
|
"workflow_example_6": "Envoyer un SMS personnalisé quand un nouvel événement est réservé à un hôte",
|
||||||
|
"welcome_to_cal_header": "Bienvenue sur Cal.com !",
|
||||||
|
"edit_form_later_subtitle": "Vous pourrez modifier cela plus tard.",
|
||||||
|
"connect_calendar_later": "Je connecterai mon calendrier plus tard",
|
||||||
|
"set_my_availability_later": "Je vais définir ma disponibilité plus tard",
|
||||||
|
"problem_saving_user_profile": "Un problème est survenu lors de l'enregistrement de vos données. Veuillez réessayer ou contacter le service client.",
|
||||||
|
"purchase_missing_seats": "Acheter des places manquantes",
|
||||||
|
"slot_length": "Durée du créneau",
|
||||||
|
"booking_appearance": "Apparence de réservation",
|
||||||
|
"appearance_team_description": "Gérer les paramètres pour l'apparence de réservation de votre équipe",
|
||||||
|
"only_owner_change": "Seul le propriétaire de cette équipe peut apporter des modifications à la réservation de l'équipe ",
|
||||||
|
"team_disable_cal_branding_description": "Supprime les marques associées à Cal, c'est-à-dire \"Powered by Cal\"",
|
||||||
|
"invited_by_team": "{{teamName}} vous a invité à rejoindre son équipe en tant que {{role}}",
|
||||||
|
"token_invalid_expired": "Le jeton est invalide ou expiré.",
|
||||||
|
"exchange_add": "Se connecter à Microsoft Exchange",
|
||||||
|
"exchange_authentication": "Méthode d'authentification",
|
||||||
|
"exchange_authentication_standard": "Authentification de base",
|
||||||
|
"exchange_authentication_ntlm": "Authentification NTLM",
|
||||||
|
"exchange_compression": "Compression GZip",
|
||||||
|
"routing_forms_description": "Vous pouvez voir tous les formulaires et tous les parcours que vous avez créés ici.",
|
||||||
|
"add_new_form": "Ajouter un nouveau formulaire",
|
||||||
|
"form_description": "Créez votre formulaire pour acheminer un organisateur",
|
||||||
|
"copy_link_to_form": "Copier le lien vers le formulaire",
|
||||||
|
"theme": "Thème",
|
||||||
|
"theme_applies_note": "Ceci s'applique uniquement à vos pages publiques de réservation",
|
||||||
"theme_light": "Clair",
|
"theme_light": "Clair",
|
||||||
"theme_dark": "Sombre"
|
"theme_dark": "Sombre",
|
||||||
|
"theme_system": "Défaut du système",
|
||||||
|
"add_a_team": "Ajouter une équipe",
|
||||||
|
"saml_config": "Configuration SAML",
|
||||||
|
"add_webhook_description": "Recevoir les données de la réunion en temps réel lorsque quelque chose se passe sur Cal.com",
|
||||||
|
"triggers_when": "Se déclenche quand",
|
||||||
|
"enable_webhook": "Activer le Webhook",
|
||||||
|
"add_webhook": "Ajouter un Webhook",
|
||||||
|
"webhook_edited_successfully": "Webhook enregistré",
|
||||||
|
"webhooks_description": "Recevez les données de la réunion en temps réel lorsque quelque chose se passe sur Cal.com",
|
||||||
|
"api_keys_description": "Générer des clés API pour accéder à votre propre compte",
|
||||||
|
"new_api_key": "Nouvelle clé API",
|
||||||
|
"active": "Actif",
|
||||||
|
"api_key_updated": "Nom de clé API mis à jour",
|
||||||
|
"api_key_update_failed": "Erreur de mise à jour du nom de la clé API",
|
||||||
|
"embeds_title": "Intégration d'iframe HTML",
|
||||||
|
"embeds_description": "Intégrez tous vos types d'événements sur votre site web",
|
||||||
|
"create_first_api_key": "Créez votre première clé API",
|
||||||
|
"create_first_api_key_description": "Les clés API permettent à d'autres applications de communiquer avec Cal.com",
|
||||||
|
"back_to_signin": "Retour à la connexion",
|
||||||
|
"reset_link_sent": "Lien de réinitialisation envoyé",
|
||||||
|
"password_updated": "Mot de passe mis à jour !",
|
||||||
|
"pending_payment": "Paiement en attente",
|
||||||
|
"not_on_cal": "Pas sur Cal.com",
|
||||||
|
"no_calendar_installed": "Aucun calendrier installé",
|
||||||
|
"no_calendar_installed_description": "Vous n'avez pas encore connecté vos calendriers",
|
||||||
|
"add_a_calendar": "Ajouter au calendrier",
|
||||||
|
"change_email_hint": "Vous devrez peut-être vous déconnecter et vous reconnecter pour que le changement prenne effet",
|
||||||
|
"seats": "places",
|
||||||
|
"every_app_published": "Chaque application publiée sur l'App Store de Cal.com est open source et soigneusement testée via les évaluations par les pairs. Néanmoins, Cal.com, Inc. n'approuve pas ou ne certifie pas ces applications à moins qu'elles ne soient publiées par Cal.com. Si vous rencontrez un contenu ou un comportement inapproprié, veuillez le signaler.",
|
||||||
|
"report_app": "Signaler une application"
|
||||||
}
|
}
|
||||||
@@ -112,7 +112,6 @@
|
|||||||
"use_link_to_reset_password": "נא להשתמש בקישור הבא כדי לאפס את הסיסמה",
|
"use_link_to_reset_password": "נא להשתמש בקישור הבא כדי לאפס את הסיסמה",
|
||||||
"hey_there": "שלום,",
|
"hey_there": "שלום,",
|
||||||
"forgot_your_password_calcom": "שכחתה את הסיסמה? - cal.com",
|
"forgot_your_password_calcom": "שכחתה את הסיסמה? - cal.com",
|
||||||
"event_type_title": "{{eventTypeTitle}} | סוג האירוע",
|
|
||||||
"delete_webhook_confirmation_message": "בטוח שברצונך למחוק את ה-Webhook הזה? אם אירוע יבוטל או שייקבע עבורו מועד, לא תקבל יותר נתוני פגישות מ-Cal.com בזמן אמת או בכתובת ה-URL שציינת.",
|
"delete_webhook_confirmation_message": "בטוח שברצונך למחוק את ה-Webhook הזה? אם אירוע יבוטל או שייקבע עבורו מועד, לא תקבל יותר נתוני פגישות מ-Cal.com בזמן אמת או בכתובת ה-URL שציינת.",
|
||||||
"confirm_delete_webhook": "כן, אני רוצה למחוק את ה-Webhook",
|
"confirm_delete_webhook": "כן, אני רוצה למחוק את ה-Webhook",
|
||||||
"edit_webhook": "עריכת Webhook",
|
"edit_webhook": "עריכת Webhook",
|
||||||
@@ -809,7 +808,7 @@
|
|||||||
"booking_full": "אין יותר מקומות זמינים",
|
"booking_full": "אין יותר מקומות זמינים",
|
||||||
"api_keys": "מפתחות ממשק תכנות יישומים (API)",
|
"api_keys": "מפתחות ממשק תכנות יישומים (API)",
|
||||||
"api_key": "מפתח ממשק תכנות יישומים (API)",
|
"api_key": "מפתח ממשק תכנות יישומים (API)",
|
||||||
"test_api_key": "בדיקת מפתח ממשק תכנות יישומים (API)",
|
"test_api_key": "לבדוק מפתח ממשק תכנות יישומים (API)",
|
||||||
"test_passed": "הבדיקה עברה בהצלחה!",
|
"test_passed": "הבדיקה עברה בהצלחה!",
|
||||||
"test_failed": "הבדיקה נכשלה",
|
"test_failed": "הבדיקה נכשלה",
|
||||||
"provide_api_key": "נא לציין מפתח ממשק תכנות יישומים (API)",
|
"provide_api_key": "נא לציין מפתח ממשק תכנות יישומים (API)",
|
||||||
@@ -850,7 +849,7 @@
|
|||||||
"edit_booking": "עריכת ההזמנה",
|
"edit_booking": "עריכת ההזמנה",
|
||||||
"reschedule_booking": "שנה/י את מועד ההזמנה",
|
"reschedule_booking": "שנה/י את מועד ההזמנה",
|
||||||
"former_time": "המועד הקודם",
|
"former_time": "המועד הקודם",
|
||||||
"confirmation_page_gif": "נא להוסיף קובץ GIF לדף האישור",
|
"confirmation_page_gif": "להוסיף קובץ GIF לדף האישור",
|
||||||
"search": "חיפוש",
|
"search": "חיפוש",
|
||||||
"impersonate": "התחזות",
|
"impersonate": "התחזות",
|
||||||
"user_impersonation_heading": "התחזות למשתמשים",
|
"user_impersonation_heading": "התחזות למשתמשים",
|
||||||
|
|||||||
@@ -112,7 +112,6 @@
|
|||||||
"use_link_to_reset_password": "Usa il link qui sotto per reimpostare la tua password",
|
"use_link_to_reset_password": "Usa il link qui sotto per reimpostare la tua password",
|
||||||
"hey_there": "Ciao,",
|
"hey_there": "Ciao,",
|
||||||
"forgot_your_password_calcom": "Hai dimenticato la password? - Cal.com",
|
"forgot_your_password_calcom": "Hai dimenticato la password? - Cal.com",
|
||||||
"event_type_title": "{{eventTypeTitle}} | Tipo di evento",
|
|
||||||
"delete_webhook_confirmation_message": "Sei sicuro di voler eliminare questo webhook? Non riceverai più Cal.com dati di riunione in un URL specificato, in tempo reale, quando un evento è programmato o annullato.",
|
"delete_webhook_confirmation_message": "Sei sicuro di voler eliminare questo webhook? Non riceverai più Cal.com dati di riunione in un URL specificato, in tempo reale, quando un evento è programmato o annullato.",
|
||||||
"confirm_delete_webhook": "Sì, elimina webhook",
|
"confirm_delete_webhook": "Sì, elimina webhook",
|
||||||
"edit_webhook": "Modifica Webhook",
|
"edit_webhook": "Modifica Webhook",
|
||||||
@@ -143,6 +142,7 @@
|
|||||||
"view_public_page": "Visualizza la pagina pubblica",
|
"view_public_page": "Visualizza la pagina pubblica",
|
||||||
"sign_out": "Esci",
|
"sign_out": "Esci",
|
||||||
"add_another": "Aggiungi un altro",
|
"add_another": "Aggiungi un altro",
|
||||||
|
"install_another": "Installa un altro",
|
||||||
"until": "fino a",
|
"until": "fino a",
|
||||||
"powered_by": "offerto da",
|
"powered_by": "offerto da",
|
||||||
"unavailable": "Non Disponibile",
|
"unavailable": "Non Disponibile",
|
||||||
@@ -157,6 +157,7 @@
|
|||||||
"checkbox": "Casella di controllo",
|
"checkbox": "Casella di controllo",
|
||||||
"is_required": "È obbligatorio",
|
"is_required": "È obbligatorio",
|
||||||
"required": "Obbligatorio",
|
"required": "Obbligatorio",
|
||||||
|
"optional": "Facoltativo",
|
||||||
"input_type": "Tipo di input",
|
"input_type": "Tipo di input",
|
||||||
"rejected": "Rifiutato",
|
"rejected": "Rifiutato",
|
||||||
"unconfirmed": "Non Confermato",
|
"unconfirmed": "Non Confermato",
|
||||||
@@ -227,7 +228,9 @@
|
|||||||
"connect_your_calendar_instructions": "Collega il tuo calendario per controllare automaticamente gli orari occupati e i nuovi eventi appena vengono pianificati.",
|
"connect_your_calendar_instructions": "Collega il tuo calendario per controllare automaticamente gli orari occupati e i nuovi eventi appena vengono pianificati.",
|
||||||
"set_up_later": "Configura più tardi",
|
"set_up_later": "Configura più tardi",
|
||||||
"current_time": "Orario corrente",
|
"current_time": "Orario corrente",
|
||||||
|
"details": "Dettagli",
|
||||||
"welcome": "Benvenuto",
|
"welcome": "Benvenuto",
|
||||||
|
"welcome_back": "Bentornato",
|
||||||
"welcome_to_calcom": "Benvenuto in Cal.com",
|
"welcome_to_calcom": "Benvenuto in Cal.com",
|
||||||
"welcome_instructions": "Dimmi come chiamarti e facci sapere in che timezone sei. Potrai cambiarlo dopo.",
|
"welcome_instructions": "Dimmi come chiamarti e facci sapere in che timezone sei. Potrai cambiarlo dopo.",
|
||||||
"connect_caldav": "Connetti al server CalDav",
|
"connect_caldav": "Connetti al server CalDav",
|
||||||
@@ -240,6 +243,7 @@
|
|||||||
"when": "Quando",
|
"when": "Quando",
|
||||||
"where": "Dove",
|
"where": "Dove",
|
||||||
"add_to_calendar": "Aggiungi al calendario",
|
"add_to_calendar": "Aggiungi al calendario",
|
||||||
|
"add_another_calendar": "Aggiungi un altro calendario",
|
||||||
"other": "Altro",
|
"other": "Altro",
|
||||||
"emailed_you_and_attendees": "Abbiamo inviato via email a te e agli altri partecipanti un invito al calendario con tutti i dettagli.",
|
"emailed_you_and_attendees": "Abbiamo inviato via email a te e agli altri partecipanti un invito al calendario con tutti i dettagli.",
|
||||||
"emailed_you_and_attendees_recurring": "Abbiamo inviato via email a te e agli altri partecipanti un invito al primo di questi eventi ricorrenti.",
|
"emailed_you_and_attendees_recurring": "Abbiamo inviato via email a te e agli altri partecipanti un invito al primo di questi eventi ricorrenti.",
|
||||||
@@ -261,6 +265,8 @@
|
|||||||
"enter_new_password": "Inserisci la nuova password che desideri per il tuo account.",
|
"enter_new_password": "Inserisci la nuova password che desideri per il tuo account.",
|
||||||
"reset_password": "Reimposta Password",
|
"reset_password": "Reimposta Password",
|
||||||
"change_your_password": "Cambia la tua password",
|
"change_your_password": "Cambia la tua password",
|
||||||
|
"show_password": "Mostra password",
|
||||||
|
"hide_password": "Nascondi password",
|
||||||
"try_again": "Prova Di Nuovo",
|
"try_again": "Prova Di Nuovo",
|
||||||
"request_is_expired": "Quella richiesta è scaduta.",
|
"request_is_expired": "Quella richiesta è scaduta.",
|
||||||
"reset_instructions": "Inserisci l'indirizzo email associato al tuo account e ti invieremo un link per reimpostare la password.",
|
"reset_instructions": "Inserisci l'indirizzo email associato al tuo account e ti invieremo un link per reimpostare la password.",
|
||||||
@@ -306,6 +312,7 @@
|
|||||||
"recurring_bookings": "Quando qualcuno prenoterà una riunione ricorrente con te, la riunione apparirà qui.",
|
"recurring_bookings": "Quando qualcuno prenoterà una riunione ricorrente con te, la riunione apparirà qui.",
|
||||||
"past_bookings": "Le tue prenotazioni passate appariranno qui.",
|
"past_bookings": "Le tue prenotazioni passate appariranno qui.",
|
||||||
"cancelled_bookings": "Le tue prenotazioni passate appariranno qui.",
|
"cancelled_bookings": "Le tue prenotazioni passate appariranno qui.",
|
||||||
|
"unconfirmed_bookings": "Le tue prenotazioni non confermate appariranno qui.",
|
||||||
"on": "su",
|
"on": "su",
|
||||||
"and": "e",
|
"and": "e",
|
||||||
"calendar_shows_busy_between": "Il tuo calendario ti mostra come occupato tra",
|
"calendar_shows_busy_between": "Il tuo calendario ti mostra come occupato tra",
|
||||||
@@ -346,6 +353,7 @@
|
|||||||
"booking_cancelled": "Prenotazione Annullata",
|
"booking_cancelled": "Prenotazione Annullata",
|
||||||
"booking_rescheduled": "Prenotazione Riprogrammata",
|
"booking_rescheduled": "Prenotazione Riprogrammata",
|
||||||
"booking_created": "Prenotazione Creata",
|
"booking_created": "Prenotazione Creata",
|
||||||
|
"meeting_ended": "Riunione terminata",
|
||||||
"form_submitted": "Modulo inviato",
|
"form_submitted": "Modulo inviato",
|
||||||
"event_triggers": "Attivatori Evento",
|
"event_triggers": "Attivatori Evento",
|
||||||
"subscriber_url": "Url del Subscriber",
|
"subscriber_url": "Url del Subscriber",
|
||||||
@@ -488,6 +496,9 @@
|
|||||||
"lets_create_first_administrator_user": "Creiamo il primo utente amministratore.",
|
"lets_create_first_administrator_user": "Creiamo il primo utente amministratore.",
|
||||||
"new_member": "Nuovo Membro",
|
"new_member": "Nuovo Membro",
|
||||||
"invite": "Invita",
|
"invite": "Invita",
|
||||||
|
"add_team_members": "Aggiungi membri del team",
|
||||||
|
"add_team_members_description": "Invita altri utenti a unirsi al tuo team",
|
||||||
|
"add_team_member": "Aggiungi un membro del team",
|
||||||
"invite_new_member": "Invita un nuovo membro",
|
"invite_new_member": "Invita un nuovo membro",
|
||||||
"invite_new_team_member": "Invita qualcuno nel tuo team.",
|
"invite_new_team_member": "Invita qualcuno nel tuo team.",
|
||||||
"change_member_role": "Cambia il ruolo del membro del team",
|
"change_member_role": "Cambia il ruolo del membro del team",
|
||||||
@@ -600,6 +611,7 @@
|
|||||||
"create_first_team_and_invite_others": "Crea il tuo primo team e invita altri utenti a lavorare insieme a te.",
|
"create_first_team_and_invite_others": "Crea il tuo primo team e invita altri utenti a lavorare insieme a te.",
|
||||||
"create_team_to_get_started": "Crea una squadra per iniziare",
|
"create_team_to_get_started": "Crea una squadra per iniziare",
|
||||||
"teams": "Team",
|
"teams": "Team",
|
||||||
|
"team": "Team",
|
||||||
"team_billing": "Fatturazione team",
|
"team_billing": "Fatturazione team",
|
||||||
"upgrade_to_flexible_pro_title": "Abbiamo cambiato la fatturazione per i team",
|
"upgrade_to_flexible_pro_title": "Abbiamo cambiato la fatturazione per i team",
|
||||||
"upgrade_to_flexible_pro_message": "Alcuni membri del tuo team non hanno un posto. Aggiorna il tuo piano Pro per coprire i posti mancanti.",
|
"upgrade_to_flexible_pro_message": "Alcuni membri del tuo team non hanno un posto. Aggiorna il tuo piano Pro per coprire i posti mancanti.",
|
||||||
@@ -620,7 +632,9 @@
|
|||||||
"billing": "Fatturazione",
|
"billing": "Fatturazione",
|
||||||
"manage_your_billing_info": "Gestisci le tue informazioni di fatturazione e annulla il tuo abbonamento.",
|
"manage_your_billing_info": "Gestisci le tue informazioni di fatturazione e annulla il tuo abbonamento.",
|
||||||
"availability": "Disponibilità",
|
"availability": "Disponibilità",
|
||||||
|
"edit_availability": "Modifica disponibilità",
|
||||||
"configure_availability": "Cambia quando sei disponibile per le prenotazioni.",
|
"configure_availability": "Cambia quando sei disponibile per le prenotazioni.",
|
||||||
|
"copy_times_to": "Copia orari in",
|
||||||
"change_weekly_schedule": "Cambia il tuo programma settimanale",
|
"change_weekly_schedule": "Cambia il tuo programma settimanale",
|
||||||
"logo": "Logo",
|
"logo": "Logo",
|
||||||
"error": "Errore",
|
"error": "Errore",
|
||||||
@@ -635,6 +649,7 @@
|
|||||||
"event_name_tooltip": "Il nome che apparirà nei calendari",
|
"event_name_tooltip": "Il nome che apparirà nei calendari",
|
||||||
"meeting_with_user": "Riunione con {ATTENDEE}",
|
"meeting_with_user": "Riunione con {ATTENDEE}",
|
||||||
"additional_inputs": "Input Aggiuntivi",
|
"additional_inputs": "Input Aggiuntivi",
|
||||||
|
"additional_input_description": "Chiedi al creatore del programma di inserire dei campi di input aggiuntivi prima che la prenotazione sia confermata",
|
||||||
"label": "Etichetta",
|
"label": "Etichetta",
|
||||||
"placeholder": "Segnaposto",
|
"placeholder": "Segnaposto",
|
||||||
"type": "Tipo",
|
"type": "Tipo",
|
||||||
@@ -649,6 +664,8 @@
|
|||||||
"disable_guests": "Disabilita Ospiti",
|
"disable_guests": "Disabilita Ospiti",
|
||||||
"disable_guests_description": "Disabilita l'aggiunta di ulteriori ospiti durante la prenotazione.",
|
"disable_guests_description": "Disabilita l'aggiunta di ulteriori ospiti durante la prenotazione.",
|
||||||
"private_link": "Genera URL privato",
|
"private_link": "Genera URL privato",
|
||||||
|
"private_link_label": "Link privato",
|
||||||
|
"private_link_hint": "Il tuo link privato verrà rigenerato dopo ogni utilizzo",
|
||||||
"copy_private_link": "Copia link privato",
|
"copy_private_link": "Copia link privato",
|
||||||
"private_link_description": "Genera un URL privato da condividere senza mostrare il tuo nome utente Cal",
|
"private_link_description": "Genera un URL privato da condividere senza mostrare il tuo nome utente Cal",
|
||||||
"invitees_can_schedule": "Gli inviti possono programmare",
|
"invitees_can_schedule": "Gli inviti possono programmare",
|
||||||
@@ -690,16 +707,21 @@
|
|||||||
"delete_account_confirmation_message": "Sei sicuro di voler eliminare il tuo account Cal.com? Chiunque abbia il link del tuo account non potrà più utilizzarlo per prenotare e le preferenze che hai salvato andranno perse.",
|
"delete_account_confirmation_message": "Sei sicuro di voler eliminare il tuo account Cal.com? Chiunque abbia il link del tuo account non potrà più utilizzarlo per prenotare e le preferenze che hai salvato andranno perse.",
|
||||||
"integrations": "Integrazioni",
|
"integrations": "Integrazioni",
|
||||||
"apps": "App",
|
"apps": "App",
|
||||||
|
"category_apps": "App {{category}}",
|
||||||
"app_store": "App Store",
|
"app_store": "App Store",
|
||||||
"app_store_description": "Collegare persone, tecnologia e luogo di lavoro.",
|
"app_store_description": "Collegare persone, tecnologia e luogo di lavoro.",
|
||||||
"settings": "Impostazioni",
|
"settings": "Impostazioni",
|
||||||
"event_type_moved_successfully": "Il tipo di evento è stato spostato con successo",
|
"event_type_moved_successfully": "Il tipo di evento è stato spostato con successo",
|
||||||
|
"next_step_text": "Prossimo passo",
|
||||||
"next_step": "Salta passo",
|
"next_step": "Salta passo",
|
||||||
"prev_step": "Passo precedente",
|
"prev_step": "Passo precedente",
|
||||||
|
"install": "Installa",
|
||||||
"installed": "Installato",
|
"installed": "Installato",
|
||||||
"active_install_one": "{{count}} installazione attiva",
|
"active_install_one": "{{count}} installazione attiva",
|
||||||
"active_install_other": "{{count}} installazioni attive",
|
"active_install_other": "{{count}} installazioni attive",
|
||||||
"globally_install": "Installato a livello globale",
|
"globally_install": "Installato a livello globale",
|
||||||
|
"app_successfully_installed": "App installata correttamente",
|
||||||
|
"app_could_not_be_installed": "Impossibile installare l'app",
|
||||||
"disconnect": "Disconnetti",
|
"disconnect": "Disconnetti",
|
||||||
"embed_your_calendar": "Incorpora il tuo calendario nella tua pagina web",
|
"embed_your_calendar": "Incorpora il tuo calendario nella tua pagina web",
|
||||||
"connect_your_favourite_apps": "Collega le tue app preferite.",
|
"connect_your_favourite_apps": "Collega le tue app preferite.",
|
||||||
@@ -710,6 +732,7 @@
|
|||||||
"connect_additional_calendar": "Collega calendario aggiuntivo",
|
"connect_additional_calendar": "Collega calendario aggiuntivo",
|
||||||
"conferencing": "Conferenze",
|
"conferencing": "Conferenze",
|
||||||
"calendar": "Calendario",
|
"calendar": "Calendario",
|
||||||
|
"payments": "Pagamenti",
|
||||||
"not_installed": "Non installato",
|
"not_installed": "Non installato",
|
||||||
"error_password_mismatch": "Le password non corrispondono.",
|
"error_password_mismatch": "Le password non corrispondono.",
|
||||||
"error_required_field": "Questo campo è richiesto.",
|
"error_required_field": "Questo campo è richiesto.",
|
||||||
@@ -743,9 +766,22 @@
|
|||||||
"import_from": "Importa da",
|
"import_from": "Importa da",
|
||||||
"access_token": "Token di accesso",
|
"access_token": "Token di accesso",
|
||||||
"visit_roadmap": "Roadmap",
|
"visit_roadmap": "Roadmap",
|
||||||
|
"featured_categories": "Categorie in evidenza",
|
||||||
"popular_categories": "Categorie popolari",
|
"popular_categories": "Categorie popolari",
|
||||||
|
"number_apps_one": "{{count}} App",
|
||||||
|
"number_apps_other": "{{count}} App",
|
||||||
"trending_apps": "App di tendenza",
|
"trending_apps": "App di tendenza",
|
||||||
|
"explore_apps": "App {{category}}",
|
||||||
"installed_apps": "App installate",
|
"installed_apps": "App installate",
|
||||||
|
"no_category_apps": "Nessuna app {{category}}",
|
||||||
|
"no_category_apps_description_calendar": "Aggiungi un'app di calendario per controllare i conflitti ed evitare doppie prenotazioni",
|
||||||
|
"no_category_apps_description_conferencing": "Prova ad aggiungere un'app di conferenza per integrare le videochiamate con i clienti",
|
||||||
|
"no_category_apps_description_payment": "Aggiungi un'app di pagamento per facilitare le transazioni con i clienti",
|
||||||
|
"no_category_apps_description_other": "Aggiungi qualsiasi altra app per fare altre attività",
|
||||||
|
"installed_app_calendar_description": "Imposta uno o più calendari per controllare i conflitti ed evitare doppie prenotazioni.",
|
||||||
|
"installed_app_conferencing_description": "Aggiungi le tue app di videoconferenza preferite per le tue riunioni",
|
||||||
|
"installed_app_payment_description": "Configura quale servizio di elaborazione dei pagamenti usare per addebitare i clienti.",
|
||||||
|
"installed_app_other_description": "Tutte le app installate appartenenti alle altre categorie.",
|
||||||
"empty_installed_apps_headline": "Nessuna app installata",
|
"empty_installed_apps_headline": "Nessuna app installata",
|
||||||
"empty_installed_apps_description": "Le app consentono di ottimizzare il flusso di lavoro e di migliorare significativamente la pianificazione.",
|
"empty_installed_apps_description": "Le app consentono di ottimizzare il flusso di lavoro e di migliorare significativamente la pianificazione.",
|
||||||
"empty_installed_apps_button": "Esplora l'App Store",
|
"empty_installed_apps_button": "Esplora l'App Store",
|
||||||
@@ -766,6 +802,7 @@
|
|||||||
"remove": "Rimuovi",
|
"remove": "Rimuovi",
|
||||||
"add": "Aggiungi",
|
"add": "Aggiungi",
|
||||||
"installed_one": "Installato",
|
"installed_one": "Installato",
|
||||||
|
"installed_other": "{{count}} installate",
|
||||||
"verify_wallet": "Verifica Wallet",
|
"verify_wallet": "Verifica Wallet",
|
||||||
"connect_metamask": "Connetti Metamask",
|
"connect_metamask": "Connetti Metamask",
|
||||||
"create_events_on": "Crea eventi su:",
|
"create_events_on": "Crea eventi su:",
|
||||||
@@ -783,6 +820,8 @@
|
|||||||
"set_to_default": "Impostazione predefinita",
|
"set_to_default": "Impostazione predefinita",
|
||||||
"new_schedule_btn": "Nuovo programma",
|
"new_schedule_btn": "Nuovo programma",
|
||||||
"add_new_schedule": "Aggiungi un nuovo programma",
|
"add_new_schedule": "Aggiungi un nuovo programma",
|
||||||
|
"add_new_calendar": "Aggiungi un nuovo calendario",
|
||||||
|
"set_calendar": "Imposta dove aggiungere nuovi eventi quando vi è una prenotazione.",
|
||||||
"delete_schedule": "Elimina programma",
|
"delete_schedule": "Elimina programma",
|
||||||
"schedule_created_successfully": "Programma {{scheduleName}} creato",
|
"schedule_created_successfully": "Programma {{scheduleName}} creato",
|
||||||
"availability_updated_successfully": "Disponibilità aggiornata con successo",
|
"availability_updated_successfully": "Disponibilità aggiornata con successo",
|
||||||
@@ -811,7 +850,7 @@
|
|||||||
"api_key": "Chiave API",
|
"api_key": "Chiave API",
|
||||||
"test_api_key": "Prova chiave API",
|
"test_api_key": "Prova chiave API",
|
||||||
"test_passed": "Test superato!",
|
"test_passed": "Test superato!",
|
||||||
"test_failed": "Test non superato",
|
"test_failed": "Prova non superata",
|
||||||
"provide_api_key": "Fornisci chiave API",
|
"provide_api_key": "Fornisci chiave API",
|
||||||
"api_key_modal_subtitle": "Le chiavi API consentono di effettuare chiamate API per il proprio account.",
|
"api_key_modal_subtitle": "Le chiavi API consentono di effettuare chiamate API per il proprio account.",
|
||||||
"api_keys_subtitle": "Genera chiavi API da usare per accedere al tuo account.",
|
"api_keys_subtitle": "Genera chiavi API da usare per accedere al tuo account.",
|
||||||
@@ -936,6 +975,7 @@
|
|||||||
"workflows": "Flussi di lavoro",
|
"workflows": "Flussi di lavoro",
|
||||||
"new_workflow_btn": "Nuovo flusso di lavoro",
|
"new_workflow_btn": "Nuovo flusso di lavoro",
|
||||||
"add_new_workflow": "Aggiungi un nuovo flusso di lavoro",
|
"add_new_workflow": "Aggiungi un nuovo flusso di lavoro",
|
||||||
|
"reschedule_event_trigger": "quando un evento viene riprogrammato",
|
||||||
"trigger": "Attivatore",
|
"trigger": "Attivatore",
|
||||||
"triggers": "Attivatori",
|
"triggers": "Attivatori",
|
||||||
"action": "Azione",
|
"action": "Azione",
|
||||||
@@ -963,10 +1003,13 @@
|
|||||||
"change_username_standard_to_premium": "Poiché stai passando da un nome utente standard a un nome utente premium, sarai portato alla pagina di pagamento per effettuare l'upgrade.",
|
"change_username_standard_to_premium": "Poiché stai passando da un nome utente standard a un nome utente premium, sarai portato alla pagina di pagamento per effettuare l'upgrade.",
|
||||||
"change_username_premium_to_standard": "Poiché stai passando da un nome utente premium a un nome utente standard, sarai portato alla pagina di pagamento per effettuare il downgrade.",
|
"change_username_premium_to_standard": "Poiché stai passando da un nome utente premium a un nome utente standard, sarai portato alla pagina di pagamento per effettuare il downgrade.",
|
||||||
"go_to_stripe_billing": "Vai alla fatturazione",
|
"go_to_stripe_billing": "Vai alla fatturazione",
|
||||||
|
"stripe_description": "Richiedi pagamento per le prenotazioni (0,5% + 0,10 € di commissione per transazione)",
|
||||||
"trial_expired": "Il periodo di prova è scaduto",
|
"trial_expired": "Il periodo di prova è scaduto",
|
||||||
"remove_app": "Rimuovi app",
|
"remove_app": "Rimuovi app",
|
||||||
"yes_remove_app": "Sì, rimuovi l'app",
|
"yes_remove_app": "Sì, rimuovi l'app",
|
||||||
"are_you_sure_you_want_to_remove_this_app": "Rimuovere questa app?",
|
"are_you_sure_you_want_to_remove_this_app": "Rimuovere questa app?",
|
||||||
|
"app_removed_successfully": "App rimossa correttamente",
|
||||||
|
"error_removing_app": "Errore durante la rimozione dell'app",
|
||||||
"web_conference": "Conferenza Web",
|
"web_conference": "Conferenza Web",
|
||||||
"number_for_sms_reminders": "Numero di telefono (per promemoria via SMS)",
|
"number_for_sms_reminders": "Numero di telefono (per promemoria via SMS)",
|
||||||
"requires_confirmation": "Richiede conferma",
|
"requires_confirmation": "Richiede conferma",
|
||||||
@@ -1022,20 +1065,205 @@
|
|||||||
"navigate": "Esplora",
|
"navigate": "Esplora",
|
||||||
"open": "Apri",
|
"open": "Apri",
|
||||||
"close": "Chiudi",
|
"close": "Chiudi",
|
||||||
|
"team_feature_teams": "Questa è una funzionalità del piano Team. Effettua l'upgrade al piano Team per vedere la disponibilità del tuo team.",
|
||||||
|
"team_feature_workflows": "Questa è una funzionalità del piano Team. Effettua l'upgrade al piano Team per automatizzare le notifiche e i promemoria degli eventi per i flussi di lavoro.",
|
||||||
|
"show_eventtype_on_profile": "Mostra nel profilo",
|
||||||
"embed": "Incorpora",
|
"embed": "Incorpora",
|
||||||
"new_username": "Nuovo nome utente",
|
"new_username": "Nuovo nome utente",
|
||||||
"current_username": "Nome utente corrente",
|
"current_username": "Nome utente corrente",
|
||||||
"example_1": "Esempio 1",
|
"example_1": "Esempio 1",
|
||||||
"example_2": "Esempio 2",
|
"example_2": "Esempio 2",
|
||||||
|
"additional_input_label": "Etichetta del campo di input aggiuntivo",
|
||||||
"company_size": "Dimensione dell'azienda",
|
"company_size": "Dimensione dell'azienda",
|
||||||
"what_help_needed": "Per cosa ti serve assistenza?",
|
"what_help_needed": "Per cosa ti serve assistenza?",
|
||||||
"variable_format": "Formato variabile",
|
"variable_format": "Formato variabile",
|
||||||
|
"webhook_subscriber_url_reserved": "URL dell'abbonato Webhook già definito",
|
||||||
"custom_input_as_variable_info": "Ignora tutti i caratteri speciali dell'etichetta del campo di input aggiuntivo (usa solo lettere e numeri), usa solo lettere maiuscole e sostituisci gli spazi con il trattino basso.",
|
"custom_input_as_variable_info": "Ignora tutti i caratteri speciali dell'etichetta del campo di input aggiuntivo (usa solo lettere e numeri), usa solo lettere maiuscole e sostituisci gli spazi con il trattino basso.",
|
||||||
"using_additional_inputs_as_variables": "Come usare i campi di input aggiuntivi come variabili?",
|
"using_additional_inputs_as_variables": "Come usare i campi di input aggiuntivi come variabili?",
|
||||||
"download_desktop_app": "Scarica app desktop",
|
"download_desktop_app": "Scarica app desktop",
|
||||||
"set_ping_link": "Imposta link di Ping",
|
"set_ping_link": "Imposta link di Ping",
|
||||||
|
"rate_limit_exceeded": "Limite di frequenza superato",
|
||||||
|
"when_something_happens": "Quando succede qualcosa",
|
||||||
|
"action_is_performed": "Viene eseguita un'azione",
|
||||||
|
"test_action": "Azione di test",
|
||||||
|
"notification_sent": "Notifica inviata",
|
||||||
|
"no_input": "Nessun input",
|
||||||
|
"test_workflow_action": "Verifica azione del flusso di lavoro",
|
||||||
|
"send_sms": "Invia SMS",
|
||||||
|
"send_sms_to_number": "Inviare un SMS a {{number}}?",
|
||||||
"missing_connected_calendar": "Nessun calendario predefinito collegato",
|
"missing_connected_calendar": "Nessun calendario predefinito collegato",
|
||||||
|
"connect_your_calendar_and_link": "Puoi collegare il tuo calendario <1>qui</1>.",
|
||||||
|
"default_calendar_selected": "Calendario predefinito",
|
||||||
|
"hide_from_profile": "Nascondi nel profilo",
|
||||||
|
"event_setup_tab_title": "Impostazione evento",
|
||||||
|
"event_limit_tab_title": "Limiti",
|
||||||
|
"event_limit_tab_description": "Con quale frequenza è possibile fare una prenotazione",
|
||||||
|
"event_advanced_tab_description": "Impostazioni calendario e altro...",
|
||||||
|
"event_advanced_tab_title": "Avanzate",
|
||||||
|
"select_which_cal": "Seleziona il calendario al quale aggiungere prenotazioni",
|
||||||
|
"custom_event_name": "Nome evento personalizzato",
|
||||||
|
"custom_event_name_description": "Crea nomi di eventi personalizzati da visualizzare nell'evento del calendario",
|
||||||
|
"2fa_required": "Autenticazione a due fattori necessaria",
|
||||||
|
"incorrect_2fa": "Codice di autenticazione a due fattori errato",
|
||||||
|
"which_event_type_apply": "A quale tipo di evento si applicherà?",
|
||||||
|
"no_workflows_description": "I flussi di lavoro attivano una semplice automazione per inviare notifiche e promemoria che ti consentono di creare processi per i tuoi eventi.",
|
||||||
|
"create_workflow": "Crea un flusso di lavoro",
|
||||||
|
"do_this": "Esegui questa operazione",
|
||||||
|
"turn_off": "Disattiva",
|
||||||
|
"settings_updated_successfully": "Impostazioni aggiornate correttamente",
|
||||||
|
"error_updating_settings": "Errore durante l'aggiornamento delle impostazioni",
|
||||||
|
"personal_cal_url": "Il mio URL personale di Cal",
|
||||||
|
"bio_hint": "Scrivi qualcosa di te. Queste informazioni appariranno nella tua pagina personale.",
|
||||||
|
"delete_account_modal_title": "Elimina account",
|
||||||
|
"confirm_delete_account_modal": "Eliminare il tuo account Cal.com?",
|
||||||
|
"delete_my_account": "Elimina il mio account",
|
||||||
|
"start_of_week": "Inizio della settimana",
|
||||||
|
"select_calendars": "Seleziona su quali calendari desideri controllare i conflitti per evitare doppie prenotazioni.",
|
||||||
|
"check_for_conflicts": "Controlla conflitti",
|
||||||
|
"adding_events_to": "Aggiungendo eventi a",
|
||||||
|
"follow_system_preferences": "Segui le preferenze di sistema",
|
||||||
|
"custom_brand_colors": "Colori del marchio personalizzati",
|
||||||
|
"customize_your_brand_colors": "Personalizza la tua pagina di prenotazione con i colori del tuo marchio.",
|
||||||
|
"pro": "Pro",
|
||||||
|
"removes_cal_branding": "Rimuove tutte le scritte con il marchio Cal, ad es., 'Powered by Cal.'",
|
||||||
|
"profile_picture": "Immagine del profilo",
|
||||||
|
"upload": "Carica",
|
||||||
|
"web3": "Web3",
|
||||||
|
"rainbow_token_gated": "Questo tipo di evento è protetto da token.",
|
||||||
|
"rainbow_connect_wallet_gate": "Collega il tuo portafoglio se possiedi <1>{{name}}</1> (<3>{{symbol}}</3>).",
|
||||||
|
"rainbow_insufficient_balance": "Il portafoglio collegato non contiene abbastanza <1>{{symbol}}</1>.",
|
||||||
|
"rainbow_sign_message_request": "Firma la richiesta di messaggio sul tuo portafoglio.",
|
||||||
|
"rainbow_signature_error": "Errore durante la richiesta di firma al tuo portafoglio.",
|
||||||
|
"token_address": "Indirizzo token",
|
||||||
|
"blockchain": "Blockchain",
|
||||||
|
"old_password": "Vecchia password",
|
||||||
|
"secure_password": "La tua nuova password super sicura",
|
||||||
|
"error_updating_password": "Errore durante l'aggiornamento della password",
|
||||||
|
"two_factor_auth": "Autenticazione a due fattori",
|
||||||
|
"recurring_event_tab_description": "Imposta una pianificazione ricorrente",
|
||||||
|
"today": "oggi",
|
||||||
|
"appearance": "Aspetto",
|
||||||
|
"appearance_subtitle": "Gestisci le impostazioni di aspetto delle tue prenotazioni",
|
||||||
|
"my_account": "Il mio account",
|
||||||
|
"general": "Generale",
|
||||||
|
"calendars": "Calendari",
|
||||||
|
"2fa_auth": "Autenticazione a due fattori",
|
||||||
|
"invoices": "Fatture",
|
||||||
|
"embeds": "Incorpora",
|
||||||
|
"impersonation": "Impersonificazione",
|
||||||
|
"users": "Utenti",
|
||||||
|
"profile_description": "Gestisci le impostazioni del tuo profilo cal",
|
||||||
|
"general_description": "Gestisci le impostazioni di lingua e fuso orario",
|
||||||
|
"calendars_description": "Configura come i tipi di eventi devono interagire con i tuoi calendari",
|
||||||
|
"appearance_description": "Gestisci le impostazioni di aspetto delle tue prenotazioni",
|
||||||
|
"conferencing_description": "Gestisci le app di videoconferenza per le tue riunioni",
|
||||||
|
"password_description": "Gestisci le impostazioni relative alle password del tuo account",
|
||||||
|
"2fa_description": "Gestisci le impostazioni relative alle password del tuo account",
|
||||||
|
"we_just_need_basic_info": "Abbiamo bisogno di alcune informazioni di base per completare la configurazione del tuo profilo.",
|
||||||
|
"skip": "Salta",
|
||||||
|
"do_this_later": "Più tardi",
|
||||||
|
"set_availability_getting_started_subtitle_1": "Definisci gli intervalli di tempo quando sei disponibile",
|
||||||
|
"set_availability_getting_started_subtitle_2": "È possibile personalizzare queste impostazioni in un secondo tempo nella pagina della disponibilità.",
|
||||||
|
"connect_calendars_from_app_store": "È possibile aggiungere altri calendari dall'App store",
|
||||||
|
"connect_conference_apps": "Connetti app di conferenza",
|
||||||
|
"connect_calendar_apps": "Connetti app di calendario",
|
||||||
|
"connect_payment_apps": "Connetti app di pagamento",
|
||||||
|
"connect_other_apps": "Connetti altre app",
|
||||||
|
"current_step_of_total": "Passo {{currentStep}} di {{maxSteps}}",
|
||||||
|
"add_variable": "Aggiungi variabile",
|
||||||
|
"custom_phone_number": "Numero di telefono personalizzato",
|
||||||
|
"message_template": "Modello di messaggio",
|
||||||
|
"email_subject": "Oggetto e-mail",
|
||||||
|
"add_dynamic_variables": "Aggiungi variabili di testo dinamico",
|
||||||
|
"event_name_info": "Nome del tipo di evento",
|
||||||
|
"event_date_info": "Data dell'evento",
|
||||||
|
"event_time_info": "Ora di inizio dell'evento",
|
||||||
|
"location_info": "Luogo dell'evento",
|
||||||
"organizer_name_info": "Il tuo nome",
|
"organizer_name_info": "Il tuo nome",
|
||||||
|
"additional_notes_info": "Note aggiuntive sulla prenotazione",
|
||||||
|
"attendee_name_info": "Nome della persona che prenota",
|
||||||
|
"to": "A",
|
||||||
|
"attendee_required_enter_number": "Al partecipante verrà richiesto di inserire un numero di telefono al momento della prenotazione",
|
||||||
|
"workflow_turned_on_successfully": "Flusso di lavoro {{workflowName}} impostato come {{offOn}} correttamente",
|
||||||
|
"download_responses": "Scarica risposte",
|
||||||
|
"create_your_first_form": "Crea il tuo primo modulo",
|
||||||
|
"create_your_first_form_description": "I Moduli di instradamento consentono di porre domande qualificanti agli utenti per indirizzarli a persone o eventi pertinenti.",
|
||||||
|
"create_your_first_webhook": "Crea il tuo primo Webhook",
|
||||||
|
"create_your_first_webhook_description": "I Webhook consentono di ricevere in tempo reale le informazioni sulle riunioni quando si verifica un evento su Cal.com.",
|
||||||
|
"for_a_maximum_of": "Per un massimo di",
|
||||||
|
"event_one": "evento",
|
||||||
|
"event_other": "eventi",
|
||||||
|
"profile_team_description": "Gestisci le impostazioni del profilo del tuo team",
|
||||||
|
"members_team_description": "Utenti nel gruppo",
|
||||||
|
"team_url": "URL del team",
|
||||||
|
"delete_team": "Elimina team",
|
||||||
|
"team_members": "Membri del team",
|
||||||
|
"more": "Altro",
|
||||||
|
"more_page_footer": "Consideriamo l'applicazione mobile un'estensione dell'applicazione web. Se si stanno eseguendo delle azioni complesse, si prega di fare riferimento all'applicazione web.",
|
||||||
|
"workflow_example_1": "Invia al partecipante un promemoria via SMS 24 ore prima dell'inizio dell'evento",
|
||||||
|
"workflow_example_2": "Invia al partecipante un SMS personalizzato se l'evento viene riprogrammato",
|
||||||
|
"workflow_example_3": "Invia all'organizzatore un'e-mail personalizzata quando viene prenotato un nuovo evento",
|
||||||
|
"workflow_example_4": "Invia al partecipante un promemoria via e-mail un'ora prima dell'inizio dell'evento",
|
||||||
|
"workflow_example_5": "Invia all'organizzatore un'e-mail personalizzata se l'evento viene riprogrammato",
|
||||||
|
"workflow_example_6": "Invia all'organizzatore un SMS personalizzato quando viene prenotato un nuovo evento",
|
||||||
|
"welcome_to_cal_header": "Benvenuto in Cal.com!",
|
||||||
|
"edit_form_later_subtitle": "Sarà possibile apportare modifiche in un secondo tempo.",
|
||||||
|
"connect_calendar_later": "Connetterò il mio calendario più tardi",
|
||||||
|
"set_my_availability_later": "Configurerò la mia disponibilità più tardi",
|
||||||
|
"problem_saving_user_profile": "Si è verificato un problema durante il salvataggio dei dati. Riprovare o contattare l'assistenza clienti.",
|
||||||
|
"purchase_missing_seats": "Acquista posti mancanti",
|
||||||
|
"slot_length": "Durata della fascia oraria",
|
||||||
|
"booking_appearance": "Aspetto prenotazione",
|
||||||
|
"appearance_team_description": "Gestisci le impostazioni di aspetto delle prenotazioni del tuo team",
|
||||||
|
"only_owner_change": "Solo il proprietario del team può apportare modifiche alla prenotazione del team ",
|
||||||
|
"team_disable_cal_branding_description": "Rimuove tutte le scritte con il marchio Cal, ad es., 'Powered by Cal'",
|
||||||
|
"invited_by_team": "{{teamName}} ti ha invitato a unirti al team come {{role}}",
|
||||||
|
"token_invalid_expired": "Il token non è valido o scaduto.",
|
||||||
|
"exchange_add": "Connetti a Microsoft Exchange",
|
||||||
|
"exchange_authentication": "Metodo di autenticazione",
|
||||||
|
"exchange_authentication_standard": "Autenticazione di base",
|
||||||
|
"exchange_authentication_ntlm": "Autenticazione NTLM",
|
||||||
|
"exchange_compression": "Compressione GZip",
|
||||||
|
"routing_forms_description": "È possibile vedere qui tutti i moduli e tutti i percorsi che hai creato.",
|
||||||
|
"add_new_form": "Aggiungi nuovo modulo",
|
||||||
|
"form_description": "Crea un modulo per instradare le persone che prenotano",
|
||||||
|
"copy_link_to_form": "Copia il link al modulo",
|
||||||
|
"theme": "Tema",
|
||||||
|
"theme_applies_note": "Si applica solo alle pagine di prenotazione pubbliche",
|
||||||
"theme_light": "Chiaro",
|
"theme_light": "Chiaro",
|
||||||
"theme_dark": "Scuro"
|
"theme_dark": "Scuro",
|
||||||
|
"theme_system": "Predefinito di sistema",
|
||||||
|
"add_a_team": "Aggiungi un team",
|
||||||
|
"saml_config": "Configurazione SAML",
|
||||||
|
"add_webhook_description": "Ricevi in tempo reale le informazioni sulle riunioni quando si verifica un evento su Cal.com",
|
||||||
|
"triggers_when": "Viene attivato quando",
|
||||||
|
"test_webhook": "Eseguire un test del ping prima di creare.",
|
||||||
|
"enable_webhook": "Abilita Webhook",
|
||||||
|
"add_webhook": "Aggiungi Webhook",
|
||||||
|
"webhook_edited_successfully": "Webhook salvato",
|
||||||
|
"webhooks_description": "Ricevi in tempo reale le informazioni sulle riunioni quando si verifica un evento su Cal.com",
|
||||||
|
"api_keys_description": "Genera chiavi API per accedere al tuo account",
|
||||||
|
"new_api_key": "Nuova chiave API",
|
||||||
|
"active": "Attivo",
|
||||||
|
"api_key_updated": "Nome chiave API aggiornato",
|
||||||
|
"api_key_update_failed": "Errore durante l'aggiornamento del nome della chiave API",
|
||||||
|
"embeds_title": "iframe HTML incorporato",
|
||||||
|
"embeds_description": "Incorpora tutti i tipi di eventi nel tuo sito web",
|
||||||
|
"create_first_api_key": "Crea la tua prima chiave API",
|
||||||
|
"create_first_api_key_description": "Le chiavi API consentono alle altre applicazioni di comunicare con Cal.com",
|
||||||
|
"back_to_signin": "Torna alla pagina di accesso",
|
||||||
|
"reset_link_sent": "Link per la reimpostazione inviato",
|
||||||
|
"password_reset_email": "Un'e-mail con le istruzioni per reimpostare la password è stata inviata all'indirizzo {{email}}.",
|
||||||
|
"password_updated": "Password aggiornata!",
|
||||||
|
"pending_payment": "Pagamento in sospeso",
|
||||||
|
"confirmation_page_rainbow": "Proteggi i tuoi eventi con token o NFT su Ethereum, Polygon e altri.",
|
||||||
|
"not_on_cal": "Non presente su Cal.com",
|
||||||
|
"no_calendar_installed": "Nessun calendario installato",
|
||||||
|
"no_calendar_installed_description": "Non hai ancora collegato alcun calendario",
|
||||||
|
"add_a_calendar": "Aggiungi un calendario",
|
||||||
|
"change_email_hint": "Per rendere effettive le modifiche, potrebbe essere necessario disconnettersi e accedere nuovamente",
|
||||||
|
"confirm_password_change_email": "Conferma la password prima di cambiare l'indirizzo e-mail",
|
||||||
|
"seats": "posti",
|
||||||
|
"every_app_published": "Tutte le applicazioni pubblicate nell'App store di Cal.com sono open source e sono state testate in modo approfondito attraverso una valutazione tra pari. Tuttavia, Cal.com, Inc. non promuove né certifica tali applicazioni, a meno che non siano pubblicate da Cal.com. Se notate contenuti o comportamenti inappropriati, vi preghiamo di segnalarceli.",
|
||||||
|
"report_app": "Segnala app"
|
||||||
}
|
}
|
||||||
Loaded 100 of 283 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user