Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8e8c96c267 | ||
|
|
fab765c5ee | ||
|
|
89ed07a097 | ||
|
|
d7d73d2caf | ||
|
|
aa92730e28 | ||
|
|
430430e0cd | ||
|
|
62713940b0 | ||
|
|
75aef09338 | ||
|
|
4e65c30e18 | ||
|
|
8b873e2828 | ||
|
|
e70d179628 | ||
|
|
ca9a836300 | ||
|
|
abdf72dc0f | ||
|
|
227cd165f6 | ||
|
|
a0135cdc59 | ||
|
|
112d504148 | ||
|
|
d275930732 | ||
|
|
97e33bdd7e | ||
|
|
3f13791faf | ||
|
|
359cfc4be0 | ||
|
|
1ad6bba0ab | ||
|
|
6dc4211d81 | ||
|
|
e5f0452728 | ||
|
|
d95bba63f4 | ||
|
|
6f48869021 | ||
|
|
845bfae887 | ||
|
|
3fe02fba26 | ||
|
|
4ca5ca9fe2 | ||
|
|
364e187080 | ||
|
|
b1193eef1e | ||
|
|
e110f12cf1 | ||
|
|
022b513935 | ||
|
|
010f39a7a4 | ||
|
|
6b6eed66eb | ||
|
|
c214e01f03 | ||
|
|
a28ac3634d | ||
|
|
a0709fac88 | ||
|
|
e5b6a3332e | ||
|
|
979686920a | ||
|
|
793850f3aa | ||
|
|
fa9d72fc0a | ||
|
|
0d485ffed6 | ||
|
|
9a2e55d528 | ||
|
|
81ecbb86a5 | ||
|
|
2cd816932b | ||
|
|
d83411162d | ||
|
|
c9c54db3a1 | ||
|
|
d100600789 | ||
|
|
6f9011a167 | ||
|
|
ae004c8a6c | ||
|
|
ccbb16fe76 | ||
|
|
b77ce4a010 | ||
|
|
f72f709e34 | ||
|
|
37ceb25f8c | ||
|
|
0141d8f954 | ||
|
|
47fe791006 | ||
|
|
0cbaba73e4 | ||
|
|
aaac491dc7 | ||
|
|
fc4203e963 | ||
|
|
8430e9612e | ||
|
|
de81934619 | ||
|
|
5aedcbee55 | ||
|
|
7bc8d7e991 | ||
|
|
df183f5882 | ||
|
|
27d9fad292 | ||
|
|
bed798d440 | ||
|
|
e5a8a4e34d |
@@ -0,0 +1,42 @@
|
||||
// For format details, see https://aka.ms/devcontainer.json. For config options, see the
|
||||
// README at: https://github.com/devcontainers/templates/tree/main/src/docker-outside-of-docker
|
||||
{
|
||||
"name": "Docker outside of Docker",
|
||||
// Or use a Dockerfile or Docker Compose file. More info: https://containers.dev/guide/dockerfile
|
||||
"image": "mcr.microsoft.com/devcontainers/base:bullseye",
|
||||
|
||||
"features": {
|
||||
"ghcr.io/devcontainers/features/docker-from-docker:1": {
|
||||
"version": "latest",
|
||||
"enableNonRootDocker": "true",
|
||||
"moby": "true"
|
||||
},
|
||||
"ghcr.io/devcontainers/features/node:1": {},
|
||||
"ghcr.io/devcontainers-contrib/features/npm-package:1": {},
|
||||
"ghcr.io/devcontainers-contrib/features/jest:2": {},
|
||||
"ghcr.io/devcontainers-contrib/features/prisma:2": {},
|
||||
"ghcr.io/guiyomh/features/vim:0": {}
|
||||
},
|
||||
|
||||
// Use this environment variable if you need to bind mount your local source code into a new container.
|
||||
"remoteEnv": {
|
||||
"LOCAL_WORKSPACE_FOLDER": "${localWorkspaceFolder}"
|
||||
},
|
||||
|
||||
"hostRequirements": {
|
||||
"cpus": 4,
|
||||
"memory": "8gb"
|
||||
},
|
||||
|
||||
// Use 'postCreateCommand' to run commands after the container is created.
|
||||
"postCreateCommand": "./deploy/install.sh"
|
||||
|
||||
// Use 'forwardPorts' to make a list of ports inside the container available locally.
|
||||
// "forwardPorts": [],
|
||||
|
||||
// Configure tool-specific properties.
|
||||
// "customizations": {},
|
||||
|
||||
// Uncomment to connect as root instead. More info: https://aka.ms/dev-containers-non-root.
|
||||
// "remoteUser": "root"
|
||||
}
|
||||
@@ -102,6 +102,8 @@ STRIPE_TEAM_MONTHLY_PRICE_ID=
|
||||
STRIPE_WEBHOOK_SECRET=
|
||||
STRIPE_PRIVATE_KEY=
|
||||
STRIPE_CLIENT_ID=
|
||||
PAYMENT_FEE_FIXED=
|
||||
PAYMENT_FEE_PERCENTAGE=
|
||||
|
||||
# Use for internal Public API Keys and optional
|
||||
API_KEY_PREFIX=cal_
|
||||
|
||||
@@ -22,6 +22,7 @@ jobs:
|
||||
upload_translations: true
|
||||
download_translations: true
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
# So required checks run on Crowdin PRs
|
||||
GITHUB_TOKEN: ${{ secrets.GH_ACCESS_TOKEN }}
|
||||
CROWDIN_PROJECT_ID: ${{ secrets.CROWDIN_PROJECT_ID }}
|
||||
CROWDIN_PERSONAL_TOKEN: ${{ secrets.CROWDIN_PERSONAL_TOKEN }}
|
||||
|
||||
@@ -14,3 +14,5 @@ jobs:
|
||||
- uses: actions/labeler@v4
|
||||
with:
|
||||
repo-token: "${{ secrets.GITHUB_TOKEN }}"
|
||||
# https://github.com/actions/labeler/issues/442#issuecomment-1297359481
|
||||
sync-labels: ""
|
||||
|
||||
+1
-1
Submodule apps/api updated: 604d937661...7aebdb8c96
+1
-1
Submodule apps/console updated: 2d577dd9ed...8dd0779c43
@@ -17,7 +17,7 @@
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"iframe-resizer-react": "^1.1.0",
|
||||
"next": "^12.3.1",
|
||||
"next": "^13.1.1",
|
||||
"nextra": "^1.1.0",
|
||||
"nextra-theme-docs": "^1.2.2",
|
||||
"react": "^18.2.0",
|
||||
|
||||
@@ -31,7 +31,7 @@ All apps can be found under `packages/app-store`. In this folder is `_example` w
|
||||
| ├──index.ts
|
||||
| ├──package.json
|
||||
| ├──.env.example
|
||||
| ├──README.mdx
|
||||
| ├──DESCRIPTION.md
|
||||
```
|
||||
|
||||
## Getting Started
|
||||
@@ -48,9 +48,9 @@ Under the `/components` folder, this is where the install button for your app sh
|
||||
|
||||
The `/lib` folder is where the functions of your app live. For example, when creating a booking with a MS Teams link the function to make the call to grab the link lives in the `/lib` folder. Export your endpoints in an `index.ts` file under `/lib` folder and import them in your main `index.ts` file.
|
||||
|
||||
On the app store page you can customize your apps description by adding a markdown file called `README.mdx`. If you do not add one then the description from you `package.json` will be used instead.
|
||||
On the app store page you can customize your apps description by adding a markdown file called `DESCRIPTION.md`. If you do not add one then the description from you `package.json` will be used instead.
|
||||
|
||||
The `/static` folder is where you can store your app icon and any images that your `README.mdx` may use.
|
||||
The `/static` folder is where you can store your app icon and any images that your `DESCRIPTION.md` may use.
|
||||
|
||||
## Adding Your App to the App Store
|
||||
To render your app on the app store page, go to `packages/app-store/index.ts`. Import your app into the file and add it to the `appStore` object.
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
"@radix-ui/react-slider": "^1.0.0",
|
||||
"@radix-ui/react-switch": "^1.0.0",
|
||||
"@radix-ui/react-tooltip": "^1.0.0",
|
||||
"next": "^12.3.1",
|
||||
"next": "^13.1.1",
|
||||
"react": "^18.2.0",
|
||||
"react-dom": "^18.2.0"
|
||||
},
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
"dependencies": {
|
||||
"highlight.js": "^11.6.0",
|
||||
"isarray": "2.0.5",
|
||||
"next": "^12.3.1",
|
||||
"next": "^13.1.1",
|
||||
"openapi-snippet": "^0.13.0",
|
||||
"react": "^18.2.0",
|
||||
"react-dom": "^18.2.0",
|
||||
|
||||
+1
-1
@@ -1 +1 @@
|
||||
14.17
|
||||
v16
|
||||
|
||||
@@ -1,9 +0,0 @@
|
||||
import { Suspense, SuspenseProps } from "react";
|
||||
|
||||
/**
|
||||
* Wrapper around `<Suspense />` which will render the `fallback` when on server
|
||||
* Can be simply replaced by `<Suspense />` once React 18 is ready.
|
||||
*/
|
||||
export const ClientSuspense = (props: SuspenseProps) => {
|
||||
return <>{typeof window !== "undefined" ? <Suspense {...props} /> : props.fallback}</>;
|
||||
};
|
||||
@@ -62,7 +62,7 @@ const NavTabs: FC<NavTabProps> = ({ tabs, linkProps, ...props }) => {
|
||||
const className = tab.className || "";
|
||||
return (
|
||||
<Component key={tab.name}>
|
||||
<Link key={tab.name} href={href} {...linkProps}>
|
||||
<Link key={tab.name} href={href} {...linkProps} legacyBehavior>
|
||||
<a
|
||||
onClick={onClick}
|
||||
className={classNames(
|
||||
|
||||
@@ -11,9 +11,7 @@ import { APP_NAME, COMPANY_NAME, SUPPORT_MAIL_ADDRESS } from "@calcom/lib/consta
|
||||
import { useLocale } from "@calcom/lib/hooks/useLocale";
|
||||
import { trpc } from "@calcom/trpc/react";
|
||||
import { App as AppType } from "@calcom/types/App";
|
||||
import { Button, Icon, Shell, showToast, SkeletonButton, SkeletonText } from "@calcom/ui";
|
||||
|
||||
import HeadSeo from "@components/seo/head-seo";
|
||||
import { Button, Icon, Shell, showToast, SkeletonButton, SkeletonText, HeadSeo } from "@calcom/ui";
|
||||
|
||||
const Component = ({
|
||||
name,
|
||||
@@ -100,8 +98,10 @@ const Component = ({
|
||||
<h1 className="font-cal ml-4 text-3xl text-gray-900">{name}</h1>
|
||||
</div>
|
||||
<h2 className="text-sm font-medium text-gray-600">
|
||||
<Link href={`categories/${categories[0]}`}>
|
||||
<a className="rounded-md bg-gray-100 p-1 text-xs capitalize text-gray-800">{categories[0]}</a>
|
||||
<Link
|
||||
href={`categories/${categories[0]}`}
|
||||
className="rounded-md bg-gray-100 p-1 text-xs capitalize text-gray-800">
|
||||
{categories[0]}
|
||||
</Link>{" "}
|
||||
• {t("published_by", { author })}
|
||||
</h2>
|
||||
|
||||
@@ -330,7 +330,10 @@ export function CalendarListContainer(props: { heading?: boolean; fromOnboarding
|
||||
})}
|
||||
description={t(`no_category_apps_description_calendar`)}
|
||||
buttonRaw={
|
||||
<Button color="secondary" href="/apps/categories/calendar">
|
||||
<Button
|
||||
color="secondary"
|
||||
data-testid="connect-calendar-apps"
|
||||
href="/apps/categories/calendar">
|
||||
{t(`connect_calendar_apps`)}
|
||||
</Button>
|
||||
}
|
||||
|
||||
+1
-5
@@ -3,11 +3,7 @@ import { useRouter } from "next/router";
|
||||
import React, { ComponentProps } from "react";
|
||||
|
||||
import { useLocale } from "@calcom/lib/hooks/useLocale";
|
||||
import { EmptyScreen, Icon } from "@calcom/ui";
|
||||
|
||||
import Shell from "../Shell";
|
||||
import type { HorizontalTabItemProps } from "../navigation/tabs/HorizontalTabItem";
|
||||
import HorizontalTabs from "../navigation/tabs/HorizontalTabs";
|
||||
import { EmptyScreen, Icon, Shell, HorizontalTabs, HorizontalTabItemProps } from "@calcom/ui";
|
||||
|
||||
const tabs: HorizontalTabItemProps[] = [
|
||||
{
|
||||
+3
-5
@@ -3,11 +3,9 @@ import React, { ComponentProps } from "react";
|
||||
import AppCategoryNavigation from "@calcom/app-store/_components/AppCategoryNavigation";
|
||||
import { InstalledAppVariants } from "@calcom/app-store/utils";
|
||||
import { trpc } from "@calcom/trpc/react";
|
||||
|
||||
import { Icon } from "../../../components/icon";
|
||||
import Shell from "../Shell";
|
||||
import type { HorizontalTabItemProps } from "../navigation/tabs/HorizontalTabItem";
|
||||
import type { VerticalTabItemProps } from "../navigation/tabs/VerticalTabItem";
|
||||
import { Icon, Shell } from "@calcom/ui";
|
||||
import type { HorizontalTabItemProps } from "@calcom/ui/v2/core/navigation/tabs/HorizontalTabItem";
|
||||
import type { VerticalTabItemProps } from "@calcom/ui/v2/core/navigation/tabs/VerticalTabItem";
|
||||
|
||||
const tabs: (VerticalTabItemProps | HorizontalTabItemProps)[] = [
|
||||
{
|
||||
+3
-3
@@ -2,9 +2,9 @@ import { useSession } from "next-auth/react";
|
||||
import { useRouter } from "next/router";
|
||||
import React, { ComponentProps, useEffect } from "react";
|
||||
|
||||
import { ErrorBoundary } from "../../..";
|
||||
import Shell from "../Shell";
|
||||
import SettingsLayout from "./SettingsLayout";
|
||||
import SettingsLayout from "@calcom/features/settings/layouts/SettingsLayout";
|
||||
import { ErrorBoundary, Shell } from "@calcom/ui";
|
||||
|
||||
import { UserPermissionRole } from ".prisma/client";
|
||||
|
||||
export default function AdminLayout({
|
||||
@@ -114,29 +114,29 @@ const AvailableTimes: FC<AvailableTimesProps> = ({
|
||||
{!!seatsPerTimeSlot && <p className="text-sm">{t("booking_full")}</p>}
|
||||
</div>
|
||||
) : (
|
||||
<Link href={bookingUrl} prefetch={false}>
|
||||
<a
|
||||
className={classNames(
|
||||
"text-primary-500 hover:border-gray-900 hover:bg-gray-50",
|
||||
"dark:bg-darkgray-200 dark:hover:bg-darkgray-300 dark:hover:border-darkmodebrand mb-2 block rounded-md border bg-white py-2 text-sm font-medium dark:border-transparent dark:text-neutral-200",
|
||||
brand === "#fff" || brand === "#ffffff" ? "" : ""
|
||||
)}
|
||||
data-testid="time">
|
||||
{dayjs(slot.time).tz(timeZone()).format(timeFormat)}
|
||||
{!!seatsPerTimeSlot && (
|
||||
<p
|
||||
className={`${
|
||||
slot.attendees && slot.attendees / seatsPerTimeSlot >= 0.8
|
||||
? "text-rose-600"
|
||||
: slot.attendees && slot.attendees / seatsPerTimeSlot >= 0.33
|
||||
? "text-yellow-500"
|
||||
: "text-emerald-400"
|
||||
} text-sm`}>
|
||||
{slot.attendees ? seatsPerTimeSlot - slot.attendees : seatsPerTimeSlot} /{" "}
|
||||
{seatsPerTimeSlot} {t("seats_available")}
|
||||
</p>
|
||||
)}
|
||||
</a>
|
||||
<Link
|
||||
href={bookingUrl}
|
||||
prefetch={false}
|
||||
className={classNames(
|
||||
"text-primary-500 hover:border-gray-900 hover:bg-gray-50",
|
||||
"dark:bg-darkgray-200 dark:hover:bg-darkgray-300 dark:hover:border-darkmodebrand mb-2 block rounded-md border bg-white py-2 text-sm font-medium dark:border-transparent dark:text-neutral-200",
|
||||
brand === "#fff" || brand === "#ffffff" ? "" : ""
|
||||
)}
|
||||
data-testid="time">
|
||||
{dayjs(slot.time).tz(timeZone()).format(timeFormat)}
|
||||
{!!seatsPerTimeSlot && (
|
||||
<p
|
||||
className={`${
|
||||
slot.attendees && slot.attendees / seatsPerTimeSlot >= 0.8
|
||||
? "text-rose-600"
|
||||
: slot.attendees && slot.attendees / seatsPerTimeSlot >= 0.33
|
||||
? "text-yellow-500"
|
||||
: "text-emerald-400"
|
||||
} text-sm`}>
|
||||
{slot.attendees ? seatsPerTimeSlot - slot.attendees : seatsPerTimeSlot} /{" "}
|
||||
{seatsPerTimeSlot} {t("seats_available")}
|
||||
</p>
|
||||
)}
|
||||
</Link>
|
||||
)}
|
||||
</div>
|
||||
|
||||
@@ -28,7 +28,7 @@ import { getRecurringFreq } from "@calcom/lib/recurringStrings";
|
||||
import { collectPageParameters, telemetryEventTypes, useTelemetry } from "@calcom/lib/telemetry";
|
||||
import { detectBrowserTimeFormat, setIs24hClockInLocalStorage, TimeFormat } from "@calcom/lib/timeFormat";
|
||||
import { trpc } from "@calcom/trpc/react";
|
||||
import { Icon } from "@calcom/ui";
|
||||
import { Icon, HeadSeo } from "@calcom/ui";
|
||||
|
||||
import { timeZone as localStorageTimeZone } from "@lib/clock";
|
||||
import useRouterQuery from "@lib/hooks/useRouterQuery";
|
||||
@@ -37,7 +37,6 @@ import Gates, { Gate, GateState } from "@components/Gates";
|
||||
import AvailableTimes from "@components/booking/AvailableTimes";
|
||||
import BookingDescription from "@components/booking/BookingDescription";
|
||||
import TimeOptions from "@components/booking/TimeOptions";
|
||||
import { HeadSeo } from "@components/seo/head-seo";
|
||||
import PoweredByCal from "@components/ui/PoweredByCal";
|
||||
|
||||
import type { AvailabilityPageProps } from "../../../pages/[user]/[type]";
|
||||
|
||||
@@ -93,10 +93,11 @@ export const EventAdvancedTab = ({ eventType, team }: Pick<EventTypeSetupProps,
|
||||
<div className="flex flex-col">
|
||||
<div className="flex justify-between">
|
||||
<Label>{t("add_to_calendar")}</Label>
|
||||
<Link href="/apps/categories/calendar">
|
||||
<a target="_blank" className="text-sm text-gray-600 hover:text-gray-900">
|
||||
{t("add_another_calendar")}
|
||||
</a>
|
||||
<Link
|
||||
href="/apps/categories/calendar"
|
||||
target="_blank"
|
||||
className="text-sm text-gray-600 hover:text-gray-900">
|
||||
{t("add_another_calendar")}
|
||||
</Link>
|
||||
</div>
|
||||
<div className="-mt-1 w-full">
|
||||
@@ -266,12 +267,10 @@ export const EventAdvancedTab = ({ eventType, team }: Pick<EventTypeSetupProps,
|
||||
/>
|
||||
{/*TODO: Extract it out into a component when used more than once*/}
|
||||
{!IS_SELF_HOSTED && (
|
||||
<Link href="https://cal.com/pricing">
|
||||
<a target="_blank">
|
||||
<Badge variant="orange" className="ml-2">
|
||||
Platform Only
|
||||
</Badge>
|
||||
</a>
|
||||
<Link href="https://cal.com/pricing" target="_blank">
|
||||
<Badge variant="orange" className="ml-2">
|
||||
Platform Only
|
||||
</Badge>
|
||||
</Link>
|
||||
)}
|
||||
</div>
|
||||
|
||||
@@ -1,16 +1,18 @@
|
||||
import { useAutoAnimate } from "@formkit/auto-animate/react";
|
||||
import { zodResolver } from "@hookform/resolvers/zod";
|
||||
import { isValidPhoneNumber } from "libphonenumber-js";
|
||||
import { Trans } from "next-i18next";
|
||||
import Link from "next/link";
|
||||
import type { EventTypeSetupProps, FormValues } from "pages/event-types/[type]";
|
||||
import { useState } from "react";
|
||||
import { Controller, useForm, useFormContext } from "react-hook-form";
|
||||
import { MultiValue } from "react-select";
|
||||
import { z } from "zod";
|
||||
|
||||
import { EventLocationType, getEventLocationType } from "@calcom/app-store/locations";
|
||||
import { EventLocationType, getEventLocationType, MeetLocationType } from "@calcom/app-store/locations";
|
||||
import { CAL_URL } from "@calcom/lib/constants";
|
||||
import { useLocale } from "@calcom/lib/hooks/useLocale";
|
||||
import { Button, Icon, Label, Select, Skeleton, TextField, SettingsToggle } from "@calcom/ui";
|
||||
import { Button, Icon, Label, Select, SettingsToggle, Skeleton, TextField } from "@calcom/ui";
|
||||
|
||||
import { slugify } from "@lib/slugify";
|
||||
|
||||
@@ -195,6 +197,23 @@ export const EventSetupTab = (
|
||||
</li>
|
||||
);
|
||||
})}
|
||||
{validLocations.some((location) => location.type === MeetLocationType) && (
|
||||
<div className="flex text-sm text-gray-600">
|
||||
<Icon.FiCheck className="mt-0.5 mr-1.5 h-2 w-2.5" />
|
||||
<Trans i18nKey="event_type_requres_google_cal">
|
||||
<p>
|
||||
The “Add to calendar” for this event type needs to be a Google Calendar for Meet to work.
|
||||
Change it{" "}
|
||||
<Link
|
||||
href={`${CAL_URL}/event-types/${eventType.id}?tabName=advanced`}
|
||||
className="underline">
|
||||
here.
|
||||
</Link>{" "}
|
||||
We will fall back to Cal video if you do not change it.
|
||||
</p>
|
||||
</Trans>
|
||||
</div>
|
||||
)}
|
||||
{validLocations.length > 0 && validLocations.length !== locationOptions.length && (
|
||||
<li>
|
||||
<Button StartIcon={Icon.FiPlus} color="minimal" onClick={() => setShowLocationModal(true)}>
|
||||
@@ -326,6 +345,7 @@ export const EventSetupTab = (
|
||||
<Skeleton as={Label} loadingClassName="w-16">
|
||||
{t("location")}
|
||||
</Skeleton>
|
||||
|
||||
<Controller
|
||||
name="locations"
|
||||
control={formMethods.control}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { TFunction } from "next-i18next";
|
||||
import { useRouter } from "next/router";
|
||||
import { EventTypeSetupProps, FormValues } from "pages/event-types/[type]";
|
||||
import { useMemo, useState } from "react";
|
||||
import { useMemo, useState, Suspense } from "react";
|
||||
import { UseFormReturn } from "react-hook-form";
|
||||
import { TbWebhook } from "react-icons/tb";
|
||||
|
||||
@@ -32,7 +32,6 @@ import {
|
||||
VerticalTabs,
|
||||
} from "@calcom/ui";
|
||||
|
||||
import { ClientSuspense } from "@components/ClientSuspense";
|
||||
import { EmbedButton, EmbedDialog } from "@components/Embed";
|
||||
|
||||
type Props = {
|
||||
@@ -301,7 +300,7 @@ function EventTypeSingleLayout({
|
||||
</Button>
|
||||
</div>
|
||||
}>
|
||||
<ClientSuspense fallback={<Icon.FiLoader />}>
|
||||
<Suspense fallback={<Icon.FiLoader />}>
|
||||
<div className="-mt-2 flex flex-col xl:flex-row xl:space-x-8">
|
||||
<div className="hidden xl:block">
|
||||
<VerticalTabs
|
||||
@@ -324,7 +323,7 @@ function EventTypeSingleLayout({
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</ClientSuspense>
|
||||
</Suspense>
|
||||
<Dialog open={deleteDialogOpen} onOpenChange={setDeleteDialogOpen}>
|
||||
<ConfirmationDialogContent
|
||||
isLoading={deleteMutation.isLoading}
|
||||
|
||||
+1
-1
@@ -3,7 +3,7 @@ import { useRouter } from "next/router";
|
||||
import React, { useEffect, useState } from "react";
|
||||
import { Toaster } from "react-hot-toast";
|
||||
|
||||
import { StepCard, Steps } from "../../..";
|
||||
import { StepCard, Steps } from "@calcom/ui";
|
||||
|
||||
export default function WizardLayout({
|
||||
children,
|
||||
@@ -0,0 +1,4 @@
|
||||
We don't have many layouts currently however, if they are relevant to a features - please put them in their relvant component folder
|
||||
in `web/components` if you believe they will be reused in other apps please place them in `packages/features/[feature]`
|
||||
|
||||
Thanks Sean 🔥
|
||||
@@ -1,11 +1,9 @@
|
||||
import classNames from "classnames";
|
||||
|
||||
import { APP_NAME, LOGO } from "@calcom/lib/constants";
|
||||
import { Credits, HeadSeo } from "@calcom/ui";
|
||||
|
||||
import Loader from "@components/Loader";
|
||||
import { HeadSeo } from "@components/seo/head-seo";
|
||||
|
||||
import Credits from "../../../../packages/ui/v2/core/Credits";
|
||||
|
||||
interface Props {
|
||||
title: string;
|
||||
|
||||
@@ -35,13 +35,7 @@ export const AvatarGroup = function AvatarGroup(props: AvatarGroupProps) {
|
||||
|
||||
return (
|
||||
<li key={idx} className="-ltr:mr-2 inline-block rtl:ml-2">
|
||||
{item.href ? (
|
||||
<Link href={item.href}>
|
||||
<a>{avatar}</a>
|
||||
</Link>
|
||||
) : (
|
||||
avatar
|
||||
)}
|
||||
{item.href ? <Link href={item.href}>{avatar}</Link> : avatar}
|
||||
</li>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,22 +0,0 @@
|
||||
import Link from "next/link";
|
||||
|
||||
interface ILinkTextProps {
|
||||
href: string;
|
||||
children: React.ReactNode;
|
||||
classNameChildren?: string;
|
||||
target?: string;
|
||||
}
|
||||
/**
|
||||
* This component had to be made in order to make i18n work with next/link
|
||||
* @see https://github.com/i18next/react-i18next/issues/1090#issuecomment-615426145
|
||||
**/
|
||||
export const LinkText = (props: ILinkTextProps) => {
|
||||
const { target, href, children, classNameChildren, ...moreProps } = props;
|
||||
return (
|
||||
<Link href={href || ""} {...moreProps}>
|
||||
<a target={target || ""} className={classNameChildren}>
|
||||
{children}
|
||||
</a>
|
||||
</Link>
|
||||
);
|
||||
};
|
||||
@@ -9,26 +9,21 @@ const PoweredByCal = () => {
|
||||
const isEmbed = useIsEmbed();
|
||||
return (
|
||||
<div className={"p-2 text-center text-xs sm:text-right" + (isEmbed ? " max-w-3xl" : "")}>
|
||||
<Link href={POWERED_BY_URL}>
|
||||
<a target="_blank" className="text-bookinglight opacity-50 hover:opacity-100 dark:text-white">
|
||||
{t("powered_by")}{" "}
|
||||
{
|
||||
// eslint-disable-next-line @next/next/no-img-element
|
||||
<img
|
||||
className="relative -mt-px inline h-[10px] w-auto dark:hidden"
|
||||
src="/cal-logo-word.svg"
|
||||
alt="Cal.com Logo"
|
||||
/>
|
||||
}
|
||||
{
|
||||
// eslint-disable-next-line @next/next/no-img-element
|
||||
<img
|
||||
className="relativ -mt-px hidden h-[10px] w-auto dark:inline"
|
||||
src="/cal-logo-word-dark.svg"
|
||||
alt="Cal.com Logo"
|
||||
/>
|
||||
}
|
||||
</a>
|
||||
<Link
|
||||
href={POWERED_BY_URL}
|
||||
target="_blank"
|
||||
className="text-bookinglight opacity-50 hover:opacity-100 dark:text-white">
|
||||
{t("powered_by")}{" "}
|
||||
<img
|
||||
className="relative -mt-px inline h-[10px] w-auto dark:hidden"
|
||||
src="/cal-logo-word.svg"
|
||||
alt="Cal.com Logo"
|
||||
/>
|
||||
<img
|
||||
className="relativ -mt-px hidden h-[10px] w-auto dark:inline"
|
||||
src="/cal-logo-word-dark.svg"
|
||||
alt="Cal.com Logo"
|
||||
/>
|
||||
</Link>
|
||||
</div>
|
||||
);
|
||||
|
||||
@@ -187,7 +187,7 @@ const PremiumTextfield = (props: ICustomUsernameProps) => {
|
||||
<div className="flex justify-items-center">
|
||||
<Label htmlFor="username">{t("username")}</Label>
|
||||
</div>
|
||||
<div className="mt-2 flex rounded-md">
|
||||
<div className="flex rounded-md">
|
||||
<span
|
||||
className={classNames(
|
||||
isInputUsernamePremium ? "border-1 border-orange-400 " : "",
|
||||
|
||||
@@ -118,7 +118,7 @@ const UsernameTextfield = (props: ICustomUsernameProps) => {
|
||||
|
||||
return (
|
||||
<div>
|
||||
<div className="mt-2 flex rounded-md">
|
||||
<div className="flex rounded-md">
|
||||
<div className="relative w-full">
|
||||
<TextField
|
||||
ref={usernameRef}
|
||||
|
||||
@@ -1,79 +0,0 @@
|
||||
import React, { ReactNode, useState } from "react";
|
||||
|
||||
import classNames from "@lib/classNames";
|
||||
|
||||
type RadioAreaProps = Omit<React.InputHTMLAttributes<HTMLInputElement>, "onChange"> & {
|
||||
onChange?: (value: string) => void;
|
||||
defaultChecked?: boolean;
|
||||
};
|
||||
|
||||
const RadioArea = (props: RadioAreaProps) => {
|
||||
return (
|
||||
<label
|
||||
className={classNames(
|
||||
"border-1 block border p-4 focus:outline-none focus:ring focus:ring-neutral-500",
|
||||
props.checked && "border-brand",
|
||||
props.className
|
||||
)}>
|
||||
<input
|
||||
onChange={(e) => {
|
||||
if (typeof props.onChange === "function") {
|
||||
props.onChange(e.target.value);
|
||||
}
|
||||
}}
|
||||
checked={props.checked}
|
||||
className="float-right ml-3 text-neutral-900 focus:ring-neutral-500"
|
||||
name={props.name}
|
||||
value={props.value}
|
||||
type="radio"
|
||||
/>
|
||||
{props.children}
|
||||
</label>
|
||||
);
|
||||
};
|
||||
|
||||
type ChildrenProps = {
|
||||
props: RadioAreaProps;
|
||||
children?: ReactNode;
|
||||
};
|
||||
interface RadioAreaGroupProps extends Omit<React.ComponentPropsWithoutRef<"div">, "onChange" | "children"> {
|
||||
children: ChildrenProps | ChildrenProps[];
|
||||
name?: string;
|
||||
onChange?: (value: string) => void;
|
||||
}
|
||||
|
||||
const RadioAreaGroup = ({ children, name, onChange, ...passThroughProps }: RadioAreaGroupProps) => {
|
||||
const [checkedIdx, setCheckedIdx] = useState<number | null>(null);
|
||||
|
||||
const changeHandler = (value: string, idx: number) => {
|
||||
if (onChange) {
|
||||
onChange(value);
|
||||
}
|
||||
setCheckedIdx(idx);
|
||||
};
|
||||
|
||||
return (
|
||||
<div {...passThroughProps}>
|
||||
{(Array.isArray(children) ? children : [children]).map((child, idx: number) => {
|
||||
if (checkedIdx === null && child.props.defaultChecked) {
|
||||
setCheckedIdx(idx);
|
||||
}
|
||||
return (
|
||||
<Item
|
||||
{...child.props}
|
||||
key={idx}
|
||||
name={name}
|
||||
checked={idx === checkedIdx}
|
||||
onChange={(value: string) => changeHandler(value, idx)}>
|
||||
{child.props.children}
|
||||
</Item>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
const Item = RadioArea;
|
||||
const Group = RadioAreaGroup;
|
||||
|
||||
export { RadioArea, RadioAreaGroup, Item, Group };
|
||||
@@ -1,61 +0,0 @@
|
||||
import { Collapsible, CollapsibleContent, CollapsibleTrigger } from "@radix-ui/react-collapsible";
|
||||
import React from "react";
|
||||
|
||||
import { Icon } from "@calcom/ui";
|
||||
|
||||
import classNames from "@lib/classNames";
|
||||
import { useLocale } from "@lib/hooks/useLocale";
|
||||
|
||||
import { RadioArea, RadioAreaGroup } from "@components/ui/form/radio-area/RadioAreaGroup";
|
||||
|
||||
interface OptionProps
|
||||
extends Pick<React.OptionHTMLAttributes<HTMLOptionElement>, "value" | "label" | "className"> {
|
||||
description?: string;
|
||||
}
|
||||
|
||||
interface RadioAreaSelectProps extends Omit<React.SelectHTMLAttributes<HTMLSelectElement>, "onChange"> {
|
||||
options: OptionProps[]; // allow options to be passed programmatically, like options={}
|
||||
onChange?: (value: string) => void;
|
||||
}
|
||||
|
||||
export const Select = function RadioAreaSelect(props: RadioAreaSelectProps) {
|
||||
const { t } = useLocale();
|
||||
const {
|
||||
options,
|
||||
disabled = !options.length, // if not explicitly disabled and the options length is empty, disable anyway
|
||||
placeholder = t("select"),
|
||||
} = props;
|
||||
|
||||
const getLabel = (value: string | ReadonlyArray<string> | number | undefined) =>
|
||||
options.find((option: OptionProps) => option.value === value)?.label;
|
||||
|
||||
return (
|
||||
<Collapsible className={classNames("w-full", props.className)}>
|
||||
<CollapsibleTrigger
|
||||
type="button"
|
||||
disabled={disabled}
|
||||
className={classNames(
|
||||
"border-1 focus:ring-primary-500 mb-1 block w-full cursor-pointer rounded-sm border border-gray-300 bg-white p-2 text-left text-sm",
|
||||
disabled && "cursor-default bg-gray-200 focus:ring-0 "
|
||||
)}>
|
||||
{getLabel(props.value) ?? placeholder}
|
||||
<Icon.FiChevronDown className="float-right h-5 w-5 text-neutral-500" />
|
||||
</CollapsibleTrigger>
|
||||
<CollapsibleContent>
|
||||
<RadioAreaGroup className="space-y-2 text-sm" name={props.name} onChange={props.onChange}>
|
||||
{options.map((option) => (
|
||||
<RadioArea
|
||||
{...option}
|
||||
key={Array.isArray(option.value) ? option.value.join(",") : `${option.value}`}
|
||||
defaultChecked={props.value === option.value}>
|
||||
<strong className="mb-1 block">{option.label}</strong>
|
||||
<p>{option.description}</p>
|
||||
</RadioArea>
|
||||
))}
|
||||
</RadioAreaGroup>
|
||||
</CollapsibleContent>
|
||||
</Collapsible>
|
||||
);
|
||||
};
|
||||
|
||||
export default Select;
|
||||
@@ -1,2 +0,0 @@
|
||||
export * from "./RadioAreaGroup";
|
||||
export * from "./Select";
|
||||
@@ -89,6 +89,12 @@ const nextConfig = {
|
||||
eslint: {
|
||||
ignoreDuringBuilds: !!process.env.CI,
|
||||
},
|
||||
// TODO: We need to have all components in `@calcom/ui/components` in order to use this
|
||||
// modularizeImports: {
|
||||
// "@calcom/ui": {
|
||||
// transform: "@calcom/ui/components/{{member}}",
|
||||
// },
|
||||
// },
|
||||
images: {
|
||||
unoptimized: true,
|
||||
},
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@calcom/web",
|
||||
"version": "2.4.3",
|
||||
"version": "2.4.6",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"analyze": "ANALYZE=true next build",
|
||||
@@ -67,6 +67,7 @@
|
||||
"bcryptjs": "^2.4.3",
|
||||
"classnames": "^2.3.1",
|
||||
"dotenv-cli": "^6.0.0",
|
||||
"eslint-config-next": "^13.1.1",
|
||||
"googleapis": "^84.0.0",
|
||||
"gray-matter": "^4.0.3",
|
||||
"handlebars": "^4.7.7",
|
||||
@@ -80,15 +81,14 @@
|
||||
"memory-cache": "^0.2.0",
|
||||
"micro": "^9.4.1",
|
||||
"mime-types": "^2.1.35",
|
||||
"next": "^12.3.1",
|
||||
"next": "^13.1.1",
|
||||
"next-auth": "^4.10.3",
|
||||
"next-axiom": "^0.10.0",
|
||||
"next-axiom": "^0.16.0",
|
||||
"next-collect": "^0.2.1",
|
||||
"next-i18next": "^11.3.0",
|
||||
"next-mdx-remote": "^4.1.0",
|
||||
"next-seo": "^4.26.0",
|
||||
"next-themes": "^0.2.0",
|
||||
"next-transpile-modules": "^9.0.0",
|
||||
"next-transpile-modules": "^10.0.0",
|
||||
"nock": "^13.2.8",
|
||||
"nodemailer": "^6.7.8",
|
||||
"otplib": "^12.0.1",
|
||||
|
||||
+47
-51
@@ -4,12 +4,10 @@ import { useRouter } from "next/router";
|
||||
import { useEffect, useState } from "react";
|
||||
|
||||
import { COMPANY_NAME, DEVELOPER_DOCS, DOCS_URL, JOIN_SLACK, WEBSITE_URL } from "@calcom/lib/constants";
|
||||
import { Icon } from "@calcom/ui";
|
||||
import { Icon, HeadSeo } from "@calcom/ui";
|
||||
|
||||
import { useLocale } from "@lib/hooks/useLocale";
|
||||
|
||||
import { HeadSeo } from "@components/seo/head-seo";
|
||||
|
||||
import { ssgInit } from "@server/lib/ssg";
|
||||
|
||||
export default function Custom404() {
|
||||
@@ -100,26 +98,26 @@ export default function Custom404() {
|
||||
|
||||
<ul role="list" className="divide-y divide-gray-200 border-gray-200">
|
||||
<li className="px-4 py-2">
|
||||
<Link href={`${DEVELOPER_DOCS}/self-hosting/installation`}>
|
||||
<a className="relative flex items-start space-x-4 py-6 rtl:space-x-reverse">
|
||||
<div className="flex-shrink-0">
|
||||
<span className="flex h-12 w-12 items-center justify-center rounded-lg bg-gray-50">
|
||||
<Icon.FiFileText className="h-6 w-6 text-gray-700" aria-hidden="true" />
|
||||
<Link
|
||||
href={`${DEVELOPER_DOCS}/self-hosting/installation`}
|
||||
className="relative flex items-start space-x-4 py-6 rtl:space-x-reverse">
|
||||
<div className="flex-shrink-0">
|
||||
<span className="flex h-12 w-12 items-center justify-center rounded-lg bg-gray-50">
|
||||
<Icon.FiFileText className="h-6 w-6 text-gray-700" aria-hidden="true" />
|
||||
</span>
|
||||
</div>
|
||||
<div className="min-w-0 flex-1">
|
||||
<h3 className="text-base font-medium text-gray-900">
|
||||
<span className="rounded-sm focus-within:ring-2 focus-within:ring-gray-500 focus-within:ring-offset-2">
|
||||
<span className="absolute inset-0" aria-hidden="true" />
|
||||
{t("prisma_studio_tip")}
|
||||
</span>
|
||||
</div>
|
||||
<div className="min-w-0 flex-1">
|
||||
<h3 className="text-base font-medium text-gray-900">
|
||||
<span className="rounded-sm focus-within:ring-2 focus-within:ring-gray-500 focus-within:ring-offset-2">
|
||||
<span className="absolute inset-0" aria-hidden="true" />
|
||||
{t("prisma_studio_tip")}
|
||||
</span>
|
||||
</h3>
|
||||
<p className="text-base text-gray-500">{t("prisma_studio_tip_description")}</p>
|
||||
</div>
|
||||
<div className="flex-shrink-0 self-center">
|
||||
<Icon.FiChevronRight className="h-5 w-5 text-gray-400" aria-hidden="true" />
|
||||
</div>
|
||||
</a>
|
||||
</h3>
|
||||
<p className="text-base text-gray-500">{t("prisma_studio_tip_description")}</p>
|
||||
</div>
|
||||
<div className="flex-shrink-0 self-center">
|
||||
<Icon.FiChevronRight className="h-5 w-5 text-gray-400" aria-hidden="true" />
|
||||
</div>
|
||||
</Link>
|
||||
</li>
|
||||
<li className="px-4 py-2">
|
||||
@@ -169,11 +167,11 @@ export default function Custom404() {
|
||||
</li>
|
||||
</ul>
|
||||
<div className="mt-8">
|
||||
<Link href={`${WEBSITE_URL}/enterprise`}>
|
||||
<a className="text-base font-medium text-black hover:text-gray-500">
|
||||
{t("contact_sales")}
|
||||
<span aria-hidden="true"> →</span>
|
||||
</a>
|
||||
<Link
|
||||
href={`${WEBSITE_URL}/enterprise`}
|
||||
className="text-base font-medium text-black hover:text-gray-500">
|
||||
{t("contact_sales")}
|
||||
<span aria-hidden="true"> →</span>
|
||||
</Link>
|
||||
</div>
|
||||
</div>
|
||||
@@ -245,26 +243,26 @@ export default function Custom404() {
|
||||
<ul role="list" className="mt-4 divide-y divide-gray-200 border-gray-200">
|
||||
{links.map((link, linkIdx) => (
|
||||
<li key={linkIdx} className="px-4 py-2">
|
||||
<Link href={link.href}>
|
||||
<a className="relative flex items-start space-x-4 py-6 rtl:space-x-reverse">
|
||||
<div className="flex-shrink-0">
|
||||
<span className="flex h-12 w-12 items-center justify-center rounded-lg bg-gray-50">
|
||||
<link.icon className="h-6 w-6 text-gray-700" aria-hidden="true" />
|
||||
<Link
|
||||
href={link.href}
|
||||
className="relative flex items-start space-x-4 py-6 rtl:space-x-reverse">
|
||||
<div className="flex-shrink-0">
|
||||
<span className="flex h-12 w-12 items-center justify-center rounded-lg bg-gray-50">
|
||||
<link.icon className="h-6 w-6 text-gray-700" aria-hidden="true" />
|
||||
</span>
|
||||
</div>
|
||||
<div className="min-w-0 flex-1">
|
||||
<h3 className="text-base font-medium text-gray-900">
|
||||
<span className="rounded-sm focus-within:ring-2 focus-within:ring-gray-500 focus-within:ring-offset-2">
|
||||
<span className="absolute inset-0" aria-hidden="true" />
|
||||
{link.title}
|
||||
</span>
|
||||
</div>
|
||||
<div className="min-w-0 flex-1">
|
||||
<h3 className="text-base font-medium text-gray-900">
|
||||
<span className="rounded-sm focus-within:ring-2 focus-within:ring-gray-500 focus-within:ring-offset-2">
|
||||
<span className="absolute inset-0" aria-hidden="true" />
|
||||
{link.title}
|
||||
</span>
|
||||
</h3>
|
||||
<p className="text-base text-gray-500">{link.description}</p>
|
||||
</div>
|
||||
<div className="flex-shrink-0 self-center">
|
||||
<Icon.FiChevronRight className="h-5 w-5 text-gray-400" aria-hidden="true" />
|
||||
</div>
|
||||
</a>
|
||||
</h3>
|
||||
<p className="text-base text-gray-500">{link.description}</p>
|
||||
</div>
|
||||
<div className="flex-shrink-0 self-center">
|
||||
<Icon.FiChevronRight className="h-5 w-5 text-gray-400" aria-hidden="true" />
|
||||
</div>
|
||||
</Link>
|
||||
</li>
|
||||
))}
|
||||
@@ -315,11 +313,9 @@ export default function Custom404() {
|
||||
</li>
|
||||
</ul>
|
||||
<div className="mt-8">
|
||||
<Link href="/">
|
||||
<a className="text-base font-medium text-black hover:text-gray-500">
|
||||
{t("or_go_back_home")}
|
||||
<span aria-hidden="true"> →</span>
|
||||
</a>
|
||||
<Link href="/" className="text-base font-medium text-black hover:text-gray-500">
|
||||
{t("or_go_back_home")}
|
||||
<span aria-hidden="true"> →</span>
|
||||
</Link>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
+35
-38
@@ -1,6 +1,5 @@
|
||||
import classNames from "classnames";
|
||||
import { GetServerSidePropsContext } from "next";
|
||||
import dynamic from "next/dynamic";
|
||||
import Link from "next/link";
|
||||
import { useRouter } from "next/router";
|
||||
import { useEffect } from "react";
|
||||
@@ -27,7 +26,7 @@ import { collectPageParameters, telemetryEventTypes, useTelemetry } from "@calco
|
||||
import prisma from "@calcom/prisma";
|
||||
import { baseEventTypeSelect } from "@calcom/prisma/selects";
|
||||
import { EventTypeMetaDataSchema } from "@calcom/prisma/zod-utils";
|
||||
import { Icon } from "@calcom/ui";
|
||||
import { Icon, HeadSeo } from "@calcom/ui";
|
||||
|
||||
import { inferSSRProps } from "@lib/types/inferSSRProps";
|
||||
import { EmbedProps } from "@lib/withEmbedSsr";
|
||||
@@ -37,7 +36,6 @@ import { AvatarSSR } from "@components/ui/AvatarSSR";
|
||||
|
||||
import { ssrInit } from "@server/lib/ssr";
|
||||
|
||||
const HeadSeo = dynamic(() => import("@components/seo/head-seo"));
|
||||
export default function User(props: inferSSRProps<typeof getServerSideProps> & EmbedProps) {
|
||||
const { users, profile, eventTypes, isDynamicGroup, dynamicNames, dynamicUsernames, isSingleUser } = props;
|
||||
const [user] = users; //To be used when we only have a single user, not dynamic group
|
||||
@@ -61,25 +59,26 @@ export default function User(props: inferSSRProps<typeof getServerSideProps> & E
|
||||
key={index}
|
||||
className="dark:bg-darkgray-100 group relative border-b border-neutral-200 bg-white first:rounded-t-md last:rounded-b-md last:border-b-0 hover:bg-gray-50 dark:border-neutral-700 dark:hover:border-neutral-600">
|
||||
<Icon.FiArrowRight className="absolute right-3 top-3 h-4 w-4 text-black opacity-0 transition-opacity group-hover:opacity-100 dark:text-white" />
|
||||
<Link href={getUsernameSlugLink({ users: props.users, slug: type.slug })}>
|
||||
<a className="flex justify-between px-6 py-4" data-testid="event-type-link">
|
||||
<div className="flex-shrink">
|
||||
<p className="dark:text-darkgray-700 text-sm font-semibold text-neutral-900">{type.title}</p>
|
||||
<EventTypeDescription className="text-sm" eventType={type} />
|
||||
</div>
|
||||
<div className="mt-1 self-center">
|
||||
<AvatarGroup
|
||||
border="border-2 border-white dark:border-darkgray-100"
|
||||
truncateAfter={4}
|
||||
className="flex flex-shrink-0"
|
||||
size={10}
|
||||
items={props.users.map((user) => ({
|
||||
alt: user.name || "",
|
||||
image: user.avatar || "",
|
||||
}))}
|
||||
/>
|
||||
</div>
|
||||
</a>
|
||||
<Link
|
||||
href={getUsernameSlugLink({ users: props.users, slug: type.slug })}
|
||||
className="flex justify-between px-6 py-4"
|
||||
data-testid="event-type-link">
|
||||
<div className="flex-shrink">
|
||||
<p className="dark:text-darkgray-700 text-sm font-semibold text-neutral-900">{type.title}</p>
|
||||
<EventTypeDescription className="text-sm" eventType={type} />
|
||||
</div>
|
||||
<div className="mt-1 self-center">
|
||||
<AvatarGroup
|
||||
border="border-2 border-white dark:border-darkgray-100"
|
||||
truncateAfter={4}
|
||||
className="flex flex-shrink-0"
|
||||
size={10}
|
||||
items={props.users.map((user) => ({
|
||||
alt: user.name || "",
|
||||
image: user.avatar || "",
|
||||
}))}
|
||||
/>
|
||||
</div>
|
||||
</Link>
|
||||
</li>
|
||||
))}
|
||||
@@ -176,22 +175,20 @@ export default function User(props: inferSSRProps<typeof getServerSideProps> & E
|
||||
href={{
|
||||
pathname: `/${user.username}/${type.slug}`,
|
||||
query,
|
||||
}}>
|
||||
<a
|
||||
onClick={async () => {
|
||||
sdkActionManager?.fire("eventTypeSelected", {
|
||||
eventType: type,
|
||||
});
|
||||
}}
|
||||
className="block w-full p-5"
|
||||
data-testid="event-type-link">
|
||||
<div className="flex flex-wrap items-center">
|
||||
<h2 className="dark:text-darkgray-700 pr-2 text-sm font-semibold text-gray-700">
|
||||
{type.title}
|
||||
</h2>
|
||||
</div>
|
||||
<EventTypeDescription eventType={type} />
|
||||
</a>
|
||||
}}
|
||||
onClick={async () => {
|
||||
sdkActionManager?.fire("eventTypeSelected", {
|
||||
eventType: type,
|
||||
});
|
||||
}}
|
||||
className="block w-full p-5"
|
||||
data-testid="event-type-link">
|
||||
<div className="flex flex-wrap items-center">
|
||||
<h2 className="dark:text-darkgray-700 pr-2 text-sm font-semibold text-gray-700">
|
||||
{type.title}
|
||||
</h2>
|
||||
</div>
|
||||
<EventTypeDescription eventType={type} />
|
||||
</Link>
|
||||
</div>
|
||||
))
|
||||
|
||||
@@ -53,7 +53,6 @@ class MyDocument extends Document<Props> {
|
||||
return (
|
||||
<Html lang={locale} dir={dir}>
|
||||
<Head>
|
||||
<link rel="preload" href="/cal.ttf" as="font" type="font/ttf" crossOrigin="anonymous" />
|
||||
<link rel="apple-touch-icon" sizes="180x180" href="/apple-touch-icon.png" />
|
||||
<link rel="icon" type="image/png" sizes="32x32" href="/favicon-32x32.png" />
|
||||
<link rel="icon" type="image/png" sizes="16x16" href="/favicon-16x16.png" />
|
||||
|
||||
@@ -35,6 +35,24 @@ const handler = async (req: NextApiRequest, res: NextApiResponse) => {
|
||||
uid: "xxyPr4cg2xx4XoS2KeMEQy",
|
||||
metadata: {},
|
||||
recurringEvent: null,
|
||||
appsStatus: [
|
||||
{
|
||||
appName: "Outlook Calendar",
|
||||
type: "office365_calendar",
|
||||
success: 1,
|
||||
failures: 0,
|
||||
errors: [],
|
||||
warnings: [],
|
||||
},
|
||||
{
|
||||
appName: "Google Meet",
|
||||
type: "conferencing",
|
||||
success: 0,
|
||||
failures: 1,
|
||||
errors: [],
|
||||
warnings: ["In order to use Google Meet you must set your destination calendar to a Google Calendar"],
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
req.statusCode = 200;
|
||||
@@ -42,9 +60,9 @@ const handler = async (req: NextApiRequest, res: NextApiResponse) => {
|
||||
res.setHeader("Content-Type", "text/html");
|
||||
res.setHeader("Cache-Control", "no-cache, no-store, private, must-revalidate");
|
||||
res.write(
|
||||
renderEmail("OrganizerRequestEmail", {
|
||||
attendee: evt.attendees[0],
|
||||
renderEmail("OrganizerScheduledEmail", {
|
||||
calEvent: evt,
|
||||
attendee: evt.organizer,
|
||||
})
|
||||
);
|
||||
res.end();
|
||||
|
||||
@@ -2,11 +2,11 @@ import { NextApiRequest, NextApiResponse } from "next";
|
||||
import type { Session } from "next-auth";
|
||||
|
||||
import getInstalledAppPath from "@calcom/app-store/_utils/getInstalledAppPath";
|
||||
import { getSession } from "@calcom/lib/auth";
|
||||
import { deriveAppDictKeyFromType } from "@calcom/lib/deriveAppDictKeyFromType";
|
||||
import prisma from "@calcom/prisma";
|
||||
import type { AppDeclarativeHandler, AppHandler } from "@calcom/types/AppHandler";
|
||||
|
||||
import { getSession } from "@lib/auth";
|
||||
import { HttpError } from "@lib/core/http/error";
|
||||
|
||||
const defaultIntegrationAddHandler = async ({
|
||||
|
||||
@@ -1,34 +1,18 @@
|
||||
import fs from "fs";
|
||||
import matter from "gray-matter";
|
||||
import MarkdownIt from "markdown-it";
|
||||
import { GetStaticPaths, GetStaticPropsContext } from "next";
|
||||
import { MDXRemote } from "next-mdx-remote";
|
||||
import { serialize } from "next-mdx-remote/serialize";
|
||||
import Image from "next/image";
|
||||
import Link from "next/link";
|
||||
import path from "path";
|
||||
|
||||
import { getAppWithMetadata } from "@calcom/app-store/_appRegistry";
|
||||
import ExisitingGoogleCal from "@calcom/app-store/googlevideo/components/ExistingGoogleCal";
|
||||
import prisma from "@calcom/prisma";
|
||||
|
||||
import { inferSSRProps } from "@lib/types/inferSSRProps";
|
||||
|
||||
import App from "@components/apps/App";
|
||||
|
||||
const components = {
|
||||
a: ({ href = "", ...otherProps }: JSX.IntrinsicElements["a"]) => (
|
||||
<Link href={href}>
|
||||
<a {...otherProps} />
|
||||
</Link>
|
||||
),
|
||||
img: ({ src = "", alt = "", placeholder, ...rest }: JSX.IntrinsicElements["img"]) => (
|
||||
<Image src={src} alt={alt} {...rest} />
|
||||
),
|
||||
// @TODO: In v2 the slider isn't shown anymore. However, to ensure the v1 pages keep
|
||||
// working, this component is still rendered in the MDX content. To skip them in the v2
|
||||
// content we have to render null here. In v2 the gallery is shown by directly
|
||||
// using the `items` property from the MDX's meta data.
|
||||
Slider: () => <></>,
|
||||
};
|
||||
const md = new MarkdownIt("default", { html: true, breaks: true });
|
||||
|
||||
function SingleAppPage({ data, source }: inferSSRProps<typeof getStaticProps>) {
|
||||
return (
|
||||
@@ -50,10 +34,15 @@ function SingleAppPage({ data, source }: inferSSRProps<typeof getStaticProps>) {
|
||||
email={data.email}
|
||||
licenseRequired={data.licenseRequired}
|
||||
isProOnly={data.isProOnly}
|
||||
images={source?.scope?.items as string[] | undefined}
|
||||
images={source.data?.items as string[] | undefined}
|
||||
// tos="https://zoom.us/terms"
|
||||
// privacy="https://zoom.us/privacy"
|
||||
body={<MDXRemote {...source} components={components} />}
|
||||
body={
|
||||
<>
|
||||
{data.slug === "google-meet" && <ExisitingGoogleCal />}
|
||||
<div dangerouslySetInnerHTML={{ __html: md.render(source.content) }} />
|
||||
</>
|
||||
}
|
||||
/>
|
||||
);
|
||||
}
|
||||
@@ -82,7 +71,7 @@ export const getStaticProps = async (ctx: GetStaticPropsContext) => {
|
||||
if (!singleApp) return { notFound: true };
|
||||
|
||||
const appDirname = app.dirName;
|
||||
const README_PATH = path.join(process.cwd(), "..", "..", `packages/app-store/${appDirname}/README.mdx`);
|
||||
const README_PATH = path.join(process.cwd(), "..", "..", `packages/app-store/${appDirname}/DESCRIPTION.md`);
|
||||
const postFilePath = path.join(README_PATH);
|
||||
let source = "";
|
||||
|
||||
@@ -90,16 +79,15 @@ export const getStaticProps = async (ctx: GetStaticPropsContext) => {
|
||||
/* If the app doesn't have a README we fallback to the package description */
|
||||
source = fs.readFileSync(postFilePath).toString();
|
||||
} catch (error) {
|
||||
console.log(`No README.mdx provided for: ${appDirname}`);
|
||||
console.log(`No DESCRIPTION.md provided for: ${appDirname}`);
|
||||
source = singleApp.description;
|
||||
}
|
||||
|
||||
const { content, data } = matter(source);
|
||||
const mdxSource = await serialize(content, { scope: data });
|
||||
|
||||
return {
|
||||
props: {
|
||||
source: mdxSource,
|
||||
source: { content, data },
|
||||
data: singleApp,
|
||||
},
|
||||
};
|
||||
|
||||
@@ -20,10 +20,10 @@ export default function Apps({ apps }: InferGetStaticPropsType<typeof getStaticP
|
||||
backPath="/apps"
|
||||
heading={
|
||||
<>
|
||||
<Link href="/apps">
|
||||
<a className="inline-flex items-center justify-start gap-1 rounded-sm py-2 text-gray-900">
|
||||
{isLocaleReady ? t("app_store") : <SkeletonText className="h-4 w-24" />}{" "}
|
||||
</a>
|
||||
<Link
|
||||
href="/apps"
|
||||
className="inline-flex items-center justify-start gap-1 rounded-sm py-2 text-gray-900">
|
||||
{isLocaleReady ? t("app_store") : <SkeletonText className="h-4 w-24" />}{" "}
|
||||
</Link>
|
||||
{category && (
|
||||
<span className="gap-1 text-gray-600">
|
||||
|
||||
@@ -11,28 +11,28 @@ export default function Apps({ categories }: InferGetStaticPropsType<typeof getS
|
||||
return (
|
||||
<Shell isPublic large>
|
||||
<div className="text-md flex items-center gap-1 px-4 pb-3 pt-3 font-normal md:px-8 lg:px-0 lg:pt-0">
|
||||
<Link href="/apps">
|
||||
<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-6 w-24" />}{" "}
|
||||
</a>
|
||||
<Link
|
||||
href="/apps"
|
||||
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-6 w-24" />}{" "}
|
||||
</Link>
|
||||
</div>
|
||||
<div className="mb-16">
|
||||
<div className="grid h-auto w-full grid-cols-5 gap-3">
|
||||
{categories.map((category) => (
|
||||
<Link key={category.name} href={"/apps/categories/" + category.name}>
|
||||
<a
|
||||
data-testid={`app-store-category-${category.name}`}
|
||||
className="relative flex rounded-sm bg-gray-100 px-6 py-4 sm:block">
|
||||
<div className="self-center">
|
||||
<h3 className="font-medium capitalize">{category.name}</h3>
|
||||
<p className="text-sm text-gray-500">
|
||||
{t("number_apps", { count: category.count })}{" "}
|
||||
<Icon.FiArrowRight className="inline-block h-4 w-4" />
|
||||
</p>
|
||||
</div>
|
||||
</a>
|
||||
<Link
|
||||
key={category.name}
|
||||
href={"/apps/categories/" + category.name}
|
||||
data-testid={`app-store-category-${category.name}`}
|
||||
className="relative flex rounded-sm bg-gray-100 px-6 py-4 sm:block">
|
||||
<div className="self-center">
|
||||
<h3 className="font-medium capitalize">{category.name}</h3>
|
||||
<p className="text-sm text-gray-500">
|
||||
{t("number_apps", { count: category.count })}{" "}
|
||||
<Icon.FiArrowRight className="inline-block h-4 w-4" />
|
||||
</p>
|
||||
</div>
|
||||
</Link>
|
||||
))}
|
||||
</div>
|
||||
|
||||
@@ -7,7 +7,9 @@ import { getSession } from "@calcom/lib/auth";
|
||||
import { useLocale } from "@calcom/lib/hooks/useLocale";
|
||||
import type { AppCategories } from "@calcom/prisma/client";
|
||||
import { inferSSRProps } from "@calcom/types/inferSSRProps";
|
||||
import { AllApps, AppsLayout, AppStoreCategories, Icon, TextField, TrendingAppsSlider } from "@calcom/ui";
|
||||
import { AllApps, AppStoreCategories, Icon, TextField, TrendingAppsSlider } from "@calcom/ui";
|
||||
|
||||
import AppsLayout from "@components/apps/layouts/AppsLayout";
|
||||
|
||||
import { ssgInit } from "@server/lib/ssg";
|
||||
|
||||
|
||||
@@ -14,7 +14,6 @@ import {
|
||||
Button,
|
||||
EmptyScreen,
|
||||
Icon,
|
||||
InstalledAppsLayout,
|
||||
List,
|
||||
ShellSubHeading,
|
||||
AppSkeletonLoader as SkeletonLoader,
|
||||
@@ -24,6 +23,7 @@ import { QueryCell } from "@lib/QueryCell";
|
||||
|
||||
import { CalendarListContainer } from "@components/apps/CalendarListContainer";
|
||||
import IntegrationListItem from "@components/apps/IntegrationListItem";
|
||||
import InstalledAppsLayout from "@components/apps/layouts/InstalledAppsLayout";
|
||||
|
||||
function ConnectOrDisconnectIntegrationButton(props: {
|
||||
credentialIds: number[];
|
||||
@@ -32,7 +32,7 @@ function ConnectOrDisconnectIntegrationButton(props: {
|
||||
installed?: boolean;
|
||||
invalidCredentialIds?: number[];
|
||||
}) {
|
||||
const { type, credentialIds, isGlobal, installed, invalidCredentialIds } = props;
|
||||
const { type, credentialIds, isGlobal, installed } = props;
|
||||
const { t } = useLocale();
|
||||
const [credentialId] = credentialIds;
|
||||
|
||||
@@ -183,6 +183,7 @@ const IntegrationsContainer = ({ variant, exclude }: IntegrationsContainerProps)
|
||||
buttonRaw={
|
||||
<Button
|
||||
color="secondary"
|
||||
data-testid={`connect-${variant || "other"}-apps`}
|
||||
href={variant ? `/apps/categories/${variant}` : "/apps/categories/other"}>
|
||||
{t(`connect_${variant || "other"}_apps`)}
|
||||
</Button>
|
||||
|
||||
@@ -40,7 +40,7 @@ export default function Error() {
|
||||
</div>
|
||||
</div>
|
||||
<div className="mt-5 sm:mt-6">
|
||||
<Link href="/auth/login" passHref>
|
||||
<Link href="/auth/login" passHref legacyBehavior>
|
||||
<Button className="flex w-full justify-center">{t("go_back_login")}</Button>
|
||||
</Link>
|
||||
</div>
|
||||
|
||||
@@ -81,7 +81,7 @@ export default function Page({ resetPasswordRequest, csrfToken }: Props) {
|
||||
<h2 className="text-center text-3xl font-extrabold text-gray-900">{t("request_is_expired")}</h2>
|
||||
</div>
|
||||
<p>{t("request_is_expired_instructions")}</p>
|
||||
<Link href="/auth/forgot-password" passHref>
|
||||
<Link href="/auth/forgot-password" passHref legacyBehavior>
|
||||
<button
|
||||
type="button"
|
||||
className="flex w-full justify-center px-4 py-2 text-sm font-medium text-blue-600 focus:outline-none focus:ring-2 focus:ring-black focus:ring-offset-2">
|
||||
|
||||
@@ -94,8 +94,8 @@ export default function ForgotPassword({ csrfToken }: { csrfToken: string }) {
|
||||
footerText={
|
||||
!success && (
|
||||
<>
|
||||
<Link href="/auth/login">
|
||||
<a className="font-medium text-neutral-900">{t("back_to_signin")}</a>
|
||||
<Link href="/auth/login" className="font-medium text-neutral-900">
|
||||
{t("back_to_signin")}
|
||||
</Link>
|
||||
</>
|
||||
)
|
||||
|
||||
@@ -133,10 +133,11 @@ export default function Login({
|
||||
/>
|
||||
<div className="relative">
|
||||
<div className="absolute -top-[6px] z-10 ltr:right-0 rtl:left-0">
|
||||
<Link href="/auth/forgot-password">
|
||||
<a tabIndex={-1} className="text-sm font-medium text-gray-600">
|
||||
{t("forgot")}
|
||||
</a>
|
||||
<Link
|
||||
href="/auth/forgot-password"
|
||||
tabIndex={-1}
|
||||
className="text-sm font-medium text-gray-600">
|
||||
{t("forgot")}
|
||||
</Link>
|
||||
</div>
|
||||
<PasswordField
|
||||
|
||||
@@ -27,7 +27,7 @@ export default function Setup(props: inferSSRProps<typeof getServerSideProps>) {
|
||||
{
|
||||
title: t("enable_apps"),
|
||||
description: t("enable_apps_description"),
|
||||
content: <AdminAppsList baseURL="/auth/setup?step=2" />,
|
||||
content: <AdminAppsList baseURL="/auth/setup?step=2" useQueryParam={true} />,
|
||||
isLoading: false,
|
||||
},
|
||||
];
|
||||
|
||||
@@ -6,7 +6,7 @@ import * as React from "react";
|
||||
import { useEffect, useState, useRef } from "react";
|
||||
import z from "zod";
|
||||
|
||||
import { WEBAPP_URL } from "@calcom/lib/constants";
|
||||
import { APP_NAME, WEBAPP_URL } from "@calcom/lib/constants";
|
||||
import { trpc } from "@calcom/trpc/react";
|
||||
import { Button, showToast } from "@calcom/ui";
|
||||
|
||||
@@ -110,7 +110,7 @@ export default function Verify() {
|
||||
? "Your payment failed"
|
||||
: sessionId
|
||||
? "Payment successful!"
|
||||
: "Verify your email" + " | Cal.com"}
|
||||
: "Verify your email" + " | " + APP_NAME}
|
||||
</title>
|
||||
</Head>
|
||||
<div className="flex min-h-screen flex-col items-center justify-center px-6">
|
||||
|
||||
@@ -35,14 +35,13 @@ import { localStorage } from "@calcom/lib/webstorage";
|
||||
import prisma, { baseUserSelect } from "@calcom/prisma";
|
||||
import { Prisma } from "@calcom/prisma/client";
|
||||
import { customInputSchema, EventTypeMetaDataSchema } from "@calcom/prisma/zod-utils";
|
||||
import { Button, EmailInput, Icon } from "@calcom/ui";
|
||||
import { Button, EmailInput, Icon, HeadSeo } from "@calcom/ui";
|
||||
|
||||
import { timeZone } from "@lib/clock";
|
||||
import { inferSSRProps } from "@lib/types/inferSSRProps";
|
||||
|
||||
import CancelBooking from "@components/booking/CancelBooking";
|
||||
import EventReservationSchema from "@components/schemas/EventReservationSchema";
|
||||
import { HeadSeo } from "@components/seo/head-seo";
|
||||
|
||||
import { ssrInit } from "@server/lib/ssr";
|
||||
|
||||
@@ -354,10 +353,10 @@ export default function Success(props: SuccessProps) {
|
||||
)}
|
||||
{userIsOwner && !isEmbed && (
|
||||
<div className="mt-2 ml-4 -mb-4">
|
||||
<Link href={allRemainingBookings ? "/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 dark:hover:bg-transparent dark:hover:text-white">
|
||||
<Icon.FiChevronLeft className="h-5 w-5" /> {t("back_to_bookings")}
|
||||
</a>
|
||||
<Link
|
||||
href={allRemainingBookings ? "/bookings/recurring" : "/bookings/upcoming"}
|
||||
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")}
|
||||
</Link>
|
||||
</div>
|
||||
)}
|
||||
@@ -574,7 +573,9 @@ export default function Success(props: SuccessProps) {
|
||||
{!props.recurringBookings && (
|
||||
<span className="text-bookinglight inline text-gray-700">
|
||||
<span className="underline">
|
||||
<Link href={`/reschedule/${bookingInfo?.uid}`}>{t("reschedule")}</Link>
|
||||
<Link href={`/reschedule/${bookingInfo?.uid}`} legacyBehavior>
|
||||
{t("reschedule")}
|
||||
</Link>
|
||||
</span>
|
||||
<span className="mx-2">{t("or_lowercase")}</span>
|
||||
</span>
|
||||
@@ -634,17 +635,16 @@ export default function Success(props: SuccessProps) {
|
||||
? "&recur=" +
|
||||
encodeURIComponent(new RRule(props.eventType.recurringEvent).toString())
|
||||
: "")
|
||||
}>
|
||||
<a className="h-10 w-10 rounded-sm border border-neutral-200 px-3 py-2 ltr:mr-2 rtl:ml-2 dark:border-neutral-700 dark:text-white">
|
||||
<svg
|
||||
className="-mt-1.5 inline-block h-4 w-4"
|
||||
fill="currentColor"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
viewBox="0 0 24 24">
|
||||
<title>Google</title>
|
||||
<path d="M12.48 10.92v3.28h7.84c-.24 1.84-.853 3.187-1.787 4.133-1.147 1.147-2.933 2.4-6.053 2.4-4.827 0-8.6-3.893-8.6-8.72s3.773-8.72 8.6-8.72c2.6 0 4.507 1.027 5.907 2.347l2.307-2.307C18.747 1.44 16.133 0 12.48 0 5.867 0 .307 5.387.307 12s5.56 12 12.173 12c3.573 0 6.267-1.173 8.373-3.36 2.16-2.16 2.84-5.213 2.84-7.667 0-.76-.053-1.467-.173-2.053H12.48z" />
|
||||
</svg>
|
||||
</a>
|
||||
}
|
||||
className="h-10 w-10 rounded-sm border border-neutral-200 px-3 py-2 ltr:mr-2 rtl:ml-2 dark:border-neutral-700 dark:text-white">
|
||||
<svg
|
||||
className="-mt-1.5 inline-block h-4 w-4"
|
||||
fill="currentColor"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
viewBox="0 0 24 24">
|
||||
<title>Google</title>
|
||||
<path d="M12.48 10.92v3.28h7.84c-.24 1.84-.853 3.187-1.787 4.133-1.147 1.147-2.933 2.4-6.053 2.4-4.827 0-8.6-3.893-8.6-8.72s3.773-8.72 8.6-8.72c2.6 0 4.507 1.027 5.907 2.347l2.307-2.307C18.747 1.44 16.133 0 12.48 0 5.867 0 .307 5.387.307 12s5.56 12 12.173 12c3.573 0 6.267-1.173 8.373-3.36 2.16-2.16 2.84-5.213 2.84-7.667 0-.76-.053-1.467-.173-2.053H12.48z" />
|
||||
</svg>
|
||||
</Link>
|
||||
<Link
|
||||
href={
|
||||
@@ -658,19 +658,17 @@ export default function Success(props: SuccessProps) {
|
||||
"&subject=" +
|
||||
eventName
|
||||
) + (location ? "&location=" + location : "")
|
||||
}>
|
||||
<a
|
||||
className="mx-2 h-10 w-10 rounded-sm border border-neutral-200 px-3 py-2 dark:border-neutral-700 dark:text-white"
|
||||
target="_blank">
|
||||
<svg
|
||||
className="mr-1 -mt-1.5 inline-block h-4 w-4"
|
||||
fill="currentColor"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
viewBox="0 0 24 24">
|
||||
<title>Microsoft Outlook</title>
|
||||
<path d="M7.88 12.04q0 .45-.11.87-.1.41-.33.74-.22.33-.58.52-.37.2-.87.2t-.85-.2q-.35-.21-.57-.55-.22-.33-.33-.75-.1-.42-.1-.86t.1-.87q.1-.43.34-.76.22-.34.59-.54.36-.2.87-.2t.86.2q.35.21.57.55.22.34.31.77.1.43.1.88zM24 12v9.38q0 .46-.33.8-.33.32-.8.32H7.13q-.46 0-.8-.33-.32-.33-.32-.8V18H1q-.41 0-.7-.3-.3-.29-.3-.7V7q0-.41.3-.7Q.58 6 1 6h6.5V2.55q0-.44.3-.75.3-.3.75-.3h12.9q.44 0 .75.3.3.3.3.75V10.85l1.24.72h.01q.1.07.18.18.07.12.07.25zm-6-8.25v3h3v-3zm0 4.5v3h3v-3zm0 4.5v1.83l3.05-1.83zm-5.25-9v3h3.75v-3zm0 4.5v3h3.75v-3zm0 4.5v2.03l2.41 1.5 1.34-.8v-2.73zM9 3.75V6h2l.13.01.12.04v-2.3zM5.98 15.98q.9 0 1.6-.3.7-.32 1.19-.86.48-.55.73-1.28.25-.74.25-1.61 0-.83-.25-1.55-.24-.71-.71-1.24t-1.15-.83q-.68-.3-1.55-.3-.92 0-1.64.3-.71.3-1.2.85-.5.54-.75 1.3-.25.74-.25 1.63 0 .85.26 1.56.26.72.74 1.23.48.52 1.17.81.69.3 1.56.3zM7.5 21h12.39L12 16.08V17q0 .41-.3.7-.29.3-.7.3H7.5zm15-.13v-7.24l-5.9 3.54Z" />
|
||||
</svg>
|
||||
</a>
|
||||
}
|
||||
className="mx-2 h-10 w-10 rounded-sm border border-neutral-200 px-3 py-2 dark:border-neutral-700 dark:text-white"
|
||||
target="_blank">
|
||||
<svg
|
||||
className="mr-1 -mt-1.5 inline-block h-4 w-4"
|
||||
fill="currentColor"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
viewBox="0 0 24 24">
|
||||
<title>Microsoft Outlook</title>
|
||||
<path d="M7.88 12.04q0 .45-.11.87-.1.41-.33.74-.22.33-.58.52-.37.2-.87.2t-.85-.2q-.35-.21-.57-.55-.22-.33-.33-.75-.1-.42-.1-.86t.1-.87q.1-.43.34-.76.22-.34.59-.54.36-.2.87-.2t.86.2q.35.21.57.55.22.34.31.77.1.43.1.88zM24 12v9.38q0 .46-.33.8-.33.32-.8.32H7.13q-.46 0-.8-.33-.32-.33-.32-.8V18H1q-.41 0-.7-.3-.3-.29-.3-.7V7q0-.41.3-.7Q.58 6 1 6h6.5V2.55q0-.44.3-.75.3-.3.75-.3h12.9q.44 0 .75.3.3.3.3.75V10.85l1.24.72h.01q.1.07.18.18.07.12.07.25zm-6-8.25v3h3v-3zm0 4.5v3h3v-3zm0 4.5v1.83l3.05-1.83zm-5.25-9v3h3.75v-3zm0 4.5v3h3.75v-3zm0 4.5v2.03l2.41 1.5 1.34-.8v-2.73zM9 3.75V6h2l.13.01.12.04v-2.3zM5.98 15.98q.9 0 1.6-.3.7-.32 1.19-.86.48-.55.73-1.28.25-.74.25-1.61 0-.83-.25-1.55-.24-.71-.71-1.24t-1.15-.83q-.68-.3-1.55-.3-.92 0-1.64.3-.71.3-1.2.85-.5.54-.75 1.3-.25.74-.25 1.63 0 .85.26 1.56.26.72.74 1.23.48.52 1.17.81.69.3 1.56.3zM7.5 21h12.39L12 16.08V17q0 .41-.3.7-.29.3-.7.3H7.5zm15-.13v-7.24l-5.9 3.54Z" />
|
||||
</svg>
|
||||
</Link>
|
||||
<Link
|
||||
href={
|
||||
@@ -684,34 +682,31 @@ export default function Success(props: SuccessProps) {
|
||||
"&subject=" +
|
||||
eventName
|
||||
) + (location ? "&location=" + location : "")
|
||||
}>
|
||||
<a
|
||||
className="mx-2 h-10 w-10 rounded-sm border border-neutral-200 px-3 py-2 dark:border-neutral-700 dark:text-white"
|
||||
target="_blank">
|
||||
<svg
|
||||
className="mr-1 -mt-1.5 inline-block h-4 w-4"
|
||||
fill="currentColor"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
viewBox="0 0 24 24">
|
||||
<title>Microsoft Office</title>
|
||||
<path d="M21.53 4.306v15.363q0 .807-.472 1.433-.472.627-1.253.85l-6.888 1.974q-.136.037-.29.055-.156.019-.293.019-.396 0-.72-.105-.321-.106-.656-.292l-4.505-2.544q-.248-.137-.391-.366-.143-.23-.143-.515 0-.434.304-.738.304-.305.739-.305h5.831V4.964l-4.38 1.563q-.533.187-.856.658-.322.472-.322 1.03v8.078q0 .496-.248.912-.25.416-.683.651l-2.072 1.13q-.286.148-.571.148-.497 0-.844-.347-.348-.347-.348-.844V6.563q0-.62.33-1.19.328-.571.874-.881L11.07.285q.248-.136.534-.21.285-.075.57-.075.211 0 .38.031.166.031.364.093l6.888 1.899q.384.11.7.329.317.217.547.52.23.305.353.67.125.367.125.764zm-1.588 15.363V4.306q0-.273-.16-.478-.163-.204-.423-.28l-3.388-.93q-.397-.111-.794-.23-.397-.117-.794-.216v19.68l4.976-1.427q.26-.074.422-.28.161-.204.161-.477z" />
|
||||
</svg>
|
||||
</a>
|
||||
}
|
||||
className="mx-2 h-10 w-10 rounded-sm border border-neutral-200 px-3 py-2 dark:border-neutral-700 dark:text-white"
|
||||
target="_blank">
|
||||
<svg
|
||||
className="mr-1 -mt-1.5 inline-block h-4 w-4"
|
||||
fill="currentColor"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
viewBox="0 0 24 24">
|
||||
<title>Microsoft Office</title>
|
||||
<path d="M21.53 4.306v15.363q0 .807-.472 1.433-.472.627-1.253.85l-6.888 1.974q-.136.037-.29.055-.156.019-.293.019-.396 0-.72-.105-.321-.106-.656-.292l-4.505-2.544q-.248-.137-.391-.366-.143-.23-.143-.515 0-.434.304-.738.304-.305.739-.305h5.831V4.964l-4.38 1.563q-.533.187-.856.658-.322.472-.322 1.03v8.078q0 .496-.248.912-.25.416-.683.651l-2.072 1.13q-.286.148-.571.148-.497 0-.844-.347-.348-.347-.348-.844V6.563q0-.62.33-1.19.328-.571.874-.881L11.07.285q.248-.136.534-.21.285-.075.57-.075.211 0 .38.031.166.031.364.093l6.888 1.899q.384.11.7.329.317.217.547.52.23.305.353.67.125.367.125.764zm-1.588 15.363V4.306q0-.273-.16-.478-.163-.204-.423-.28l-3.388-.93q-.397-.111-.794-.23-.397-.117-.794-.216v19.68l4.976-1.427q.26-.074.422-.28.161-.204.161-.477z" />
|
||||
</svg>
|
||||
</Link>
|
||||
<Link href={"data:text/calendar," + eventLink()}>
|
||||
<a
|
||||
className="mx-2 h-10 w-10 rounded-sm border border-neutral-200 px-3 py-2 dark:border-neutral-700 dark:text-white"
|
||||
download={props.eventType.title + ".ics"}>
|
||||
<svg
|
||||
version="1.1"
|
||||
fill="currentColor"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
viewBox="0 0 1000 1000"
|
||||
className="mr-1 -mt-1.5 inline-block h-4 w-4">
|
||||
<title>{t("other")}</title>
|
||||
<path d="M971.3,154.9c0-34.7-28.2-62.9-62.9-62.9H611.7c-1.3,0-2.6,0.1-3.9,0.2V10L28.7,87.3v823.4L607.8,990v-84.6c1.3,0.1,2.6,0.2,3.9,0.2h296.7c34.7,0,62.9-28.2,62.9-62.9V154.9z M607.8,636.1h44.6v-50.6h-44.6v-21.9h44.6v-50.6h-44.6v-92h277.9v230.2c0,3.8-3.1,7-7,7H607.8V636.1z M117.9,644.7l-50.6-2.4V397.5l50.6-2.2V644.7z M288.6,607.3c17.6,0.6,37.3-2.8,49.1-7.2l9.1,48c-11,5.1-35.6,9.9-66.9,8.3c-85.4-4.3-127.5-60.7-127.5-132.6c0-86.2,57.8-136.7,133.2-140.1c30.3-1.3,53.7,4,64.3,9.2l-12.2,48.9c-12.1-4.9-28.8-9.2-49.5-8.6c-45.3,1.2-79.5,30.1-79.5,87.4C208.8,572.2,237.8,605.7,288.6,607.3z M455.5,665.2c-32.4-1.6-63.7-11.3-79.1-20.5l12.6-50.7c16.8,9.1,42.9,18.5,70.4,19.4c30.1,1,46.3-10.7,46.3-29.3c0-17.8-14-28.1-48.8-40.6c-46.9-16.4-76.8-41.7-76.8-81.5c0-46.6,39.3-84.1,106.8-87.1c33.3-1.5,58.3,4.2,76.5,11.2l-15.4,53.3c-12.1-5.3-33.5-12.8-62.3-12c-28.3,0.8-41.9,13.6-41.9,28.1c0,17.8,16.1,25.5,53.6,39c52.9,18.5,78.4,45.3,78.4,86.4C575.6,629.7,536.2,669.2,455.5,665.2z M935.3,842.7c0,14.9-12.1,27-27,27H611.7c-1.3,0-2.6-0.2-3.9-0.4V686.2h270.9c19.2,0,34.9-15.6,34.9-34.9V398.4c0-19.2-15.6-34.9-34.9-34.9h-47.1v-32.3H808v32.3h-44.8v-32.3h-22.7v32.3h-43.3v-32.3h-22.7v32.3H628v-32.3h-20.2v-203c1.31.2,2.6-0.4,3.9-0.4h296.7c14.9,0,27,12.1,27,27L935.3,842.7L935.3,842.7z" />
|
||||
</svg>
|
||||
</a>
|
||||
<Link
|
||||
href={"data:text/calendar," + eventLink()}
|
||||
className="mx-2 h-10 w-10 rounded-sm border border-neutral-200 px-3 py-2 dark:border-neutral-700 dark:text-white"
|
||||
download={props.eventType.title + ".ics"}>
|
||||
<svg
|
||||
version="1.1"
|
||||
fill="currentColor"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
viewBox="0 0 1000 1000"
|
||||
className="mr-1 -mt-1.5 inline-block h-4 w-4">
|
||||
<title>{t("other")}</title>
|
||||
<path d="M971.3,154.9c0-34.7-28.2-62.9-62.9-62.9H611.7c-1.3,0-2.6,0.1-3.9,0.2V10L28.7,87.3v823.4L607.8,990v-84.6c1.3,0.1,2.6,0.2,3.9,0.2h296.7c34.7,0,62.9-28.2,62.9-62.9V154.9z M607.8,636.1h44.6v-50.6h-44.6v-21.9h44.6v-50.6h-44.6v-92h277.9v230.2c0,3.8-3.1,7-7,7H607.8V636.1z M117.9,644.7l-50.6-2.4V397.5l50.6-2.2V644.7z M288.6,607.3c17.6,0.6,37.3-2.8,49.1-7.2l9.1,48c-11,5.1-35.6,9.9-66.9,8.3c-85.4-4.3-127.5-60.7-127.5-132.6c0-86.2,57.8-136.7,133.2-140.1c30.3-1.3,53.7,4,64.3,9.2l-12.2,48.9c-12.1-4.9-28.8-9.2-49.5-8.6c-45.3,1.2-79.5,30.1-79.5,87.4C208.8,572.2,237.8,605.7,288.6,607.3z M455.5,665.2c-32.4-1.6-63.7-11.3-79.1-20.5l12.6-50.7c16.8,9.1,42.9,18.5,70.4,19.4c30.1,1,46.3-10.7,46.3-29.3c0-17.8-14-28.1-48.8-40.6c-46.9-16.4-76.8-41.7-76.8-81.5c0-46.6,39.3-84.1,106.8-87.1c33.3-1.5,58.3,4.2,76.5,11.2l-15.4,53.3c-12.1-5.3-33.5-12.8-62.3-12c-28.3,0.8-41.9,13.6-41.9,28.1c0,17.8,16.1,25.5,53.6,39c52.9,18.5,78.4,45.3,78.4,86.4C575.6,629.7,536.2,669.2,455.5,665.2z M935.3,842.7c0,14.9-12.1,27-27,27H611.7c-1.3,0-2.6-0.2-3.9-0.4V686.2h270.9c19.2,0,34.9-15.6,34.9-34.9V398.4c0-19.2-15.6-34.9-34.9-34.9h-47.1v-32.3H808v32.3h-44.8v-32.3h-22.7v32.3h-43.3v-32.3h-22.7v32.3H628v-32.3h-20.2v-203c1.31.2,2.6-0.4,3.9-0.4h296.7c14.9,0,27,12.1,27,27L935.3,842.7L935.3,842.7z" />
|
||||
</svg>
|
||||
</Link>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -3,7 +3,6 @@ import { useAutoAnimate } from "@formkit/auto-animate/react";
|
||||
import { zodResolver } from "@hookform/resolvers/zod";
|
||||
import { PeriodType, SchedulingType } from "@prisma/client";
|
||||
import { GetServerSidePropsContext } from "next";
|
||||
import { useRouter } from "next/router";
|
||||
import { useState } from "react";
|
||||
import { useForm } from "react-hook-form";
|
||||
import { z } from "zod";
|
||||
@@ -15,6 +14,7 @@ import convertToNewDurationType from "@calcom/lib/convertToNewDurationType";
|
||||
import findDurationType from "@calcom/lib/findDurationType";
|
||||
import getEventTypeById from "@calcom/lib/getEventTypeById";
|
||||
import { useLocale } from "@calcom/lib/hooks/useLocale";
|
||||
import { useTypedQuery } from "@calcom/lib/hooks/useTypedQuery";
|
||||
import { HttpError } from "@calcom/lib/http-error";
|
||||
import prisma from "@calcom/prisma";
|
||||
import { customInputSchema, EventTypeMetaDataSchema } from "@calcom/prisma/zod-utils";
|
||||
@@ -111,8 +111,9 @@ export type EventTypeSetupProps = RouterOutputs["viewer"]["eventTypes"]["get"];
|
||||
const EventTypePage = (props: EventTypeSetupProps) => {
|
||||
const { t } = useLocale();
|
||||
const utils = trpc.useContext();
|
||||
const router = useRouter();
|
||||
const { tabName } = querySchema.parse(router.query);
|
||||
const {
|
||||
data: { tabName },
|
||||
} = useTypedQuery(querySchema);
|
||||
|
||||
const { data: eventTypeApps } = trpc.viewer.apps.useQuery({
|
||||
extendsFeature: "EventType",
|
||||
|
||||
@@ -64,27 +64,26 @@ const Item = ({ type, group, readOnly }: { type: EventType; group: EventTypeGrou
|
||||
const { t } = useLocale();
|
||||
|
||||
return (
|
||||
<Link href={`/event-types/${type.id}?tabName=setup`}>
|
||||
<a
|
||||
className="flex-1 overflow-hidden pr-4 text-sm"
|
||||
title={`${type.title} ${type.description ? `– ${type.description}` : ""}`}>
|
||||
<div>
|
||||
<span
|
||||
className="font-semibold text-gray-700 ltr:mr-1 rtl:ml-1"
|
||||
data-testid={"event-type-title-" + type.id}>
|
||||
{type.title}
|
||||
<Link
|
||||
href={`/event-types/${type.id}?tabName=setup`}
|
||||
className="flex-1 overflow-hidden pr-4 text-sm"
|
||||
title={`${type.title} ${type.description ? `– ${type.description}` : ""}`}>
|
||||
<div>
|
||||
<span
|
||||
className="font-semibold text-gray-700 ltr:mr-1 rtl:ml-1"
|
||||
data-testid={"event-type-title-" + type.id}>
|
||||
{type.title}
|
||||
</span>
|
||||
<small
|
||||
className="hidden font-normal leading-4 text-gray-600 sm:inline"
|
||||
data-testid={"event-type-slug-" + type.id}>{`/${group.profile.slug}/${type.slug}`}</small>
|
||||
{readOnly && (
|
||||
<span className="rtl:ml-2inline items-center rounded-sm bg-gray-100 px-1.5 py-0.5 text-xs font-medium text-gray-800 ltr:ml-2 ltr:mr-2">
|
||||
{t("readonly")}
|
||||
</span>
|
||||
<small
|
||||
className="hidden font-normal leading-4 text-gray-600 sm:inline"
|
||||
data-testid={"event-type-slug-" + type.id}>{`/${group.profile.slug}/${type.slug}`}</small>
|
||||
{readOnly && (
|
||||
<span className="rtl:ml-2inline items-center rounded-sm bg-gray-100 px-1.5 py-0.5 text-xs font-medium text-gray-800 ltr:ml-2 ltr:mr-2">
|
||||
{t("readonly") as string}
|
||||
</span>
|
||||
)}
|
||||
</div>
|
||||
<EventTypeDescription eventType={type} />
|
||||
</a>
|
||||
)}
|
||||
</div>
|
||||
<EventTypeDescription eventType={type} />
|
||||
</Link>
|
||||
);
|
||||
};
|
||||
@@ -297,7 +296,7 @@ export const EventTypeList = ({ group, groupIndex, readOnly, types }: EventTypeL
|
||||
{t("hidden")}
|
||||
</Badge>
|
||||
)}
|
||||
<Tooltip content={t("show_eventtype_on_profile") as string}>
|
||||
<Tooltip content={t("show_eventtype_on_profile")}>
|
||||
<div className="self-center rounded-md p-2 hover:bg-gray-200">
|
||||
<Switch
|
||||
name="Hidden"
|
||||
@@ -310,7 +309,7 @@ export const EventTypeList = ({ group, groupIndex, readOnly, types }: EventTypeL
|
||||
</Tooltip>
|
||||
|
||||
<ButtonGroup combined>
|
||||
<Tooltip content={t("preview") as string}>
|
||||
<Tooltip content={t("preview")}>
|
||||
<Button
|
||||
color="secondary"
|
||||
target="_blank"
|
||||
@@ -320,7 +319,7 @@ export const EventTypeList = ({ group, groupIndex, readOnly, types }: EventTypeL
|
||||
/>
|
||||
</Tooltip>
|
||||
|
||||
<Tooltip content={t("copy_link") as string}>
|
||||
<Tooltip content={t("copy_link")}>
|
||||
<Button
|
||||
color="secondary"
|
||||
size="icon"
|
||||
@@ -350,7 +349,7 @@ export const EventTypeList = ({ group, groupIndex, readOnly, types }: EventTypeL
|
||||
data-testid={"event-type-edit-" + type.id}
|
||||
StartIcon={Icon.FiEdit2}
|
||||
onClick={() => router.push("/event-types/" + type.id)}>
|
||||
{t("edit") as string}
|
||||
{t("edit")}
|
||||
</DropdownItem>
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuItem className="outline-none">
|
||||
@@ -359,7 +358,7 @@ export const EventTypeList = ({ group, groupIndex, readOnly, types }: EventTypeL
|
||||
data-testid={"event-type-duplicate-" + type.id}
|
||||
StartIcon={Icon.FiCopy}
|
||||
onClick={() => openDuplicateModal(type)}>
|
||||
{t("duplicate") as string}
|
||||
{t("duplicate")}
|
||||
</DropdownItem>
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuItem className="outline-none">
|
||||
@@ -383,7 +382,7 @@ export const EventTypeList = ({ group, groupIndex, readOnly, types }: EventTypeL
|
||||
}}
|
||||
StartIcon={Icon.FiTrash}
|
||||
className="w-full rounded-none">
|
||||
{t("delete") as string}
|
||||
{t("delete")}
|
||||
</DropdownItem>
|
||||
</DropdownMenuItem>
|
||||
)}
|
||||
@@ -402,15 +401,13 @@ export const EventTypeList = ({ group, groupIndex, readOnly, types }: EventTypeL
|
||||
<DropdownMenuPortal>
|
||||
<DropdownMenuContent>
|
||||
<DropdownMenuItem className="outline-none">
|
||||
<Link href={calLink}>
|
||||
<a target="_blank">
|
||||
<Button
|
||||
color="minimal"
|
||||
StartIcon={Icon.FiExternalLink}
|
||||
className="w-full rounded-none">
|
||||
{t("preview") as string}
|
||||
</Button>
|
||||
</a>
|
||||
<Link href={calLink} target="_blank">
|
||||
<Button
|
||||
color="minimal"
|
||||
StartIcon={Icon.FiExternalLink}
|
||||
className="w-full rounded-none">
|
||||
{t("preview")}
|
||||
</Button>
|
||||
</Link>
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuItem className="outline-none">
|
||||
@@ -424,7 +421,7 @@ export const EventTypeList = ({ group, groupIndex, readOnly, types }: EventTypeL
|
||||
navigator.clipboard.writeText(calLink);
|
||||
showToast(t("link_copied"), "success");
|
||||
}}>
|
||||
{t("copy_link") as string}
|
||||
{t("copy_link")}
|
||||
</Button>
|
||||
</DropdownMenuItem>
|
||||
{isNativeShare ? (
|
||||
@@ -445,7 +442,7 @@ export const EventTypeList = ({ group, groupIndex, readOnly, types }: EventTypeL
|
||||
.then(() => showToast(t("link_shared"), "success"))
|
||||
.catch(() => showToast(t("failed"), "error"));
|
||||
}}>
|
||||
{t("share") as string}
|
||||
{t("share")}
|
||||
</Button>
|
||||
</DropdownMenuItem>
|
||||
) : null}
|
||||
@@ -456,7 +453,7 @@ export const EventTypeList = ({ group, groupIndex, readOnly, types }: EventTypeL
|
||||
color="minimal"
|
||||
className="w-full rounded-none"
|
||||
StartIcon={Icon.FiEdit}>
|
||||
{t("edit") as string}
|
||||
{t("edit")}
|
||||
</Button>
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuItem className="outline-none">
|
||||
@@ -467,7 +464,7 @@ export const EventTypeList = ({ group, groupIndex, readOnly, types }: EventTypeL
|
||||
data-testid={"event-type-duplicate-" + type.id}
|
||||
StartIcon={Icon.FiCopy}
|
||||
onClick={() => openDuplicateModal(type)}>
|
||||
{t("duplicate") as string}
|
||||
{t("duplicate")}
|
||||
</Button>
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuSeparator className="h-px bg-gray-200" />
|
||||
@@ -480,7 +477,7 @@ export const EventTypeList = ({ group, groupIndex, readOnly, types }: EventTypeL
|
||||
color="destructive"
|
||||
StartIcon={Icon.FiTrash}
|
||||
className="w-full rounded-none">
|
||||
{t("delete") as string}
|
||||
{t("delete")}
|
||||
</Button>
|
||||
</DropdownMenuItem>
|
||||
</DropdownMenuContent>
|
||||
@@ -502,7 +499,7 @@ export const EventTypeList = ({ group, groupIndex, readOnly, types }: EventTypeL
|
||||
e.preventDefault();
|
||||
deleteEventTypeHandler(deleteDialogTypeId);
|
||||
}}>
|
||||
{t("delete_event_type_description") as string}
|
||||
{t("delete_event_type_description")}
|
||||
</ConfirmationDialogContent>
|
||||
</Dialog>
|
||||
</div>
|
||||
@@ -517,36 +514,32 @@ const EventTypeListHeading = ({
|
||||
return (
|
||||
<div className="mb-4 flex">
|
||||
<Link href={teamId ? `/settings/teams/${teamId}/profile` : "/settings/my-account/profile"}>
|
||||
<a>
|
||||
<Avatar
|
||||
alt={profile?.name || ""}
|
||||
imageSrc={`${WEBAPP_URL}/${profile.slug}/avatar.png` || undefined}
|
||||
size={8}
|
||||
className="mt-1 inline ltr:mr-2 rtl:ml-2"
|
||||
/>
|
||||
</a>
|
||||
<Avatar
|
||||
alt={profile?.name || ""}
|
||||
imageSrc={`${WEBAPP_URL}/${profile.slug}/avatar.png` || undefined}
|
||||
size={8}
|
||||
className="mt-1 inline ltr:mr-2 rtl:ml-2"
|
||||
/>
|
||||
</Link>
|
||||
<div>
|
||||
<Link href={teamId ? `/settings/teams/${teamId}/profile` : "/settings/my-account/profile"}>
|
||||
<a className="font-bold">{profile?.name || ""}</a>
|
||||
<Link
|
||||
href={teamId ? `/settings/teams/${teamId}/profile` : "/settings/my-account/profile"}
|
||||
className="font-bold">
|
||||
{profile?.name || ""}
|
||||
</Link>
|
||||
{membershipCount && teamId && (
|
||||
<span className="relative -top-px text-xs text-neutral-500 ltr:ml-2 ltr:mr-2 rtl:ml-2">
|
||||
<Link href={`/settings/teams/${teamId}/members`}>
|
||||
<a>
|
||||
<Badge variant="gray">
|
||||
<Icon.FiUsers className="mr-1 -mt-px inline h-3 w-3" />
|
||||
{membershipCount}
|
||||
</Badge>
|
||||
</a>
|
||||
<Badge variant="gray">
|
||||
<Icon.FiUsers className="mr-1 -mt-px inline h-3 w-3" />
|
||||
{membershipCount}
|
||||
</Badge>
|
||||
</Link>
|
||||
</span>
|
||||
)}
|
||||
{profile?.slug && (
|
||||
<Link href={`${CAL_URL}/${profile.slug}`}>
|
||||
<a className="block text-xs text-neutral-500">{`${CAL_URL?.replace("https://", "")}/${
|
||||
profile.slug
|
||||
}`}</a>
|
||||
<Link href={`${CAL_URL}/${profile.slug}`} className="block text-xs text-neutral-500">
|
||||
{`${CAL_URL?.replace("https://", "")}/${profile.slug}`}
|
||||
</Link>
|
||||
)}
|
||||
</div>
|
||||
@@ -581,10 +574,7 @@ const EventTypesPage = () => {
|
||||
|
||||
return (
|
||||
<div>
|
||||
<Shell
|
||||
heading={t("event_types_page_title") as string}
|
||||
subtitle={t("event_types_page_subtitle") as string}
|
||||
CTA={<CTA />}>
|
||||
<Shell heading={t("event_types_page_title")} subtitle={t("event_types_page_subtitle")} CTA={<CTA />}>
|
||||
<WithQuery
|
||||
customLoader={<SkeletonLoader />}
|
||||
success={({ data }) => (
|
||||
|
||||
@@ -2,7 +2,9 @@ import { GetServerSidePropsContext } from "next";
|
||||
|
||||
import AdminAppsList from "@calcom/features/apps/AdminAppsList";
|
||||
import { useLocale } from "@calcom/lib/hooks/useLocale";
|
||||
import { getAdminLayout as getLayout, Meta } from "@calcom/ui";
|
||||
import { Meta } from "@calcom/ui";
|
||||
|
||||
import { getLayout } from "@components/auth/layouts/AdminLayout";
|
||||
|
||||
import { ssrInit } from "@server/lib/ssr";
|
||||
|
||||
@@ -11,7 +13,7 @@ function AdminAppsView() {
|
||||
return (
|
||||
<>
|
||||
<Meta title={t("apps")} description={t("admin_apps_description")} />
|
||||
<AdminAppsList baseURL="/settings/admin/apps" className="w-0" />
|
||||
<AdminAppsList baseURL="/settings/admin/apps" />
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,2 @@
|
||||
export { getServerSideProps } from "./[category]";
|
||||
export { default } from "./[category]";
|
||||
@@ -3,7 +3,9 @@ import { signIn } from "next-auth/react";
|
||||
import { useRef } from "react";
|
||||
|
||||
import { useLocale } from "@calcom/lib/hooks/useLocale";
|
||||
import { Button, getAdminLayout as getLayout, Meta, TextField } from "@calcom/ui";
|
||||
import { Button, Meta, TextField } from "@calcom/ui";
|
||||
|
||||
import { getLayout } from "@components/auth/layouts/AdminLayout";
|
||||
|
||||
import { ssrInit } from "@server/lib/ssr";
|
||||
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
import { GetServerSidePropsContext } from "next";
|
||||
|
||||
import { getAdminLayout as getLayout, Meta } from "@calcom/ui";
|
||||
import { Meta } from "@calcom/ui";
|
||||
|
||||
import { getLayout } from "@components/auth/layouts/AdminLayout";
|
||||
|
||||
import { ssrInit } from "@server/lib/ssr";
|
||||
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
import { GetServerSidePropsContext } from "next";
|
||||
|
||||
import { useLocale } from "@calcom/lib/hooks/useLocale";
|
||||
import { getAdminLayout as getLayout, Meta } from "@calcom/ui";
|
||||
import { Meta } from "@calcom/ui";
|
||||
|
||||
import { getLayout } from "@components/auth/layouts/AdminLayout";
|
||||
|
||||
import { ssrInit } from "@server/lib/ssr";
|
||||
|
||||
|
||||
@@ -3,11 +3,12 @@ import { useRouter } from "next/router";
|
||||
import { useState } from "react";
|
||||
import { HelpScout, useChat } from "react-live-chat-loader";
|
||||
|
||||
import { getLayout } from "@calcom/features/settings/layouts/SettingsLayout";
|
||||
import { classNames } from "@calcom/lib";
|
||||
import { WEBAPP_URL } from "@calcom/lib/constants";
|
||||
import { useLocale } from "@calcom/lib/hooks/useLocale";
|
||||
import { trpc } from "@calcom/trpc/react";
|
||||
import { Button, getSettingsLayout as getLayout, Icon, Meta } from "@calcom/ui";
|
||||
import { Button, Icon, Meta } from "@calcom/ui";
|
||||
|
||||
import { ssrInit } from "@server/lib/ssr";
|
||||
|
||||
|
||||
@@ -5,6 +5,7 @@ import { TApiKeys } from "@calcom/ee/api-keys/components/ApiKeyListItem";
|
||||
import LicenseRequired from "@calcom/ee/common/components/v2/LicenseRequired";
|
||||
import ApiKeyDialogForm from "@calcom/features/ee/api-keys/components/ApiKeyDialogForm";
|
||||
import ApiKeyListItem from "@calcom/features/ee/api-keys/components/ApiKeyListItem";
|
||||
import { getLayout } from "@calcom/features/settings/layouts/SettingsLayout";
|
||||
import { APP_NAME } from "@calcom/lib/constants";
|
||||
import { useLocale } from "@calcom/lib/hooks/useLocale";
|
||||
import { trpc } from "@calcom/trpc/react";
|
||||
@@ -13,7 +14,6 @@ import {
|
||||
Dialog,
|
||||
DialogContent,
|
||||
EmptyScreen,
|
||||
getSettingsLayout as getLayout,
|
||||
Icon,
|
||||
Meta,
|
||||
AppSkeletonLoader as SkeletonLoader,
|
||||
|
||||
@@ -2,6 +2,7 @@ import { GetServerSidePropsContext } from "next";
|
||||
import { useSession } from "next-auth/react";
|
||||
import { Controller, useForm } from "react-hook-form";
|
||||
|
||||
import { getLayout } from "@calcom/features/settings/layouts/SettingsLayout";
|
||||
import { APP_NAME } from "@calcom/lib/constants";
|
||||
import { useLocale } from "@calcom/lib/hooks/useLocale";
|
||||
import { trpc } from "@calcom/trpc/react";
|
||||
@@ -10,7 +11,6 @@ import {
|
||||
Button,
|
||||
ColorPicker,
|
||||
Form,
|
||||
getSettingsLayout as getLayout,
|
||||
Meta,
|
||||
showToast,
|
||||
SkeletonButton,
|
||||
|
||||
@@ -6,6 +6,7 @@ import { Fragment } from "react";
|
||||
|
||||
import DisconnectIntegration from "@calcom/features/apps/components/DisconnectIntegration";
|
||||
import DestinationCalendarSelector from "@calcom/features/calendars/DestinationCalendarSelector";
|
||||
import { getLayout } from "@calcom/features/settings/layouts/SettingsLayout";
|
||||
import { useLocale } from "@calcom/lib/hooks/useLocale";
|
||||
import { trpc } from "@calcom/trpc/react";
|
||||
import {
|
||||
@@ -13,7 +14,6 @@ import {
|
||||
Badge,
|
||||
Button,
|
||||
EmptyScreen,
|
||||
getSettingsLayout as getLayout,
|
||||
Icon,
|
||||
List,
|
||||
ListItem,
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { GetServerSidePropsContext } from "next";
|
||||
import { useState } from "react";
|
||||
|
||||
import { getLayout } from "@calcom/features/settings/layouts/SettingsLayout";
|
||||
import { useLocale } from "@calcom/lib/hooks/useLocale";
|
||||
import { trpc } from "@calcom/trpc/react";
|
||||
import {
|
||||
@@ -13,7 +14,6 @@ import {
|
||||
DropdownMenuContent,
|
||||
DropdownMenuItem,
|
||||
DropdownMenuTrigger,
|
||||
getSettingsLayout as getLayout,
|
||||
Icon,
|
||||
List,
|
||||
ListItem,
|
||||
|
||||
@@ -3,12 +3,12 @@ import { useRouter } from "next/router";
|
||||
import { useMemo } from "react";
|
||||
import { Controller, useForm } from "react-hook-form";
|
||||
|
||||
import { getLayout } from "@calcom/features/settings/layouts/SettingsLayout";
|
||||
import { useLocale } from "@calcom/lib/hooks/useLocale";
|
||||
import { RouterOutputs, trpc } from "@calcom/trpc/react";
|
||||
import {
|
||||
Button,
|
||||
Form,
|
||||
getSettingsLayout as getLayout,
|
||||
Label,
|
||||
Meta,
|
||||
Select,
|
||||
|
||||
@@ -5,6 +5,7 @@ import { signOut } from "next-auth/react";
|
||||
import { BaseSyntheticEvent, useRef, useState } from "react";
|
||||
import { Controller, useForm } from "react-hook-form";
|
||||
|
||||
import { getLayout } from "@calcom/features/settings/layouts/SettingsLayout";
|
||||
import { ErrorCode } from "@calcom/lib/auth";
|
||||
import { APP_NAME } from "@calcom/lib/constants";
|
||||
import { useLocale } from "@calcom/lib/hooks/useLocale";
|
||||
@@ -21,7 +22,6 @@ import {
|
||||
DialogFooter,
|
||||
DialogTrigger,
|
||||
Form,
|
||||
getSettingsLayout as getLayout,
|
||||
Icon,
|
||||
ImageUploader,
|
||||
Label,
|
||||
@@ -181,7 +181,9 @@ const ProfileView = () => {
|
||||
};
|
||||
|
||||
if (isLoading || !user || isLoadingAvatar || !avatar)
|
||||
return <SkeletonLoader title={t("profile")} description={t("profile_description")} />;
|
||||
return (
|
||||
<SkeletonLoader title={t("profile")} description={t("profile_description", { appName: APP_NAME })} />
|
||||
);
|
||||
|
||||
const defaultValues = {
|
||||
username: user.username || "",
|
||||
|
||||
@@ -1,18 +1,10 @@
|
||||
import { GetServerSidePropsContext } from "next";
|
||||
import { useForm } from "react-hook-form";
|
||||
|
||||
import { getLayout } from "@calcom/features/settings/layouts/SettingsLayout";
|
||||
import { useLocale } from "@calcom/lib/hooks/useLocale";
|
||||
import { trpc } from "@calcom/trpc/react";
|
||||
import {
|
||||
Button,
|
||||
Form,
|
||||
getSettingsLayout as getLayout,
|
||||
Label,
|
||||
Meta,
|
||||
showToast,
|
||||
Skeleton,
|
||||
Switch,
|
||||
} from "@calcom/ui";
|
||||
import { Button, Form, Label, Meta, showToast, Skeleton, Switch } from "@calcom/ui";
|
||||
|
||||
import { ssrInit } from "@server/lib/ssr";
|
||||
|
||||
|
||||
@@ -3,10 +3,11 @@ import { GetServerSidePropsContext } from "next";
|
||||
import { Trans } from "next-i18next";
|
||||
import { useForm } from "react-hook-form";
|
||||
|
||||
import { getLayout } from "@calcom/features/settings/layouts/SettingsLayout";
|
||||
import { identityProviderNameMap } from "@calcom/lib/auth";
|
||||
import { useLocale } from "@calcom/lib/hooks/useLocale";
|
||||
import { trpc } from "@calcom/trpc/react";
|
||||
import { Button, Form, getSettingsLayout as getLayout, Meta, PasswordField, showToast } from "@calcom/ui";
|
||||
import { Button, Form, Meta, PasswordField, showToast } from "@calcom/ui";
|
||||
|
||||
import { ssrInit } from "@server/lib/ssr";
|
||||
|
||||
|
||||
@@ -1,17 +1,10 @@
|
||||
import { GetServerSidePropsContext } from "next";
|
||||
import { useState } from "react";
|
||||
|
||||
import { getLayout } from "@calcom/features/settings/layouts/SettingsLayout";
|
||||
import { useLocale } from "@calcom/lib/hooks/useLocale";
|
||||
import { trpc } from "@calcom/trpc/react";
|
||||
import {
|
||||
Badge,
|
||||
getSettingsLayout as getLayout,
|
||||
Meta,
|
||||
Switch,
|
||||
SkeletonButton,
|
||||
SkeletonContainer,
|
||||
SkeletonText,
|
||||
} from "@calcom/ui";
|
||||
import { Badge, Meta, Switch, SkeletonButton, SkeletonContainer, SkeletonText } from "@calcom/ui";
|
||||
|
||||
import DisableTwoFactorModal from "@components/settings/DisableTwoFactorModal";
|
||||
import EnableTwoFactorModal from "@components/settings/EnableTwoFactorModal";
|
||||
|
||||
@@ -2,7 +2,8 @@ import Head from "next/head";
|
||||
|
||||
import AddNewTeamMembers from "@calcom/features/ee/teams/components/AddNewTeamMembers";
|
||||
import { useLocale } from "@calcom/lib/hooks/useLocale";
|
||||
import { WizardLayout } from "@calcom/ui";
|
||||
|
||||
import WizardLayout from "@components/layouts/WizardLayout";
|
||||
|
||||
const OnboardTeamMembersPage = () => {
|
||||
const { t } = useLocale();
|
||||
|
||||
@@ -3,7 +3,8 @@ import Head from "next/head";
|
||||
|
||||
import { CreateANewTeamForm } from "@calcom/features/ee/teams/components";
|
||||
import { useLocale } from "@calcom/lib/hooks/useLocale";
|
||||
import { getWizardLayout as getLayout } from "@calcom/ui";
|
||||
|
||||
import { getLayout } from "@components/layouts/WizardLayout";
|
||||
|
||||
import { ssrInit } from "@server/lib/ssr";
|
||||
|
||||
|
||||
@@ -8,8 +8,7 @@ import { isSAMLLoginEnabled } from "@calcom/features/ee/sso/lib/saml";
|
||||
import { useLocale } from "@calcom/lib/hooks/useLocale";
|
||||
import { collectPageParameters, telemetryEventTypes, useTelemetry } from "@calcom/lib/telemetry";
|
||||
import { inferSSRProps } from "@calcom/types/inferSSRProps";
|
||||
import { Alert, Button, EmailField, PasswordField, TextField } from "@calcom/ui";
|
||||
import { HeadSeo } from "@calcom/web/components/seo/head-seo";
|
||||
import { Alert, Button, EmailField, PasswordField, TextField, HeadSeo } from "@calcom/ui";
|
||||
import { asStringOrNull } from "@calcom/web/lib/asStringOrNull";
|
||||
import { WEBAPP_URL } from "@calcom/web/lib/config/constants";
|
||||
import prisma from "@calcom/web/lib/prisma";
|
||||
|
||||
@@ -12,12 +12,11 @@ import { useLocale } from "@calcom/lib/hooks/useLocale";
|
||||
import useTheme from "@calcom/lib/hooks/useTheme";
|
||||
import { getTeamWithMembers } from "@calcom/lib/server/queries/teams";
|
||||
import { collectPageParameters, telemetryEventTypes, useTelemetry } from "@calcom/lib/telemetry";
|
||||
import { Avatar, Button, Icon } from "@calcom/ui";
|
||||
import { Avatar, Button, Icon, HeadSeo } from "@calcom/ui";
|
||||
|
||||
import { useToggleQuery } from "@lib/hooks/useToggleQuery";
|
||||
import { inferSSRProps } from "@lib/types/inferSSRProps";
|
||||
|
||||
import { HeadSeo } from "@components/seo/head-seo";
|
||||
import Team from "@components/team/screens/Team";
|
||||
import AvatarGroup from "@components/ui/AvatarGroup";
|
||||
|
||||
@@ -46,28 +45,29 @@ function TeamPage({ team }: TeamPageProps) {
|
||||
"dark:bg-darkgray-100 group relative border-b border-neutral-200 bg-white first:rounded-t-md last:rounded-b-md last:border-b-0 hover:bg-gray-50 dark:border-neutral-700 dark:hover:border-neutral-600",
|
||||
!isEmbed && "bg-white"
|
||||
)}>
|
||||
<Link href={`/team/${team.slug}/${type.slug}`}>
|
||||
<a className="flex justify-between px-6 py-4" data-testid="event-type-link">
|
||||
<div className="flex-shrink">
|
||||
<div className="flex flex-wrap items-center space-x-2 rtl:space-x-reverse">
|
||||
<h2 className="dark:text-darkgray-700 text-sm font-semibold text-gray-700">{type.title}</h2>
|
||||
</div>
|
||||
<EventTypeDescription className="text-sm" eventType={type} />
|
||||
<Link
|
||||
href={`/team/${team.slug}/${type.slug}`}
|
||||
className="flex justify-between px-6 py-4"
|
||||
data-testid="event-type-link">
|
||||
<div className="flex-shrink">
|
||||
<div className="flex flex-wrap items-center space-x-2 rtl:space-x-reverse">
|
||||
<h2 className="dark:text-darkgray-700 text-sm font-semibold text-gray-700">{type.title}</h2>
|
||||
</div>
|
||||
<div className="mt-1 self-center">
|
||||
<AvatarGroup
|
||||
border="border-2 border-white dark:border-darkgray-100"
|
||||
truncateAfter={4}
|
||||
className="flex flex-shrink-0"
|
||||
size={10}
|
||||
items={type.users.map((user) => ({
|
||||
alt: user.name || "",
|
||||
title: user.name || "",
|
||||
image: CAL_URL + "/" + user.username + "/avatar.png" || "",
|
||||
}))}
|
||||
/>
|
||||
</div>
|
||||
</a>
|
||||
<EventTypeDescription className="text-sm" eventType={type} />
|
||||
</div>
|
||||
<div className="mt-1 self-center">
|
||||
<AvatarGroup
|
||||
border="border-2 border-white dark:border-darkgray-100"
|
||||
truncateAfter={4}
|
||||
className="flex flex-shrink-0"
|
||||
size={10}
|
||||
items={type.users.map((user) => ({
|
||||
alt: user.name || "",
|
||||
title: user.name || "",
|
||||
image: CAL_URL + "/" + user.username + "/avatar.png" || "",
|
||||
}))}
|
||||
/>
|
||||
</div>
|
||||
</Link>
|
||||
</li>
|
||||
))}
|
||||
@@ -98,27 +98,32 @@ function TeamPage({ team }: TeamPageProps) {
|
||||
{!showMembers.isOn && team.eventTypes.length > 0 && (
|
||||
<div className="mx-auto max-w-3xl ">
|
||||
<EventTypes />
|
||||
<div className="relative mt-12">
|
||||
<div className="absolute inset-0 flex items-center" aria-hidden="true">
|
||||
<div className="dark:border-darkgray-300 w-full border-t border-gray-200" />
|
||||
</div>
|
||||
<div className="relative flex justify-center">
|
||||
<span className="dark:bg-darkgray-50 bg-gray-100 px-2 text-sm text-gray-500 dark:text-white">
|
||||
{t("or")}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<aside className="mt-8 flex justify-center text-center dark:text-white">
|
||||
<Button
|
||||
color="minimal"
|
||||
EndIcon={Icon.FiArrowRight}
|
||||
className="dark:hover:bg-darkgray-200"
|
||||
href={`/team/${team.slug}?members=1`}
|
||||
shallow={true}>
|
||||
{t("book_a_team_member")}
|
||||
</Button>
|
||||
</aside>
|
||||
{!team.hideBookATeamMember && (
|
||||
<div>
|
||||
<div className="relative mt-12">
|
||||
<div className="absolute inset-0 flex items-center" aria-hidden="true">
|
||||
<div className="dark:border-darkgray-300 w-full border-t border-gray-200" />
|
||||
</div>
|
||||
<div className="relative flex justify-center">
|
||||
<span className="dark:bg-darkgray-50 bg-gray-100 px-2 text-sm text-gray-500 dark:text-white">
|
||||
{t("or")}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<aside className="mt-8 flex justify-center text-center dark:text-white">
|
||||
<Button
|
||||
color="minimal"
|
||||
EndIcon={Icon.FiArrowRight}
|
||||
className="dark:hover:bg-darkgray-200"
|
||||
href={`/team/${team.slug}?members=1`}
|
||||
shallow={true}>
|
||||
{t("book_a_team_member")}
|
||||
</Button>
|
||||
</aside>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
</main>
|
||||
|
||||
@@ -18,7 +18,7 @@ function Teams() {
|
||||
size="fab"
|
||||
StartIcon={Icon.FiPlus}
|
||||
type="button"
|
||||
href={`${WEBAPP_URL}/settings/teams/new?returnTo=/teams`}>
|
||||
href={`${WEBAPP_URL}/settings/teams/new?returnTo=${WEBAPP_URL}/teams`}>
|
||||
{t("new")}
|
||||
</Button>
|
||||
}>
|
||||
|
||||
@@ -4,7 +4,7 @@ import { getSession } from "next-auth/react";
|
||||
import Head from "next/head";
|
||||
import { useEffect } from "react";
|
||||
|
||||
import { SEO_IMG_OGIMG_VIDEO, WEBSITE_URL } from "@calcom/lib/constants";
|
||||
import { APP_NAME, SEO_IMG_OGIMG_VIDEO, WEBSITE_URL } from "@calcom/lib/constants";
|
||||
import { useLocale } from "@calcom/lib/hooks/useLocale";
|
||||
import prisma, { bookingMinimalSelect } from "@calcom/prisma";
|
||||
import { inferSSRProps } from "@calcom/types/inferSSRProps";
|
||||
@@ -48,18 +48,18 @@ export default function JoinCall(props: JoinCallPageProps) {
|
||||
return (
|
||||
<>
|
||||
<Head>
|
||||
<title>Cal.com Video</title>
|
||||
<meta name="title" content="Cal.com Video" />
|
||||
<title>{APP_NAME} Video</title>
|
||||
<meta name="title" content={APP_NAME + " Video"} />
|
||||
<meta name="description" content={t("quick_video_meeting")} />
|
||||
<meta property="og:image" content={SEO_IMG_OGIMG_VIDEO} />
|
||||
<meta property="og:type" content="website" />
|
||||
<meta property="og:url" content={`${WEBSITE_URL}/video`} />
|
||||
<meta property="og:title" content="Cal.com Video" />
|
||||
<meta property="og:title" content={APP_NAME + " Video"} />
|
||||
<meta property="og:description" content={t("quick_video_meeting")} />
|
||||
<meta property="twitter:image" content={SEO_IMG_OGIMG_VIDEO} />
|
||||
<meta property="twitter:card" content="summary_large_image" />
|
||||
<meta property="twitter:url" content={`${WEBSITE_URL}/video`} />
|
||||
<meta property="twitter:title" content="Cal.com Video" />
|
||||
<meta property="twitter:title" content={APP_NAME + " Video"} />
|
||||
<meta property="twitter:description" content={t("quick_video_meeting")} />
|
||||
</Head>
|
||||
<div style={{ zIndex: 2, position: "relative" }}>
|
||||
|
||||
@@ -4,12 +4,10 @@ import dayjs from "@calcom/dayjs";
|
||||
import { useLocale } from "@calcom/lib/hooks/useLocale";
|
||||
import { detectBrowserTimeFormat } from "@calcom/lib/timeFormat";
|
||||
import prisma, { bookingMinimalSelect } from "@calcom/prisma";
|
||||
import { Button, Icon } from "@calcom/ui";
|
||||
import { Button, Icon, HeadSeo } from "@calcom/ui";
|
||||
|
||||
import { inferSSRProps } from "@lib/types/inferSSRProps";
|
||||
|
||||
import { HeadSeo } from "@components/seo/head-seo";
|
||||
|
||||
export default function MeetingUnavailable(props: inferSSRProps<typeof getServerSideProps>) {
|
||||
const { t } = useLocale();
|
||||
|
||||
|
||||
@@ -5,9 +5,7 @@ import { useLocale } from "@calcom/lib/hooks/useLocale";
|
||||
import { detectBrowserTimeFormat } from "@calcom/lib/timeFormat";
|
||||
import prisma, { bookingMinimalSelect } from "@calcom/prisma";
|
||||
import type { inferSSRProps } from "@calcom/types/inferSSRProps";
|
||||
import { Button, Icon } from "@calcom/ui";
|
||||
|
||||
import { HeadSeo } from "@components/seo/head-seo";
|
||||
import { Button, Icon, HeadSeo } from "@calcom/ui";
|
||||
|
||||
export default function MeetingNotStarted(props: inferSSRProps<typeof getServerSideProps>) {
|
||||
const { t } = useLocale();
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
import { useLocale } from "@calcom/lib/hooks/useLocale";
|
||||
import { Button, Icon } from "@calcom/ui";
|
||||
|
||||
import { HeadSeo } from "@components/seo/head-seo";
|
||||
import { Button, Icon, HeadSeo } from "@calcom/ui";
|
||||
|
||||
export default function NoMeetingFound() {
|
||||
const { t } = useLocale();
|
||||
|
||||
@@ -14,6 +14,17 @@ test.describe("App Store - Authed", () => {
|
||||
await expect(page.locator(`text=Connect to Apple Server`)).toBeVisible();
|
||||
await pro.delete();
|
||||
});
|
||||
|
||||
test("Installed Apps - Navigation", async ({ page, users }) => {
|
||||
const user = await users.create();
|
||||
await user.login();
|
||||
await page.goto("/apps/installed");
|
||||
await page.waitForSelector('[data-testid="connect-calendar-apps"]');
|
||||
await page.click('[data-testid="vertical-tab-payment"]');
|
||||
await page.waitForSelector('[data-testid="connect-payment-apps"]');
|
||||
await page.click('[data-testid="vertical-tab-automation"]');
|
||||
await page.waitForSelector('[data-testid="connect-automation-apps"]');
|
||||
});
|
||||
});
|
||||
|
||||
test.describe("App Store - Unauthed", () => {
|
||||
|
||||
@@ -5,7 +5,8 @@ import { bookTimeSlot, selectFirstAvailableTimeSlotNextMonth } from "./lib/testU
|
||||
|
||||
test.describe.configure({ mode: "parallel" });
|
||||
|
||||
test.describe("hash my url", () => {
|
||||
// TODO: This test is very flaky. Feels like tossing a coin and hope that it won't fail. Needs to be revisited.
|
||||
test.fixme("hash my url", () => {
|
||||
test.beforeEach(async ({ users }) => {
|
||||
const user = await users.create();
|
||||
await user.login();
|
||||
|
||||
@@ -457,6 +457,7 @@
|
||||
"email_address": "عنوان البريد الإلكتروني",
|
||||
"enter_valid_email": "يرجى إدخال بريد إلكتروني صالح",
|
||||
"location": "الموقع",
|
||||
"in_person_attendee_address": "شخصيًا (عنوان من سيحضر)",
|
||||
"yes": "نعم",
|
||||
"no": "لا",
|
||||
"additional_notes": "ملاحظات إضافية",
|
||||
@@ -1076,13 +1077,13 @@
|
||||
"new_seat_subject": "حضور جديد {{name}} لـ {{eventType}} في {{date}}",
|
||||
"new_seat_title": "شخص ما أضاف نفسه إلى حدث",
|
||||
"variable": "متغير",
|
||||
"event_name_workflow": "اسم الحدث",
|
||||
"organizer_name_workflow": "المنظِّم",
|
||||
"attendee_name_workflow": "الحاضر",
|
||||
"event_date_workflow": "تاريخ الحدث",
|
||||
"event_time_workflow": "وقت الحدث",
|
||||
"location_workflow": "الموقع",
|
||||
"additional_notes_workflow": "ملاحظات إضافية",
|
||||
"event_name_variable": "اسم الحدث",
|
||||
"organizer_name_variable": "المنظِّم",
|
||||
"attendee_name_variable": "الحاضر",
|
||||
"event_date_variable": "تاريخ الحدث",
|
||||
"event_time_variable": "وقت الحدث",
|
||||
"location_variable": "الموقع",
|
||||
"additional_notes_variable": "ملاحظات إضافية",
|
||||
"app_upgrade_description": "لاستخدام هذه الميزة، تحتاج إلى الترقية إلى حساب Pro.",
|
||||
"invalid_number": "رقم الهاتف غير صالح",
|
||||
"navigate": "تنقّل",
|
||||
@@ -1386,7 +1387,7 @@
|
||||
"team_url_taken": "عنوان URL هذا مأخوذ بالفعل",
|
||||
"team_publish": "نشر فريق",
|
||||
"number_sms_notifications": "رقم الهاتف (إشعارات الرسائل النصية)",
|
||||
"attendee_email_workflow": "اسم الحاضر",
|
||||
"attendee_email_variable": "اسم الحاضر",
|
||||
"attendee_email_info": "البريد الإلكتروني للشخص الحجز",
|
||||
"kbar_search_placeholder": "اكتب أمرًا أو بحثًا...",
|
||||
"invalid_credential": "لا! يبدو أن الصلاحية انتهت أو تم إلغاؤها. يرجى إعادة التثبيت مرة أخرى.",
|
||||
|
||||
@@ -457,6 +457,7 @@
|
||||
"email_address": "E-mailová adresa",
|
||||
"enter_valid_email": "Zadejte platný e-mail",
|
||||
"location": "Místo",
|
||||
"in_person_attendee_address": "Osobně (adresa účastníka)",
|
||||
"yes": "ano",
|
||||
"no": "ne",
|
||||
"additional_notes": "Doplňující poznámky",
|
||||
@@ -1075,13 +1076,13 @@
|
||||
"new_seat_subject": "Nový účastník {{name}} události {{eventType}} dne {{date}}",
|
||||
"new_seat_title": "Někdo se přidal k události",
|
||||
"variable": "Proměnná",
|
||||
"event_name_workflow": "Název události",
|
||||
"organizer_name_workflow": "Jméno organizátora",
|
||||
"attendee_name_workflow": "Jméno účastníka",
|
||||
"event_date_workflow": "Datum události",
|
||||
"event_time_workflow": "Čas události",
|
||||
"location_workflow": "Místo",
|
||||
"additional_notes_workflow": "Doplňující poznámky",
|
||||
"event_name_variable": "Název události",
|
||||
"organizer_name_variable": "Jméno organizátora",
|
||||
"attendee_name_variable": "Jméno účastníka",
|
||||
"event_date_variable": "Datum události",
|
||||
"event_time_variable": "Čas události",
|
||||
"location_variable": "Místo",
|
||||
"additional_notes_variable": "Doplňující poznámky",
|
||||
"app_upgrade_description": "Pokud chcete použít tuto funkci, musíte provést aktualizaci na účet Pro.",
|
||||
"invalid_number": "Neplatné telefonní číslo",
|
||||
"navigate": "Navigace",
|
||||
@@ -1385,7 +1386,7 @@
|
||||
"team_url_taken": "Tato adresa URL je už obsazená",
|
||||
"team_publish": "Zveřejnit tým",
|
||||
"number_sms_notifications": "Číslo telefonu (SMS oznámení)",
|
||||
"attendee_email_workflow": "E-mail účastníka",
|
||||
"attendee_email_variable": "E-mail účastníka",
|
||||
"attendee_email_info": "E-mail osoby provádějící rezervaci",
|
||||
"kbar_search_placeholder": "Zadejte příkaz nebo vyhledejte...",
|
||||
"invalid_credential": "Ale ne! Zdá se, že platnost oprávnění vypršela nebo byla zrušena. Proveďte novou instalaci.",
|
||||
|
||||
@@ -454,7 +454,7 @@
|
||||
"additional_guests": "+ Weitere Gäste",
|
||||
"your_name": "Ihr Name",
|
||||
"email_address": "E-Mail Adresse",
|
||||
"enter_valid_email": "Bitte geben Sie eine gültige E-Mail-Adresse ein",
|
||||
"enter_valid_email": "Bitte geben Sie eine gültige Emaildresse ein",
|
||||
"location": "Ort",
|
||||
"address": "Adresse",
|
||||
"enter_address": "Geben Sie eine Adresse ein",
|
||||
@@ -464,7 +464,7 @@
|
||||
"additional_notes": "Zusätzliche Notizen",
|
||||
"booking_fail": "Termin konnte nicht gebucht werden.",
|
||||
"reschedule_fail": "Termin konnte nicht neugeplant werden.",
|
||||
"share_additional_notes": "Teilen Sie uns weitere Informationen mit, die zur Vorbereitung des Termins hilfreich sind.",
|
||||
"share_additional_notes": "Bitten teilen Sie Notizen zur Vorbereitung des Termins, falls nötig.",
|
||||
"booking_confirmation": "Bestätigen Sie {{eventTypeTitle}} mit {{profileName}}",
|
||||
"booking_reschedule_confirmation": "Planen Sie Ihr {{eventTypeTitle}} mit {{profileName}} um",
|
||||
"in_person_meeting": "Vor-Ort-Termin",
|
||||
@@ -1078,13 +1078,13 @@
|
||||
"new_seat_subject": "Neuer Teilnehmer {{name}} beim {{eventType}} am {{date}}",
|
||||
"new_seat_title": "Jemand hat sich zu einem Ereignis hinzugefügt",
|
||||
"variable": "Variable",
|
||||
"event_name_workflow": "Event Name",
|
||||
"organizer_name_workflow": "Organisator",
|
||||
"attendee_name_workflow": "Teilnehmer",
|
||||
"event_date_workflow": "Event Datum",
|
||||
"event_time_workflow": "Event Zeit",
|
||||
"location_workflow": "Ort",
|
||||
"additional_notes_workflow": "Zusätzliche Notizen",
|
||||
"event_name_variable": "Event Name",
|
||||
"organizer_name_variable": "Organisator",
|
||||
"attendee_name_variable": "Teilnehmer",
|
||||
"event_date_variable": "Event Datum",
|
||||
"event_time_variable": "Event Zeit",
|
||||
"location_variable": "Ort",
|
||||
"additional_notes_variable": "Zusätzliche Notizen",
|
||||
"app_upgrade_description": "Um diese Funktion nutzen zu können, müssen Sie ein Upgrade auf einen Pro-Account durchführen.",
|
||||
"invalid_number": "Ungültige Telefonnummer",
|
||||
"navigate": "Navigieren",
|
||||
@@ -1388,7 +1388,7 @@
|
||||
"team_url_taken": "Diese URL ist bereits vergeben",
|
||||
"team_publish": "Team veröffentlichen",
|
||||
"number_sms_notifications": "Telefonnummer (SMS-Benachrichtigungen)",
|
||||
"attendee_email_workflow": "Teilnehmer E-Mail",
|
||||
"attendee_email_variable": "Teilnehmer E-Mail",
|
||||
"attendee_email_info": "Die E-Mail-Adresse der buchenden Person",
|
||||
"kbar_search_placeholder": "Geben Sie einen Befehl ein oder suchen Sie...",
|
||||
"invalid_credential": "Oh nein! Es sieht so aus, als ob die Berechtigung abgelaufen ist oder entzogen wurden. Bitte erneut installieren.",
|
||||
|
||||
@@ -521,6 +521,8 @@
|
||||
"change_member_role": "Change team member role",
|
||||
"disable_cal_branding": "Disable {{appName}} branding",
|
||||
"disable_cal_branding_description": "Hide all {{appName}} branding from your public pages.",
|
||||
"hide_book_a_team_member": "Hide Book a Team Member Button",
|
||||
"hide_book_a_team_member_description": "Hide Book a Team Member Button from your public pages.",
|
||||
"danger_zone": "Danger zone",
|
||||
"back": "Back",
|
||||
"cancel": "Cancel",
|
||||
@@ -1082,13 +1084,13 @@
|
||||
"new_seat_subject": "New Attendee {{name}} on {{eventType}} at {{date}}",
|
||||
"new_seat_title": "Someone has added themselves to an event",
|
||||
"variable": "Variable",
|
||||
"event_name_workflow": "Event name",
|
||||
"organizer_name_workflow": "Organizer",
|
||||
"attendee_name_workflow": "Attendee",
|
||||
"event_date_workflow": "Event date",
|
||||
"event_time_workflow": "Event time",
|
||||
"location_workflow": "Location",
|
||||
"additional_notes_workflow": "Additional notes",
|
||||
"event_name_variable": "Event name",
|
||||
"organizer_name_variable": "Organizer",
|
||||
"attendee_name_variable": "Attendee",
|
||||
"event_date_variable": "Event date",
|
||||
"event_time_variable": "Event time",
|
||||
"location_variable": "Location",
|
||||
"additional_notes_variable": "Additional notes",
|
||||
"app_upgrade_description": "In order to use this feature, you need to upgrade to a Pro account.",
|
||||
"invalid_number": "Invalid phone number",
|
||||
"navigate": "Navigate",
|
||||
@@ -1402,7 +1404,7 @@
|
||||
"team_url_taken": "This URL is already taken",
|
||||
"team_publish": "Publish team",
|
||||
"number_sms_notifications": "Phone number (SMS\u00a0notifications)",
|
||||
"attendee_email_workflow": "Attendee email",
|
||||
"attendee_email_variable": "Attendee email",
|
||||
"attendee_email_info": "The person booking's email",
|
||||
"kbar_search_placeholder": "Type a command or search...",
|
||||
"invalid_credential": "Oh no! Looks like permission expired or was revoked. Please reinstall again.",
|
||||
@@ -1454,10 +1456,11 @@
|
||||
"enter_option": "Enter Option {{index}}",
|
||||
"add_an_option": "Add an option",
|
||||
"radio": "Radio",
|
||||
"google_meet_warning": "In order to use Google Meet you must set your destination calendar to a Google Calendar",
|
||||
"individual":"Individual",
|
||||
"all_bookings_filter_label":"All Bookings",
|
||||
"all_users_filter_label":"All Users",
|
||||
"meeting_url_workflow": "Meeting url",
|
||||
"meeting_url_variable": "Meeting url",
|
||||
"meeting_url_info": "The event meeting conference url",
|
||||
"date_overrides": "Date overrides",
|
||||
"date_overrides_subtitle": "Add dates when your availability changes from your daily hours.",
|
||||
@@ -1488,5 +1491,11 @@
|
||||
"disable_success_page":"Disable Success Page (only works if you have a redirect URL)",
|
||||
"invalid_admin_password": "You are set as an admin but you do not have a password length of at least 15 characters",
|
||||
"change_password_admin": "Change Password to gain admin access",
|
||||
"username_already_taken": "Username is already taken"
|
||||
"username_already_taken": "Username is already taken",
|
||||
"requires_google_calendar": "This app requires a Google Calendar connection",
|
||||
"connected_google_calendar": "You have connected a Google Calendar account.",
|
||||
"using_meet_requires_calendar": "Using Google Meet requires a connected Google Calendar",
|
||||
"continue_to_install_google_calendar": "Continue to install Google Calendar",
|
||||
"install_google_meet": "Install Google Meet",
|
||||
"install_google_calendar": "Install Google Calendar"
|
||||
}
|
||||
|
||||
@@ -457,6 +457,7 @@
|
||||
"email_address": "Email",
|
||||
"enter_valid_email": "Ingresa un correo electrónico válido",
|
||||
"location": "Ubicación",
|
||||
"in_person_attendee_address": "En persona (dirección del asistente)",
|
||||
"yes": "Sí",
|
||||
"no": "No",
|
||||
"additional_notes": "Notas Adicionales",
|
||||
@@ -510,7 +511,7 @@
|
||||
"add_team_members_description": "Invitar a otros a unirse a tu equipo",
|
||||
"add_team_member": "Añadir miembro del equipo",
|
||||
"invite_new_member": "Invitar a un nuevo miembro",
|
||||
"invite_new_member_description": "Nota: Esto costará <1>un cupo adicional ($15/m)</1> en su suscripción.",
|
||||
"invite_new_member_description": "Nota: Esto costará <1>una plaza adicional ($15/m)</1> en su suscripción.",
|
||||
"invite_new_team_member": "Invita a alguien a tu equipo.",
|
||||
"change_member_role": "Cambiar rol del miembro del equipo",
|
||||
"disable_cal_branding": "Desactivar marca de {{appName}}",
|
||||
@@ -1075,13 +1076,13 @@
|
||||
"new_seat_subject": "Nuevo asistente {{name}} en {{eventType}} el {{date}}",
|
||||
"new_seat_title": "Alguien se ha añadido a un evento",
|
||||
"variable": "Variable",
|
||||
"event_name_workflow": "Nombre del evento",
|
||||
"organizer_name_workflow": "Nombre del organizador",
|
||||
"attendee_name_workflow": "Nombre del asistente",
|
||||
"event_date_workflow": "Fecha del evento",
|
||||
"event_time_workflow": "Hora del evento",
|
||||
"location_workflow": "Lugar",
|
||||
"additional_notes_workflow": "Notas Adicionales",
|
||||
"event_name_variable": "Nombre del evento",
|
||||
"organizer_name_variable": "Nombre del organizador",
|
||||
"attendee_name_variable": "Nombre del asistente",
|
||||
"event_date_variable": "Fecha del evento",
|
||||
"event_time_variable": "Hora del evento",
|
||||
"location_variable": "Lugar",
|
||||
"additional_notes_variable": "Notas Adicionales",
|
||||
"app_upgrade_description": "Para poder usar esta función, necesita actualizarse a una cuenta Pro.",
|
||||
"invalid_number": "Número de teléfono no válido",
|
||||
"navigate": "Navegar",
|
||||
@@ -1385,7 +1386,7 @@
|
||||
"team_url_taken": "Esta URL ya está en uso",
|
||||
"team_publish": "Publicar equipo",
|
||||
"number_sms_notifications": "Número de teléfono (notificaciones por SMS)",
|
||||
"attendee_email_workflow": "Correo electrónico del asistente",
|
||||
"attendee_email_variable": "Correo electrónico del asistente",
|
||||
"attendee_email_info": "El correo electrónico de la persona que reserva",
|
||||
"kbar_search_placeholder": "Escriba un comando o búsqueda...",
|
||||
"invalid_credential": "¡Oh no! Parece que el permiso ha caducado o se ha revocado. Vuelva a instalarlo.",
|
||||
@@ -1395,7 +1396,7 @@
|
||||
"sender_id": "ID del remitente",
|
||||
"sender_id_error_message": "Sólo se permiten letras, números y espacios (máx. 11 caracteres)",
|
||||
"test_routing_form": "Prueba de formulario de ruta",
|
||||
"test_preview": "Vista previa de la prueba",
|
||||
"test_preview": "Probar vista previa",
|
||||
"route_to": "Ruta hacia",
|
||||
"test_preview_description": "Pruebe su formulario de ruta sin enviar ningún dato",
|
||||
"test_routing": "Prueba de ruta",
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -457,6 +457,7 @@
|
||||
"email_address": "כתובת דוא\"ל",
|
||||
"enter_valid_email": "יש להזין כתובת דוא״ל תקינה",
|
||||
"location": "מיקום",
|
||||
"in_person_attendee_address": "פנים-אל-פנים (הכתובת של המשתתף/ת)",
|
||||
"yes": "כן",
|
||||
"no": "לא",
|
||||
"additional_notes": "הערות נוספות",
|
||||
@@ -1075,13 +1076,13 @@
|
||||
"new_seat_subject": "משתתף/ת חדש/ה {{name}} ב{{eventType}} בתאריך {{date}}",
|
||||
"new_seat_title": "מישהו הוסיף את עצמו לאירוע",
|
||||
"variable": "משתנה",
|
||||
"event_name_workflow": "שם האירוע",
|
||||
"organizer_name_workflow": "שם המארגן/ת",
|
||||
"attendee_name_workflow": "שם המשתתף/ת",
|
||||
"event_date_workflow": "תאריך האירוע",
|
||||
"event_time_workflow": "שעת האירוע",
|
||||
"location_workflow": "מיקום",
|
||||
"additional_notes_workflow": "הערות נוספות",
|
||||
"event_name_variable": "שם האירוע",
|
||||
"organizer_name_variable": "שם המארגן/ת",
|
||||
"attendee_name_variable": "שם המשתתף/ת",
|
||||
"event_date_variable": "תאריך האירוע",
|
||||
"event_time_variable": "שעת האירוע",
|
||||
"location_variable": "מיקום",
|
||||
"additional_notes_variable": "הערות נוספות",
|
||||
"app_upgrade_description": "כדי להשתמש בתכונה זו, עליך לשדרג לחשבון Pro.",
|
||||
"invalid_number": "מספר טלפון לא תקין",
|
||||
"navigate": "ניווט",
|
||||
@@ -1385,7 +1386,7 @@
|
||||
"team_url_taken": "כתובת ה-URL הזו כבר תפוסה",
|
||||
"team_publish": "פרסום צוות",
|
||||
"number_sms_notifications": "מספר טלפון (הודעות SMS)",
|
||||
"attendee_email_workflow": "כתובת הדוא\"ל של המשתתף/ת",
|
||||
"attendee_email_variable": "כתובת הדוא\"ל של המשתתף/ת",
|
||||
"attendee_email_info": "כתובת הדוא\"ל של האדם שביצע את ההזמנה",
|
||||
"kbar_search_placeholder": "הקלד/י פקודה או חפש/י...",
|
||||
"invalid_credential": "נראה שתוקף ההרשאה פג או שההרשאה בוטלה. יש להתקין מחדש שוב.",
|
||||
|
||||
@@ -212,9 +212,9 @@
|
||||
"remove_app": "Alkalmazás eltávolítása",
|
||||
"yes_remove_app": "Igen, távolítsd el az alkalmazást",
|
||||
"web_conference": "Online konferencia",
|
||||
"organizer_name_workflow": "Szervező",
|
||||
"location_workflow": "Helyszín",
|
||||
"additional_notes_workflow": "Egyéb jegyzetek",
|
||||
"organizer_name_variable": "Szervező",
|
||||
"location_variable": "Helyszín",
|
||||
"additional_notes_variable": "Egyéb jegyzetek",
|
||||
"organizer_name_info": "Neved",
|
||||
"theme_light": "Világos",
|
||||
"theme_dark": "Sötét"
|
||||
|
||||
@@ -457,6 +457,7 @@
|
||||
"email_address": "Indirizzo email",
|
||||
"enter_valid_email": "Immettere un indirizzo e-mail valido",
|
||||
"location": "Luogo",
|
||||
"in_person_attendee_address": "Di persona (indirizzo del partecipante)",
|
||||
"yes": "sì",
|
||||
"no": "no",
|
||||
"additional_notes": "Note aggiuntive",
|
||||
@@ -1076,13 +1077,13 @@
|
||||
"new_seat_subject": "Nuovo partecipante {{name}} a {{eventType}} il {{date}}",
|
||||
"new_seat_title": "Qualcuno ha aggiunto se stesso a un evento",
|
||||
"variable": "Variabile",
|
||||
"event_name_workflow": "Nome evento",
|
||||
"organizer_name_workflow": "Organizzatore",
|
||||
"attendee_name_workflow": "Partecipante",
|
||||
"event_date_workflow": "Data evento",
|
||||
"event_time_workflow": "Ora evento",
|
||||
"location_workflow": "Luogo",
|
||||
"additional_notes_workflow": "Note aggiuntive",
|
||||
"event_name_variable": "Nome evento",
|
||||
"organizer_name_variable": "Organizzatore",
|
||||
"attendee_name_variable": "Partecipante",
|
||||
"event_date_variable": "Data evento",
|
||||
"event_time_variable": "Ora evento",
|
||||
"location_variable": "Luogo",
|
||||
"additional_notes_variable": "Note aggiuntive",
|
||||
"app_upgrade_description": "Per poter utilizzare questa funzionalità, è necessario passare a un account Pro.",
|
||||
"invalid_number": "Numero di telefono non valido",
|
||||
"navigate": "Esplora",
|
||||
@@ -1386,7 +1387,7 @@
|
||||
"team_url_taken": "URL già occupato",
|
||||
"team_publish": "Pubblica team",
|
||||
"number_sms_notifications": "Numero di telefono (notifiche SMS)",
|
||||
"attendee_email_workflow": "E-mail partecipante",
|
||||
"attendee_email_variable": "E-mail partecipante",
|
||||
"attendee_email_info": "E-mail della persona che prenota",
|
||||
"kbar_search_placeholder": "Digitare un comando o eseguire una ricerca...",
|
||||
"invalid_credential": "Errore! Sembra che l'autorizzazione sia scaduta o che sia stata revocata. Prova a reinstallare.",
|
||||
|
||||
@@ -457,6 +457,7 @@
|
||||
"email_address": "メールアドレス",
|
||||
"enter_valid_email": "有効なメールアドレスを入力してください",
|
||||
"location": "所在地",
|
||||
"in_person_attendee_address": "対面(出席者のアドレス)",
|
||||
"yes": "はい",
|
||||
"no": "いいえ",
|
||||
"additional_notes": "追加メモ",
|
||||
@@ -611,7 +612,7 @@
|
||||
"monthly_other": "月",
|
||||
"yearly_one": "年",
|
||||
"yearly_other": "年",
|
||||
"plus_more": "あと {{count}} 回",
|
||||
"plus_more": "あと {{count}} 件",
|
||||
"max": "最大",
|
||||
"single_theme": "シングルテーマ",
|
||||
"brand_color": "ブランドカラー",
|
||||
@@ -1075,13 +1076,13 @@
|
||||
"new_seat_subject": "{{date}} の {{eventType}} への新規参加者 {{name}}",
|
||||
"new_seat_title": "別のユーザーがイベントに自身を追加しました",
|
||||
"variable": "変数",
|
||||
"event_name_workflow": "イベントの名前",
|
||||
"organizer_name_workflow": "主催者の名前",
|
||||
"attendee_name_workflow": "出席者の名前",
|
||||
"event_date_workflow": "イベントの日付",
|
||||
"event_time_workflow": "イベントの時間",
|
||||
"location_workflow": "場所",
|
||||
"additional_notes_workflow": "備考",
|
||||
"event_name_variable": "イベントの名前",
|
||||
"organizer_name_variable": "主催者の名前",
|
||||
"attendee_name_variable": "出席者の名前",
|
||||
"event_date_variable": "イベントの日付",
|
||||
"event_time_variable": "イベントの時間",
|
||||
"location_variable": "場所",
|
||||
"additional_notes_variable": "備考",
|
||||
"app_upgrade_description": "この機能を利用するには、Pro アカウントへのアップグレードが必要です。",
|
||||
"invalid_number": "電話番号が無効です",
|
||||
"navigate": "ナビゲート",
|
||||
@@ -1385,7 +1386,7 @@
|
||||
"team_url_taken": "この URL は既に使用されています",
|
||||
"team_publish": "チームを公開",
|
||||
"number_sms_notifications": "電話番号(SMS 通知)",
|
||||
"attendee_email_workflow": "出席者のメールアドレス",
|
||||
"attendee_email_variable": "出席者のメールアドレス",
|
||||
"attendee_email_info": "予約者のメールアドレス",
|
||||
"kbar_search_placeholder": "コマンドを入力するか、検索...",
|
||||
"invalid_credential": "アクセス許可の有効期限が切れたか、取り消されたようです。もう一度インストールしてください。",
|
||||
|
||||
@@ -457,6 +457,7 @@
|
||||
"email_address": "이메일 주소",
|
||||
"enter_valid_email": "유효한 이메일을 입력하세요",
|
||||
"location": "위치",
|
||||
"in_person_attendee_address": "직접 방문(참석자 주소)",
|
||||
"yes": "네",
|
||||
"no": "아니요",
|
||||
"additional_notes": "추가 참고 사항",
|
||||
@@ -1076,13 +1077,13 @@
|
||||
"new_seat_subject": "신규 참석자 {{name}}님이 {{date}}, {{eventType}}에 참석",
|
||||
"new_seat_title": "누군가가 이벤트에 자신을 추가했습니다",
|
||||
"variable": "변수",
|
||||
"event_name_workflow": "이벤트 이름",
|
||||
"organizer_name_workflow": "주최자",
|
||||
"attendee_name_workflow": "참석자",
|
||||
"event_date_workflow": "이벤트 날짜",
|
||||
"event_time_workflow": "이벤트 시간",
|
||||
"location_workflow": "위치",
|
||||
"additional_notes_workflow": "추가 참고 사항",
|
||||
"event_name_variable": "이벤트 이름",
|
||||
"organizer_name_variable": "주최자",
|
||||
"attendee_name_variable": "참석자",
|
||||
"event_date_variable": "이벤트 날짜",
|
||||
"event_time_variable": "이벤트 시간",
|
||||
"location_variable": "위치",
|
||||
"additional_notes_variable": "추가 참고 사항",
|
||||
"app_upgrade_description": "이 기능을 사용하려면 Pro 계정으로 업그레이드해야 합니다.",
|
||||
"invalid_number": "유효하지 않은 전화 번호",
|
||||
"navigate": "탐색하기",
|
||||
@@ -1386,7 +1387,7 @@
|
||||
"team_url_taken": "이미 사용 중인 URL입니다",
|
||||
"team_publish": "팀 게시",
|
||||
"number_sms_notifications": "전화번호 (SMS notifications)",
|
||||
"attendee_email_workflow": "참석자 이메일",
|
||||
"attendee_email_variable": "참석자 이메일",
|
||||
"attendee_email_info": "예약자 이메일",
|
||||
"kbar_search_placeholder": "명령어를 입력하거나 검색하세요...",
|
||||
"invalid_credential": "죄송합니다! 권한이 만료되었거나 취소된 것 같습니다. 다시 설치하십시오.",
|
||||
|
||||
@@ -457,6 +457,7 @@
|
||||
"email_address": "E-mail adres",
|
||||
"enter_valid_email": "Voer een geldig e-mailadres in",
|
||||
"location": "Locatie",
|
||||
"in_person_attendee_address": "Persoonlijk (adres deelnemer)",
|
||||
"yes": "ja",
|
||||
"no": "nee",
|
||||
"additional_notes": "Aanvullende notities",
|
||||
@@ -611,7 +612,7 @@
|
||||
"monthly_other": "maanden",
|
||||
"yearly_one": "jaar",
|
||||
"yearly_other": "jaar",
|
||||
"plus_more": "{{count}} meer",
|
||||
"plus_more": "Nog {{count}}",
|
||||
"max": "Max.",
|
||||
"single_theme": "Enkel Thema",
|
||||
"brand_color": "Merkkleur",
|
||||
@@ -1075,13 +1076,13 @@
|
||||
"new_seat_subject": "Nieuwe deelnemer {{name}} op {{eventType}} om {{date}}",
|
||||
"new_seat_title": "Iemand heeft zichzelf toegevoegd aan een evenement",
|
||||
"variable": "Variabel",
|
||||
"event_name_workflow": "Naam gebeurtenis",
|
||||
"organizer_name_workflow": "Naam organisator",
|
||||
"attendee_name_workflow": "Deelnemer",
|
||||
"event_date_workflow": "Datum gebeurtenis",
|
||||
"event_time_workflow": "Tijd gebeurtenis",
|
||||
"location_workflow": "Locatie",
|
||||
"additional_notes_workflow": "Aanvullende opmerkingen",
|
||||
"event_name_variable": "Naam gebeurtenis",
|
||||
"organizer_name_variable": "Naam organisator",
|
||||
"attendee_name_variable": "Deelnemer",
|
||||
"event_date_variable": "Datum gebeurtenis",
|
||||
"event_time_variable": "Tijd gebeurtenis",
|
||||
"location_variable": "Locatie",
|
||||
"additional_notes_variable": "Aanvullende opmerkingen",
|
||||
"app_upgrade_description": "Om deze functie te gebruiken, moet u upgraden naar een Pro-account.",
|
||||
"invalid_number": "Ongeldig telefoonnummer",
|
||||
"navigate": "Navigeren",
|
||||
@@ -1385,11 +1386,11 @@
|
||||
"team_url_taken": "Deze URL is al in gebruik",
|
||||
"team_publish": "Team publiceren",
|
||||
"number_sms_notifications": "Telefoonnummer (sms-meldingen)",
|
||||
"attendee_email_workflow": "E-mailadres deelnemer",
|
||||
"attendee_email_variable": "E-mailadres deelnemer",
|
||||
"attendee_email_info": "Het e-mailadres van de persoon die boekt",
|
||||
"kbar_search_placeholder": "Typ een opdracht of zoek...",
|
||||
"invalid_credential": "Oh nee! Het lijkt erop dat de machtiging is verlopen of is ingetrokken. Installeer het opnieuw.",
|
||||
"choose_common_schedule_team_event": "Kies een gemeenschappelijke planning",
|
||||
"choose_common_schedule_team_event": "Kies een gezamenlijke planning",
|
||||
"choose_common_schedule_team_event_description": "Schakel dit in als u een gemeenschappelijke planning tussen organisatoren wilt gebruiken. Indien uitgeschakeld, wordt elke organisator geboekt op basis van zijn standaardplanning.",
|
||||
"reason": "Reden",
|
||||
"sender_id": "Afzender-ID",
|
||||
|
||||
@@ -460,6 +460,7 @@
|
||||
"email_address": "Epost adresse",
|
||||
"enter_valid_email": "Vennligst skriv inn en gyldig e-postadresse",
|
||||
"location": "Sted",
|
||||
"in_person_attendee_address": "Personlig Oppmøte (Deltakers Adresse)",
|
||||
"yes": "ja",
|
||||
"no": "nei",
|
||||
"additional_notes": "Tilleggsinformasjon",
|
||||
@@ -1079,13 +1080,13 @@
|
||||
"new_seat_subject": "Ny Deltaker {{name}} på {{eventType}} kl. {{date}}",
|
||||
"new_seat_title": "Noen har lagt seg til en hendelse",
|
||||
"variable": "Variabel",
|
||||
"event_name_workflow": "Hendelsesnavn",
|
||||
"organizer_name_workflow": "Arrangør",
|
||||
"attendee_name_workflow": "Deltaker",
|
||||
"event_date_workflow": "Hendelsesdato",
|
||||
"event_time_workflow": "Tidspunkt for hendelse",
|
||||
"location_workflow": "Sted",
|
||||
"additional_notes_workflow": "Tilleggsinformasjon",
|
||||
"event_name_variable": "Hendelsesnavn",
|
||||
"organizer_name_variable": "Arrangør",
|
||||
"attendee_name_variable": "Deltaker",
|
||||
"event_date_variable": "Hendelsesdato",
|
||||
"event_time_variable": "Tidspunkt for hendelse",
|
||||
"location_variable": "Sted",
|
||||
"additional_notes_variable": "Tilleggsinformasjon",
|
||||
"app_upgrade_description": "For å bruke denne funksjonen må du oppgradere til en Pro-konto.",
|
||||
"invalid_number": "Ugyldig telefonnummer",
|
||||
"navigate": "Naviger",
|
||||
@@ -1399,7 +1400,7 @@
|
||||
"team_url_taken": "Denne URL'en er allerede tatt",
|
||||
"team_publish": "Publiser team",
|
||||
"number_sms_notifications": "Telefonnummer (SMS varsler)",
|
||||
"attendee_email_workflow": "Deltakerens e-post",
|
||||
"attendee_email_variable": "Deltakerens e-post",
|
||||
"attendee_email_info": "Den som booker sin e-post",
|
||||
"kbar_search_placeholder": "Skriv inn en kommando eller søk...",
|
||||
"invalid_credential": "Å nei! Det ser ut til at tillatelsen er utløpt eller tilbakekalt. Vennligst installer på nytt.",
|
||||
|
||||
@@ -457,6 +457,7 @@
|
||||
"email_address": "Adres e-mail",
|
||||
"enter_valid_email": "Wprowadź prawidłowy adres e-mail",
|
||||
"location": "Lokalizacja",
|
||||
"in_person_attendee_address": "Osobiście (adres uczestnika)",
|
||||
"yes": "tak",
|
||||
"no": "nie",
|
||||
"additional_notes": "Dotatkowe uwagi",
|
||||
@@ -1075,13 +1076,13 @@
|
||||
"new_seat_subject": "Nowy uczestnik ({{name}}) wydarzenia {{eventType}} odbywającego się {{date}}",
|
||||
"new_seat_title": "Ktoś dodał się do wydarzenia",
|
||||
"variable": "Zmienna",
|
||||
"event_name_workflow": "Nazwa wydarzenia",
|
||||
"organizer_name_workflow": "Organizator",
|
||||
"attendee_name_workflow": "Uczestnik",
|
||||
"event_date_workflow": "Data wydarzenia",
|
||||
"event_time_workflow": "Godzina wydarzenia",
|
||||
"location_workflow": "Lokalizacja",
|
||||
"additional_notes_workflow": "Dodatkowe uwagi",
|
||||
"event_name_variable": "Nazwa wydarzenia",
|
||||
"organizer_name_variable": "Organizator",
|
||||
"attendee_name_variable": "Uczestnik",
|
||||
"event_date_variable": "Data wydarzenia",
|
||||
"event_time_variable": "Godzina wydarzenia",
|
||||
"location_variable": "Lokalizacja",
|
||||
"additional_notes_variable": "Dodatkowe uwagi",
|
||||
"app_upgrade_description": "Aby korzystać z tej funkcji, musisz uaktualnić do konta Pro.",
|
||||
"invalid_number": "Nieprawidłowy numer telefonu",
|
||||
"navigate": "Nawigacja",
|
||||
@@ -1385,7 +1386,7 @@
|
||||
"team_url_taken": "Ten adres URL jest już zajęty",
|
||||
"team_publish": "Opublikuj zespół",
|
||||
"number_sms_notifications": "Numer telefonu (powiadomienia SMS)",
|
||||
"attendee_email_workflow": "Adres e-mail uczestnika",
|
||||
"attendee_email_variable": "Adres e-mail uczestnika",
|
||||
"attendee_email_info": "Adres e-mail osoby rezerwującej",
|
||||
"kbar_search_placeholder": "Wpisz polecenie lub wyszukaj...",
|
||||
"invalid_credential": "O nie! Wygląda na to, że uprawnienia wygasły lub zostały cofnięte. Zainstaluj aplikację ponownie.",
|
||||
|
||||
@@ -457,6 +457,7 @@
|
||||
"email_address": "Endereço de e-mail",
|
||||
"enter_valid_email": "Insira um e-mail válido",
|
||||
"location": "Local",
|
||||
"in_person_attendee_address": "Pessoalmente (endereço do participante)",
|
||||
"yes": "sim",
|
||||
"no": "não",
|
||||
"additional_notes": "Observações adicionais",
|
||||
@@ -510,7 +511,7 @@
|
||||
"add_team_members_description": "Convidar outros para se juntar à sua equipe",
|
||||
"add_team_member": "Adicionar membro da equipe",
|
||||
"invite_new_member": "Convidar um novo membro",
|
||||
"invite_new_member_description": "Observação: isso <1>custará um assento extra ($15/m)</1> na sua assinatura.",
|
||||
"invite_new_member_description": "Observação: isso <1>custará um lugar extra ($15/m)</1> na sua assinatura.",
|
||||
"invite_new_team_member": "Convidar alguém para seu time.",
|
||||
"change_member_role": "Alterar função de membro da equipe",
|
||||
"disable_cal_branding": "Remover a marca {{appName}}",
|
||||
@@ -1075,13 +1076,13 @@
|
||||
"new_seat_subject": "Novo participante {{name}} no {{eventType}} em {{date}}",
|
||||
"new_seat_title": "Alguém se adicionou a um evento",
|
||||
"variable": "Variável",
|
||||
"event_name_workflow": "Nome do evento",
|
||||
"organizer_name_workflow": "Nome do organizador",
|
||||
"attendee_name_workflow": "Nome do participante",
|
||||
"event_date_workflow": "Data do evento",
|
||||
"event_time_workflow": "Horário do evento",
|
||||
"location_workflow": "Local",
|
||||
"additional_notes_workflow": "Observações adicionais",
|
||||
"event_name_variable": "Nome do evento",
|
||||
"organizer_name_variable": "Nome do organizador",
|
||||
"attendee_name_variable": "Nome do participante",
|
||||
"event_date_variable": "Data do evento",
|
||||
"event_time_variable": "Horário do evento",
|
||||
"location_variable": "Local",
|
||||
"additional_notes_variable": "Observações adicionais",
|
||||
"app_upgrade_description": "Para usar este recurso, atualize para uma conta Pro.",
|
||||
"invalid_number": "Número de telefone inválido",
|
||||
"navigate": "Navegar",
|
||||
@@ -1385,7 +1386,7 @@
|
||||
"team_url_taken": "Este URL já está em uso",
|
||||
"team_publish": "Publicar equipe",
|
||||
"number_sms_notifications": "Número de telefone (notificações de SMS)",
|
||||
"attendee_email_workflow": "E-mail do participante",
|
||||
"attendee_email_variable": "E-mail do participante",
|
||||
"attendee_email_info": "O e-mail da pessoa que fez a reserva",
|
||||
"kbar_search_placeholder": "Digite um comando ou procure...",
|
||||
"invalid_credential": "Ah, não! Parece que a permissão expirou ou foi revogada. Reinstale novamente.",
|
||||
|
||||
@@ -457,6 +457,7 @@
|
||||
"email_address": "Endereço de email",
|
||||
"enter_valid_email": "Insira um e-mail válido",
|
||||
"location": "Localização",
|
||||
"in_person_attendee_address": "Pessoalmente (endereço do participante)",
|
||||
"yes": "Sim",
|
||||
"no": "Não",
|
||||
"additional_notes": "Notas Adicionais",
|
||||
@@ -1076,13 +1077,13 @@
|
||||
"new_seat_subject": "Novo participante {{name}} em {{eventType}} em {{date}}",
|
||||
"new_seat_title": "Alguém se adicionou a um evento",
|
||||
"variable": "Variável",
|
||||
"event_name_workflow": "Nome do evento",
|
||||
"organizer_name_workflow": "Organizador",
|
||||
"attendee_name_workflow": "Participante",
|
||||
"event_date_workflow": "Data do evento",
|
||||
"event_time_workflow": "Hora do evento",
|
||||
"location_workflow": "Localização",
|
||||
"additional_notes_workflow": "Notas Adicionais",
|
||||
"event_name_variable": "Nome do evento",
|
||||
"organizer_name_variable": "Organizador",
|
||||
"attendee_name_variable": "Participante",
|
||||
"event_date_variable": "Data do evento",
|
||||
"event_time_variable": "Hora do evento",
|
||||
"location_variable": "Localização",
|
||||
"additional_notes_variable": "Notas Adicionais",
|
||||
"app_upgrade_description": "Para usar esta funcionalidade, tem de actualizar para uma conta Pro.",
|
||||
"invalid_number": "Número de telefone inválido",
|
||||
"navigate": "Navegar",
|
||||
@@ -1386,7 +1387,7 @@
|
||||
"team_url_taken": "Este endereço já está a ser utilizado",
|
||||
"team_publish": "Publicar equipa",
|
||||
"number_sms_notifications": "Número de telefone (notificações SMS)",
|
||||
"attendee_email_workflow": "E-mail do participante",
|
||||
"attendee_email_variable": "E-mail do participante",
|
||||
"attendee_email_info": "O e-mail do responsável pela reserva",
|
||||
"kbar_search_placeholder": "Digite um comando ou pesquise...",
|
||||
"invalid_credential": "Oh não! Parece que a permissão expirou ou foi revogada. Por favor, reinstale novamente.",
|
||||
|
||||
@@ -457,6 +457,7 @@
|
||||
"email_address": "Adresa de e-mail",
|
||||
"enter_valid_email": "Introduceți un e-mail valid",
|
||||
"location": "Locaţie",
|
||||
"in_person_attendee_address": "În persoană (adresă participant)",
|
||||
"yes": "da",
|
||||
"no": "nu",
|
||||
"additional_notes": "Date suplimentare",
|
||||
@@ -1075,13 +1076,13 @@
|
||||
"new_seat_subject": "Participant nou, {{name}}, la {{eventType}} de pe {{date}}",
|
||||
"new_seat_title": "Cineva s-a adăugat pe sine la un eveniment",
|
||||
"variable": "Variabilă",
|
||||
"event_name_workflow": "Denumire eveniment",
|
||||
"organizer_name_workflow": "Organizator",
|
||||
"attendee_name_workflow": "Participant",
|
||||
"event_date_workflow": "Dată eveniment",
|
||||
"event_time_workflow": "Oră eveniment",
|
||||
"location_workflow": "Loc",
|
||||
"additional_notes_workflow": "Note suplimentare",
|
||||
"event_name_variable": "Denumire eveniment",
|
||||
"organizer_name_variable": "Organizator",
|
||||
"attendee_name_variable": "Participant",
|
||||
"event_date_variable": "Dată eveniment",
|
||||
"event_time_variable": "Oră eveniment",
|
||||
"location_variable": "Loc",
|
||||
"additional_notes_variable": "Note suplimentare",
|
||||
"app_upgrade_description": "Pentru a utiliza această caracteristică, trebuie să faceți upgrade la un cont Pro.",
|
||||
"invalid_number": "Număr de telefon nevalid",
|
||||
"navigate": "Navigare",
|
||||
@@ -1385,7 +1386,7 @@
|
||||
"team_url_taken": "Acest URL este folosit deja",
|
||||
"team_publish": "Publicați echipa",
|
||||
"number_sms_notifications": "Număr de telefon (notificări SMS)",
|
||||
"attendee_email_workflow": "E-mail participant",
|
||||
"attendee_email_variable": "E-mail participant",
|
||||
"attendee_email_info": "E-mailul persoanei care efectuează rezervarea",
|
||||
"kbar_search_placeholder": "Scrie o comandă sau caută...",
|
||||
"invalid_credential": "Vai, nu! Se pare că permisiunea a expirat sau a fost revocată. Reinstalați din nou.",
|
||||
|
||||
@@ -457,6 +457,7 @@
|
||||
"email_address": "Адрес электронной почты",
|
||||
"enter_valid_email": "Укажите допустимый адрес электронной почты",
|
||||
"location": "Местоположение",
|
||||
"in_person_attendee_address": "Лично (адрес участника)",
|
||||
"yes": "да",
|
||||
"no": "нет",
|
||||
"additional_notes": "Дополнительная информация",
|
||||
@@ -1075,13 +1076,13 @@
|
||||
"new_seat_subject": "{{eventType}}, {{date}}: новый участник {{name}}",
|
||||
"new_seat_title": "Кто-то добавился к событию",
|
||||
"variable": "Переменная",
|
||||
"event_name_workflow": "Название события",
|
||||
"organizer_name_workflow": "Организатор",
|
||||
"attendee_name_workflow": "Участник",
|
||||
"event_date_workflow": "Дата события",
|
||||
"event_time_workflow": "Время события",
|
||||
"location_workflow": "Местоположение",
|
||||
"additional_notes_workflow": "Дополнительная информация",
|
||||
"event_name_variable": "Название события",
|
||||
"organizer_name_variable": "Организатор",
|
||||
"attendee_name_variable": "Участник",
|
||||
"event_date_variable": "Дата события",
|
||||
"event_time_variable": "Время события",
|
||||
"location_variable": "Местоположение",
|
||||
"additional_notes_variable": "Дополнительная информация",
|
||||
"app_upgrade_description": "Чтобы использовать эту функцию, необходимо перейти на аккаунт Pro.",
|
||||
"invalid_number": "Неверный номер телефона",
|
||||
"navigate": "Перейти",
|
||||
@@ -1385,7 +1386,7 @@
|
||||
"team_url_taken": "Этот URL-адрес уже занят",
|
||||
"team_publish": "Опубликовать команду",
|
||||
"number_sms_notifications": "Номер телефона (SMS-уведомления)",
|
||||
"attendee_email_workflow": "Электронная почта участника",
|
||||
"attendee_email_variable": "Электронная почта участника",
|
||||
"attendee_email_info": "Электронная почта участника, на которого оформляется бронирование",
|
||||
"kbar_search_placeholder": "Введите команду или начните поиск...",
|
||||
"invalid_credential": "Похоже, разрешение истекло или было отозвано. Необходима переустановка.",
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user