Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
56a2b66190 | ||
|
|
a0f55707e2 | ||
|
|
b247075a19 | ||
|
|
25ec5313fb | ||
|
|
33f35e77fd | ||
|
|
69808bb9a4 | ||
|
|
18b6a93476 | ||
|
|
e627cc51fd | ||
|
|
b349def58b | ||
|
|
6a6faf30ff | ||
|
|
5616dba4db | ||
|
|
bca1a1b86c | ||
|
|
ddf7a234ab | ||
|
|
fa7260d72a | ||
|
|
5f9f6ef025 | ||
|
|
3d41c64d81 | ||
|
|
8a9b985760 | ||
|
|
c8956680ad | ||
|
|
c2668acd33 | ||
|
|
89bf8321ba | ||
|
|
da625f1527 | ||
|
|
2dddd4ce77 | ||
|
|
cc1d606ba8 | ||
|
|
262c8cf37c | ||
|
|
4366405b21 | ||
|
|
07399974ce | ||
|
|
9d7cd73c7f | ||
|
|
1551a293c5 | ||
|
|
47e948fbbc | ||
|
|
c8b01f6992 | ||
|
|
f3143d99ee | ||
|
|
61a5c3a3b5 | ||
|
|
056edd8ec2 | ||
|
|
d8387835a8 | ||
|
|
26ea249481 | ||
|
|
2d26d73eb3 | ||
|
|
b8b24c04dc | ||
|
|
62dcd6612c | ||
|
|
295748adca | ||
|
|
6e93224c9b | ||
|
|
4d8198d113 | ||
|
|
5fe0ca7913 | ||
|
|
cfb625e934 | ||
|
|
e12b21a73c | ||
|
|
841346c5f2 | ||
|
|
1270742078 | ||
|
|
517cfde5b8 | ||
|
|
51bf613621 | ||
|
|
f4c3ab6431 | ||
|
|
e8acc3e500 | ||
|
|
a6ba0f5b57 | ||
|
|
b82d924f03 | ||
|
|
1cdb51f424 | ||
|
|
aca0dc1b01 | ||
|
|
e5e8c33c34 | ||
|
|
c76847a8f1 | ||
|
|
7b1ced914b | ||
|
|
a6cd173910 | ||
|
|
dcd39c3f04 | ||
|
|
aa0a1fcc95 | ||
|
|
76cf352bce | ||
|
|
86ab19be30 | ||
|
|
e4b766b9d6 | ||
|
|
2529f71770 | ||
|
|
9ea0f02c93 | ||
|
|
fb1828c8f9 | ||
|
|
12f2c1f431 | ||
|
|
29e9bd0ee7 | ||
|
|
9c794bac1a | ||
|
|
feca7c23fb | ||
|
|
31599cdd26 | ||
|
|
e018eb9ebe | ||
|
|
a3f3f1f263 | ||
|
|
d19eaae5b6 | ||
|
|
4eecd42204 | ||
|
|
b9f90144c5 | ||
|
|
8b07b839e9 | ||
|
|
2a98ca4b91 | ||
|
|
b9064b1f72 | ||
|
|
0ec71e52ef | ||
|
|
c20835a4c8 | ||
|
|
8c63b42cec | ||
|
|
ddb752102f | ||
|
|
ef0a7950cf | ||
|
|
641301afab | ||
|
|
7d1bc5f0c5 | ||
|
|
aaccfa49ce | ||
|
|
1b1f3ddfd9 | ||
|
|
f7eda5aa3a | ||
|
|
b2b846647d | ||
|
|
4edc973876 | ||
|
|
3b0126ff35 | ||
|
|
cc4192817b |
+12
-11
@@ -17,16 +17,17 @@ scripts/ @calcom/core
|
||||
apps/docs @calcom/docs
|
||||
apps/swagger @calcom/docs
|
||||
|
||||
packages/app-store-cli @hariombalhara
|
||||
packages/dayjs @zomars
|
||||
packages/emails @zomars
|
||||
packages/embeds @hariombalhara
|
||||
packages/eslint-plugin @zomars
|
||||
packages/features @zomars
|
||||
packages/features/kbar @alishaz-polymath
|
||||
packages/features/ee/impersonation @sean-brydon
|
||||
packages/features/ee/payments @alannnc
|
||||
packages/features/ee/workflows @CarinaWolli
|
||||
packages/features/tips @PeerRich
|
||||
packages/app-store-cli @hariombalhara @calcom/core
|
||||
packages/dayjs @zomars @calcom/core
|
||||
packages/emails @zomars @calcom/core
|
||||
packages/embeds @hariombalhara @calcom/core
|
||||
packages/eslint-plugin @zomars @calcom/core
|
||||
packages/features @zomars @calcom/core
|
||||
packages/features/kbar @alishaz-polymath @calcom/core
|
||||
packages/features/ee/impersonation @sean-brydon @calcom/core
|
||||
packages/features/ee/payments @alannnc @calcom/core
|
||||
packages/features/ee/workflows @CarinaWolli @calcom/core
|
||||
packages/features/tips @PeerRich @calcom/core
|
||||
packages/ui @calcom/ui
|
||||
packages/config @calcom/core
|
||||
packages/app-store/ee/routing-forms @hariombalhara @calcom/core
|
||||
|
||||
@@ -1,23 +1,28 @@
|
||||
name: Cache production build binaries
|
||||
description: "Cache or restore if necessary"
|
||||
env:
|
||||
node_version: v16.x
|
||||
inputs:
|
||||
node_version:
|
||||
required: false
|
||||
default: v16.x
|
||||
runs:
|
||||
using: "composite"
|
||||
steps:
|
||||
- name: Cache production build
|
||||
uses: actions/cache@v3
|
||||
id: cache-build
|
||||
env:
|
||||
cache-name: prod-build
|
||||
key-1: ${{ env.node_version }}-${{ hashFiles('yarn.lock') }}
|
||||
key-2: ${{ hashFiles('apps/web/next.config.js') }}
|
||||
key-1: ${{ inputs.node_version }}-${{ hashFiles('yarn.lock') }}
|
||||
key-2: ${{ hashFiles('apps/**/**.[jt]s', 'apps/**/**.[jt]sx', 'packages/**/**.[jt]s', 'packages/**/**.[jt]sx', '!**/node_modules') }}
|
||||
key-3: ${{ github.event.pull_request.number || github.ref }}
|
||||
# Ensures production-build.yml will always be fresh
|
||||
key-4: ${{ github.sha }}
|
||||
with:
|
||||
path: |
|
||||
apps/web/.next
|
||||
node_modules/.cache/turbo
|
||||
${{ github.workspace }}/apps/web/.next
|
||||
**/.turbo/**
|
||||
**/dist/**
|
||||
key: ${{ runner.os }}-${{ env.cache-name }}-${{ env.key-1 }}-${{ env.key-2 }}-${{ github.sha }}
|
||||
restore-keys: |
|
||||
${{ runner.os }}-${{ env.cache-name }}-${{ env.key-1 }}-${{ env.key-2 }}-
|
||||
${{ runner.os }}-${{ env.cache-name }}-${{ env.key-1 }}-
|
||||
key: ${{ runner.os }}-${{ env.cache-name }}-${{ env.key-1 }}-${{ env.key-2 }}-${{ env.key-3 }}-${{ env.key-4 }}
|
||||
- run: yarn build
|
||||
if: steps.cache-build.outputs.cache-hit != 'true'
|
||||
shell: bash
|
||||
|
||||
@@ -2,7 +2,8 @@ name: Cache database between jobs
|
||||
description: "Cache or restore if necessary"
|
||||
inputs:
|
||||
DATABASE_URL:
|
||||
required: true
|
||||
required: false
|
||||
default: "postgresql://postgres:@localhost:5432/calendso"
|
||||
path:
|
||||
required: false
|
||||
default: "backups/backup.sql"
|
||||
@@ -14,11 +15,14 @@ runs:
|
||||
uses: actions/cache@v3
|
||||
env:
|
||||
cache-name: cache-db
|
||||
key-1: ${{ hashFiles('packages/prisma/schema.prisma', 'packages/prisma/migrations/**/**.sql', 'packages/prisma/*.ts') }}
|
||||
key-2: ${{ github.event.pull_request.number || github.ref }}
|
||||
with:
|
||||
path: ${{ inputs.path }}
|
||||
key: ${{ runner.os }}-${{ env.cache-name }}-${{ inputs.path }}-${{ github.sha }}
|
||||
restore-keys: |
|
||||
${{ runner.os }}-${{ env.cache-name }}-${{ inputs.path }}-${{ github.sha }}
|
||||
key: ${{ runner.os }}-${{ env.cache-name }}-${{ inputs.path }}-${{ env.key-1 }}-${{ env.key-2 }}
|
||||
- run: yarn db-seed
|
||||
if: steps.cache-db.outputs.cache-hit != 'true'
|
||||
shell: bash
|
||||
- name: Postgres Dump Backup
|
||||
if: steps.cache-db.outputs.cache-hit != 'true'
|
||||
uses: tj-actions/pg-dump@v2.3
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
name: "Set environment variables"
|
||||
description: "Configures environment variables for a workflow"
|
||||
runs:
|
||||
using: "composite"
|
||||
steps:
|
||||
- name: Create env file
|
||||
uses: actions/cache@v3
|
||||
id: env-cache
|
||||
with:
|
||||
path: gh.env
|
||||
key: env-cache-${{ hashFiles('gh.env') }}
|
||||
restore-keys: env-cache-
|
||||
- name: Set Environment Variables
|
||||
uses: tw3lveparsecs/github-actions-setvars@latest
|
||||
with:
|
||||
envFilePath: gh.env
|
||||
@@ -1,104 +0,0 @@
|
||||
name: Production Build
|
||||
description: "Creates a production build, caches it and restores if necessary"
|
||||
inputs:
|
||||
DATABASE_URL:
|
||||
required: true
|
||||
NEXT_PUBLIC_WEBAPP_URL:
|
||||
required: true
|
||||
NEXT_PUBLIC_WEBSITE_URL:
|
||||
required: true
|
||||
NEXTAUTH_SECRET:
|
||||
required: true
|
||||
GOOGLE_API_CREDENTIALS:
|
||||
required: true
|
||||
GOOGLE_LOGIN_ENABLED:
|
||||
required: true
|
||||
CRON_API_KEY:
|
||||
required: false
|
||||
CALENDSO_ENCRYPTION_KEY:
|
||||
required: true
|
||||
DAILY_API_KEY:
|
||||
required: true
|
||||
NEXT_PUBLIC_STRIPE_PUBLIC_KEY:
|
||||
required: true
|
||||
NEXT_PUBLIC_STRIPE_FREE_PLAN_PRICE:
|
||||
required: true
|
||||
NEXT_PUBLIC_STRIPE_PRO_PLAN_PRICE:
|
||||
required: true
|
||||
NEXT_PUBLIC_STRIPE_PREMIUM_PLAN_PRICE:
|
||||
required: true
|
||||
NEXT_PUBLIC_STRIPE_PREMIUM_NEW_PLAN_PRICE:
|
||||
required: true
|
||||
NEXT_PUBLIC_IS_PREMIUM_NEW_PLAN:
|
||||
required: true
|
||||
STRIPE_PRIVATE_KEY:
|
||||
required: true
|
||||
STRIPE_CLIENT_ID:
|
||||
required: true
|
||||
STRIPE_WEBHOOK_SECRET:
|
||||
required: true
|
||||
STRIPE_PRO_PLAN_PRODUCT_ID:
|
||||
required: true
|
||||
STRIPE_PREMIUM_PLAN_PRODUCT_ID:
|
||||
required: true
|
||||
STRIPE_FREE_PLAN_PRODUCT_ID:
|
||||
required: true
|
||||
PAYMENT_FEE_PERCENTAGE:
|
||||
required: true
|
||||
PAYMENT_FEE_FIXED:
|
||||
required: true
|
||||
SAML_DATABASE_URL:
|
||||
required: true
|
||||
SAML_ADMINS:
|
||||
required: true
|
||||
NEXTAUTH_URL:
|
||||
required: true
|
||||
NEXT_PUBLIC_IS_E2E:
|
||||
required: true
|
||||
TURBO_TOKEN:
|
||||
required: true
|
||||
TURBO_TEAM:
|
||||
required: true
|
||||
|
||||
runs:
|
||||
using: "composite"
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: ./.github/actions/yarn-install
|
||||
- uses: ./.github/actions/cache-build
|
||||
id: prod-build-cache
|
||||
- name: Next.js production build
|
||||
if: steps.prod-build-cache.outputs.cache-hit != 'true'
|
||||
shell: bash
|
||||
env:
|
||||
DATABASE_URL: ${{ inputs.DATABASE_URL }}
|
||||
NEXT_PUBLIC_WEBAPP_URL: ${{ inputs.NEXT_PUBLIC_WEBAPP_URL }}
|
||||
NEXT_PUBLIC_WEBSITE_URL: ${{ inputs.NEXT_PUBLIC_WEBSITE_URL }}
|
||||
NEXTAUTH_SECRET: ${{ inputs.NEXTAUTH_SECRET }}
|
||||
GOOGLE_API_CREDENTIALS: ${{ inputs.GOOGLE_API_CREDENTIALS }}
|
||||
GOOGLE_LOGIN_ENABLED: ${{ inputs.GOOGLE_LOGIN_ENABLED }}
|
||||
CALENDSO_ENCRYPTION_KEY: ${{ inputs.CALENDSO_ENCRYPTION_KEY }}
|
||||
DAILY_API_KEY: ${{ inputs.DAILY_API_KEY }}
|
||||
NEXT_PUBLIC_STRIPE_PUBLIC_KEY: ${{ inputs.NEXT_PUBLIC_STRIPE_PUBLIC_KEY }}
|
||||
NEXT_PUBLIC_STRIPE_FREE_PLAN_PRICE: ${{ inputs.NEXT_PUBLIC_STRIPE_FREE_PLAN_PRICE }}
|
||||
NEXT_PUBLIC_STRIPE_PRO_PLAN_PRICE: ${{ inputs.NEXT_PUBLIC_STRIPE_PRO_PLAN_PRICE }}
|
||||
NEXT_PUBLIC_STRIPE_PREMIUM_PLAN_PRICE: ${{ inputs.NEXT_PUBLIC_STRIPE_PREMIUM_PLAN_PRICE }}
|
||||
NEXT_PUBLIC_STRIPE_PREMIUM_NEW_PLAN_PRICE: ${{ inputs.NEXT_PUBLIC_STRIPE_PREMIUM_NEW_PLAN_PRICE }}
|
||||
NEXT_PUBLIC_IS_PREMIUM_NEW_PLAN: ${{ inputs.NEXT_PUBLIC_IS_PREMIUM_NEW_PLAN }}
|
||||
STRIPE_PRIVATE_KEY: ${{ inputs.STRIPE_PRIVATE_KEY }}
|
||||
STRIPE_CLIENT_ID: ${{ inputs.STRIPE_CLIENT_ID }}
|
||||
STRIPE_WEBHOOK_SECRET: ${{ inputs.STRIPE_WEBHOOK_SECRET }}
|
||||
STRIPE_PRO_PLAN_PRODUCT_ID: ${{ inputs.STRIPE_PRO_PLAN_PRODUCT_ID }}
|
||||
STRIPE_PREMIUM_PLAN_PRODUCT_ID: ${{ inputs.STRIPE_PREMIUM_PLAN_PRODUCT_ID }}
|
||||
STRIPE_FREE_PLAN_PRODUCT_ID: ${{ inputs.STRIPE_FREE_PLAN_PRODUCT_ID }}
|
||||
PAYMENT_FEE_PERCENTAGE: ${{ inputs.PAYMENT_FEE_PERCENTAGE }}
|
||||
PAYMENT_FEE_FIXED: ${{ inputs.PAYMENT_FEE_FIXED }}
|
||||
SAML_DATABASE_URL: ${{ inputs.SAML_DATABASE_URL }}
|
||||
SAML_ADMINS: ${{ inputs.SAML_ADMINS }}
|
||||
NEXTAUTH_URL: ${{ inputs.NEXTAUTH_URL }}
|
||||
NEXT_PUBLIC_IS_E2E: ${{ inputs.NEXT_PUBLIC_IS_E2E }}
|
||||
TURBO_TOKEN: ${{ inputs.TURBO_TOKEN }}
|
||||
TURBO_TEAM: ${{ inputs.TURBO_TEAM }}
|
||||
run: |
|
||||
yarn db-seed
|
||||
yarn build
|
||||
@@ -1,30 +1,19 @@
|
||||
name: Yarn install
|
||||
description: "Install all NPM dependencies, caches them and restores if necessary"
|
||||
env:
|
||||
node_version: v16.x
|
||||
inputs:
|
||||
node_version:
|
||||
required: false
|
||||
default: v16.x
|
||||
runs:
|
||||
using: "composite"
|
||||
steps:
|
||||
- name: Use Node ${{ env.node_version }}
|
||||
- name: Use Node ${{ inputs.node_version }}
|
||||
uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: ${{ env.node_version }}
|
||||
node-version: ${{ inputs.node_version }}
|
||||
cache: "yarn"
|
||||
- name: node_modules cache
|
||||
id: node-modules-cache
|
||||
uses: actions/cache@v3
|
||||
env:
|
||||
cache-name: node-modules-yarn
|
||||
cache-key: ${{ env.node_version }}-${{ hashFiles('yarn.lock', 'packages/prisma/schema.prisma') }}
|
||||
with:
|
||||
path: |
|
||||
**/node_modules/**
|
||||
packages/prisma/zod
|
||||
key: ${{ runner.os }}-${{ env.cache-name }}-${{ env.cache-key }}
|
||||
restore-keys: ${{ runner.os }}-${{ env.cache-name }}-
|
||||
- name: Yarn install
|
||||
shell: bash
|
||||
if: steps.node-modules-cache.outputs.cache-hit != 'true'
|
||||
run: |
|
||||
yarn install --prefer-offline --frozen-lockfile
|
||||
yarn prisma generate
|
||||
|
||||
@@ -7,37 +7,6 @@ jobs:
|
||||
timeout-minutes: 20
|
||||
name: E2E App-Store Apps
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
env:
|
||||
DATABASE_URL: postgresql://postgres:@localhost:5432/calendso
|
||||
NEXT_PUBLIC_WEBAPP_URL: http://localhost:3000
|
||||
NEXT_PUBLIC_WEBSITE_URL: http://localhost:3000
|
||||
NEXTAUTH_SECRET: secret
|
||||
GOOGLE_API_CREDENTIALS: ${{ secrets.CI_GOOGLE_API_CREDENTIALS }}
|
||||
GOOGLE_LOGIN_ENABLED: true
|
||||
# CRON_API_KEY: xxx
|
||||
CALENDSO_ENCRYPTION_KEY: ${{ secrets.CI_CALENDSO_ENCRYPTION_KEY }}
|
||||
NEXT_PUBLIC_STRIPE_PUBLIC_KEY: ${{ secrets.CI_NEXT_PUBLIC_STRIPE_PUBLIC_KEY }}
|
||||
STRIPE_PRIVATE_KEY: ${{ secrets.CI_STRIPE_PRIVATE_KEY }}
|
||||
STRIPE_CLIENT_ID: ${{ secrets.CI_STRIPE_CLIENT_ID }}
|
||||
STRIPE_WEBHOOK_SECRET: ${{ secrets.CI_STRIPE_WEBHOOK_SECRET }}
|
||||
PAYMENT_FEE_PERCENTAGE: 0.005
|
||||
PAYMENT_FEE_FIXED: 10
|
||||
SAML_DATABASE_URL: postgresql://postgres:@localhost:5432/calendso
|
||||
SAML_ADMINS: pro@example.com
|
||||
NEXTAUTH_URL: http://localhost:3000/api/auth
|
||||
NEXT_PUBLIC_IS_E2E: 1
|
||||
# EMAIL_FROM: e2e@cal.com
|
||||
# EMAIL_SERVER_HOST: ${{ secrets.CI_EMAIL_SERVER_HOST }}
|
||||
# EMAIL_SERVER_PORT: ${{ secrets.CI_EMAIL_SERVER_PORT }}
|
||||
# EMAIL_SERVER_USER: ${{ secrets.CI_EMAIL_SERVER_USER }}
|
||||
# EMAIL_SERVER_PASSWORD: ${{ secrets.CI_EMAIL_SERVER_PASSWORD }}
|
||||
# MS_GRAPH_CLIENT_ID: xxx
|
||||
# MS_GRAPH_CLIENT_SECRET: xxx
|
||||
# ZOOM_CLIENT_ID: xxx
|
||||
# ZOOM_CLIENT_SECRET: xxx
|
||||
TURBO_TOKEN: ${{ secrets.TURBO_TOKEN }}
|
||||
TURBO_TEAM: ${{ secrets.TURBO_TEAM }}
|
||||
services:
|
||||
postgres:
|
||||
image: postgres:12.1
|
||||
@@ -53,13 +22,13 @@ jobs:
|
||||
- run: echo 'NODE_OPTIONS="--max_old_space_size=4096"' >> $GITHUB_ENV
|
||||
- uses: ./.github/actions/yarn-install
|
||||
- uses: ./.github/actions/yarn-playwright-install
|
||||
- uses: ./.github/actions/env-read-file
|
||||
- uses: ./.github/actions/cache-db
|
||||
with:
|
||||
DATABASE_URL: ${{ env.DATABASE_URL }}
|
||||
- uses: ./.github/actions/cache-build
|
||||
- name: Run Tests
|
||||
run: yarn test-e2e:app-store
|
||||
|
||||
env:
|
||||
DEPLOYSENTINEL_API_KEY: ${{ secrets.DEPLOYSENTINEL_API_KEY }}
|
||||
- name: Upload Test Results
|
||||
if: ${{ always() }}
|
||||
uses: actions/upload-artifact@v2
|
||||
|
||||
@@ -6,41 +6,6 @@ jobs:
|
||||
e2e-embed:
|
||||
timeout-minutes: 20
|
||||
runs-on: ubuntu-latest
|
||||
env:
|
||||
DATABASE_URL: postgresql://postgres:@localhost:5432/calendso
|
||||
NEXT_PUBLIC_WEBAPP_URL: http://localhost:3000
|
||||
NEXT_PUBLIC_WEBSITE_URL: http://localhost:3000
|
||||
NEXTAUTH_SECRET: secret
|
||||
GOOGLE_API_CREDENTIALS: ${{ secrets.CI_GOOGLE_API_CREDENTIALS }}
|
||||
GOOGLE_LOGIN_ENABLED: true
|
||||
# CRON_API_KEY: xxx
|
||||
CALENDSO_ENCRYPTION_KEY: ${{ secrets.CI_CALENDSO_ENCRYPTION_KEY }}
|
||||
NEXT_PUBLIC_STRIPE_PUBLIC_KEY: ${{ secrets.CI_NEXT_PUBLIC_STRIPE_PUBLIC_KEY }}
|
||||
NEXT_PUBLIC_STRIPE_FREE_PLAN_PRICE: ${{ secrets.CI_NEXT_PUBLIC_STRIPE_FREE_PLAN_PRICE }}
|
||||
NEXT_PUBLIC_STRIPE_PRO_PLAN_PRICE: ${{ secrets.CI_NEXT_PUBLIC_STRIPE_PRO_PLAN_PRICE }}
|
||||
NEXT_PUBLIC_STRIPE_PREMIUM_PLAN_PRICE: ${{ secrets.CI_NEXT_PUBLIC_STRIPE_PREMIUM_PLAN_PRICE }}
|
||||
NEXT_PUBLIC_STRIPE_PREMIUM_NEW_PLAN_PRICE: ${{ secrets.NEXT_PUBLIC_STRIPE_PREMIUM_NEW_PLAN_PRICE }}
|
||||
NEXT_PUBLIC_IS_PREMIUM_NEW_PLAN: 1
|
||||
STRIPE_PRIVATE_KEY: ${{ secrets.CI_STRIPE_PRIVATE_KEY }}
|
||||
STRIPE_CLIENT_ID: ${{ secrets.CI_STRIPE_CLIENT_ID }}
|
||||
STRIPE_WEBHOOK_SECRET: ${{ secrets.CI_STRIPE_WEBHOOK_SECRET }}
|
||||
PAYMENT_FEE_PERCENTAGE: 0.005
|
||||
PAYMENT_FEE_FIXED: 10
|
||||
SAML_DATABASE_URL: postgresql://postgres:@localhost:5432/calendso
|
||||
SAML_ADMINS: pro@example.com
|
||||
NEXTAUTH_URL: http://localhost:3000/api/auth
|
||||
NEXT_PUBLIC_IS_E2E: 1
|
||||
# EMAIL_FROM: e2e@cal.com
|
||||
# EMAIL_SERVER_HOST: ${{ secrets.CI_EMAIL_SERVER_HOST }}
|
||||
# EMAIL_SERVER_PORT: ${{ secrets.CI_EMAIL_SERVER_PORT }}
|
||||
# EMAIL_SERVER_USER: ${{ secrets.CI_EMAIL_SERVER_USER }}
|
||||
# EMAIL_SERVER_PASSWORD: ${{ secrets.CI_EMAIL_SERVER_PASSWORD }}
|
||||
# MS_GRAPH_CLIENT_ID: xxx
|
||||
# MS_GRAPH_CLIENT_SECRET: xxx
|
||||
# ZOOM_CLIENT_ID: xxx
|
||||
# ZOOM_CLIENT_SECRET: xxx
|
||||
TURBO_TOKEN: ${{ secrets.TURBO_TOKEN }}
|
||||
TURBO_TEAM: ${{ secrets.TURBO_TEAM }}
|
||||
services:
|
||||
postgres:
|
||||
image: postgres:12.1
|
||||
@@ -56,22 +21,23 @@ jobs:
|
||||
- run: echo 'NODE_OPTIONS="--max_old_space_size=4096"' >> $GITHUB_ENV
|
||||
- uses: ./.github/actions/yarn-install
|
||||
- uses: ./.github/actions/yarn-playwright-install
|
||||
- uses: ./.github/actions/env-read-file
|
||||
- uses: ./.github/actions/cache-db
|
||||
with:
|
||||
DATABASE_URL: ${{ env.DATABASE_URL }}
|
||||
- uses: ./.github/actions/cache-build
|
||||
- name: Run Tests
|
||||
run: yarn turbo run embed-tests-update-snapshots:ci --scope=@calcom/embed-react --concurrency=1
|
||||
env:
|
||||
DEPLOYSENTINEL_API_KEY: ${{ secrets.DEPLOYSENTINEL_API_KEY }}
|
||||
- name: Upload embed-core results
|
||||
if: ${{ always() }}
|
||||
uses: actions/upload-artifact@v2
|
||||
with:
|
||||
name: test-results-core
|
||||
name: test-results-embed-core
|
||||
path: packages/embeds/embed-core/playwright/results
|
||||
|
||||
- name: Upload embed-react results
|
||||
if: ${{ always() }}
|
||||
uses: actions/upload-artifact@v2
|
||||
with:
|
||||
name: test-results-react
|
||||
name: test-results-embed-react
|
||||
path: packages/embeds/embed-react/playwright/results
|
||||
|
||||
@@ -4,46 +4,8 @@ on:
|
||||
jobs:
|
||||
e2e:
|
||||
timeout-minutes: 20
|
||||
runs-on: buildjet-4vcpu-ubuntu-2204
|
||||
env:
|
||||
DATABASE_URL: postgresql://postgres:@localhost:5432/calendso
|
||||
NEXT_PUBLIC_WEBAPP_URL: http://localhost:3000
|
||||
NEXT_PUBLIC_WEBSITE_URL: http://localhost:3000
|
||||
NEXTAUTH_SECRET: secret
|
||||
GOOGLE_API_CREDENTIALS: ${{ secrets.CI_GOOGLE_API_CREDENTIALS }}
|
||||
GOOGLE_LOGIN_ENABLED: true
|
||||
# CRON_API_KEY: xxx
|
||||
CALENDSO_ENCRYPTION_KEY: ${{ secrets.CI_CALENDSO_ENCRYPTION_KEY }}
|
||||
DAILY_API_KEY: ${{ secrets.CI_DAILY_API_KEY }}
|
||||
NEXT_PUBLIC_STRIPE_PUBLIC_KEY: ${{ secrets.CI_NEXT_PUBLIC_STRIPE_PUBLIC_KEY }}
|
||||
NEXT_PUBLIC_STRIPE_FREE_PLAN_PRICE: ${{ secrets.CI_NEXT_PUBLIC_STRIPE_FREE_PLAN_PRICE }}
|
||||
NEXT_PUBLIC_STRIPE_PRO_PLAN_PRICE: ${{ secrets.CI_NEXT_PUBLIC_STRIPE_PRO_PLAN_PRICE }}
|
||||
NEXT_PUBLIC_STRIPE_PREMIUM_PLAN_PRICE: ${{ secrets.CI_NEXT_PUBLIC_STRIPE_PREMIUM_PLAN_PRICE }}
|
||||
NEXT_PUBLIC_STRIPE_PREMIUM_NEW_PLAN_PRICE: ${{ secrets.NEXT_PUBLIC_STRIPE_PREMIUM_NEW_PLAN_PRICE }}
|
||||
NEXT_PUBLIC_IS_PREMIUM_NEW_PLAN: 1
|
||||
STRIPE_PRIVATE_KEY: ${{ secrets.CI_STRIPE_PRIVATE_KEY }}
|
||||
STRIPE_CLIENT_ID: ${{ secrets.CI_STRIPE_CLIENT_ID }}
|
||||
STRIPE_WEBHOOK_SECRET: ${{ secrets.CI_STRIPE_WEBHOOK_SECRET }}
|
||||
STRIPE_PRO_PLAN_PRODUCT_ID: ${{ secrets.CI_STRIPE_PRO_PLAN_PRODUCT_ID }}
|
||||
STRIPE_PREMIUM_PLAN_PRODUCT_ID: ${{ secrets.CI_STRIPE_PREMIUM_PLAN_PRODUCT_ID }}
|
||||
STRIPE_FREE_PLAN_PRODUCT_ID: ${{ secrets.CI_STRIPE_FREE_PLAN_PRODUCT_ID }}
|
||||
PAYMENT_FEE_PERCENTAGE: 0.005
|
||||
PAYMENT_FEE_FIXED: 10
|
||||
SAML_DATABASE_URL: postgresql://postgres:@localhost:5432/calendso
|
||||
SAML_ADMINS: pro@example.com
|
||||
NEXTAUTH_URL: http://localhost:3000/api/auth
|
||||
NEXT_PUBLIC_IS_E2E: 1
|
||||
# EMAIL_FROM: e2e@cal.com
|
||||
# EMAIL_SERVER_HOST: ${{ secrets.CI_EMAIL_SERVER_HOST }}
|
||||
# EMAIL_SERVER_PORT: ${{ secrets.CI_EMAIL_SERVER_PORT }}
|
||||
# EMAIL_SERVER_USER: ${{ secrets.CI_EMAIL_SERVER_USER }}
|
||||
# EMAIL_SERVER_PASSWORD: ${{ secrets.CI_EMAIL_SERVER_PASSWORD }}
|
||||
# MS_GRAPH_CLIENT_ID: xxx
|
||||
# MS_GRAPH_CLIENT_SECRET: xxx
|
||||
# ZOOM_CLIENT_ID: xxx
|
||||
# ZOOM_CLIENT_SECRET: xxx
|
||||
TURBO_TOKEN: ${{ secrets.TURBO_TOKEN }}
|
||||
TURBO_TEAM: ${{ secrets.TURBO_TEAM }}
|
||||
name: E2E tests
|
||||
runs-on: ubuntu-latest
|
||||
services:
|
||||
postgres:
|
||||
image: postgres:12.1
|
||||
@@ -52,19 +14,20 @@ jobs:
|
||||
POSTGRES_DB: calendso
|
||||
ports:
|
||||
- 5432:5432
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: ./.github/actions/dangerous-git-checkout
|
||||
- run: echo 'NODE_OPTIONS="--max_old_space_size=4096"' >> $GITHUB_ENV
|
||||
- uses: ./.github/actions/yarn-install
|
||||
- uses: ./.github/actions/yarn-playwright-install
|
||||
- uses: ./.github/actions/env-read-file
|
||||
- uses: ./.github/actions/cache-db
|
||||
with:
|
||||
DATABASE_URL: ${{ env.DATABASE_URL }}
|
||||
- uses: ./.github/actions/cache-build
|
||||
- run: yarn test-e2e
|
||||
- name: Upload test results
|
||||
- name: Run Tests
|
||||
run: yarn test-e2e
|
||||
env:
|
||||
DEPLOYSENTINEL_API_KEY: ${{ secrets.DEPLOYSENTINEL_API_KEY }}
|
||||
- name: Upload Test Results
|
||||
if: ${{ always() }}
|
||||
uses: actions/upload-artifact@v2
|
||||
with:
|
||||
|
||||
@@ -0,0 +1,49 @@
|
||||
name: Create .env file
|
||||
|
||||
on:
|
||||
workflow_call:
|
||||
|
||||
env:
|
||||
INPUT_ENV_DATABASE_URL: postgresql://postgres:@localhost:5432/calendso
|
||||
INPUT_ENV_NEXT_PUBLIC_WEBAPP_URL: http://localhost:3000
|
||||
INPUT_ENV_NEXT_PUBLIC_WEBSITE_URL: http://localhost:3000
|
||||
INPUT_ENV_NEXTAUTH_SECRET: secret
|
||||
INPUT_ENV_GOOGLE_API_CREDENTIALS: ${{ secrets.CI_GOOGLE_API_CREDENTIALS }}
|
||||
INPUT_ENV_GOOGLE_LOGIN_ENABLED: true
|
||||
# INPUT_ENV_CRON_API_KEY: xxx
|
||||
INPUT_ENV_CALENDSO_ENCRYPTION_KEY: ${{ secrets.CI_CALENDSO_ENCRYPTION_KEY }}
|
||||
INPUT_ENV_NEXT_PUBLIC_STRIPE_PUBLIC_KEY: ${{ secrets.CI_NEXT_PUBLIC_STRIPE_PUBLIC_KEY }}
|
||||
INPUT_ENV_STRIPE_PRIVATE_KEY: ${{ secrets.CI_STRIPE_PRIVATE_KEY }}
|
||||
INPUT_ENV_STRIPE_CLIENT_ID: ${{ secrets.CI_STRIPE_CLIENT_ID }}
|
||||
INPUT_ENV_STRIPE_WEBHOOK_SECRET: ${{ secrets.CI_STRIPE_WEBHOOK_SECRET }}
|
||||
INPUT_ENV_PAYMENT_FEE_PERCENTAGE: 0.005
|
||||
INPUT_ENV_PAYMENT_FEE_FIXED: 10
|
||||
INPUT_ENV_SAML_DATABASE_URL: postgresql://postgres:@localhost:5432/calendso
|
||||
INPUT_ENV_SAML_ADMINS: pro@example.com
|
||||
INPUT_ENV_NEXTAUTH_URL: http://localhost:3000/api/auth
|
||||
INPUT_ENV_NEXT_PUBLIC_IS_E2E: 1
|
||||
# INPUT_ENV_EMAIL_FROM: e2e@cal.com
|
||||
# INPUT_ENV_EMAIL_SERVER_HOST: ${{ secrets.CI_EMAIL_SERVER_HOST }}
|
||||
# INPUT_ENV_EMAIL_SERVER_PORT: ${{ secrets.CI_EMAIL_SERVER_PORT }}
|
||||
# INPUT_ENV_EMAIL_SERVER_USER: ${{ secrets.CI_EMAIL_SERVER_USER }}
|
||||
# INPUT_ENV_EMAIL_SERVER_PASSWORD: ${{ secrets.CI_EMAIL_SERVER_PASSWORD }}
|
||||
# INPUT_ENV_MS_GRAPH_CLIENT_ID: xxx
|
||||
# INPUT_ENV_MS_GRAPH_CLIENT_SECRET: xxx
|
||||
# INPUT_ENV_ZOOM_CLIENT_ID: xxx
|
||||
# INPUT_ENV_ZOOM_CLIENT_SECRET: xxx
|
||||
INPUT_ENV_TURBO_TOKEN: ${{ secrets.TURBO_TOKEN }}
|
||||
INPUT_ENV_TURBO_TEAM: ${{ secrets.TURBO_TEAM }}
|
||||
|
||||
jobs:
|
||||
create_env_file:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: ozaytsev86/create-env-file@v1
|
||||
with:
|
||||
file-name: ${{ github.workspace }}/gh.env
|
||||
- uses: actions/cache@v3
|
||||
id: env-cache
|
||||
with:
|
||||
path: gh.env
|
||||
key: env-cache-${{ hashFiles('gh.env') }}
|
||||
@@ -4,6 +4,9 @@ on:
|
||||
pull_request_target:
|
||||
branches:
|
||||
- main
|
||||
paths-ignore:
|
||||
- "**.md"
|
||||
- ".github/CODEOWNERS"
|
||||
workflow_dispatch:
|
||||
|
||||
concurrency:
|
||||
@@ -32,38 +35,35 @@ jobs:
|
||||
- 'apps/web/**'
|
||||
- 'packages/embeds/**'
|
||||
|
||||
setup:
|
||||
name: Yarn install & cache
|
||||
uses: ./.github/workflows/yarn-install.yml
|
||||
env:
|
||||
name: Create env file
|
||||
uses: ./.github/workflows/env-create-file.yml
|
||||
secrets: inherit
|
||||
|
||||
type-check:
|
||||
name: Type check
|
||||
needs: setup
|
||||
uses: ./.github/workflows/check-types.yml
|
||||
secrets: inherit
|
||||
|
||||
test:
|
||||
name: Unit tests
|
||||
needs: setup
|
||||
uses: ./.github/workflows/test.yml
|
||||
secrets: inherit
|
||||
|
||||
lint:
|
||||
name: Linters
|
||||
needs: setup
|
||||
uses: ./.github/workflows/lint.yml
|
||||
secrets: inherit
|
||||
|
||||
build:
|
||||
name: Production build
|
||||
needs: setup
|
||||
needs: env
|
||||
uses: ./.github/workflows/production-build.yml
|
||||
secrets: inherit
|
||||
|
||||
e2e:
|
||||
name: E2E tests
|
||||
needs: [lint, build]
|
||||
needs: [changes, lint, build]
|
||||
uses: ./.github/workflows/e2e.yml
|
||||
secrets: inherit
|
||||
|
||||
@@ -78,7 +78,7 @@ jobs:
|
||||
name: E2E embeds tests
|
||||
if: ${{ needs.changes.outputs.embed == 'true' }}
|
||||
needs: [changes, lint, build]
|
||||
uses: ./.github/workflows/e2e.yml
|
||||
uses: ./.github/workflows/e2e-embed.yml
|
||||
secrets: inherit
|
||||
|
||||
analyze:
|
||||
|
||||
@@ -3,36 +3,6 @@ name: Production Build
|
||||
on:
|
||||
workflow_call:
|
||||
|
||||
env:
|
||||
DATABASE_URL: postgresql://postgres:@localhost:5432/calendso
|
||||
NEXT_PUBLIC_WEBAPP_URL: http://localhost:3000
|
||||
NEXT_PUBLIC_WEBSITE_URL: http://localhost:3000
|
||||
NEXTAUTH_SECRET: secret
|
||||
GOOGLE_API_CREDENTIALS: ${{ secrets.CI_GOOGLE_API_CREDENTIALS }}
|
||||
GOOGLE_LOGIN_ENABLED: true
|
||||
# CRON_API_KEY: xxx
|
||||
CALENDSO_ENCRYPTION_KEY: ${{ secrets.CI_CALENDSO_ENCRYPTION_KEY }}
|
||||
DAILY_API_KEY: ${{ secrets.CI_DAILY_API_KEY }}
|
||||
NEXT_PUBLIC_STRIPE_PUBLIC_KEY: ${{ secrets.CI_NEXT_PUBLIC_STRIPE_PUBLIC_KEY }}
|
||||
NEXT_PUBLIC_STRIPE_FREE_PLAN_PRICE: ${{ secrets.CI_NEXT_PUBLIC_STRIPE_FREE_PLAN_PRICE }}
|
||||
NEXT_PUBLIC_STRIPE_PRO_PLAN_PRICE: ${{ secrets.CI_NEXT_PUBLIC_STRIPE_PRO_PLAN_PRICE }}
|
||||
NEXT_PUBLIC_STRIPE_PREMIUM_PLAN_PRICE: ${{ secrets.CI_NEXT_PUBLIC_STRIPE_PREMIUM_PLAN_PRICE }}
|
||||
NEXT_PUBLIC_STRIPE_PREMIUM_NEW_PLAN_PRICE: ${{ secrets.NEXT_PUBLIC_STRIPE_PREMIUM_NEW_PLAN_PRICE }}
|
||||
NEXT_PUBLIC_IS_PREMIUM_NEW_PLAN: 1
|
||||
STRIPE_PRIVATE_KEY: ${{ secrets.CI_STRIPE_PRIVATE_KEY }}
|
||||
STRIPE_CLIENT_ID: ${{ secrets.CI_STRIPE_CLIENT_ID }}
|
||||
STRIPE_WEBHOOK_SECRET: ${{ secrets.CI_STRIPE_WEBHOOK_SECRET }}
|
||||
STRIPE_PRO_PLAN_PRODUCT_ID: ${{ secrets.CI_STRIPE_PRO_PLAN_PRODUCT_ID }}
|
||||
STRIPE_PREMIUM_PLAN_PRODUCT_ID: ${{ secrets.CI_STRIPE_PREMIUM_PLAN_PRODUCT_ID }}
|
||||
STRIPE_FREE_PLAN_PRODUCT_ID: ${{ secrets.CI_STRIPE_FREE_PLAN_PRODUCT_ID }}
|
||||
PAYMENT_FEE_PERCENTAGE: 0.005
|
||||
PAYMENT_FEE_FIXED: 10
|
||||
SAML_DATABASE_URL: postgresql://postgres:@localhost:5432/calendso
|
||||
SAML_ADMINS: pro@example.com
|
||||
NEXTAUTH_URL: http://localhost:3000/api/auth
|
||||
NEXT_PUBLIC_IS_E2E: 1
|
||||
TURBO_TOKEN: ${{ secrets.TURBO_TOKEN }}
|
||||
TURBO_TEAM: ${{ secrets.TURBO_TEAM }}
|
||||
jobs:
|
||||
build:
|
||||
name: Build
|
||||
@@ -48,38 +18,8 @@ jobs:
|
||||
- 5432:5432
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: ./.github/actions/dangerous-git-checkout
|
||||
- uses: ./.github/actions/yarn-install
|
||||
- uses: ./.github/actions/yarn-build
|
||||
with:
|
||||
# GitHub Composite actions cannot read secrets, we have to pass them in here
|
||||
DATABASE_URL: ${{ env.DATABASE_URL }}
|
||||
NEXT_PUBLIC_WEBAPP_URL: ${{ env.NEXT_PUBLIC_WEBAPP_URL }}
|
||||
NEXT_PUBLIC_WEBSITE_URL: ${{ env.NEXT_PUBLIC_WEBSITE_URL }}
|
||||
NEXTAUTH_SECRET: ${{ env.NEXTAUTH_SECRET }}
|
||||
GOOGLE_API_CREDENTIALS: ${{ env.GOOGLE_API_CREDENTIALS }}
|
||||
GOOGLE_LOGIN_ENABLED: ${{ env.GOOGLE_LOGIN_ENABLED }}
|
||||
CALENDSO_ENCRYPTION_KEY: ${{ env.CALENDSO_ENCRYPTION_KEY }}
|
||||
DAILY_API_KEY: ${{ env.DAILY_API_KEY }}
|
||||
NEXT_PUBLIC_STRIPE_PUBLIC_KEY: ${{ env.NEXT_PUBLIC_STRIPE_PUBLIC_KEY }}
|
||||
NEXT_PUBLIC_STRIPE_FREE_PLAN_PRICE: ${{ env.NEXT_PUBLIC_STRIPE_FREE_PLAN_PRICE }}
|
||||
NEXT_PUBLIC_STRIPE_PRO_PLAN_PRICE: ${{ env.NEXT_PUBLIC_STRIPE_PRO_PLAN_PRICE }}
|
||||
NEXT_PUBLIC_STRIPE_PREMIUM_PLAN_PRICE: ${{ env.NEXT_PUBLIC_STRIPE_PREMIUM_PLAN_PRICE }}
|
||||
NEXT_PUBLIC_STRIPE_PREMIUM_NEW_PLAN_PRICE: ${{ env.NEXT_PUBLIC_STRIPE_PREMIUM_NEW_PLAN_PRICE }}
|
||||
NEXT_PUBLIC_IS_PREMIUM_NEW_PLAN: ${{ env.NEXT_PUBLIC_IS_PREMIUM_NEW_PLAN }}
|
||||
STRIPE_PRIVATE_KEY: ${{ env.STRIPE_PRIVATE_KEY }}
|
||||
STRIPE_CLIENT_ID: ${{ env.STRIPE_CLIENT_ID }}
|
||||
STRIPE_WEBHOOK_SECRET: ${{ env.STRIPE_WEBHOOK_SECRET }}
|
||||
STRIPE_PRO_PLAN_PRODUCT_ID: ${{ env.STRIPE_PRO_PLAN_PRODUCT_ID }}
|
||||
STRIPE_PREMIUM_PLAN_PRODUCT_ID: ${{ env.STRIPE_PREMIUM_PLAN_PRODUCT_ID }}
|
||||
STRIPE_FREE_PLAN_PRODUCT_ID: ${{ env.STRIPE_FREE_PLAN_PRODUCT_ID }}
|
||||
PAYMENT_FEE_PERCENTAGE: ${{ env.PAYMENT_FEE_PERCENTAGE }}
|
||||
PAYMENT_FEE_FIXED: ${{ env.PAYMENT_FEE_FIXED }}
|
||||
SAML_DATABASE_URL: ${{ env.SAML_DATABASE_URL }}
|
||||
SAML_ADMINS: ${{ env.SAML_ADMINS }}
|
||||
NEXTAUTH_URL: ${{ env.NEXTAUTH_URL }}
|
||||
NEXT_PUBLIC_IS_E2E: ${{ env.NEXT_PUBLIC_IS_E2E }}
|
||||
TURBO_TOKEN: ${{ env.TURBO_TOKEN }}
|
||||
TURBO_TEAM: ${{ env.TURBO_TEAM }}
|
||||
- uses: ./.github/actions/env-read-file
|
||||
- uses: ./.github/actions/cache-db
|
||||
with:
|
||||
DATABASE_URL: ${{ env.DATABASE_URL }}
|
||||
- uses: ./.github/actions/cache-build
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
name: TODO to Issue
|
||||
on:
|
||||
pull_request_target: # So we can test on forks
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
workflow_dispatch:
|
||||
@@ -12,17 +12,13 @@ on:
|
||||
description: "By default, the commit entered above is compared to the one directly before it; to go back further, enter an earlier SHA here"
|
||||
required: false
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
|
||||
group: ${{ github.workflow }}-${{ github.ref }}
|
||||
cancel-in-progress: true
|
||||
jobs:
|
||||
todos:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout repo
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
ref: ${{ github.event.pull_request.head.sha }}
|
||||
fetch-depth: 2
|
||||
- uses: actions/checkout@v3
|
||||
- name: "Add TODOs to issues"
|
||||
uses: "alstr/todo-to-issue-action@v4"
|
||||
env:
|
||||
|
||||
Vendored
+12
-30
@@ -2,38 +2,20 @@
|
||||
"version": "0.2.0",
|
||||
"configurations": [
|
||||
{
|
||||
"name": "Next.js: Server",
|
||||
"type": "node-terminal",
|
||||
"type": "node",
|
||||
"request": "launch",
|
||||
"command": "npm run dev",
|
||||
"skipFiles": ["<node_internals>/**"],
|
||||
"outFiles": [
|
||||
"${workspaceFolder}/**/*.js",
|
||||
"!**/node_modules/**"
|
||||
],
|
||||
"sourceMaps": true,
|
||||
"resolveSourceMapLocations": [
|
||||
"${workspaceFolder}/**",
|
||||
"!**/node_modules/**"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Next.js: Client",
|
||||
"type": "pwa-chrome",
|
||||
"request": "launch",
|
||||
"url": "http://localhost:3000"
|
||||
},
|
||||
{
|
||||
"name": "Next.js: Full Stack",
|
||||
"type": "node-terminal",
|
||||
"request": "launch",
|
||||
"command": "npm run dev",
|
||||
"name": "Next.js Node Debug",
|
||||
"runtimeExecutable": "${workspaceFolder}/node_modules/next/dist/bin/next",
|
||||
"env": {
|
||||
"NODE_OPTIONS": "--inspect"
|
||||
},
|
||||
"cwd": "${workspaceFolder}/apps/web",
|
||||
"console": "integratedTerminal",
|
||||
"serverReadyAction": {
|
||||
"pattern": "started server on .+, url: (https?://.+)",
|
||||
"uriFormat": "%s",
|
||||
"action": "debugWithChrome"
|
||||
"sourceMapPathOverrides": {
|
||||
"meteor://💻app/*": "${workspaceFolder}/*",
|
||||
"webpack:///./~/*": "${workspaceFolder}/node_modules/*",
|
||||
"webpack://?:*/*": "${workspaceFolder}/*"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -128,6 +128,6 @@ If you get errors, be sure to fix them before committing.
|
||||
## Making a Pull Request
|
||||
|
||||
- Be sure to [check the "Allow edits from maintainers" option](https://docs.github.com/en/pull-requests/collaborating-with-pull-requests/working-with-forks/allowing-changes-to-a-pull-request-branch-created-from-a-fork) while creating you PR.
|
||||
- If your PR refers to or fixes an issue, be sure to add `refs #XXX` or `fixes #XXX` to the PR description. Replacing `XXX` with the respective issue number. Se more about [Linking a pull request to an issue
|
||||
- If your PR refers to or fixes an issue, be sure to add `refs #XXX` or `fixes #XXX` to the PR description. Replacing `XXX` with the respective issue number. See more about [Linking a pull request to an issue
|
||||
](https://docs.github.com/en/issues/tracking-your-work-with-issues/linking-a-pull-request-to-an-issue).
|
||||
- Be sure to fill the PR Template accordingly.
|
||||
|
||||
@@ -350,8 +350,17 @@ We have a list of [help wanted](https://github.com/calcom/cal.com/issues?q=is:is
|
||||
<img alt="Bounties of cal" src="https://console.algora.io/api/og/cal/bounties.png?p=0&status=open&theme=light">
|
||||
</picture>
|
||||
</a>
|
||||
|
||||
|
||||
<!-- CONTRIBUTORS -->
|
||||
|
||||
### Contributors
|
||||
|
||||
<a href="https://github.com/calcom/cal.com/graphs/contributors">
|
||||
<img src="https://contrib.rocks/image?repo=calcom/cal.com" />
|
||||
</a>
|
||||
|
||||
|
||||
<!-- TRANSLATIONS -->
|
||||
|
||||
### Translations
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"iframe-resizer-react": "^1.1.0",
|
||||
"next": "^13.1.1",
|
||||
"next": "^13.2.1",
|
||||
"nextra": "^1.1.0",
|
||||
"nextra-theme-docs": "^1.2.2",
|
||||
"react": "^18.2.0",
|
||||
|
||||
@@ -1,21 +1,7 @@
|
||||
const withBundleAnalyzer = require("@next/bundle-analyzer");
|
||||
|
||||
const withTM = require("next-transpile-modules")([
|
||||
"@calcom/app-store",
|
||||
"@calcom/dayjs",
|
||||
"@calcom/emails",
|
||||
"@calcom/trpc",
|
||||
"@calcom/embed-core",
|
||||
"@calcom/embed-react",
|
||||
"@calcom/features",
|
||||
"@calcom/lib",
|
||||
"@calcom/prisma",
|
||||
"@calcom/ui",
|
||||
]);
|
||||
const glob = require("glob");
|
||||
|
||||
const plugins = [];
|
||||
plugins.push(withTM, withBundleAnalyzer({ enabled: process.env.ANALYZE === "true" }));
|
||||
plugins.push(withBundleAnalyzer({ enabled: process.env.ANALYZE === "true" }));
|
||||
|
||||
/** @type {import("next").NextConfig} */
|
||||
const nextConfig = {
|
||||
@@ -27,7 +13,18 @@ const nextConfig = {
|
||||
typescript: {
|
||||
ignoreBuildErrors: true,
|
||||
},
|
||||
experimental: { images: { allowFutureImage: true } },
|
||||
transpilePackages: [
|
||||
"@calcom/app-store",
|
||||
"@calcom/dayjs",
|
||||
"@calcom/emails",
|
||||
"@calcom/trpc",
|
||||
"@calcom/embed-core",
|
||||
"@calcom/embed-react",
|
||||
"@calcom/features",
|
||||
"@calcom/lib",
|
||||
"@calcom/prisma",
|
||||
"@calcom/ui",
|
||||
],
|
||||
eslint: {
|
||||
ignoreDuringBuilds: true,
|
||||
},
|
||||
|
||||
@@ -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": "^13.1.1",
|
||||
"next": "^13.2.1",
|
||||
"react": "^18.2.0",
|
||||
"react-dom": "^18.2.0",
|
||||
"storybook-addon-rtl-direction": "^0.0.19"
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
"dependencies": {
|
||||
"highlight.js": "^11.6.0",
|
||||
"isarray": "2.0.5",
|
||||
"next": "^13.1.1",
|
||||
"next": "^13.2.1",
|
||||
"openapi-snippet": "^0.13.0",
|
||||
"react": "^18.2.0",
|
||||
"react-dom": "^18.2.0",
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import React from "react";
|
||||
|
||||
import { SkeletonText } from "@calcom/ui";
|
||||
import { Button, SkeletonText } from "@calcom/ui";
|
||||
import { FiMoreHorizontal } from "@calcom/ui/components/icon";
|
||||
|
||||
import classNames from "@lib/classNames";
|
||||
|
||||
@@ -18,17 +19,21 @@ export default SkeletonLoader;
|
||||
|
||||
function SkeletonItem() {
|
||||
return (
|
||||
<li className="group flex w-full items-center justify-between px-2 py-[23px] sm:px-6">
|
||||
<div className="flex-grow truncate text-sm">
|
||||
<div className="flex flex-col space-y-2">
|
||||
<SkeletonText className="h-4 w-32" />
|
||||
<SkeletonText className="h-2 w-32" />
|
||||
</div>
|
||||
</div>
|
||||
<div className="mt-4 hidden flex-shrink-0 sm:mt-0 sm:ml-5 lg:flex">
|
||||
<div className="flex justify-between space-x-2 rtl:space-x-reverse">
|
||||
<SkeletonText className="h-6 w-12" />
|
||||
<li>
|
||||
<div className="flex items-center justify-between py-5 hover:bg-neutral-50 ltr:pl-4 rtl:pr-4 sm:ltr:pl-0 sm:rtl:pr-0">
|
||||
<div className="items-between flex w-full flex-col justify-center hover:bg-neutral-50 sm:px-6">
|
||||
<SkeletonText className="my-1 h-4 w-32" />
|
||||
<SkeletonText className="my-1 h-2 w-24" />
|
||||
<SkeletonText className="my-1 h-2 w-40" />
|
||||
</div>
|
||||
<Button
|
||||
className="mx-5"
|
||||
type="button"
|
||||
variant="icon"
|
||||
color="secondary"
|
||||
StartIcon={FiMoreHorizontal}
|
||||
disabled
|
||||
/>
|
||||
</div>
|
||||
</li>
|
||||
);
|
||||
|
||||
@@ -6,7 +6,7 @@ import dayjs from "@calcom/dayjs";
|
||||
import classNames from "@calcom/lib/classNames";
|
||||
import { useLocale } from "@calcom/lib/hooks/useLocale";
|
||||
import { Badge } from "@calcom/ui";
|
||||
import { FiCheckSquare, FiClock, FiInfo } from "@calcom/ui/components/icon";
|
||||
import { FiCheckSquare, FiClock } from "@calcom/ui/components/icon";
|
||||
|
||||
import useRouterQuery from "@lib/hooks/useRouterQuery";
|
||||
|
||||
@@ -94,15 +94,7 @@ const BookingDescription: FC<Props> = (props) => {
|
||||
"flex",
|
||||
isBookingPage && "dark:text-darkgray-600 text-sm font-medium text-gray-600"
|
||||
)}>
|
||||
<div>
|
||||
<FiInfo
|
||||
className={classNames(
|
||||
"ml-[2px] inline-block h-4 w-4 ltr:mr-[10px] rtl:ml-[10px]",
|
||||
isBookingPage && "dark:text-darkgray-600 -mt-1 text-gray-500"
|
||||
)}
|
||||
/>
|
||||
</div>
|
||||
<div className="max-w-[calc(100%_-_2rem)] flex-shrink break-words">
|
||||
<div className="scroll-bar scrollbar-track-w-20 max-h-[200px] max-w-full flex-shrink break-words [&_a]:text-blue-500 [&_a]:underline [&_a]:hover:text-blue-600">
|
||||
<EventTypeDescriptionSafeHTML eventType={eventType} />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -0,0 +1,24 @@
|
||||
import { FormattedNumber, IntlProvider } from "react-intl";
|
||||
|
||||
import getPaymentAppData from "@calcom/lib/getPaymentAppData";
|
||||
import { FiCreditCard } from "@calcom/ui/components/icon";
|
||||
|
||||
const BookingDescriptionPayment = (props: { eventType: Parameters<typeof getPaymentAppData>[0] }) => {
|
||||
const paymentAppData = getPaymentAppData(props.eventType);
|
||||
if (!paymentAppData || paymentAppData.price <= 0) return null;
|
||||
|
||||
return (
|
||||
<p className="text-bookinglight -ml-2 px-2 text-sm ">
|
||||
<FiCreditCard className="ml-[2px] -mt-1 inline-block h-4 w-4 ltr:mr-[10px] rtl:ml-[10px]" />
|
||||
<IntlProvider locale="en">
|
||||
<FormattedNumber
|
||||
value={paymentAppData.price / 100.0}
|
||||
style="currency"
|
||||
currency={paymentAppData.currency?.toUpperCase()}
|
||||
/>
|
||||
</IntlProvider>
|
||||
</p>
|
||||
);
|
||||
};
|
||||
|
||||
export default BookingDescriptionPayment;
|
||||
@@ -223,6 +223,8 @@ function BookingListItem(booking: BookingItemProps) {
|
||||
};
|
||||
const showRecordingsButtons =
|
||||
(booking.location === "integrations:daily" || booking?.location?.trim() === "") && isPast && isConfirmed;
|
||||
|
||||
const title = decodeURIComponent(booking.title);
|
||||
return (
|
||||
<>
|
||||
<RescheduleDialog
|
||||
@@ -355,12 +357,12 @@ function BookingListItem(booking: BookingItemProps) {
|
||||
|
||||
<div className="cursor-pointer py-4">
|
||||
<div
|
||||
title={booking.title}
|
||||
title={title}
|
||||
className={classNames(
|
||||
"max-w-10/12 sm:max-w-56 text-sm font-medium leading-6 text-gray-900 md:max-w-full",
|
||||
isCancelled ? "line-through" : ""
|
||||
)}>
|
||||
{booking.title}
|
||||
{title}
|
||||
<span> </span>
|
||||
|
||||
{!!booking?.eventType?.price && !booking.paid && (
|
||||
|
||||
@@ -17,7 +17,7 @@ export function TimezoneDropdown({
|
||||
|
||||
return (
|
||||
<>
|
||||
<div className="dark:focus-within:bg-darkgray-200 dark:bg-darkgray-100 dark:hover:bg-darkgray-200 -mx-[2px] !mt-3 flex w-fit items-center rounded-[4px] px-1 py-[2px] text-sm font-medium focus-within:bg-gray-200 hover:bg-gray-100 [&_svg]:focus-within:text-gray-900 dark:[&_svg]:focus-within:text-white [&_p]:focus-within:text-gray-900 dark:[&_p]:focus-within:text-white">
|
||||
<div className="dark:focus-within:bg-darkgray-200 dark:bg-darkgray-100 dark:hover:bg-darkgray-200 -mx-[2px] !mt-3 flex w-fit max-w-[20rem] items-center rounded-[4px] px-1 py-[2px] text-sm font-medium focus-within:bg-gray-200 hover:bg-gray-100 lg:max-w-[12rem] [&_svg]:focus-within:text-gray-900 dark:[&_svg]:focus-within:text-white [&_p]:focus-within:text-gray-900 dark:[&_p]:focus-within:text-white">
|
||||
<FiGlobe className="dark:text-darkgray-600 flex h-4 w-4 text-gray-600 ltr:mr-[2px] rtl:ml-[2px]" />
|
||||
<TimeOptions onSelectTimeZone={handleSelectTimeZone} />
|
||||
</div>
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -4,7 +4,7 @@ import { isValidPhoneNumber } from "libphonenumber-js";
|
||||
import { Trans } from "next-i18next";
|
||||
import Link from "next/link";
|
||||
import { useEffect } from "react";
|
||||
import { Controller, useForm, useWatch } from "react-hook-form";
|
||||
import { Controller, useForm, useWatch, useFormContext } from "react-hook-form";
|
||||
import { z } from "zod";
|
||||
|
||||
import type { EventLocationType, LocationObject } from "@calcom/app-store/locations";
|
||||
@@ -49,16 +49,19 @@ const LocationInput = (props: {
|
||||
defaultValue?: string;
|
||||
}): JSX.Element | null => {
|
||||
const { eventLocationType, locationFormMethods, ...remainingProps } = props;
|
||||
const { control } = useFormContext() as typeof locationFormMethods;
|
||||
if (eventLocationType?.organizerInputType === "text") {
|
||||
return (
|
||||
<input {...locationFormMethods.register(eventLocationType.variable)} type="text" {...remainingProps} />
|
||||
);
|
||||
} else if (eventLocationType?.organizerInputType === "phone") {
|
||||
return (
|
||||
<PhoneInput
|
||||
<Controller
|
||||
name={eventLocationType.variable}
|
||||
control={locationFormMethods.control}
|
||||
{...remainingProps}
|
||||
control={control}
|
||||
render={({ field: { onChange, value } }) => {
|
||||
return <PhoneInput onChange={onChange} value={value} {...remainingProps} />;
|
||||
}}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -113,7 +113,7 @@ const EventTypeScheduleDetails = () => {
|
||||
);
|
||||
|
||||
const filterDays = (dayNum: number) =>
|
||||
schedule?.schedule.availability.filter((item) => item.days.includes((dayNum + 1) % 7)) || [];
|
||||
schedule?.schedule.filter((item) => item.days.includes((dayNum + 1) % 7)) || [];
|
||||
|
||||
return (
|
||||
<div className="space-y-4 rounded border px-6 pb-4">
|
||||
@@ -156,15 +156,17 @@ const EventTypeScheduleDetails = () => {
|
||||
<FiGlobe className="ltr:mr-2 rtl:ml-2" />
|
||||
{schedule?.timeZone || <SkeletonText className="block h-5 w-32" />}
|
||||
</span>
|
||||
<Button
|
||||
href={`/availability/${schedule?.schedule.id}`}
|
||||
disabled={isLoading}
|
||||
color="minimal"
|
||||
EndIcon={FiExternalLink}
|
||||
target="_blank"
|
||||
rel="noopener noreferrer">
|
||||
{t("edit_availability")}
|
||||
</Button>
|
||||
{!!schedule?.id && (
|
||||
<Button
|
||||
href={`/availability/${schedule.id}`}
|
||||
disabled={isLoading}
|
||||
color="minimal"
|
||||
EndIcon={FiExternalLink}
|
||||
target="_blank"
|
||||
rel="noopener noreferrer">
|
||||
{t("edit_availability")}
|
||||
</Button>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
||||
@@ -0,0 +1,144 @@
|
||||
import type { FC } from "react";
|
||||
import type { SubmitHandler } from "react-hook-form";
|
||||
import { FormProvider } from "react-hook-form";
|
||||
import { useForm, useFormContext } from "react-hook-form";
|
||||
|
||||
import type { EventNameObjectType } from "@calcom/core/event";
|
||||
import { getEventName } from "@calcom/core/event";
|
||||
import { validateCustomEventName } from "@calcom/core/event";
|
||||
import { useLocale } from "@calcom/lib/hooks/useLocale";
|
||||
import { Button, Dialog, DialogClose, DialogFooter, DialogContent, TextField } from "@calcom/ui";
|
||||
|
||||
interface FormValues {
|
||||
customEventName: string;
|
||||
}
|
||||
|
||||
interface CustomEventTypeModalFormProps {
|
||||
placeHolder: string;
|
||||
close: () => void;
|
||||
setValue: (value: string) => void;
|
||||
event: EventNameObjectType;
|
||||
defaultValue: string;
|
||||
}
|
||||
|
||||
const CustomEventTypeModalForm: FC<CustomEventTypeModalFormProps> = (props) => {
|
||||
const { t } = useLocale();
|
||||
const { placeHolder, close, setValue, event } = props;
|
||||
const { register, handleSubmit, watch, getValues } = useFormContext<FormValues>();
|
||||
const onSubmit: SubmitHandler<FormValues> = (data) => {
|
||||
setValue(data.customEventName);
|
||||
close();
|
||||
};
|
||||
|
||||
// const customEventName = watch("customEventName");
|
||||
const previewText = getEventName({ ...event, eventName: watch("customEventName") });
|
||||
const placeHolder_ = watch("customEventName") === "" ? previewText : placeHolder;
|
||||
|
||||
return (
|
||||
<form
|
||||
id="custom-event-name"
|
||||
onSubmit={(e) => {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
const isEmpty = getValues("customEventName") === "";
|
||||
if (isEmpty) {
|
||||
setValue("");
|
||||
}
|
||||
|
||||
handleSubmit(onSubmit)(e);
|
||||
}}>
|
||||
<TextField
|
||||
label={t("event_name_in_calendar")}
|
||||
type="text"
|
||||
placeholder={placeHolder_}
|
||||
{...register("customEventName", {
|
||||
validate: (value) => validateCustomEventName(value, t("invalid_event_name_variables")),
|
||||
})}
|
||||
className="mb-0"
|
||||
/>
|
||||
<div className="pt-6 text-sm">
|
||||
<div className="mb-6 rounded-md bg-gray-100 p-2">
|
||||
<h1 className="mb-2 ml-1 font-medium text-gray-900">{t("available_variables")}</h1>
|
||||
<div className="mb-2.5 flex font-normal">
|
||||
<p className="ml-1 mr-5 w-28 text-gray-400">{`{Event type title}`}</p>
|
||||
<p className="text-gray-900">{t("event_name_info")}</p>
|
||||
</div>
|
||||
<div className="mb-2.5 flex font-normal">
|
||||
<p className="ml-1 mr-5 w-28 text-gray-400">{`{Organiser}`}</p>
|
||||
<p className="text-gray-900">{t("your_full_name")}</p>
|
||||
</div>
|
||||
<div className="mb-2.5 flex font-normal">
|
||||
<p className="ml-1 mr-5 w-28 text-gray-400">{`{Scheduler}`}</p>
|
||||
<p className="text-gray-900">{t("scheduler_full_name")}</p>
|
||||
</div>
|
||||
<div className="mb-1 flex font-normal">
|
||||
<p className="ml-1 mr-5 w-28 text-gray-400">{`{Location}`}</p>
|
||||
<p className="text-gray-900">{t("location_info")}</p>
|
||||
</div>
|
||||
</div>
|
||||
<h1 className="mb-2 text-[14px] font-medium leading-4">{t("preview")}</h1>
|
||||
<div
|
||||
className="flex h-[212px] w-full rounded-md border-y bg-cover bg-center"
|
||||
style={{
|
||||
backgroundImage: "url(/calendar-preview.svg)",
|
||||
}}>
|
||||
<div className="m-auto flex items-center justify-center self-stretch">
|
||||
<div className="mt-3 ml-11 box-border h-[110px] w-[120px] flex-col items-start gap-1 rounded-md border border-solid border-black bg-gray-100 text-[12px] leading-3">
|
||||
<p className="overflow-hidden text-ellipsis p-1.5 font-medium text-gray-900">{previewText}</p>
|
||||
<p className="ml-1.5 text-[10px] font-normal text-gray-600">8 - 10 AM</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
);
|
||||
};
|
||||
|
||||
interface CustomEventTypeModalProps {
|
||||
placeHolder: string;
|
||||
defaultValue: string;
|
||||
close: () => void;
|
||||
setValue: (value: string) => void;
|
||||
event: EventNameObjectType;
|
||||
}
|
||||
|
||||
const CustomEventTypeModal: FC<CustomEventTypeModalProps> = (props) => {
|
||||
const { t } = useLocale();
|
||||
|
||||
const { defaultValue, placeHolder, close, setValue, event } = props;
|
||||
|
||||
const methods = useForm<FormValues>({
|
||||
defaultValues: {
|
||||
customEventName: defaultValue,
|
||||
},
|
||||
});
|
||||
|
||||
return (
|
||||
<Dialog open={true} onOpenChange={close}>
|
||||
<DialogContent
|
||||
title={t("custom_event_name")}
|
||||
description={t("custom_event_name_description")}
|
||||
type="creation"
|
||||
enableOverflow>
|
||||
<FormProvider {...methods}>
|
||||
<CustomEventTypeModalForm
|
||||
event={event}
|
||||
close={close}
|
||||
setValue={setValue}
|
||||
placeHolder={placeHolder}
|
||||
defaultValue={defaultValue}
|
||||
/>
|
||||
</FormProvider>
|
||||
<DialogFooter>
|
||||
<DialogClose>{t("cancel")}</DialogClose>
|
||||
|
||||
<Button form="custom-event-name" type="submit" color="primary">
|
||||
{t("create")}
|
||||
</Button>
|
||||
</DialogFooter>
|
||||
</DialogContent>
|
||||
</Dialog>
|
||||
);
|
||||
};
|
||||
|
||||
export default CustomEventTypeModal;
|
||||
@@ -1,214 +0,0 @@
|
||||
import { useAutoAnimate } from "@formkit/auto-animate/react";
|
||||
import { EventTypeCustomInputType } from "@prisma/client";
|
||||
import type { CustomInputParsed } from "pages/event-types/[type]";
|
||||
import type { FC } from "react";
|
||||
import type { Control, UseFormRegister } from "react-hook-form";
|
||||
import { Controller, useFieldArray, useForm, useWatch } from "react-hook-form";
|
||||
|
||||
import { useLocale } from "@calcom/lib/hooks/useLocale";
|
||||
import { Button, Label, Select, TextField } from "@calcom/ui";
|
||||
import { FiPlus, FiX } from "@calcom/ui/components/icon";
|
||||
|
||||
interface OptionTypeBase {
|
||||
label: string;
|
||||
value: EventTypeCustomInputType;
|
||||
options?: { label: string; type: string }[];
|
||||
}
|
||||
|
||||
interface Props {
|
||||
onSubmit: (output: CustomInputParsed) => void;
|
||||
onCancel: () => void;
|
||||
selectedCustomInput?: CustomInputParsed;
|
||||
}
|
||||
|
||||
type IFormInput = CustomInputParsed;
|
||||
|
||||
/**
|
||||
* Getting a random ID gives us the option to know WHICH field is changed
|
||||
* when the user edits a custom field.
|
||||
* This UUID is only used to check for changes in the UI and not the ID we use in the DB
|
||||
* There is very very very slim chance that this will cause a collision
|
||||
* */
|
||||
const randomId = () => Math.floor(Math.random() * 1000000 + new Date().getTime());
|
||||
|
||||
const CustomInputTypeForm: FC<Props> = (props) => {
|
||||
const { t } = useLocale();
|
||||
const inputOptions: OptionTypeBase[] = [
|
||||
{ value: EventTypeCustomInputType.TEXT, label: t("text") },
|
||||
{ value: EventTypeCustomInputType.TEXTLONG, label: t("multiline_text") },
|
||||
{ value: EventTypeCustomInputType.NUMBER, label: t("number") },
|
||||
{ value: EventTypeCustomInputType.BOOL, label: t("checkbox") },
|
||||
{
|
||||
value: EventTypeCustomInputType.RADIO,
|
||||
label: t("radio"),
|
||||
},
|
||||
{ value: EventTypeCustomInputType.PHONE, label: t("phone_number") },
|
||||
];
|
||||
|
||||
const { selectedCustomInput } = props;
|
||||
|
||||
const defaultValues = selectedCustomInput
|
||||
? { ...selectedCustomInput, id: selectedCustomInput?.id || randomId() }
|
||||
: {
|
||||
id: randomId(),
|
||||
type: EventTypeCustomInputType.TEXT,
|
||||
};
|
||||
|
||||
const { register, control, getValues } = useForm<IFormInput>({
|
||||
defaultValues,
|
||||
});
|
||||
const selectedInputType = useWatch({ name: "type", control });
|
||||
const selectedInputOption = inputOptions.find((e) => selectedInputType === e.value);
|
||||
|
||||
const onCancel = () => {
|
||||
props.onCancel();
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="flex flex-col space-y-4">
|
||||
<div>
|
||||
<label htmlFor="type" className="block text-sm font-medium text-gray-700">
|
||||
{t("input_type")}
|
||||
</label>
|
||||
<Controller
|
||||
name="type"
|
||||
control={control}
|
||||
render={({ field }) => (
|
||||
<Select
|
||||
id="type"
|
||||
defaultValue={selectedInputOption}
|
||||
options={inputOptions}
|
||||
isSearchable={false}
|
||||
className="mt-1 mb-2 block w-full min-w-0 flex-1 text-sm"
|
||||
onChange={(option) => option && field.onChange(option.value)}
|
||||
value={selectedInputOption}
|
||||
onBlur={field.onBlur}
|
||||
name={field.name}
|
||||
/>
|
||||
)}
|
||||
/>
|
||||
</div>
|
||||
<TextField
|
||||
label={t("label")}
|
||||
type="text"
|
||||
id="label"
|
||||
required
|
||||
className="block w-full rounded-sm border-gray-300 text-sm"
|
||||
defaultValue={selectedCustomInput?.label}
|
||||
{...register("label", { required: true })}
|
||||
/>
|
||||
{(selectedInputType === EventTypeCustomInputType.TEXT ||
|
||||
selectedInputType === EventTypeCustomInputType.TEXTLONG) && (
|
||||
<TextField
|
||||
label={t("placeholder")}
|
||||
type="text"
|
||||
id="placeholder"
|
||||
className="block w-full rounded-sm border-gray-300 text-sm"
|
||||
defaultValue={selectedCustomInput?.placeholder}
|
||||
{...register("placeholder")}
|
||||
/>
|
||||
)}
|
||||
{selectedInputType === EventTypeCustomInputType.RADIO && (
|
||||
<RadioInputHandler control={control} register={register} />
|
||||
)}
|
||||
|
||||
<div className="flex h-5 items-center">
|
||||
<input
|
||||
id="required"
|
||||
type="checkbox"
|
||||
className="text-primary-600 focus:ring-primary-500 h-4 w-4 rounded border-gray-300 ltr:mr-2 rtl:ml-2"
|
||||
defaultChecked={selectedCustomInput?.required ?? true}
|
||||
{...register("required")}
|
||||
/>
|
||||
<label htmlFor="required" className="block text-sm font-medium text-gray-700">
|
||||
{t("is_required")}
|
||||
</label>
|
||||
</div>
|
||||
<input
|
||||
type="hidden"
|
||||
id="eventTypeId"
|
||||
value={selectedCustomInput?.eventTypeId || -1}
|
||||
{...register("eventTypeId", { valueAsNumber: true })}
|
||||
/>
|
||||
<input
|
||||
type="hidden"
|
||||
id="id"
|
||||
value={selectedCustomInput?.id || -1}
|
||||
{...register("id", { valueAsNumber: true })}
|
||||
/>
|
||||
<div className="mt-5 flex justify-end space-x-2 rtl:space-x-reverse sm:mt-4">
|
||||
<Button onClick={onCancel} type="button" color="secondary" className="ltr:mr-2 rtl:ml-2">
|
||||
{t("cancel")}
|
||||
</Button>
|
||||
<Button
|
||||
type="button"
|
||||
onClick={() => {
|
||||
props.onSubmit(getValues());
|
||||
}}>
|
||||
{t("save")}
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
function RadioInputHandler({
|
||||
register,
|
||||
control,
|
||||
}: {
|
||||
register: UseFormRegister<IFormInput>;
|
||||
control: Control<IFormInput>;
|
||||
}) {
|
||||
const { t } = useLocale();
|
||||
const { fields, append, remove } = useFieldArray<IFormInput>({
|
||||
control,
|
||||
name: "options",
|
||||
shouldUnregister: true,
|
||||
});
|
||||
const [animateRef] = useAutoAnimate<HTMLUListElement>();
|
||||
|
||||
return (
|
||||
<div className="flex flex-col ">
|
||||
<Label htmlFor="radio_options">{t("options")}</Label>
|
||||
<ul
|
||||
className="flex max-h-80 w-full flex-col space-y-1 overflow-y-scroll rounded-md bg-gray-50 p-4"
|
||||
ref={animateRef}>
|
||||
<>
|
||||
{fields.map((option, index) => (
|
||||
<li key={`${option.id}`}>
|
||||
<TextField
|
||||
id={option.id}
|
||||
placeholder={t("enter_option", { index: index + 1 })}
|
||||
addOnFilled={false}
|
||||
label={t("option", { index: index + 1 })}
|
||||
labelSrOnly
|
||||
{...register(`options.${index}.label` as const, { required: true })}
|
||||
addOnSuffix={
|
||||
<Button
|
||||
variant="icon"
|
||||
color="minimal"
|
||||
StartIcon={FiX}
|
||||
onClick={() => {
|
||||
remove(index);
|
||||
}}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
</li>
|
||||
))}
|
||||
<Button
|
||||
color="minimal"
|
||||
StartIcon={FiPlus}
|
||||
className="!text-sm !font-medium"
|
||||
onClick={() => {
|
||||
append({ label: "", type: "text" });
|
||||
}}>
|
||||
{t("add_an_option")}
|
||||
</Button>
|
||||
</>
|
||||
</ul>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default CustomInputTypeForm;
|
||||
@@ -1,5 +1,6 @@
|
||||
import dynamic from "next/dynamic";
|
||||
import Link from "next/link";
|
||||
import type { CustomInputParsed, EventTypeSetupProps, FormValues } from "pages/event-types/[type]";
|
||||
import type { EventTypeSetupProps, FormValues } from "pages/event-types/[type]";
|
||||
import { useEffect, useState } from "react";
|
||||
import { Controller, useFormContext } from "react-hook-form";
|
||||
import short from "short-uuid";
|
||||
@@ -8,30 +9,17 @@ import { v5 as uuidv5 } from "uuid";
|
||||
import type { EventNameObjectType } from "@calcom/core/event";
|
||||
import { getEventName } from "@calcom/core/event";
|
||||
import DestinationCalendarSelector from "@calcom/features/calendars/DestinationCalendarSelector";
|
||||
import CustomInputItem from "@calcom/features/eventtypes/components/CustomInputItem";
|
||||
import { FormBuilder } from "@calcom/features/form-builder/FormBuilder";
|
||||
import { APP_NAME, CAL_URL, IS_SELF_HOSTED } from "@calcom/lib/constants";
|
||||
import { useLocale } from "@calcom/lib/hooks/useLocale";
|
||||
import { trpc } from "@calcom/trpc/react";
|
||||
import {
|
||||
Badge,
|
||||
Button,
|
||||
Checkbox,
|
||||
Dialog,
|
||||
DialogClose,
|
||||
DialogContent,
|
||||
DialogFooter,
|
||||
Label,
|
||||
SettingsToggle,
|
||||
showToast,
|
||||
TextField,
|
||||
Tooltip,
|
||||
} from "@calcom/ui";
|
||||
import { FiEdit, FiCopy, FiPlus } from "@calcom/ui/components/icon";
|
||||
|
||||
import CustomInputTypeForm from "@components/eventtype/CustomInputTypeForm";
|
||||
import { Badge, Button, Checkbox, Label, SettingsToggle, showToast, TextField, Tooltip } from "@calcom/ui";
|
||||
import { FiEdit, FiCopy } from "@calcom/ui/components/icon";
|
||||
|
||||
import RequiresConfirmationController from "./RequiresConfirmationController";
|
||||
|
||||
const CustomEventTypeModal = dynamic(() => import("@components/eventtype/CustomEventTypeModal"));
|
||||
|
||||
const generateHashedLink = (id: number) => {
|
||||
const translator = short();
|
||||
const seed = `${id}:${new Date().getTime()}`;
|
||||
@@ -39,22 +27,11 @@ const generateHashedLink = (id: number) => {
|
||||
return uid;
|
||||
};
|
||||
|
||||
const getRandomId = (length = 8) => {
|
||||
return (
|
||||
-1 *
|
||||
parseInt(
|
||||
Math.ceil(Math.random() * Date.now())
|
||||
.toPrecision(length)
|
||||
.toString()
|
||||
.replace(".", "")
|
||||
)
|
||||
);
|
||||
};
|
||||
|
||||
export const EventAdvancedTab = ({ eventType, team }: Pick<EventTypeSetupProps, "eventType" | "team">) => {
|
||||
const connectedCalendarsQuery = trpc.viewer.connectedCalendars.useQuery();
|
||||
const formMethods = useFormContext<FormValues>();
|
||||
const { t } = useLocale();
|
||||
|
||||
const [showEventNameTip, setShowEventNameTip] = useState(false);
|
||||
const [hashedLinkVisible, setHashedLinkVisible] = useState(!!eventType.hashedLink);
|
||||
const [redirectUrlVisible, setRedirectUrlVisible] = useState(!!eventType.successRedirectUrl);
|
||||
@@ -66,44 +43,39 @@ export const EventAdvancedTab = ({ eventType, team }: Pick<EventTypeSetupProps,
|
||||
host: eventType.users[0]?.name || "Nameless",
|
||||
t,
|
||||
};
|
||||
const [previewText, setPreviewText] = useState(getEventName(eventNameObject));
|
||||
const [customInputs, setCustomInputs] = useState<CustomInputParsed[]>(
|
||||
eventType.customInputs.sort((a, b) => a.id - b.id) || []
|
||||
);
|
||||
const [selectedCustomInput, setSelectedCustomInput] = useState<CustomInputParsed | undefined>(undefined);
|
||||
const [selectedCustomInputModalOpen, setSelectedCustomInputModalOpen] = useState(false);
|
||||
|
||||
const [requiresConfirmation, setRequiresConfirmation] = useState(eventType.requiresConfirmation);
|
||||
const placeholderHashedLink = `${CAL_URL}/d/${hashedUrl}/${eventType.slug}`;
|
||||
const seatsEnabled = formMethods.watch("seatsPerTimeSlotEnabled");
|
||||
|
||||
const removeCustom = (index: number) => {
|
||||
formMethods.getValues("customInputs").splice(index, 1);
|
||||
customInputs.splice(index, 1);
|
||||
setCustomInputs([...customInputs]);
|
||||
};
|
||||
|
||||
const replaceEventNamePlaceholder = (eventNameObject: EventNameObjectType, previewEventName: string) =>
|
||||
previewEventName
|
||||
.replace("{Event type title}", eventNameObject.eventType)
|
||||
.replace("{Scheduler}", eventNameObject.attendeeName)
|
||||
.replace("{Organiser}", eventNameObject.host);
|
||||
|
||||
const changePreviewText = (eventNameObject: EventNameObjectType, previewEventName: string) => {
|
||||
setPreviewText(replaceEventNamePlaceholder(eventNameObject, previewEventName));
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
!hashedUrl && setHashedUrl(generateHashedLink(eventType.users[0]?.id ?? team?.id));
|
||||
}, [eventType.users, hashedUrl, team?.id]);
|
||||
|
||||
useEffect(() => {
|
||||
if (eventType.customInputs) {
|
||||
setCustomInputs(eventType.customInputs.sort((a, b) => a.id - b.id));
|
||||
}
|
||||
}, [eventType.customInputs]);
|
||||
const toggleGuests = (enabled: boolean) => {
|
||||
const bookingFields = formMethods.getValues("bookingFields");
|
||||
formMethods.setValue(
|
||||
"bookingFields",
|
||||
bookingFields.map((field) => {
|
||||
if (field.name === "guests") {
|
||||
return {
|
||||
...field,
|
||||
hidden: !enabled,
|
||||
};
|
||||
}
|
||||
return field;
|
||||
})
|
||||
);
|
||||
};
|
||||
|
||||
const eventNamePlaceholder = replaceEventNamePlaceholder(eventNameObject, t("meeting_with_user"));
|
||||
const eventNamePlaceholder = getEventName({
|
||||
...eventNameObject,
|
||||
eventName: formMethods.watch("eventName"),
|
||||
});
|
||||
|
||||
const closeEventNameTip = () => setShowEventNameTip(false);
|
||||
|
||||
const setEventName = (value: string) => formMethods.setValue("eventName", value);
|
||||
return (
|
||||
<div className="flex flex-col space-y-8">
|
||||
{/**
|
||||
@@ -146,14 +118,7 @@ export const EventAdvancedTab = ({ eventType, team }: Pick<EventTypeSetupProps,
|
||||
type="text"
|
||||
placeholder={eventNamePlaceholder}
|
||||
defaultValue={eventType.eventName || ""}
|
||||
{...formMethods.register("eventName", {
|
||||
onChange: (e) => {
|
||||
if (!e.target.value || !formMethods.getValues("eventName")) {
|
||||
return setPreviewText(getEventName(eventNameObject));
|
||||
}
|
||||
changePreviewText(eventNameObject, e.target.value);
|
||||
},
|
||||
})}
|
||||
{...formMethods.register("eventName")}
|
||||
addOnSuffix={
|
||||
<Button
|
||||
type="button"
|
||||
@@ -162,53 +127,18 @@ export const EventAdvancedTab = ({ eventType, team }: Pick<EventTypeSetupProps,
|
||||
color="minimal"
|
||||
className="hover:stroke-3 min-w-fit px-0 hover:bg-transparent hover:text-black"
|
||||
onClick={() => setShowEventNameTip((old) => !old)}
|
||||
aria-label="edit custom name"
|
||||
/>
|
||||
}
|
||||
/>
|
||||
</div>
|
||||
<hr />
|
||||
<div className="">
|
||||
<SettingsToggle
|
||||
title={t("additional_inputs")}
|
||||
description={t("additional_input_description")}
|
||||
checked={customInputs.length > 0}
|
||||
onCheckedChange={(e) => {
|
||||
if (e && customInputs.length === 0) {
|
||||
// Push a placeholders
|
||||
setSelectedCustomInputModalOpen(true);
|
||||
} else if (!e) {
|
||||
formMethods.setValue("customInputs", []);
|
||||
}
|
||||
}}>
|
||||
<ul className="my-4 rounded-md border">
|
||||
{customInputs.map((customInput, idx) => (
|
||||
<CustomInputItem
|
||||
key={idx}
|
||||
question={customInput.label}
|
||||
type={customInput.type}
|
||||
required={customInput.required}
|
||||
editOnClick={() => {
|
||||
setSelectedCustomInput(customInput);
|
||||
setSelectedCustomInputModalOpen(true);
|
||||
}}
|
||||
deleteOnClick={() => removeCustom(idx)}
|
||||
/>
|
||||
))}
|
||||
</ul>
|
||||
{customInputs.length > 0 && (
|
||||
<Button
|
||||
StartIcon={FiPlus}
|
||||
color="minimal"
|
||||
type="button"
|
||||
onClick={() => {
|
||||
setSelectedCustomInput(undefined);
|
||||
setSelectedCustomInputModalOpen(true);
|
||||
}}>
|
||||
{t("add_input")}
|
||||
</Button>
|
||||
)}
|
||||
</SettingsToggle>
|
||||
</div>
|
||||
<FormBuilder
|
||||
title={t("booking_questions_title")}
|
||||
description={t("booking_questions_description")}
|
||||
addFieldLabel={t("add_a_booking_question")}
|
||||
formProp="bookingFields"
|
||||
/>
|
||||
<hr />
|
||||
<RequiresConfirmationController
|
||||
seatsEnabled={seatsEnabled}
|
||||
@@ -216,22 +146,6 @@ export const EventAdvancedTab = ({ eventType, team }: Pick<EventTypeSetupProps,
|
||||
requiresConfirmation={requiresConfirmation}
|
||||
onRequiresConfirmation={setRequiresConfirmation}
|
||||
/>
|
||||
<hr />
|
||||
<Controller
|
||||
name="disableGuests"
|
||||
control={formMethods.control}
|
||||
defaultValue={eventType.disableGuests}
|
||||
render={({ field: { value, onChange } }) => (
|
||||
<SettingsToggle
|
||||
title={t("disable_guests")}
|
||||
description={t("disable_guests_description")}
|
||||
checked={value}
|
||||
onCheckedChange={(e) => onChange(e)}
|
||||
disabled={seatsEnabled}
|
||||
/>
|
||||
)}
|
||||
/>
|
||||
|
||||
<hr />
|
||||
<Controller
|
||||
name="hideCalendarNotes"
|
||||
@@ -247,22 +161,6 @@ export const EventAdvancedTab = ({ eventType, team }: Pick<EventTypeSetupProps,
|
||||
)}
|
||||
/>
|
||||
<hr />
|
||||
<Controller
|
||||
name="metadata.additionalNotesRequired"
|
||||
control={formMethods.control}
|
||||
defaultValue={!!eventType.metadata.additionalNotesRequired}
|
||||
render={({ field: { value, onChange } }) => (
|
||||
<div className="flex space-x-3 ">
|
||||
<SettingsToggle
|
||||
title={t("require_additional_notes")}
|
||||
description={t("require_additional_notes_description")}
|
||||
checked={!!value}
|
||||
onCheckedChange={(e) => onChange(e)}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
/>
|
||||
<hr />
|
||||
<Controller
|
||||
name="successRedirectUrl"
|
||||
control={formMethods.control}
|
||||
@@ -363,13 +261,13 @@ export const EventAdvancedTab = ({ eventType, team }: Pick<EventTypeSetupProps,
|
||||
onCheckedChange={(e) => {
|
||||
// Enabling seats will disable guests and requiring confirmation until fully supported
|
||||
if (e) {
|
||||
formMethods.setValue("disableGuests", true);
|
||||
toggleGuests(false);
|
||||
formMethods.setValue("requiresConfirmation", false);
|
||||
setRequiresConfirmation(false);
|
||||
formMethods.setValue("seatsPerTimeSlot", 2);
|
||||
} else {
|
||||
formMethods.setValue("seatsPerTimeSlot", null);
|
||||
formMethods.setValue("disableGuests", false);
|
||||
toggleGuests(true);
|
||||
}
|
||||
onChange(e);
|
||||
}}>
|
||||
@@ -407,130 +305,14 @@ export const EventAdvancedTab = ({ eventType, team }: Pick<EventTypeSetupProps,
|
||||
/>
|
||||
|
||||
{showEventNameTip && (
|
||||
<Dialog open={showEventNameTip} onOpenChange={setShowEventNameTip}>
|
||||
<DialogContent
|
||||
title={t("custom_event_name")}
|
||||
description={t("custom_event_name_description")}
|
||||
type="creation"
|
||||
enableOverflow>
|
||||
<TextField
|
||||
label={t("event_name_in_calendar")}
|
||||
type="text"
|
||||
placeholder={eventNamePlaceholder}
|
||||
defaultValue={eventType.eventName || ""}
|
||||
{...formMethods.register("eventName", {
|
||||
onChange: (e) => {
|
||||
if (!e.target.value || !formMethods.getValues("eventName")) {
|
||||
return setPreviewText(getEventName(eventNameObject));
|
||||
}
|
||||
changePreviewText(eventNameObject, e.target.value);
|
||||
},
|
||||
})}
|
||||
className="mb-0"
|
||||
/>
|
||||
<div className="text-sm">
|
||||
<div className="mb-6 rounded-md bg-gray-100 p-2">
|
||||
<h1 className="mb-2 ml-1 font-medium text-gray-900">{t("available_variables")}</h1>
|
||||
<div className="mb-2.5 flex font-normal">
|
||||
<p className="ml-1 mr-5 w-28 text-gray-400">{`{Event type title}`}</p>
|
||||
<p className="text-gray-900">{t("event_name_info")}</p>
|
||||
</div>
|
||||
<div className="mb-2.5 flex font-normal">
|
||||
<p className="ml-1 mr-5 w-28 text-gray-400">{`{Organiser}`}</p>
|
||||
<p className="text-gray-900">{t("your_full_name")}</p>
|
||||
</div>
|
||||
<div className="mb-2.5 flex font-normal">
|
||||
<p className="ml-1 mr-5 w-28 text-gray-400">{`{Scheduler}`}</p>
|
||||
<p className="text-gray-900">{t("scheduler_full_name")}</p>
|
||||
</div>
|
||||
<div className="mb-1 flex font-normal">
|
||||
<p className="ml-1 mr-5 w-28 text-gray-400">{`{Location}`}</p>
|
||||
<p className="text-gray-900">{t("location_info")}</p>
|
||||
</div>
|
||||
</div>
|
||||
<h1 className="mb-2 text-[14px] font-medium leading-4">{t("preview")}</h1>
|
||||
<div
|
||||
className="flex h-[212px] w-full rounded-md border-y bg-cover bg-center"
|
||||
style={{
|
||||
backgroundImage: "url(/calendar-preview.svg)",
|
||||
}}>
|
||||
<div className="m-auto flex items-center justify-center self-stretch">
|
||||
<div className="mt-3 ml-11 box-border h-[110px] w-[120px] flex-col items-start gap-1 rounded-md border border-solid border-black bg-gray-100 text-[12px] leading-3">
|
||||
<p className="overflow-hidden text-ellipsis p-1.5 font-medium text-gray-900">
|
||||
{previewText}
|
||||
</p>
|
||||
<p className="ml-1.5 text-[10px] font-normal text-gray-600">8 - 10 AM</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<DialogFooter>
|
||||
<DialogClose onClick={() => formMethods.setValue("eventName", eventType.eventName ?? "")}>
|
||||
{t("cancel")}
|
||||
</DialogClose>
|
||||
<Button color="primary" onClick={() => setShowEventNameTip(false)}>
|
||||
{t("create")}
|
||||
</Button>
|
||||
</DialogFooter>
|
||||
</DialogContent>
|
||||
</Dialog>
|
||||
<CustomEventTypeModal
|
||||
close={closeEventNameTip}
|
||||
setValue={setEventName}
|
||||
defaultValue={eventType.eventName || ""}
|
||||
placeHolder={eventNamePlaceholder}
|
||||
event={eventNameObject}
|
||||
/>
|
||||
)}
|
||||
<Controller
|
||||
name="customInputs"
|
||||
control={formMethods.control}
|
||||
defaultValue={customInputs}
|
||||
render={() => (
|
||||
<Dialog open={selectedCustomInputModalOpen} onOpenChange={setSelectedCustomInputModalOpen}>
|
||||
<DialogContent
|
||||
type="creation"
|
||||
Icon={FiPlus}
|
||||
title={t("add_new_custom_input_field")}
|
||||
description={t("this_input_will_shown_booking_this_event")}>
|
||||
<CustomInputTypeForm
|
||||
selectedCustomInput={selectedCustomInput}
|
||||
onSubmit={(values) => {
|
||||
const customInput: CustomInputParsed = {
|
||||
id: getRandomId(),
|
||||
eventTypeId: -1,
|
||||
label: values.label,
|
||||
placeholder: values.placeholder,
|
||||
required: values.required,
|
||||
type: values.type,
|
||||
options: values.options,
|
||||
hasToBeCreated: true,
|
||||
};
|
||||
if (selectedCustomInput) {
|
||||
selectedCustomInput.label = customInput.label;
|
||||
selectedCustomInput.placeholder = customInput.placeholder;
|
||||
selectedCustomInput.required = customInput.required;
|
||||
selectedCustomInput.type = customInput.type;
|
||||
selectedCustomInput.options = customInput.options || undefined;
|
||||
selectedCustomInput.hasToBeCreated = false;
|
||||
// Update by id
|
||||
const inputIndex = customInputs.findIndex((input) => input.id === values.id);
|
||||
customInputs[inputIndex] = selectedCustomInput;
|
||||
setCustomInputs(customInputs);
|
||||
formMethods.setValue("customInputs", customInputs);
|
||||
} else {
|
||||
const concatted = customInputs.concat({
|
||||
...customInput,
|
||||
options: customInput.options,
|
||||
});
|
||||
console.log(concatted);
|
||||
setCustomInputs(concatted);
|
||||
formMethods.setValue("customInputs", concatted);
|
||||
}
|
||||
|
||||
setSelectedCustomInputModalOpen(false);
|
||||
}}
|
||||
onCancel={() => {
|
||||
setSelectedCustomInputModalOpen(false);
|
||||
}}
|
||||
/>
|
||||
</DialogContent>
|
||||
</Dialog>
|
||||
)}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -13,8 +13,10 @@ import type { EventLocationType } from "@calcom/app-store/locations";
|
||||
import { getEventLocationType, MeetLocationType, LocationType } from "@calcom/app-store/locations";
|
||||
import { CAL_URL } from "@calcom/lib/constants";
|
||||
import { useLocale } from "@calcom/lib/hooks/useLocale";
|
||||
import { md } from "@calcom/lib/markdownIt";
|
||||
import { slugify } from "@calcom/lib/slugify";
|
||||
import { Button, Label, Select, SettingsToggle, Skeleton, TextField } from "@calcom/ui";
|
||||
import turndown from "@calcom/lib/turndownService";
|
||||
import { Button, Editor, Label, Select, SettingsToggle, Skeleton, TextField } from "@calcom/ui";
|
||||
import { FiEdit2, FiCheck, FiX, FiPlus } from "@calcom/ui/components/icon";
|
||||
|
||||
import { EditLocationDialog } from "@components/dialog/EditLocationDialog";
|
||||
@@ -44,11 +46,14 @@ const getDefaultLocationValue = (options: EventTypeSetupProps["locationOptions"]
|
||||
};
|
||||
|
||||
export const EventSetupTab = (
|
||||
props: Pick<EventTypeSetupProps, "eventType" | "locationOptions" | "team" | "teamMembers">
|
||||
props: Pick<
|
||||
EventTypeSetupProps,
|
||||
"eventType" | "locationOptions" | "team" | "teamMembers" | "destinationCalendar"
|
||||
>
|
||||
) => {
|
||||
const { t } = useLocale();
|
||||
const formMethods = useFormContext<FormValues>();
|
||||
const { eventType, locationOptions, team } = props;
|
||||
const { eventType, locationOptions, team, destinationCalendar } = props;
|
||||
const [showLocationModal, setShowLocationModal] = useState(false);
|
||||
const [editingLocationType, setEditingLocationType] = useState<string>("");
|
||||
const [selectedLocation, setSelectedLocation] = useState<LocationOption | undefined>(undefined);
|
||||
@@ -229,7 +234,10 @@ export const EventSetupTab = (
|
||||
</li>
|
||||
);
|
||||
})}
|
||||
{validLocations.some((location) => location.type === MeetLocationType) && (
|
||||
{validLocations.some(
|
||||
(location) =>
|
||||
location.type === MeetLocationType && destinationCalendar?.integration !== "google_calendar"
|
||||
) && (
|
||||
<div className="flex text-sm text-gray-600">
|
||||
<FiCheck className="mt-0.5 mr-1.5 h-2 w-2.5" />
|
||||
<Trans i18nKey="event_type_requres_google_cal">
|
||||
@@ -241,7 +249,6 @@ export const EventSetupTab = (
|
||||
className="underline">
|
||||
here.
|
||||
</Link>{" "}
|
||||
We will fall back to Cal video if you do not change it.
|
||||
</p>
|
||||
</Trans>
|
||||
</div>
|
||||
@@ -272,12 +279,15 @@ export const EventSetupTab = (
|
||||
defaultValue={eventType.title}
|
||||
{...formMethods.register("title")}
|
||||
/>
|
||||
<TextField
|
||||
label={t("description")}
|
||||
placeholder={t("quick_video_meeting")}
|
||||
defaultValue={eventType.description ?? ""}
|
||||
{...formMethods.register("description")}
|
||||
/>
|
||||
<div>
|
||||
<Label>{t("description")}</Label>
|
||||
<Editor
|
||||
getText={() => md.render(formMethods.getValues("description") || eventType.description || "")}
|
||||
setText={(value: string) => formMethods.setValue("description", turndown(value))}
|
||||
excludedToolbarItems={["blockType"]}
|
||||
placeholder={t("quick_video_meeting")}
|
||||
/>
|
||||
</div>
|
||||
<TextField
|
||||
required
|
||||
label={t("URL")}
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
import { ArrowRightIcon } from "@heroicons/react/solid";
|
||||
import MarkdownIt from "markdown-it";
|
||||
import { useRouter } from "next/router";
|
||||
import type { FormEvent } from "react";
|
||||
import { useRef, useState } from "react";
|
||||
import { useForm } from "react-hook-form";
|
||||
|
||||
import { useLocale } from "@calcom/lib/hooks/useLocale";
|
||||
import { md } from "@calcom/lib/markdownIt";
|
||||
import { telemetryEventTypes, useTelemetry } from "@calcom/lib/telemetry";
|
||||
import turndown from "@calcom/lib/turndownService";
|
||||
import { trpc } from "@calcom/trpc/react";
|
||||
@@ -14,8 +14,6 @@ import { Avatar } from "@calcom/ui";
|
||||
|
||||
import type { IOnboardingPageProps } from "../../../pages/getting-started/[[...step]]";
|
||||
|
||||
const md = new MarkdownIt("default", { html: true, breaks: true });
|
||||
|
||||
type FormData = {
|
||||
bio: string;
|
||||
};
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
import { ShieldCheckIcon } from "@calcom/ui/components/icon";
|
||||
import { FiShield } from "@calcom/ui/components/icon";
|
||||
|
||||
const TwoFactorModalHeader = ({ title, description }: { title: string; description: string }) => {
|
||||
return (
|
||||
<div className="mb-4 sm:flex sm:items-start">
|
||||
<div className="bg-brand text-brandcontrast dark:bg-darkmodebrand dark:text-darkmodebrandcontrast mx-auto flex h-12 w-12 flex-shrink-0 items-center justify-center rounded-full bg-opacity-5 sm:mx-0 sm:h-10 sm:w-10">
|
||||
<ShieldCheckIcon className="h-6 w-6 text-white" />
|
||||
<FiShield className="h-6 w-6 text-white" />
|
||||
</div>
|
||||
<div className="mt-3 text-center sm:mt-0 sm:ml-4 sm:text-left">
|
||||
<h3 className="font-cal text-lg font-medium leading-6 text-gray-900" id="modal-title">
|
||||
|
||||
@@ -1,13 +1,11 @@
|
||||
import MarkdownIt from "markdown-it";
|
||||
import Link from "next/link";
|
||||
import type { TeamPageProps } from "pages/team/[slug]";
|
||||
|
||||
import { WEBAPP_URL } from "@calcom/lib/constants";
|
||||
import { useLocale } from "@calcom/lib/hooks/useLocale";
|
||||
import { md } from "@calcom/lib/markdownIt";
|
||||
import { Avatar } from "@calcom/ui";
|
||||
|
||||
const md = new MarkdownIt("default", { html: true, breaks: true, linkify: true });
|
||||
|
||||
type TeamType = TeamPageProps["team"];
|
||||
type MembersType = TeamType["members"];
|
||||
type MemberType = MembersType[number];
|
||||
@@ -19,7 +17,7 @@ const Member = ({ member, teamName }: { member: MemberType; teamName: string | n
|
||||
|
||||
return (
|
||||
<Link key={member.id} href={`/${member.username}`}>
|
||||
<div className="sm:min-w-80 sm:max-w-80 dark:bg-darkgray-200 dark:hover:bg-darkgray-300 group flex min-h-full flex-col space-y-2 rounded-md bg-white p-4 hover:cursor-pointer hover:bg-gray-50 ">
|
||||
<div className="sm:min-w-80 sm:max-w-80 dark:bg-darkgray-200 dark:hover:bg-darkgray-300 group flex min-h-full flex-col space-y-2 rounded-md bg-white p-4 hover:cursor-pointer hover:bg-gray-50 ">
|
||||
<Avatar
|
||||
size="md"
|
||||
alt={member.name || ""}
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import { StarIcon as StarIconSolid } from "@heroicons/react/solid";
|
||||
import classNames from "classnames";
|
||||
import { debounce, noop } from "lodash";
|
||||
import { useRouter } from "next/router";
|
||||
@@ -14,7 +15,7 @@ import type { RouterOutputs } from "@calcom/trpc/react";
|
||||
import { trpc } from "@calcom/trpc/react";
|
||||
import type { AppRouter } from "@calcom/trpc/server/routers/_app";
|
||||
import { Button, Dialog, DialogClose, DialogContent, DialogHeader, Input, Label } from "@calcom/ui";
|
||||
import { FiCheck, FiEdit2, FiExternalLink, StarIconSolid } from "@calcom/ui/components/icon";
|
||||
import { FiCheck, FiEdit2, FiExternalLink } from "@calcom/ui/components/icon";
|
||||
|
||||
export enum UsernameChangeStatusEnum {
|
||||
UPGRADE = "UPGRADE",
|
||||
|
||||
@@ -6,7 +6,7 @@ import type {
|
||||
User,
|
||||
VerificationToken,
|
||||
} from "@prisma/client";
|
||||
import { PrismaClientKnownRequestError } from "@prisma/client/runtime";
|
||||
import { PrismaClientKnownRequestError } from "@prisma/client/runtime/library";
|
||||
|
||||
import { identityProviderNameMap } from "@lib/auth";
|
||||
|
||||
|
||||
@@ -1,7 +1,56 @@
|
||||
import type { Prisma, PrismaClient } from "@prisma/client";
|
||||
import type { z } from "zod";
|
||||
|
||||
async function getBooking(prisma: PrismaClient, uid: string) {
|
||||
const booking = await prisma.booking.findFirst({
|
||||
import { getBookingResponsesPartialSchema } from "@calcom/features/bookings/lib/getBookingResponsesSchema";
|
||||
import slugify from "@calcom/lib/slugify";
|
||||
import type { eventTypeBookingFields } from "@calcom/prisma/zod-utils";
|
||||
|
||||
type BookingSelect = {
|
||||
description: true;
|
||||
customInputs: true;
|
||||
attendees: {
|
||||
select: {
|
||||
email: true;
|
||||
name: true;
|
||||
};
|
||||
};
|
||||
location: true;
|
||||
smsReminderNumber: true;
|
||||
};
|
||||
|
||||
// Backward Compatibility for booking created before we had managed booking questions
|
||||
function getResponsesFromOldBooking(
|
||||
rawBooking: Prisma.BookingGetPayload<{
|
||||
select: BookingSelect;
|
||||
}>
|
||||
) {
|
||||
const customInputs = rawBooking.customInputs || {};
|
||||
const responses = Object.keys(customInputs).reduce((acc, label) => {
|
||||
acc[slugify(label) as keyof typeof acc] = customInputs[label as keyof typeof customInputs];
|
||||
return acc;
|
||||
}, {});
|
||||
return {
|
||||
// It is possible to have no attendees in a booking when the booking is cancelled.
|
||||
name: rawBooking.attendees[0]?.name || "Nameless",
|
||||
email: rawBooking.attendees[0]?.email || "",
|
||||
guests: rawBooking.attendees.slice(1).map((attendee) => {
|
||||
return attendee.email;
|
||||
}),
|
||||
notes: rawBooking.description || "",
|
||||
location: {
|
||||
value: rawBooking.location || "",
|
||||
optionValue: rawBooking.location || "",
|
||||
},
|
||||
...responses,
|
||||
};
|
||||
}
|
||||
|
||||
async function getBooking(
|
||||
prisma: PrismaClient,
|
||||
uid: string,
|
||||
bookingFields: z.infer<typeof eventTypeBookingFields> & z.BRAND<"HAS_SYSTEM_FIELDS">
|
||||
) {
|
||||
const rawBooking = await prisma.booking.findFirst({
|
||||
where: {
|
||||
uid,
|
||||
},
|
||||
@@ -9,6 +58,7 @@ async function getBooking(prisma: PrismaClient, uid: string) {
|
||||
startTime: true,
|
||||
description: true,
|
||||
customInputs: true,
|
||||
responses: true,
|
||||
smsReminderNumber: true,
|
||||
location: true,
|
||||
attendees: {
|
||||
@@ -20,6 +70,14 @@ async function getBooking(prisma: PrismaClient, uid: string) {
|
||||
},
|
||||
});
|
||||
|
||||
if (!rawBooking) {
|
||||
return rawBooking;
|
||||
}
|
||||
|
||||
const booking = getBookingWithResponses(rawBooking, {
|
||||
bookingFields,
|
||||
});
|
||||
|
||||
if (booking) {
|
||||
// @NOTE: had to do this because Server side cant return [Object objects]
|
||||
// probably fixable with json.stringify -> json.parse
|
||||
@@ -31,4 +89,23 @@ async function getBooking(prisma: PrismaClient, uid: string) {
|
||||
|
||||
export type GetBookingType = Prisma.PromiseReturnType<typeof getBooking>;
|
||||
|
||||
export const getBookingWithResponses = <
|
||||
T extends Prisma.BookingGetPayload<{
|
||||
select: BookingSelect & {
|
||||
responses: true;
|
||||
};
|
||||
}>
|
||||
>(
|
||||
booking: T,
|
||||
eventType: {
|
||||
bookingFields: z.infer<typeof eventTypeBookingFields> & z.BRAND<"HAS_SYSTEM_FIELDS">;
|
||||
}
|
||||
) => {
|
||||
return {
|
||||
...booking,
|
||||
responses: getBookingResponsesPartialSchema({
|
||||
bookingFields: eventType.bookingFields,
|
||||
}).parse(booking.responses || getResponsesFromOldBooking(booking)),
|
||||
};
|
||||
};
|
||||
export default getBooking;
|
||||
|
||||
@@ -1,8 +1,11 @@
|
||||
import * as fetch from "@lib/core/http/fetch-wrapper";
|
||||
import type { BookingCreateBody, BookingResponse } from "@lib/types/booking";
|
||||
import type { BookingCreateBody } from "@calcom/prisma/zod-utils";
|
||||
|
||||
const createBooking = async (data: BookingCreateBody) => {
|
||||
const response = await fetch.post<BookingCreateBody, BookingResponse>("/api/book/event", data);
|
||||
import * as fetch from "@lib/core/http/fetch-wrapper";
|
||||
import type { BookingResponse } from "@lib/types/booking";
|
||||
|
||||
type BookingCreateBodyForMutation = Omit<BookingCreateBody, "location">;
|
||||
const createBooking = async (data: BookingCreateBodyForMutation) => {
|
||||
const response = await fetch.post<BookingCreateBodyForMutation, BookingResponse>("/api/book/event", data);
|
||||
|
||||
return response;
|
||||
};
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
import type { BookingCreateBody } from "@calcom/prisma/zod-utils";
|
||||
import type { AppsStatus } from "@calcom/types/Calendar";
|
||||
|
||||
import * as fetch from "@lib/core/http/fetch-wrapper";
|
||||
import type { BookingCreateBody, BookingResponse } from "@lib/types/booking";
|
||||
import type { BookingResponse } from "@lib/types/booking";
|
||||
|
||||
type ExtendedBookingCreateBody = BookingCreateBody & {
|
||||
noEmail?: boolean;
|
||||
|
||||
@@ -2,36 +2,6 @@ import type { Attendee, Booking } from "@prisma/client";
|
||||
|
||||
import type { AppsStatus } from "@calcom/types/Calendar";
|
||||
|
||||
export type BookingCreateBody = {
|
||||
email: string;
|
||||
end: string;
|
||||
web3Details?: {
|
||||
userWallet: string;
|
||||
userSignature: unknown;
|
||||
};
|
||||
eventTypeId: number;
|
||||
eventTypeSlug: string;
|
||||
guests?: string[];
|
||||
location: string;
|
||||
name: string;
|
||||
notes?: string;
|
||||
rescheduleUid?: string;
|
||||
recurringEventId?: string;
|
||||
start: string;
|
||||
timeZone: string;
|
||||
user?: string | string[];
|
||||
language: string;
|
||||
bookingUid?: string;
|
||||
customInputs: { label: string; value: string | boolean }[];
|
||||
metadata: {
|
||||
[key: string]: string;
|
||||
};
|
||||
hasHashedBookingLink: boolean;
|
||||
hashedLink?: string | null;
|
||||
smsReminderNumber?: string;
|
||||
ethSignature?: string;
|
||||
};
|
||||
|
||||
export type BookingResponse = Booking & {
|
||||
paymentUid?: string;
|
||||
attendees: Attendee[];
|
||||
|
||||
+25
-21
@@ -2,20 +2,6 @@ require("dotenv").config({ path: "../../.env" });
|
||||
const CopyWebpackPlugin = require("copy-webpack-plugin");
|
||||
const { withSentryConfig } = require("@sentry/nextjs");
|
||||
const os = require("os");
|
||||
const withTM = require("next-transpile-modules")([
|
||||
"@calcom/app-store",
|
||||
"@calcom/core",
|
||||
"@calcom/dayjs",
|
||||
"@calcom/emails",
|
||||
"@calcom/embed-core",
|
||||
"@calcom/embed-react",
|
||||
"@calcom/embed-snippet",
|
||||
"@calcom/features",
|
||||
"@calcom/lib",
|
||||
"@calcom/prisma",
|
||||
"@calcom/trpc",
|
||||
"@calcom/ui",
|
||||
]);
|
||||
|
||||
const { withAxiom } = require("next-axiom");
|
||||
const { i18n } = require("./next-i18next.config");
|
||||
@@ -80,7 +66,6 @@ if (process.env.ANALYZE === "true") {
|
||||
plugins.push(withBundleAnalyzer);
|
||||
}
|
||||
|
||||
plugins.push(withTM);
|
||||
plugins.push(withAxiom);
|
||||
/** @type {import("next").NextConfig} */
|
||||
const nextConfig = {
|
||||
@@ -94,12 +79,31 @@ 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}}",
|
||||
// },
|
||||
// },
|
||||
transpilePackages: [
|
||||
"@calcom/app-store",
|
||||
"@calcom/core",
|
||||
"@calcom/dayjs",
|
||||
"@calcom/emails",
|
||||
"@calcom/embed-core",
|
||||
"@calcom/embed-react",
|
||||
"@calcom/embed-snippet",
|
||||
"@calcom/features",
|
||||
"@calcom/lib",
|
||||
"@calcom/prisma",
|
||||
"@calcom/trpc",
|
||||
"@calcom/ui",
|
||||
],
|
||||
modularizeImports: {
|
||||
"@calcom/ui/components/icon": {
|
||||
transform: "@react-icons/all-files/fi/{{member}}",
|
||||
skipDefaultConversion: true,
|
||||
preventFullImport: true,
|
||||
},
|
||||
// TODO: We need to have all components in `@calcom/ui/components` in order to use this
|
||||
// "@calcom/ui": {
|
||||
// transform: "@calcom/ui/components/{{member}}",
|
||||
// },
|
||||
},
|
||||
images: {
|
||||
unoptimized: true,
|
||||
},
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@calcom/web",
|
||||
"version": "2.6.6",
|
||||
"version": "2.6.7",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"analyze": "ANALYZE=true next build",
|
||||
@@ -45,7 +45,6 @@
|
||||
"@hookform/resolvers": "^2.9.7",
|
||||
"@next-auth/prisma-adapter": "^1.0.4",
|
||||
"@next/bundle-analyzer": "^13.1.6",
|
||||
"@next/font": "^13.1.1",
|
||||
"@radix-ui/react-avatar": "^1.0.0",
|
||||
"@radix-ui/react-collapsible": "^1.0.0",
|
||||
"@radix-ui/react-dialog": "^1.0.0",
|
||||
@@ -70,12 +69,13 @@
|
||||
"bcryptjs": "^2.4.3",
|
||||
"classnames": "^2.3.1",
|
||||
"dotenv-cli": "^6.0.0",
|
||||
"eslint-config-next": "^13.1.6",
|
||||
"eslint-config-next": "^13.2.1",
|
||||
"googleapis": "^84.0.0",
|
||||
"gray-matter": "^4.0.3",
|
||||
"handlebars": "^4.7.7",
|
||||
"ical.js": "^1.4.0",
|
||||
"ics": "^2.37.0",
|
||||
"jose": "^4.13.1",
|
||||
"kbar": "^0.1.0-beta.36",
|
||||
"libphonenumber-js": "^1.10.12",
|
||||
"lodash": "^4.17.21",
|
||||
@@ -85,14 +85,13 @@
|
||||
"memory-cache": "^0.2.0",
|
||||
"micro": "^10.0.1",
|
||||
"mime-types": "^2.1.35",
|
||||
"next": "^13.1.1",
|
||||
"next": "^13.2.1",
|
||||
"next-auth": "^4.18.8",
|
||||
"next-axiom": "^0.16.0",
|
||||
"next-collect": "^0.2.1",
|
||||
"next-i18next": "^11.3.0",
|
||||
"next-seo": "^4.26.0",
|
||||
"next-themes": "^0.2.0",
|
||||
"next-transpile-modules": "^10.0.0",
|
||||
"nodemailer": "^6.7.8",
|
||||
"otplib": "^12.0.1",
|
||||
"qrcode": "^1.5.1",
|
||||
@@ -104,7 +103,7 @@
|
||||
"react-dom": "^18.2.0",
|
||||
"react-easy-crop": "^3.5.2",
|
||||
"react-feather": "^2.0.10",
|
||||
"react-hook-form": "^7.34.2",
|
||||
"react-hook-form": "^7.43.3",
|
||||
"react-hot-toast": "^2.3.0",
|
||||
"react-intl": "^5.25.1",
|
||||
"react-live-chat-loader": "^2.7.3",
|
||||
@@ -116,9 +115,11 @@
|
||||
"react-use-intercom": "1.5.1",
|
||||
"react-virtualized-auto-sizer": "^1.0.6",
|
||||
"react-window": "^1.8.7",
|
||||
"remark": "^14.0.2",
|
||||
"rrule": "^2.7.1",
|
||||
"schema-dts": "^1.1.0",
|
||||
"short-uuid": "^4.2.0",
|
||||
"strip-markdown": "^5.0.0",
|
||||
"stripe": "^9.16.0",
|
||||
"superjson": "1.9.1",
|
||||
"tailwindcss-radix": "^2.6.0",
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { BadgeCheckIcon } from "@heroicons/react/solid";
|
||||
import classNames from "classnames";
|
||||
import MarkdownIt from "markdown-it";
|
||||
import type { GetServerSidePropsContext } from "next";
|
||||
import Link from "next/link";
|
||||
import { useRouter } from "next/router";
|
||||
@@ -23,20 +23,19 @@ import defaultEvents, {
|
||||
} from "@calcom/lib/defaultEvents";
|
||||
import { useLocale } from "@calcom/lib/hooks/useLocale";
|
||||
import useTheme from "@calcom/lib/hooks/useTheme";
|
||||
import { md } from "@calcom/lib/markdownIt";
|
||||
import { collectPageParameters, telemetryEventTypes, useTelemetry } from "@calcom/lib/telemetry";
|
||||
import prisma from "@calcom/prisma";
|
||||
import { baseEventTypeSelect } from "@calcom/prisma/selects";
|
||||
import { EventTypeMetaDataSchema } from "@calcom/prisma/zod-utils";
|
||||
import { HeadSeo, AvatarGroup, Avatar } from "@calcom/ui";
|
||||
import { BadgeCheckIcon, FiArrowRight } from "@calcom/ui/components/icon";
|
||||
import { Avatar, AvatarGroup, HeadSeo } from "@calcom/ui";
|
||||
import { FiArrowRight } from "@calcom/ui/components/icon";
|
||||
|
||||
import type { inferSSRProps } from "@lib/types/inferSSRProps";
|
||||
import type { EmbedProps } from "@lib/withEmbedSsr";
|
||||
|
||||
import { ssrInit } from "@server/lib/ssr";
|
||||
|
||||
const md = new MarkdownIt("default", { html: true, breaks: true, linkify: true });
|
||||
|
||||
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
|
||||
@@ -146,7 +145,7 @@ export default function User(props: inferSSRProps<typeof getServerSideProps> & E
|
||||
{!isBioEmpty && (
|
||||
<>
|
||||
<div
|
||||
className="dark:text-darkgray-600 text-sm text-gray-500 [&_a]:text-blue-500 [&_a]:underline [&_a]:hover:text-blue-600"
|
||||
className=" dark:text-darkgray-600 text-sm text-gray-500 [&_a]:text-blue-500 [&_a]:underline [&_a]:hover:text-blue-600"
|
||||
dangerouslySetInnerHTML={{ __html: md.render(user.bio || "") }}
|
||||
/>
|
||||
</>
|
||||
|
||||
@@ -5,6 +5,7 @@ import type { LocationObject } from "@calcom/app-store/locations";
|
||||
import { IS_TEAM_BILLING_ENABLED, WEBAPP_URL } from "@calcom/lib/constants";
|
||||
import hasKeyInMetadata from "@calcom/lib/hasKeyInMetadata";
|
||||
import { useLocale } from "@calcom/lib/hooks/useLocale";
|
||||
import { addListFormatting } from "@calcom/lib/markdownIt";
|
||||
import type { User } from "@calcom/prisma/client";
|
||||
|
||||
import { isBrandingHidden } from "@lib/isBrandingHidden";
|
||||
@@ -70,7 +71,8 @@ async function getUserPageProps(context: GetStaticPropsContext) {
|
||||
|
||||
const user = await prisma.user.findUnique({
|
||||
where: {
|
||||
username,
|
||||
/** TODO: We should standarize this */
|
||||
username: username.toLowerCase().replace(/( |%20)/g, "+"),
|
||||
},
|
||||
select: {
|
||||
id: true,
|
||||
@@ -123,13 +125,7 @@ async function getUserPageProps(context: GetStaticPropsContext) {
|
||||
},
|
||||
});
|
||||
|
||||
const md = new MarkdownIt("zero").enable([
|
||||
//
|
||||
"emphasis",
|
||||
"list",
|
||||
"newline",
|
||||
"strikethrough",
|
||||
]);
|
||||
const md = new MarkdownIt("default", { html: true, breaks: true, linkify: true });
|
||||
|
||||
if (!user || !user.eventTypes.length) return { notFound: true };
|
||||
|
||||
@@ -157,7 +153,7 @@ async function getUserPageProps(context: GetStaticPropsContext) {
|
||||
metadata: EventTypeMetaDataSchema.parse(eventType.metadata || {}),
|
||||
recurringEvent: parseRecurringEvent(eventType.recurringEvent),
|
||||
locations: privacyFilteredLocations(locations),
|
||||
descriptionAsSafeHTML: eventType.description ? md.render(eventType.description) : null,
|
||||
descriptionAsSafeHTML: eventType.description ? addListFormatting(md.render(eventType.description)) : null,
|
||||
});
|
||||
// Check if the user you are logging into has any active teams or premium user name
|
||||
const hasActiveTeam =
|
||||
|
||||
@@ -3,6 +3,7 @@ import type { GetServerSidePropsContext } from "next";
|
||||
import type { LocationObject } from "@calcom/app-store/locations";
|
||||
import { privacyFilteredLocations } from "@calcom/app-store/locations";
|
||||
import { getAppFromSlug } from "@calcom/app-store/utils";
|
||||
import { getBookingFieldsWithSystemFields } from "@calcom/features/bookings/lib/getBookingFields";
|
||||
import { parseRecurringEvent } from "@calcom/lib";
|
||||
import {
|
||||
getDefaultEvent,
|
||||
@@ -118,10 +119,10 @@ export async function getServerSideProps(context: GetServerSidePropsContext) {
|
||||
});
|
||||
|
||||
if (!eventTypeRaw) return { notFound: true };
|
||||
|
||||
const eventType = {
|
||||
...eventTypeRaw,
|
||||
metadata: EventTypeMetaDataSchema.parse(eventTypeRaw.metadata || {}),
|
||||
bookingFields: getBookingFieldsWithSystemFields(eventTypeRaw),
|
||||
recurringEvent: parseRecurringEvent(eventTypeRaw.recurringEvent),
|
||||
};
|
||||
|
||||
@@ -183,7 +184,8 @@ export async function getServerSideProps(context: GetServerSidePropsContext) {
|
||||
prisma,
|
||||
context.query.rescheduleUid
|
||||
? (context.query.rescheduleUid as string)
|
||||
: (context.query.bookingUid as string)
|
||||
: (context.query.bookingUid as string),
|
||||
eventTypeObject.bookingFields
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { Inter } from "@next/font/google";
|
||||
import localFont from "@next/font/local";
|
||||
import { DefaultSeo } from "next-seo";
|
||||
import { Inter } from "next/font/google";
|
||||
import localFont from "next/font/local";
|
||||
import Head from "next/head";
|
||||
import Script from "next/script";
|
||||
|
||||
|
||||
@@ -2,6 +2,7 @@ import type { UserPermissionRole } from "@prisma/client";
|
||||
import { IdentityProvider } from "@prisma/client";
|
||||
import { readFileSync } from "fs";
|
||||
import Handlebars from "handlebars";
|
||||
import { SignJWT } from "jose";
|
||||
import type { Session } from "next-auth";
|
||||
import NextAuth from "next-auth";
|
||||
import { encode } from "next-auth/jwt";
|
||||
@@ -18,7 +19,7 @@ import checkLicense from "@calcom/features/ee/common/server/checkLicense";
|
||||
import ImpersonationProvider from "@calcom/features/ee/impersonation/lib/ImpersonationProvider";
|
||||
import { hostedCal, isSAMLLoginEnabled } from "@calcom/features/ee/sso/lib/saml";
|
||||
import { ErrorCode, isPasswordValid, verifyPassword } from "@calcom/lib/auth";
|
||||
import { APP_NAME, IS_TEAM_BILLING_ENABLED, WEBAPP_URL } from "@calcom/lib/constants";
|
||||
import { APP_NAME, IS_TEAM_BILLING_ENABLED, WEBAPP_URL, WEBSITE_URL } from "@calcom/lib/constants";
|
||||
import { symmetricDecrypt } from "@calcom/lib/crypto";
|
||||
import { defaultCookies } from "@calcom/lib/default-cookies";
|
||||
import { randomString } from "@calcom/lib/random";
|
||||
@@ -38,6 +39,21 @@ const transporter = nodemailer.createTransport<TransportOptions>({
|
||||
|
||||
const usernameSlug = (username: string) => slugify(username) + "-" + randomString(6).toLowerCase();
|
||||
|
||||
const signJwt = async (payload: { email: string }) => {
|
||||
const secret = new TextEncoder().encode(process.env.CALENDSO_ENCRYPTION_KEY);
|
||||
return new SignJWT(payload)
|
||||
.setProtectedHeader({ alg: "HS256" })
|
||||
.setSubject(payload.email)
|
||||
.setIssuedAt()
|
||||
.setIssuer(WEBSITE_URL)
|
||||
.setAudience(`${WEBSITE_URL}/auth/login`)
|
||||
.setExpirationTime("2m")
|
||||
.sign(secret);
|
||||
};
|
||||
|
||||
const loginWithTotp = async (user: { email: string }) =>
|
||||
`/auth/login?totp=${await signJwt({ email: user.email })}`;
|
||||
|
||||
const providers: Provider[] = [
|
||||
CredentialsProvider({
|
||||
id: "credentials",
|
||||
@@ -82,17 +98,19 @@ const providers: Provider[] = [
|
||||
throw new Error(ErrorCode.IncorrectUsernamePassword);
|
||||
}
|
||||
|
||||
if (user.identityProvider !== IdentityProvider.CAL) {
|
||||
if (user.identityProvider !== IdentityProvider.CAL && !credentials.totpCode) {
|
||||
throw new Error(ErrorCode.ThirdPartyIdentityProviderEnabled);
|
||||
}
|
||||
|
||||
if (!user.password) {
|
||||
if (!user.password && user.identityProvider !== IdentityProvider.CAL && !credentials.totpCode) {
|
||||
throw new Error(ErrorCode.IncorrectUsernamePassword);
|
||||
}
|
||||
|
||||
const isCorrectPassword = await verifyPassword(credentials.password, user.password);
|
||||
if (!isCorrectPassword) {
|
||||
throw new Error(ErrorCode.IncorrectUsernamePassword);
|
||||
if (user.password) {
|
||||
const isCorrectPassword = await verifyPassword(credentials.password, user.password);
|
||||
if (!isCorrectPassword) {
|
||||
throw new Error(ErrorCode.IncorrectUsernamePassword);
|
||||
}
|
||||
}
|
||||
|
||||
if (user.twoFactorEnabled) {
|
||||
@@ -130,7 +148,7 @@ const providers: Provider[] = [
|
||||
await limiter.check(10, user.email); // 10 requests per minute
|
||||
// Check if the user you are logging into has any active teams
|
||||
const hasActiveTeams =
|
||||
user.teams.filter((m) => {
|
||||
user.teams.filter((m: { team: { metadata: unknown } }) => {
|
||||
if (!IS_TEAM_BILLING_ENABLED) return true;
|
||||
const metadata = teamMetadataSchema.safeParse(m.team.metadata);
|
||||
if (metadata.success && metadata.data?.subscriptionId) return true;
|
||||
@@ -449,7 +467,11 @@ export default NextAuth({
|
||||
console.error("Error while linking account of already existing user");
|
||||
}
|
||||
}
|
||||
return true;
|
||||
if (existingUser.twoFactorEnabled) {
|
||||
return loginWithTotp(existingUser);
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// If the email address doesn't match, check if an account already exists
|
||||
@@ -461,7 +483,11 @@ export default NextAuth({
|
||||
|
||||
if (!userWithNewEmail) {
|
||||
await prisma.user.update({ where: { id: existingUser.id }, data: { email: user.email } });
|
||||
return true;
|
||||
if (existingUser.twoFactorEnabled) {
|
||||
return loginWithTotp(existingUser);
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
} else {
|
||||
return "/auth/error?error=new-email-conflict";
|
||||
}
|
||||
@@ -477,7 +503,11 @@ export default NextAuth({
|
||||
if (existingUserWithEmail) {
|
||||
// if self-hosted then we can allow auto-merge of identity providers if email is verified
|
||||
if (!hostedCal && existingUserWithEmail.emailVerified) {
|
||||
return true;
|
||||
if (existingUserWithEmail.twoFactorEnabled) {
|
||||
return loginWithTotp(existingUserWithEmail);
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// check if user was invited
|
||||
@@ -499,7 +529,11 @@ export default NextAuth({
|
||||
},
|
||||
});
|
||||
|
||||
return true;
|
||||
if (existingUserWithEmail.twoFactorEnabled) {
|
||||
return loginWithTotp(existingUserWithEmail);
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// User signs up with email/password and then tries to login with Google/SAML using the same email
|
||||
@@ -511,7 +545,11 @@ export default NextAuth({
|
||||
where: { email: existingUserWithEmail.email },
|
||||
data: { password: null },
|
||||
});
|
||||
return true;
|
||||
if (existingUserWithEmail.twoFactorEnabled) {
|
||||
return loginWithTotp(existingUserWithEmail);
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
} else if (existingUserWithEmail.identityProvider === IdentityProvider.CAL) {
|
||||
return "/auth/error?error=use-password-login";
|
||||
}
|
||||
@@ -534,7 +572,11 @@ export default NextAuth({
|
||||
const linkAccountNewUserData = { ...account, userId: newUser.id };
|
||||
await calcomAdapter.linkAccount(linkAccountNewUserData);
|
||||
|
||||
return true;
|
||||
if (account.twoFactorEnabled) {
|
||||
return loginWithTotp(newUser);
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
|
||||
@@ -83,7 +83,7 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse)
|
||||
// get user's credentials + their connected integrations
|
||||
const calendarCredentials = getCalendarCredentials(user.credentials);
|
||||
// get all the connected integrations' calendars (from third party)
|
||||
const connectedCalendars = await getConnectedCalendars(calendarCredentials, user.selectedCalendars);
|
||||
const { connectedCalendars } = await getConnectedCalendars(calendarCredentials, user.selectedCalendars);
|
||||
const calendars = connectedCalendars.flatMap((c) => c.calendars).filter(notEmpty);
|
||||
const selectableCalendars = calendars.map((cal) => {
|
||||
return { selected: selectedCalendarIds.findIndex((s) => s.externalId === cal.externalId) > -1, ...cal };
|
||||
|
||||
@@ -8,7 +8,9 @@ async function handler(req: NextApiRequest & { userId?: number }) {
|
||||
const session = await getSession({ req });
|
||||
/* To mimic API behavior and comply with types */
|
||||
req.userId = session?.user?.id || -1;
|
||||
const booking = await handleNewBooking(req);
|
||||
const booking = await handleNewBooking(req, {
|
||||
isNotAnApiCall: true,
|
||||
});
|
||||
return booking;
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
import type { NextRequest } from "next/server";
|
||||
|
||||
export const config = {
|
||||
runtime: "edge",
|
||||
};
|
||||
|
||||
export default async function handler(req: NextRequest) {
|
||||
const countryCode = req.headers.get("x-vercel-ip-country") ?? "";
|
||||
return new Response(
|
||||
JSON.stringify({
|
||||
countryCode,
|
||||
}),
|
||||
{
|
||||
status: 200,
|
||||
headers: {
|
||||
"content-type": "application/json",
|
||||
},
|
||||
}
|
||||
);
|
||||
}
|
||||
@@ -1,39 +0,0 @@
|
||||
import type { NextApiRequest, NextApiResponse } from "next";
|
||||
import { z } from "zod";
|
||||
|
||||
import { fetcher } from "@calcom/app-store/dailyvideo/lib/VideoApiAdapter";
|
||||
import { getSession } from "@calcom/lib/auth";
|
||||
import { IS_SELF_HOSTED } from "@calcom/lib/constants";
|
||||
import { defaultHandler, defaultResponder } from "@calcom/lib/server";
|
||||
|
||||
const getAccessLinkSchema = z.object({
|
||||
download_link: z.string().url(),
|
||||
// expires (timestamp), s3_bucket, s3_region, s3_key
|
||||
});
|
||||
|
||||
const requestQuery = z.object({
|
||||
recordingId: z.string(),
|
||||
});
|
||||
|
||||
const isDownloadAllowed = async (req: NextApiRequest) => {
|
||||
if (IS_SELF_HOSTED) return true;
|
||||
const session = await getSession({ req });
|
||||
// Check if user belong to active team
|
||||
return !session?.user?.belongsToActiveTeam;
|
||||
};
|
||||
|
||||
async function handler(
|
||||
req: NextApiRequest,
|
||||
res: NextApiResponse<z.infer<typeof getAccessLinkSchema> | void>
|
||||
) {
|
||||
const { recordingId } = requestQuery.parse(req.query);
|
||||
|
||||
if (!(await isDownloadAllowed(req))) return res.status(403);
|
||||
|
||||
const response = await fetcher(`/recordings/${recordingId}/access-link`).then(getAccessLinkSchema.parse);
|
||||
return res.status(200).json(response);
|
||||
}
|
||||
|
||||
export default defaultHandler({
|
||||
GET: Promise.resolve({ default: defaultResponder(handler) }),
|
||||
});
|
||||
@@ -1,6 +1,8 @@
|
||||
import { ImageResponse } from "@vercel/og";
|
||||
import type { NextApiRequest } from "next";
|
||||
import { remark } from "remark";
|
||||
import type { SatoriOptions } from "satori";
|
||||
import strip from "strip-markdown";
|
||||
import { z } from "zod";
|
||||
|
||||
import { Meeting, App, Generic } from "@calcom/lib/OgImages";
|
||||
@@ -18,7 +20,7 @@ const interFontMedium = fetch(new URL("../../../../public/fonts/Inter-Medium.ttf
|
||||
);
|
||||
|
||||
export const config = {
|
||||
runtime: "experimental-edge",
|
||||
runtime: "edge",
|
||||
};
|
||||
|
||||
const meetingSchema = z.object({
|
||||
@@ -106,8 +108,8 @@ export default async function handler(req: NextApiRequest) {
|
||||
description: searchParams.get("description"),
|
||||
imageType,
|
||||
});
|
||||
|
||||
const img = new ImageResponse(<Generic title={title} description={description} />, ogConfig) as {
|
||||
const description_ = await (await remark().use(strip).process(description)).toString();
|
||||
const img = new ImageResponse(<Generic title={title} description={description_} />, ogConfig) as {
|
||||
body: Buffer;
|
||||
};
|
||||
|
||||
|
||||
@@ -65,6 +65,7 @@ export default trpcNext.createNextApiHandler({
|
||||
"viewer.public.i18n": `no-cache`,
|
||||
// Revalidation time here should be 1 second, per https://github.com/calcom/cal.com/pull/6823#issuecomment-1423215321
|
||||
"viewer.public.slots.getSchedule": `no-cache`, // FIXME
|
||||
"viewer.public.cityTimezones": `max-age=${ONE_DAY_IN_SECONDS}, stale-while-revalidate`,
|
||||
} as const;
|
||||
|
||||
// Find which element above is an exact match for this group of paths
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { useRouter } from "next/router";
|
||||
import { useReducer, useState } from "react";
|
||||
import { useCallback, useReducer, useState } from "react";
|
||||
import z from "zod";
|
||||
|
||||
import { AppSettings } from "@calcom/app-store/_components/AppSettings";
|
||||
@@ -7,8 +7,9 @@ import { InstallAppButton } from "@calcom/app-store/components";
|
||||
import type { EventLocationType } from "@calcom/app-store/locations";
|
||||
import { getEventLocationTypeFromApp } from "@calcom/app-store/locations";
|
||||
import { InstalledAppVariants } from "@calcom/app-store/utils";
|
||||
import { AppSetDefaultLinkDailog } from "@calcom/features/apps/components/AppSetDefaultLinkDialog";
|
||||
import { AppSetDefaultLinkDialog } from "@calcom/features/apps/components/AppSetDefaultLinkDialog";
|
||||
import DisconnectIntegrationModal from "@calcom/features/apps/components/DisconnectIntegrationModal";
|
||||
import { BulkEditDefaultConferencingModal } from "@calcom/features/eventtypes/components/BulkEditDefaultConferencingModal";
|
||||
import { useLocale } from "@calcom/lib/hooks/useLocale";
|
||||
import type { RouterOutputs } from "@calcom/trpc/react";
|
||||
import { trpc } from "@calcom/trpc/react";
|
||||
@@ -113,11 +114,16 @@ interface IntegrationsListProps {
|
||||
const IntegrationsList = ({ data, handleDisconnect, variant }: IntegrationsListProps) => {
|
||||
const { data: defaultConferencingApp } = trpc.viewer.getUsersDefaultConferencingApp.useQuery();
|
||||
const utils = trpc.useContext();
|
||||
|
||||
const [bulkUpdateModal, setBulkUpdateModal] = useState(false);
|
||||
const [locationType, setLocationType] = useState<(EventLocationType & { slug: string }) | undefined>(
|
||||
undefined
|
||||
);
|
||||
|
||||
const onSuccessCallback = useCallback(() => {
|
||||
setBulkUpdateModal(true);
|
||||
showToast("Default app updated successfully", "success");
|
||||
}, []);
|
||||
|
||||
const updateDefaultAppMutation = trpc.viewer.updateUserDefaultConferencingApp.useMutation({
|
||||
onSuccess: () => {
|
||||
showToast("Default app updated successfully", "success");
|
||||
@@ -172,6 +178,7 @@ const IntegrationsList = ({ data, handleDisconnect, variant }: IntegrationsListP
|
||||
updateDefaultAppMutation.mutate({
|
||||
appSlug,
|
||||
});
|
||||
setBulkUpdateModal(true);
|
||||
}
|
||||
}}>
|
||||
{t("change_default_conferencing_app")}
|
||||
@@ -196,11 +203,16 @@ const IntegrationsList = ({ data, handleDisconnect, variant }: IntegrationsListP
|
||||
})}
|
||||
</List>
|
||||
{locationType && (
|
||||
<AppSetDefaultLinkDailog
|
||||
<AppSetDefaultLinkDialog
|
||||
locationType={locationType}
|
||||
setLocationType={() => setLocationType(undefined)}
|
||||
onSuccess={onSuccessCallback}
|
||||
/>
|
||||
)}
|
||||
|
||||
{bulkUpdateModal && (
|
||||
<BulkEditDefaultConferencingModal open={bulkUpdateModal} setOpen={setBulkUpdateModal} />
|
||||
)}
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import classNames from "classnames";
|
||||
import { jwtVerify } from "jose";
|
||||
import type { GetServerSidePropsContext } from "next";
|
||||
import { getCsrfToken, signIn } from "next-auth/react";
|
||||
import Link from "next/link";
|
||||
@@ -42,14 +43,14 @@ export default function Login({
|
||||
isSAMLLoginEnabled,
|
||||
samlTenantID,
|
||||
samlProductID,
|
||||
totpEmail,
|
||||
}: inferSSRProps<typeof _getServerSideProps> & WithNonceProps) {
|
||||
const { t } = useLocale();
|
||||
const router = useRouter();
|
||||
const methods = useForm<LoginValues>();
|
||||
|
||||
const { register, formState } = methods;
|
||||
|
||||
const [twoFactorRequired, setTwoFactorRequired] = useState(false);
|
||||
const [twoFactorRequired, setTwoFactorRequired] = useState(!!totpEmail || false);
|
||||
const [errorMessage, setErrorMessage] = useState<string | null>(null);
|
||||
|
||||
const errorMessages: { [key: string]: string } = {
|
||||
@@ -94,6 +95,16 @@ export default function Login({
|
||||
</Button>
|
||||
);
|
||||
|
||||
const ExternalTotpFooter = (
|
||||
<Button
|
||||
onClick={() => {
|
||||
window.location.replace("/");
|
||||
}}
|
||||
color="minimal">
|
||||
{t("cancel")}
|
||||
</Button>
|
||||
);
|
||||
|
||||
const onSubmit = async (values: LoginValues) => {
|
||||
setErrorMessage(null);
|
||||
telemetry.event(telemetryEventTypes.login, collectPageParameters());
|
||||
@@ -120,7 +131,9 @@ export default function Login({
|
||||
heading={twoFactorRequired ? t("2fa_code") : t("welcome_back")}
|
||||
footerText={
|
||||
twoFactorRequired
|
||||
? TwoFactorFooter
|
||||
? !totpEmail
|
||||
? TwoFactorFooter
|
||||
: ExternalTotpFooter
|
||||
: process.env.NEXT_PUBLIC_DISABLE_SIGNUP !== "true"
|
||||
? LoginFooter
|
||||
: null
|
||||
@@ -135,7 +148,7 @@ export default function Login({
|
||||
<EmailField
|
||||
id="email"
|
||||
label={t("email_address")}
|
||||
defaultValue={router.query.email as string}
|
||||
defaultValue={totpEmail || (router.query.email as string)}
|
||||
placeholder="john.doe@example.com"
|
||||
required
|
||||
{...register("email")}
|
||||
@@ -152,7 +165,7 @@ export default function Login({
|
||||
<PasswordField
|
||||
id="password"
|
||||
autoComplete="off"
|
||||
required
|
||||
required={!totpEmail}
|
||||
className="mb-0"
|
||||
{...register("password")}
|
||||
/>
|
||||
@@ -211,6 +224,40 @@ const _getServerSideProps = async function getServerSideProps(context: GetServer
|
||||
const session = await getSession({ req });
|
||||
const ssr = await ssrInit(context);
|
||||
|
||||
const verifyJwt = (jwt: string) => {
|
||||
const secret = new TextEncoder().encode(process.env.CALENDSO_ENCRYPTION_KEY);
|
||||
|
||||
return jwtVerify(jwt, secret, {
|
||||
issuer: WEBSITE_URL,
|
||||
audience: `${WEBSITE_URL}/auth/login`,
|
||||
algorithms: ["HS256"],
|
||||
});
|
||||
};
|
||||
|
||||
let totpEmail = null;
|
||||
if (context.query.totp) {
|
||||
try {
|
||||
const decryptedJwt = await verifyJwt(context.query.totp as string);
|
||||
if (decryptedJwt.payload) {
|
||||
totpEmail = decryptedJwt.payload.email as string;
|
||||
} else {
|
||||
return {
|
||||
redirect: {
|
||||
destination: "/auth/error?error=JWT%20Invalid%20Payload",
|
||||
permanent: false,
|
||||
},
|
||||
};
|
||||
}
|
||||
} catch (e) {
|
||||
return {
|
||||
redirect: {
|
||||
destination: "/auth/error?error=Invalid%20JWT%3A%20Please%20try%20again",
|
||||
permanent: false,
|
||||
},
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
if (session) {
|
||||
return {
|
||||
redirect: {
|
||||
@@ -238,6 +285,7 @@ const _getServerSideProps = async function getServerSideProps(context: GetServer
|
||||
isSAMLLoginEnabled,
|
||||
samlTenantID,
|
||||
samlProductID,
|
||||
totpEmail,
|
||||
},
|
||||
};
|
||||
};
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import type { GetServerSidePropsContext } from "next";
|
||||
import { useRouter } from "next/router";
|
||||
import { Controller, useFieldArray, useForm } from "react-hook-form";
|
||||
import { z } from "zod";
|
||||
|
||||
@@ -8,7 +8,7 @@ import Shell from "@calcom/features/shell/Shell";
|
||||
import { availabilityAsString } from "@calcom/lib/availability";
|
||||
import { yyyymmdd } from "@calcom/lib/date-fns";
|
||||
import { useLocale } from "@calcom/lib/hooks/useLocale";
|
||||
import { stringOrNumber } from "@calcom/prisma/zod-utils";
|
||||
import { useTypedQuery } from "@calcom/lib/hooks/useTypedQuery";
|
||||
import { trpc } from "@calcom/trpc/react";
|
||||
import useMeQuery from "@calcom/trpc/react/hooks/useMeQuery";
|
||||
import type { Schedule as ScheduleType, TimeRange, WorkingHours } from "@calcom/types/schedule";
|
||||
@@ -22,19 +22,20 @@ import {
|
||||
Switch,
|
||||
TimezoneSelect,
|
||||
Tooltip,
|
||||
Dialog,
|
||||
DialogTrigger,
|
||||
ConfirmationDialogContent,
|
||||
VerticalDivider,
|
||||
} from "@calcom/ui";
|
||||
import { FiInfo, FiPlus } from "@calcom/ui/components/icon";
|
||||
import { FiInfo, FiPlus, FiTrash } from "@calcom/ui/components/icon";
|
||||
|
||||
import { HttpError } from "@lib/core/http/error";
|
||||
|
||||
import { SelectSkeletonLoader } from "@components/availability/SkeletonLoader";
|
||||
import EditableHeading from "@components/ui/EditableHeading";
|
||||
|
||||
import { ssrInit } from "@server/lib/ssr";
|
||||
|
||||
const querySchema = z.object({
|
||||
schedule: stringOrNumber,
|
||||
schedule: z.coerce.number().positive().optional(),
|
||||
});
|
||||
|
||||
type AvailabilityFormValues = {
|
||||
@@ -84,15 +85,29 @@ const DateOverride = ({ workingHours }: { workingHours: WorkingHours[] }) => {
|
||||
);
|
||||
};
|
||||
|
||||
export default function Availability({ schedule }: { schedule: number }) {
|
||||
export default function Availability() {
|
||||
const { t, i18n } = useLocale();
|
||||
const router = useRouter();
|
||||
const utils = trpc.useContext();
|
||||
const me = useMeQuery();
|
||||
const {
|
||||
data: { schedule: scheduleId },
|
||||
} = useTypedQuery(querySchema);
|
||||
|
||||
const { timeFormat } = me.data || { timeFormat: null };
|
||||
const { data, isLoading } = trpc.viewer.availability.schedule.get.useQuery({ scheduleId: schedule });
|
||||
const { data: defaultValues } = trpc.viewer.availability.defaultValues.useQuery({ scheduleId: schedule });
|
||||
const form = useForm<AvailabilityFormValues>({ defaultValues });
|
||||
const { control } = form;
|
||||
const { data: schedule, isLoading } = trpc.viewer.availability.schedule.get.useQuery(
|
||||
{ scheduleId },
|
||||
{
|
||||
enabled: !!scheduleId,
|
||||
}
|
||||
);
|
||||
|
||||
const form = useForm<AvailabilityFormValues>({
|
||||
values: schedule && {
|
||||
...schedule,
|
||||
schedule: schedule?.availability || [],
|
||||
},
|
||||
});
|
||||
const updateMutation = trpc.viewer.availability.schedule.update.useMutation({
|
||||
onSuccess: async ({ prevDefaultId, currentDefaultId, ...data }) => {
|
||||
if (prevDefaultId && currentDefaultId) {
|
||||
@@ -120,10 +135,26 @@ export default function Availability({ schedule }: { schedule: number }) {
|
||||
},
|
||||
});
|
||||
|
||||
const deleteMutation = trpc.viewer.availability.schedule.delete.useMutation({
|
||||
onError: (err) => {
|
||||
if (err instanceof HttpError) {
|
||||
const message = `${err.statusCode}: ${err.message}`;
|
||||
showToast(message, "error");
|
||||
}
|
||||
},
|
||||
onSettled: () => {
|
||||
utils.viewer.availability.list.invalidate();
|
||||
},
|
||||
onSuccess: () => {
|
||||
showToast(t("schedule_deleted_successfully"), "success");
|
||||
router.push("/availability");
|
||||
},
|
||||
});
|
||||
|
||||
return (
|
||||
<Shell
|
||||
backPath="/availability"
|
||||
title={data?.schedule.name ? data.schedule.name + " | " + t("availability") : t("availability")}
|
||||
title={schedule?.name ? schedule.name + " | " + t("availability") : t("availability")}
|
||||
heading={
|
||||
<Controller
|
||||
control={form.control}
|
||||
@@ -134,8 +165,8 @@ export default function Availability({ schedule }: { schedule: number }) {
|
||||
/>
|
||||
}
|
||||
subtitle={
|
||||
data ? (
|
||||
data.schedule.availability
|
||||
schedule ? (
|
||||
schedule.schedule
|
||||
.filter((availability) => !!availability.days.length)
|
||||
.map((availability) => (
|
||||
<span key={availability.id}>
|
||||
@@ -158,7 +189,7 @@ export default function Availability({ schedule }: { schedule: number }) {
|
||||
</Skeleton>
|
||||
<Switch
|
||||
id="hiddenSwitch"
|
||||
disabled={isLoading || data?.isDefault}
|
||||
disabled={isLoading || schedule?.isDefault}
|
||||
checked={form.watch("isDefault")}
|
||||
onCheckedChange={(e) => {
|
||||
form.setValue("isDefault", e);
|
||||
@@ -166,6 +197,24 @@ export default function Availability({ schedule }: { schedule: number }) {
|
||||
/>
|
||||
</div>
|
||||
|
||||
<VerticalDivider />
|
||||
<Dialog>
|
||||
<DialogTrigger asChild>
|
||||
<Button StartIcon={FiTrash} variant="icon" color="destructive" aria-label={t("delete")} />
|
||||
</DialogTrigger>
|
||||
<ConfirmationDialogContent
|
||||
isLoading={deleteMutation.isLoading}
|
||||
variety="danger"
|
||||
title={t("delete_schedule")}
|
||||
confirmBtnText={t("delete")}
|
||||
loadingText={t("delete")}
|
||||
onConfirm={() => {
|
||||
scheduleId && deleteMutation.mutate({ scheduleId });
|
||||
}}>
|
||||
{t("delete_schedule_description")}
|
||||
</ConfirmationDialogContent>
|
||||
</Dialog>
|
||||
|
||||
<VerticalDivider />
|
||||
|
||||
<div className="border-l-2 border-gray-300" />
|
||||
@@ -179,11 +228,12 @@ export default function Availability({ schedule }: { schedule: number }) {
|
||||
form={form}
|
||||
id="availability-form"
|
||||
handleSubmit={async ({ dateOverrides, ...values }) => {
|
||||
updateMutation.mutate({
|
||||
scheduleId: schedule,
|
||||
dateOverrides: dateOverrides.flatMap((override) => override.ranges),
|
||||
...values,
|
||||
});
|
||||
scheduleId &&
|
||||
updateMutation.mutate({
|
||||
scheduleId,
|
||||
dateOverrides: dateOverrides.flatMap((override) => override.ranges),
|
||||
...values,
|
||||
});
|
||||
}}
|
||||
className="flex flex-col sm:mx-0 xl:flex-row xl:space-x-6">
|
||||
<div className="flex-1 flex-row xl:mr-0">
|
||||
@@ -191,7 +241,7 @@ export default function Availability({ schedule }: { schedule: number }) {
|
||||
<div>
|
||||
{typeof me.data?.weekStart === "string" && (
|
||||
<Schedule
|
||||
control={control}
|
||||
control={form.control}
|
||||
name="schedule"
|
||||
weekStart={
|
||||
["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"].indexOf(
|
||||
@@ -203,7 +253,7 @@ export default function Availability({ schedule }: { schedule: number }) {
|
||||
</div>
|
||||
</div>
|
||||
<div className="my-6 rounded-md border">
|
||||
{data?.workingHours && <DateOverride workingHours={data.workingHours} />}
|
||||
{schedule?.workingHours && <DateOverride workingHours={schedule.workingHours} />}
|
||||
</div>
|
||||
</div>
|
||||
<div className="min-w-40 col-span-3 space-y-2 lg:col-span-1">
|
||||
@@ -243,20 +293,3 @@ export default function Availability({ schedule }: { schedule: number }) {
|
||||
</Shell>
|
||||
);
|
||||
}
|
||||
|
||||
export const getServerSideProps = async (ctx: GetServerSidePropsContext) => {
|
||||
const params = querySchema.safeParse(ctx.params);
|
||||
const ssr = await ssrInit(ctx);
|
||||
|
||||
if (!params.success) return { notFound: true };
|
||||
|
||||
const scheduleId = params.data.schedule;
|
||||
await ssr.viewer.availability.schedule.get.fetch({ scheduleId });
|
||||
await ssr.viewer.availability.defaultValues.fetch({ scheduleId });
|
||||
return {
|
||||
props: {
|
||||
schedule: scheduleId,
|
||||
trpcState: ssr.dehydrate(),
|
||||
},
|
||||
};
|
||||
};
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { BookingStatus, WorkflowActions } from "@prisma/client";
|
||||
import { BookingStatus } from "@prisma/client";
|
||||
import { Collapsible, CollapsibleContent, CollapsibleTrigger } from "@radix-ui/react-collapsible";
|
||||
import classNames from "classnames";
|
||||
import { createEvent } from "ics";
|
||||
@@ -23,6 +23,10 @@ import {
|
||||
useIsBackgroundTransparent,
|
||||
useIsEmbed,
|
||||
} from "@calcom/embed-core/embed-iframe";
|
||||
import {
|
||||
SystemField,
|
||||
getBookingFieldsWithSystemFields,
|
||||
} from "@calcom/features/bookings/lib/getBookingFields";
|
||||
import { parseRecurringEvent } from "@calcom/lib";
|
||||
import CustomBranding from "@calcom/lib/CustomBranding";
|
||||
import { APP_NAME } from "@calcom/lib/constants";
|
||||
@@ -42,10 +46,11 @@ import prisma from "@calcom/prisma";
|
||||
import type { Prisma } from "@calcom/prisma/client";
|
||||
import { bookingMetadataSchema } from "@calcom/prisma/zod-utils";
|
||||
import { customInputSchema, EventTypeMetaDataSchema } from "@calcom/prisma/zod-utils";
|
||||
import { Button, EmailInput, HeadSeo } from "@calcom/ui";
|
||||
import { Badge, Button, EmailInput, HeadSeo } from "@calcom/ui";
|
||||
import { FiX, FiExternalLink, FiChevronLeft, FiCheck, FiCalendar } from "@calcom/ui/components/icon";
|
||||
|
||||
import { timeZone } from "@lib/clock";
|
||||
import { getBookingWithResponses } from "@lib/getBooking";
|
||||
import type { inferSSRProps } from "@lib/types/inferSSRProps";
|
||||
|
||||
import CancelBooking from "@components/booking/CancelBooking";
|
||||
@@ -195,10 +200,7 @@ export default function Success(props: SuccessProps) {
|
||||
window.scrollTo(0, document.body.scrollHeight);
|
||||
}
|
||||
|
||||
const location: ReturnType<typeof getEventLocationValue> = props.bookingInfo.location
|
||||
? props.bookingInfo.location
|
||||
: // If there is no location set then we default to Cal Video
|
||||
"integrations:daily";
|
||||
const location = props.bookingInfo.location as ReturnType<typeof getEventLocationValue>;
|
||||
|
||||
const locationVideoCallUrl: string | undefined = bookingMetadataSchema.parse(
|
||||
props?.bookingInfo?.metadata || {}
|
||||
@@ -335,12 +337,12 @@ export default function Success(props: SuccessProps) {
|
||||
}
|
||||
return t("emailed_you_and_attendees" + titleSuffix);
|
||||
}
|
||||
|
||||
const userIsOwner = !!(session?.user?.id && eventType.owner?.id === session.user.id);
|
||||
useTheme(isSuccessBookingPage ? props.profile.theme : "light");
|
||||
const title = t(
|
||||
`booking_${needsConfirmation ? "submitted" : "confirmed"}${props.recurringBookings ? "_recurring" : ""}`
|
||||
);
|
||||
const customInputs = bookingInfo?.customInputs;
|
||||
|
||||
const locationToDisplay = getSuccessPageLocationMessage(
|
||||
locationVideoCallUrl ? locationVideoCallUrl : location,
|
||||
@@ -348,10 +350,6 @@ export default function Success(props: SuccessProps) {
|
||||
bookingInfo.status
|
||||
);
|
||||
|
||||
const hasSMSAttendeeAction =
|
||||
eventType.workflows.find((workflowEventType) =>
|
||||
workflowEventType.workflow.steps.find((step) => step.action === WorkflowActions.SMS_ATTENDEE)
|
||||
) !== undefined;
|
||||
const providerName = guessEventLocationType(location)?.label;
|
||||
|
||||
return (
|
||||
@@ -499,7 +497,12 @@ export default function Success(props: SuccessProps) {
|
||||
<>
|
||||
{bookingInfo?.user && (
|
||||
<div className="mb-3">
|
||||
<p>{bookingInfo.user.name}</p>
|
||||
<p>
|
||||
<span className="mr-2">{bookingInfo.user.name}</span>
|
||||
<Badge variant="blue" bold>
|
||||
{t("Host")}
|
||||
</Badge>
|
||||
</p>
|
||||
<p className="text-bookinglight">{bookingInfo.user.email}</p>
|
||||
</div>
|
||||
)}
|
||||
@@ -541,63 +544,28 @@ export default function Success(props: SuccessProps) {
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
{customInputs &&
|
||||
Object.keys(customInputs).map((key) => {
|
||||
// This breaks if you have two label that are the same.
|
||||
// TODO: Fix this in another PR
|
||||
const customInput = customInputs[key as keyof typeof customInputs];
|
||||
const eventTypeCustomFound = eventType.customInputs?.find((ci) => ci.label === key);
|
||||
return (
|
||||
<>
|
||||
{eventTypeCustomFound?.type === "RADIO" && (
|
||||
<>
|
||||
<div className="border-bookinglightest dark:border-darkgray-300 col-span-3 mt-8 border-t pt-8 pr-3 font-medium">
|
||||
{eventTypeCustomFound.label}
|
||||
</div>
|
||||
<div className="col-span-3 mt-1 mb-2">
|
||||
{eventTypeCustomFound.options &&
|
||||
eventTypeCustomFound.options.map((option) => {
|
||||
const selected = option.label == customInput;
|
||||
return (
|
||||
<div
|
||||
key={option.label}
|
||||
className={classNames(
|
||||
"flex space-x-1",
|
||||
!selected && "text-gray-500"
|
||||
)}>
|
||||
<p>{option.label}</p>
|
||||
<span>{option.label === customInput && "✅"}</span>
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
{eventTypeCustomFound?.type !== "RADIO" && customInput !== "" && (
|
||||
<>
|
||||
<div className="border-bookinglightest dark:border-darkgray-300 col-span-3 mt-8 border-t pt-8 pr-3 font-medium">
|
||||
{key}
|
||||
</div>
|
||||
<div className="col-span-3 mt-2 mb-2">
|
||||
{typeof customInput === "boolean" ? (
|
||||
<p>{customInput ? "true" : "false"}</p>
|
||||
) : (
|
||||
<p>{customInput}</p>
|
||||
)}
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
</>
|
||||
);
|
||||
})}
|
||||
{bookingInfo?.smsReminderNumber && hasSMSAttendeeAction && (
|
||||
<>
|
||||
<div className="mt-9 font-medium">{t("number_sms_notifications")}</div>
|
||||
<div className="col-span-2 mb-2 mt-9">
|
||||
<p>{bookingInfo.smsReminderNumber}</p>
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
|
||||
{Object.entries(bookingInfo.responses).map(([name, response]) => {
|
||||
const field = eventType.bookingFields.find((field) => field.name === name);
|
||||
// We show location in the "where" section
|
||||
// We show Booker Name, Emails and guests in Who section
|
||||
// We show notes in additional notes section
|
||||
// We show rescheduleReason at the top
|
||||
if (!field) return null;
|
||||
const isSystemField = SystemField.safeParse(field.name);
|
||||
if (isSystemField.success) return null;
|
||||
|
||||
const label = field.label || t(field.defaultLabel || "");
|
||||
|
||||
return (
|
||||
<>
|
||||
<div className="mt-9 font-medium">{label}</div>
|
||||
<div className="col-span-2 mb-2 mt-9">
|
||||
<p className="break-words">{response.toString()}</p>
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
</div>
|
||||
{(!needsConfirmation || !userIsOwner) &&
|
||||
@@ -828,7 +796,6 @@ export function RecurringBookings({
|
||||
t,
|
||||
i18n: { language },
|
||||
} = useLocale();
|
||||
|
||||
const recurringBookingsSorted = recurringBookings
|
||||
? recurringBookings.sort((a: ConfigType, b: ConfigType) => (dayjs(a).isAfter(dayjs(b)) ? 1 : -1))
|
||||
: null;
|
||||
@@ -855,7 +822,7 @@ export function RecurringBookings({
|
||||
{formatToLocalizedTime(dayjs(dateStr), language, undefined, !is24h)} -{" "}
|
||||
{formatToLocalizedTime(dayjs(dateStr).add(duration, "m"), language, undefined, !is24h)}{" "}
|
||||
<span className="text-bookinglight">
|
||||
({formatToLocalizedTimezone(dayjs(dateStr), language)})
|
||||
({formatToLocalizedTimezone(dayjs(dateStr), language, timeZone())})
|
||||
</span>
|
||||
</div>
|
||||
))}
|
||||
@@ -875,7 +842,7 @@ export function RecurringBookings({
|
||||
{formatToLocalizedTime(date, language, undefined, !is24h)} -{" "}
|
||||
{formatToLocalizedTime(dayjs(date).add(duration, "m"), language, undefined, !is24h)}{" "}
|
||||
<span className="text-bookinglight">
|
||||
({formatToLocalizedTimezone(dayjs(dateStr), language)})
|
||||
({formatToLocalizedTimezone(dayjs(dateStr), language, timeZone())})
|
||||
</span>
|
||||
</div>
|
||||
))}
|
||||
@@ -892,7 +859,7 @@ export function RecurringBookings({
|
||||
<br />
|
||||
{formatToLocalizedTime(date, language, undefined, !is24h)} -{" "}
|
||||
{formatToLocalizedTime(dayjs(date).add(duration, "m"), language, undefined, !is24h)}{" "}
|
||||
<span className="text-bookinglight">({formatToLocalizedTimezone(date, language)})</span>
|
||||
<span className="text-bookinglight">({formatToLocalizedTimezone(date, language, timeZone())})</span>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -927,6 +894,8 @@ const getEventTypesFromDB = async (id: number) => {
|
||||
locations: true,
|
||||
price: true,
|
||||
currency: true,
|
||||
bookingFields: true,
|
||||
disableGuests: true,
|
||||
owner: {
|
||||
select: userSelect,
|
||||
},
|
||||
@@ -951,6 +920,7 @@ const getEventTypesFromDB = async (id: number) => {
|
||||
select: {
|
||||
workflow: {
|
||||
select: {
|
||||
id: true,
|
||||
steps: true,
|
||||
},
|
||||
},
|
||||
@@ -973,6 +943,7 @@ const getEventTypesFromDB = async (id: number) => {
|
||||
return {
|
||||
isDynamic: false,
|
||||
...eventType,
|
||||
bookingFields: getBookingFieldsWithSystemFields(eventType),
|
||||
metadata,
|
||||
};
|
||||
};
|
||||
@@ -1017,7 +988,7 @@ export async function getServerSideProps(context: GetServerSidePropsContext) {
|
||||
if (!parsedQuery.success) return { notFound: true };
|
||||
const { uid, email, eventTypeSlug, cancel } = parsedQuery.data;
|
||||
|
||||
const bookingInfo = await prisma.booking.findFirst({
|
||||
const bookingInfoRaw = await prisma.booking.findFirst({
|
||||
where: {
|
||||
uid,
|
||||
},
|
||||
@@ -1035,6 +1006,7 @@ export async function getServerSideProps(context: GetServerSidePropsContext) {
|
||||
status: true,
|
||||
metadata: true,
|
||||
cancellationReason: true,
|
||||
responses: true,
|
||||
rejectionReason: true,
|
||||
user: {
|
||||
select: {
|
||||
@@ -1059,27 +1031,28 @@ export async function getServerSideProps(context: GetServerSidePropsContext) {
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
if (!bookingInfo) {
|
||||
if (!bookingInfoRaw) {
|
||||
return {
|
||||
notFound: true,
|
||||
};
|
||||
}
|
||||
|
||||
// @NOTE: had to do this because Server side cant return [Object objects]
|
||||
// probably fixable with json.stringify -> json.parse
|
||||
bookingInfo["startTime"] = (bookingInfo?.startTime as Date)?.toISOString() as unknown as Date;
|
||||
bookingInfo["endTime"] = (bookingInfo?.endTime as Date)?.toISOString() as unknown as Date;
|
||||
|
||||
const eventTypeRaw = !bookingInfo.eventTypeId
|
||||
const eventTypeRaw = !bookingInfoRaw.eventTypeId
|
||||
? getDefaultEvent(eventTypeSlug || "")
|
||||
: await getEventTypesFromDB(bookingInfo.eventTypeId);
|
||||
: await getEventTypesFromDB(bookingInfoRaw.eventTypeId);
|
||||
if (!eventTypeRaw) {
|
||||
return {
|
||||
notFound: true,
|
||||
};
|
||||
}
|
||||
|
||||
const bookingInfo = getBookingWithResponses(bookingInfoRaw, eventTypeRaw);
|
||||
|
||||
// @NOTE: had to do this because Server side cant return [Object objects]
|
||||
// probably fixable with json.stringify -> json.parse
|
||||
bookingInfo["startTime"] = (bookingInfo?.startTime as Date)?.toISOString() as unknown as Date;
|
||||
bookingInfo["endTime"] = (bookingInfo?.endTime as Date)?.toISOString() as unknown as Date;
|
||||
|
||||
eventTypeRaw.users = !!eventTypeRaw.hosts?.length
|
||||
? eventTypeRaw.hosts.map((host) => host.user)
|
||||
: eventTypeRaw.users;
|
||||
|
||||
@@ -3,7 +3,7 @@ import type { GetServerSidePropsContext } from "next";
|
||||
import { parseRecurringEvent } from "@calcom/lib";
|
||||
import prisma from "@calcom/prisma";
|
||||
import { bookEventTypeSelect } from "@calcom/prisma/selects";
|
||||
import { customInputSchema, EventTypeMetaDataSchema } from "@calcom/prisma/zod-utils";
|
||||
import { customInputSchema, eventTypeBookingFields, EventTypeMetaDataSchema } from "@calcom/prisma/zod-utils";
|
||||
|
||||
import { asStringOrNull, asStringOrThrow } from "@lib/asStringOrNull";
|
||||
import type { inferSSRProps } from "@lib/types/inferSSRProps";
|
||||
@@ -71,6 +71,7 @@ export async function getServerSideProps(context: GetServerSidePropsContext) {
|
||||
...eventTypeRaw,
|
||||
metadata: EventTypeMetaDataSchema.parse(eventTypeRaw.metadata || {}),
|
||||
recurringEvent: parseRecurringEvent(eventTypeRaw.recurringEvent),
|
||||
bookingFields: eventTypeBookingFields.parse(eventTypeRaw.bookingFields || []),
|
||||
};
|
||||
|
||||
const eventTypeObject = [eventType].map((e) => {
|
||||
|
||||
@@ -4,10 +4,11 @@ import { zodResolver } from "@hookform/resolvers/zod";
|
||||
import type { PeriodType } from "@prisma/client";
|
||||
import { SchedulingType } from "@prisma/client";
|
||||
import type { GetServerSidePropsContext } from "next";
|
||||
import { useState } from "react";
|
||||
import { useEffect, useState } from "react";
|
||||
import { useForm } from "react-hook-form";
|
||||
import { z } from "zod";
|
||||
|
||||
import { validateCustomEventName } from "@calcom/core/event";
|
||||
import type { EventLocationType } from "@calcom/core/location";
|
||||
import { validateBookingLimitOrder } from "@calcom/lib";
|
||||
import { CAL_URL } from "@calcom/lib/constants";
|
||||
@@ -16,6 +17,7 @@ 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 { eventTypeBookingFields } from "@calcom/prisma/zod-utils";
|
||||
import type { customInputSchema, EventTypeMetaDataSchema } from "@calcom/prisma/zod-utils";
|
||||
import type { RouterOutputs } from "@calcom/trpc/react";
|
||||
import { trpc } from "@calcom/trpc/react";
|
||||
@@ -86,6 +88,7 @@ export type FormValues = {
|
||||
bookingLimits?: BookingLimit;
|
||||
hosts: { userId: number }[];
|
||||
hostsFixed: { userId: number }[];
|
||||
bookingFields: z.infer<typeof eventTypeBookingFields>;
|
||||
};
|
||||
|
||||
export type CustomInputParsed = typeof customInputSchema._output;
|
||||
@@ -120,7 +123,7 @@ const EventTypePage = (props: EventTypeSetupProps) => {
|
||||
extendsFeature: "EventType",
|
||||
});
|
||||
|
||||
const { eventType, locationOptions, team, teamMembers, currentUserMembership } = props;
|
||||
const { eventType, locationOptions, team, teamMembers, currentUserMembership, destinationCalendar } = props;
|
||||
const [animationParentRef] = useAutoAnimate<HTMLDivElement>();
|
||||
|
||||
const updateMutation = trpc.viewer.eventTypes.update.useMutation({
|
||||
@@ -178,48 +181,65 @@ const EventTypePage = (props: EventTypeSetupProps) => {
|
||||
delete metadata.config?.useHostSchedulesForTeamEvent;
|
||||
}
|
||||
|
||||
const formMethods = useForm<FormValues>({
|
||||
defaultValues: {
|
||||
title: eventType.title,
|
||||
locations: eventType.locations || [],
|
||||
recurringEvent: eventType.recurringEvent || null,
|
||||
description: eventType.description ?? undefined,
|
||||
schedule: eventType.schedule || undefined,
|
||||
bookingLimits: eventType.bookingLimits || undefined,
|
||||
length: eventType.length,
|
||||
hidden: eventType.hidden,
|
||||
periodDates: {
|
||||
startDate: periodDates.startDate,
|
||||
endDate: periodDates.endDate,
|
||||
},
|
||||
periodType: eventType.periodType,
|
||||
periodCountCalendarDays: eventType.periodCountCalendarDays ? "1" : "0",
|
||||
schedulingType: eventType.schedulingType,
|
||||
minimumBookingNotice: eventType.minimumBookingNotice,
|
||||
metadata,
|
||||
hosts: !!eventType.hosts?.length
|
||||
? eventType.hosts.filter((host) => !host.isFixed)
|
||||
: eventType.users
|
||||
.filter(() => eventType.schedulingType === SchedulingType.ROUND_ROBIN)
|
||||
.map((user) => ({ userId: user.id })),
|
||||
hostsFixed: !!eventType.hosts?.length
|
||||
? eventType.hosts.filter((host) => host.isFixed)
|
||||
: eventType.users
|
||||
.filter(() => eventType.schedulingType === SchedulingType.COLLECTIVE)
|
||||
.map((user) => ({ userId: user.id })),
|
||||
const defaultValues = {
|
||||
title: eventType.title,
|
||||
locations: eventType.locations || [],
|
||||
recurringEvent: eventType.recurringEvent || null,
|
||||
description: eventType.description ?? undefined,
|
||||
schedule: eventType.schedule || undefined,
|
||||
bookingLimits: eventType.bookingLimits || undefined,
|
||||
length: eventType.length,
|
||||
hidden: eventType.hidden,
|
||||
periodDates: {
|
||||
startDate: periodDates.startDate,
|
||||
endDate: periodDates.endDate,
|
||||
},
|
||||
bookingFields: eventType.bookingFields,
|
||||
periodType: eventType.periodType,
|
||||
periodCountCalendarDays: eventType.periodCountCalendarDays ? "1" : "0",
|
||||
schedulingType: eventType.schedulingType,
|
||||
minimumBookingNotice: eventType.minimumBookingNotice,
|
||||
metadata,
|
||||
hosts: !!eventType.hosts?.length
|
||||
? eventType.hosts.filter((host) => !host.isFixed)
|
||||
: eventType.users
|
||||
.filter(() => eventType.schedulingType === SchedulingType.ROUND_ROBIN)
|
||||
.map((user) => ({ userId: user.id })),
|
||||
hostsFixed: !!eventType.hosts?.length
|
||||
? eventType.hosts.filter((host) => host.isFixed)
|
||||
: eventType.users
|
||||
.filter(() => eventType.schedulingType === SchedulingType.COLLECTIVE)
|
||||
.map((user) => ({ userId: user.id })),
|
||||
} as const;
|
||||
|
||||
const formMethods = useForm<FormValues>({
|
||||
defaultValues,
|
||||
resolver: zodResolver(
|
||||
z
|
||||
.object({
|
||||
// Length if string, is converted to a number or it can be a number
|
||||
// Make it optional because it's not submitted from all tabs of the page
|
||||
eventName: z
|
||||
.string()
|
||||
.refine((val) => validateCustomEventName(val, t("invalid_event_name_variables")) === true, {
|
||||
message: t("invalid_event_name_variables"),
|
||||
})
|
||||
.optional(),
|
||||
length: z.union([z.string().transform((val) => +val), z.number()]).optional(),
|
||||
bookingFields: eventTypeBookingFields,
|
||||
})
|
||||
// TODO: Add schema for other fields later.
|
||||
.passthrough()
|
||||
),
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
if (!formMethods.formState.isDirty) {
|
||||
//TODO: What's the best way to sync the form with backend
|
||||
formMethods.setValue("bookingFields", defaultValues.bookingFields);
|
||||
}
|
||||
}, [defaultValues]);
|
||||
|
||||
const appsMetadata = formMethods.getValues("metadata")?.apps;
|
||||
const numberOfInstalledApps = eventTypeApps?.filter((app) => app.isInstalled).length || 0;
|
||||
let numberOfActiveApps = 0;
|
||||
@@ -241,6 +261,7 @@ const EventTypePage = (props: EventTypeSetupProps) => {
|
||||
locationOptions={locationOptions}
|
||||
team={team}
|
||||
teamMembers={teamMembers}
|
||||
destinationCalendar={destinationCalendar}
|
||||
/>
|
||||
),
|
||||
availability: <AvailabilityTab isTeamEvent={!!team} />,
|
||||
@@ -342,13 +363,7 @@ const EventTypePage = (props: EventTypeSetupProps) => {
|
||||
};
|
||||
|
||||
const EventTypePageWrapper = (props: inferSSRProps<typeof getServerSideProps>) => {
|
||||
const { data, isLoading } = trpc.viewer.eventTypes.get.useQuery(
|
||||
{ id: props.type },
|
||||
{
|
||||
initialData: props.initialData,
|
||||
}
|
||||
);
|
||||
|
||||
const { data, isLoading } = trpc.viewer.eventTypes.get.useQuery({ id: props.type });
|
||||
if (isLoading || !data) return null;
|
||||
return <EventTypePage {...data} />;
|
||||
};
|
||||
@@ -391,9 +406,7 @@ export const getServerSideProps = async (context: GetServerSidePropsContext) =>
|
||||
},
|
||||
};
|
||||
} catch (err) {
|
||||
return {
|
||||
notFound: true,
|
||||
};
|
||||
throw err;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -5,10 +5,9 @@ import type { FC } from "react";
|
||||
import { useEffect, useState, memo } from "react";
|
||||
import { z } from "zod";
|
||||
|
||||
import {
|
||||
CreateEventTypeButton,
|
||||
EventTypeDescriptionLazy as EventTypeDescription,
|
||||
} from "@calcom/features/eventtypes/components";
|
||||
import { EventTypeDescriptionLazy as EventTypeDescription } from "@calcom/features/eventtypes/components";
|
||||
import CreateEventTypeDialog from "@calcom/features/eventtypes/components/CreateEventTypeDialog";
|
||||
import { DuplicateDialog } from "@calcom/features/eventtypes/components/DuplicateDialog";
|
||||
import Shell from "@calcom/features/shell/Shell";
|
||||
import { APP_NAME, CAL_URL, WEBAPP_URL } from "@calcom/lib/constants";
|
||||
import { useLocale } from "@calcom/lib/hooks/useLocale";
|
||||
@@ -35,6 +34,7 @@ import {
|
||||
showToast,
|
||||
Switch,
|
||||
Tooltip,
|
||||
CreateButton,
|
||||
HorizontalTabs,
|
||||
} from "@calcom/ui";
|
||||
import {
|
||||
@@ -119,7 +119,7 @@ const Item = ({ type, group, readOnly }: { type: EventType; group: EventTypeGrou
|
||||
<Link
|
||||
href={`/event-types/${type.id}?tabName=setup`}
|
||||
className="flex-1 overflow-hidden pr-4 text-sm"
|
||||
title={`${type.title} ${type.description ? `– ${type.description}` : ""}`}>
|
||||
title={type.title}>
|
||||
<div>
|
||||
<span
|
||||
className="font-semibold text-gray-700 ltr:mr-1 rtl:ml-1"
|
||||
@@ -134,14 +134,15 @@ const Item = ({ type, group, readOnly }: { type: EventType; group: EventTypeGrou
|
||||
</small>
|
||||
) : null}
|
||||
{readOnly && (
|
||||
<span className="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 rtl:ml-2">
|
||||
<Badge variant="gray" className="ml-2">
|
||||
{t("readonly")}
|
||||
</span>
|
||||
</Badge>
|
||||
)}
|
||||
</div>
|
||||
<EventTypeDescription
|
||||
// @ts-expect-error FIXME: We have a type mismatch here @hariombalhara @sean-brydon
|
||||
eventType={type}
|
||||
shortenDescription
|
||||
/>
|
||||
</Link>
|
||||
);
|
||||
@@ -240,7 +241,7 @@ export const EventTypeList = ({ group, groupIndex, readOnly, types }: EventTypeL
|
||||
const openDuplicateModal = (eventType: EventType, group: EventTypeGroup) => {
|
||||
const query = {
|
||||
...router.query,
|
||||
dialog: "duplicate-event-type",
|
||||
dialog: "duplicate",
|
||||
title: eventType.title,
|
||||
description: eventType.description,
|
||||
slug: eventType.slug,
|
||||
@@ -627,17 +628,37 @@ const CreateFirstEventTypeView = () => {
|
||||
};
|
||||
|
||||
const CTA = () => {
|
||||
const { t } = useLocale();
|
||||
|
||||
const query = trpc.viewer.eventTypes.getByViewer.useQuery();
|
||||
|
||||
if (!query.data) return null;
|
||||
|
||||
return <CreateEventTypeButton canAddEvents={true} options={query.data.profiles} />;
|
||||
const profileOptions = query.data.profiles
|
||||
.filter((profile) => !profile.readOnly)
|
||||
.map((profile) => {
|
||||
return {
|
||||
teamId: profile.teamId,
|
||||
label: profile.name || profile.slug,
|
||||
image: profile.image,
|
||||
slug: profile.slug,
|
||||
};
|
||||
});
|
||||
|
||||
return (
|
||||
<CreateButton
|
||||
subtitle={t("create_event_on").toUpperCase()}
|
||||
options={profileOptions}
|
||||
createDialog={CreateEventTypeDialog}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
const WithQuery = withQuery(trpc.viewer.eventTypes.getByViewer);
|
||||
|
||||
const EventTypesPage = () => {
|
||||
const { t } = useLocale();
|
||||
const router = useRouter();
|
||||
|
||||
const isMobile = useMediaQuery("(max-width: 768px)");
|
||||
|
||||
@@ -683,6 +704,7 @@ const EventTypesPage = () => {
|
||||
)}
|
||||
|
||||
<EmbedDialog />
|
||||
{router.query.dialog === "duplicate" && <DuplicateDialog />}
|
||||
</>
|
||||
)}
|
||||
/>
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
import { useState } from "react";
|
||||
import { useCallback, useState } from "react";
|
||||
|
||||
import type { EventLocationType } from "@calcom/app-store/locations";
|
||||
import { getEventLocationTypeFromApp } from "@calcom/app-store/locations";
|
||||
import { AppSetDefaultLinkDailog } from "@calcom/features/apps/components/AppSetDefaultLinkDialog";
|
||||
import { AppSetDefaultLinkDialog } from "@calcom/features/apps/components/AppSetDefaultLinkDialog";
|
||||
import { BulkEditDefaultConferencingModal } from "@calcom/features/eventtypes/components/BulkEditDefaultConferencingModal";
|
||||
import { getLayout } from "@calcom/features/settings/layouts/SettingsLayout";
|
||||
import { useLocale } from "@calcom/lib/hooks/useLocale";
|
||||
import { trpc } from "@calcom/trpc/react";
|
||||
@@ -62,17 +63,20 @@ const ConferencingLayout = () => {
|
||||
},
|
||||
});
|
||||
|
||||
const onSuccessCallback = useCallback(() => {
|
||||
setBulkUpdateModal(true);
|
||||
showToast("Default app updated successfully", "success");
|
||||
}, []);
|
||||
|
||||
const updateDefaultAppMutation = trpc.viewer.updateUserDefaultConferencingApp.useMutation({
|
||||
onSuccess: () => {
|
||||
showToast("Default app updated successfully", "success");
|
||||
utils.viewer.getUsersDefaultConferencingApp.invalidate();
|
||||
},
|
||||
onSuccess: onSuccessCallback,
|
||||
onError: (error) => {
|
||||
showToast(`Error: ${error.message}`, "error");
|
||||
},
|
||||
});
|
||||
|
||||
const [deleteAppModal, setDeleteAppModal] = useState(false);
|
||||
const [bulkUpdateModal, setBulkUpdateModal] = useState(false);
|
||||
const [locationType, setLocationType] = useState<(EventLocationType & { slug: string }) | undefined>(
|
||||
undefined
|
||||
);
|
||||
@@ -167,7 +171,14 @@ const ConferencingLayout = () => {
|
||||
</Dialog>
|
||||
|
||||
{locationType && (
|
||||
<AppSetDefaultLinkDailog locationType={locationType} setLocationType={setLocationType} />
|
||||
<AppSetDefaultLinkDialog
|
||||
locationType={locationType}
|
||||
setLocationType={setLocationType}
|
||||
onSuccess={onSuccessCallback}
|
||||
/>
|
||||
)}
|
||||
{bulkUpdateModal && (
|
||||
<BulkEditDefaultConferencingModal open={bulkUpdateModal} setOpen={setBulkUpdateModal} />
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
import { IdentityProvider } from "@prisma/client";
|
||||
import crypto from "crypto";
|
||||
import MarkdownIt from "markdown-it";
|
||||
import { signOut } from "next-auth/react";
|
||||
import type { BaseSyntheticEvent } from "react";
|
||||
import { useRef, useState } from "react";
|
||||
@@ -10,6 +9,7 @@ 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";
|
||||
import { md } from "@calcom/lib/markdownIt";
|
||||
import turndown from "@calcom/lib/turndownService";
|
||||
import type { TRPCClientErrorLike } from "@calcom/trpc/client";
|
||||
import { trpc } from "@calcom/trpc/react";
|
||||
@@ -41,8 +41,6 @@ import { FiAlertTriangle, FiTrash2 } from "@calcom/ui/components/icon";
|
||||
import TwoFactor from "@components/auth/TwoFactor";
|
||||
import { UsernameAvailabilityField } from "@components/ui/UsernameAvailability";
|
||||
|
||||
const md = new MarkdownIt("default", { html: true, breaks: true });
|
||||
|
||||
const SkeletonLoader = ({ title, description }: { title: string; description: string }) => {
|
||||
return (
|
||||
<SkeletonContainer>
|
||||
@@ -371,6 +369,7 @@ const ProfileForm = ({
|
||||
formMethods.setValue("bio", turndown(value), { shouldDirty: true });
|
||||
}}
|
||||
excludedToolbarItems={["blockType"]}
|
||||
disableLists
|
||||
/>
|
||||
</div>
|
||||
<Button disabled={isDisabled} color="primary" className="mt-8" type="submit">
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
import classNames from "classnames";
|
||||
import MarkdownIt from "markdown-it";
|
||||
import type { GetServerSidePropsContext } from "next";
|
||||
import Link from "next/link";
|
||||
import { useRouter } from "next/router";
|
||||
@@ -11,6 +10,7 @@ import { CAL_URL } from "@calcom/lib/constants";
|
||||
import { getPlaceholderAvatar } from "@calcom/lib/getPlaceholderAvatar";
|
||||
import { useLocale } from "@calcom/lib/hooks/useLocale";
|
||||
import useTheme from "@calcom/lib/hooks/useTheme";
|
||||
import { md } from "@calcom/lib/markdownIt";
|
||||
import { getTeamWithMembers } from "@calcom/lib/server/queries/teams";
|
||||
import { collectPageParameters, telemetryEventTypes, useTelemetry } from "@calcom/lib/telemetry";
|
||||
import { Avatar, Button, HeadSeo, AvatarGroup } from "@calcom/ui";
|
||||
@@ -23,8 +23,6 @@ import Team from "@components/team/screens/Team";
|
||||
|
||||
import { ssrInit } from "@server/lib/ssr";
|
||||
|
||||
const md = new MarkdownIt("default", { html: true, breaks: true, linkify: true });
|
||||
|
||||
export type TeamPageProps = inferSSRProps<typeof getServerSideProps>;
|
||||
function TeamPage({ team }: TeamPageProps) {
|
||||
useTheme(team.theme);
|
||||
|
||||
@@ -2,6 +2,7 @@ import type { GetServerSidePropsContext } from "next";
|
||||
|
||||
import type { LocationObject } from "@calcom/core/location";
|
||||
import { privacyFilteredLocations } from "@calcom/core/location";
|
||||
import { getBookingFieldsWithSystemFields } from "@calcom/features/bookings/lib/getBookingFields";
|
||||
import { parseRecurringEvent } from "@calcom/lib";
|
||||
import { getWorkingHours } from "@calcom/lib/availability";
|
||||
import prisma from "@calcom/prisma";
|
||||
@@ -78,6 +79,7 @@ export const getServerSideProps = async (context: GetServerSidePropsContext) =>
|
||||
availability: true,
|
||||
description: true,
|
||||
length: true,
|
||||
disableGuests: true,
|
||||
schedulingType: true,
|
||||
periodType: true,
|
||||
periodStartDate: true,
|
||||
@@ -96,12 +98,24 @@ export const getServerSideProps = async (context: GetServerSidePropsContext) =>
|
||||
slotInterval: true,
|
||||
metadata: true,
|
||||
seatsPerTimeSlot: true,
|
||||
bookingFields: true,
|
||||
customInputs: true,
|
||||
schedule: {
|
||||
select: {
|
||||
timeZone: true,
|
||||
availability: true,
|
||||
},
|
||||
},
|
||||
workflows: {
|
||||
select: {
|
||||
workflow: {
|
||||
select: {
|
||||
id: true,
|
||||
steps: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
team: {
|
||||
select: {
|
||||
members: {
|
||||
@@ -163,7 +177,7 @@ export const getServerSideProps = async (context: GetServerSidePropsContext) =>
|
||||
|
||||
let booking: GetBookingType | null = null;
|
||||
if (rescheduleUid) {
|
||||
booking = await getBooking(prisma, rescheduleUid);
|
||||
booking = await getBooking(prisma, rescheduleUid, getBookingFieldsWithSystemFields(eventTypeObject));
|
||||
}
|
||||
|
||||
const weekStart = eventType.team?.members?.[0]?.user?.weekStart;
|
||||
|
||||
@@ -2,9 +2,10 @@ import type { GetServerSidePropsContext } from "next";
|
||||
|
||||
import type { LocationObject } from "@calcom/app-store/locations";
|
||||
import { privacyFilteredLocations } from "@calcom/app-store/locations";
|
||||
import { getBookingFieldsWithSystemFields } from "@calcom/features/bookings/lib/getBookingFields";
|
||||
import { parseRecurringEvent } from "@calcom/lib";
|
||||
import prisma from "@calcom/prisma";
|
||||
import { customInputSchema, EventTypeMetaDataSchema } from "@calcom/prisma/zod-utils";
|
||||
import { customInputSchema, eventTypeBookingFields, EventTypeMetaDataSchema } from "@calcom/prisma/zod-utils";
|
||||
|
||||
import { asStringOrNull, asStringOrThrow } from "@lib/asStringOrNull";
|
||||
import type { GetBookingType } from "@lib/getBooking";
|
||||
@@ -13,6 +14,8 @@ import type { inferSSRProps } from "@lib/types/inferSSRProps";
|
||||
|
||||
import BookingPage from "@components/booking/pages/BookingPage";
|
||||
|
||||
import { ssrInit } from "@server/lib/ssr";
|
||||
|
||||
export type TeamBookingPageProps = inferSSRProps<typeof getServerSideProps>;
|
||||
|
||||
export default function TeamBookingPage(props: TeamBookingPageProps) {
|
||||
@@ -22,6 +25,7 @@ export default function TeamBookingPage(props: TeamBookingPageProps) {
|
||||
TeamBookingPage.isThemeSupported = true;
|
||||
|
||||
export async function getServerSideProps(context: GetServerSidePropsContext) {
|
||||
const ssr = await ssrInit(context);
|
||||
const eventTypeId = parseInt(asStringOrThrow(context.query.type));
|
||||
const recurringEventCountQuery = asStringOrNull(context.query.count);
|
||||
if (typeof eventTypeId !== "number" || eventTypeId % 1 !== 0) {
|
||||
@@ -55,6 +59,7 @@ export async function getServerSideProps(context: GetServerSidePropsContext) {
|
||||
metadata: true,
|
||||
seatsPerTimeSlot: true,
|
||||
schedulingType: true,
|
||||
bookingFields: true,
|
||||
workflows: {
|
||||
include: {
|
||||
workflow: {
|
||||
@@ -92,12 +97,13 @@ export async function getServerSideProps(context: GetServerSidePropsContext) {
|
||||
//TODO: Use zodSchema to verify it instead of using Type Assertion
|
||||
locations: privacyFilteredLocations((eventTypeRaw.locations || []) as LocationObject[]),
|
||||
recurringEvent: parseRecurringEvent(eventTypeRaw.recurringEvent),
|
||||
bookingFields: eventTypeBookingFields.parse(eventTypeRaw.bookingFields || []),
|
||||
};
|
||||
|
||||
const eventTypeObject = [eventType].map((e) => {
|
||||
return {
|
||||
...e,
|
||||
metadata: EventTypeMetaDataSchema.parse(eventType.metadata || {}),
|
||||
metadata: EventTypeMetaDataSchema.parse(e.metadata || {}),
|
||||
bookingFields: getBookingFieldsWithSystemFields(eventType),
|
||||
periodStartDate: e.periodStartDate?.toString() ?? null,
|
||||
periodEndDate: e.periodEndDate?.toString() ?? null,
|
||||
customInputs: customInputSchema.array().parse(e.customInputs || []),
|
||||
@@ -114,7 +120,7 @@ export async function getServerSideProps(context: GetServerSidePropsContext) {
|
||||
|
||||
let booking: GetBookingType | null = null;
|
||||
if (context.query.rescheduleUid) {
|
||||
booking = await getBooking(prisma, context.query.rescheduleUid as string);
|
||||
booking = await getBooking(prisma, context.query.rescheduleUid as string, eventTypeObject.bookingFields);
|
||||
}
|
||||
|
||||
// Checking if number of recurring event ocurrances is valid against event type configuration
|
||||
@@ -128,6 +134,7 @@ export async function getServerSideProps(context: GetServerSidePropsContext) {
|
||||
|
||||
return {
|
||||
props: {
|
||||
trpcState: ssr.dehydrate(),
|
||||
profile: {
|
||||
...eventTypeObject.team,
|
||||
// FIXME: This slug is used as username on success page which is wrong. This is correctly set as username for user booking.
|
||||
|
||||
@@ -4,6 +4,8 @@ import { test } from "./lib/fixtures";
|
||||
|
||||
test.describe.configure({ mode: "parallel" });
|
||||
|
||||
test.afterEach(({ users }) => users.deleteAll());
|
||||
|
||||
test.describe("App Store - Authed", () => {
|
||||
test("Browse apple-calendar and try to install", async ({ page, users }) => {
|
||||
const pro = await users.create();
|
||||
@@ -12,7 +14,6 @@ test.describe("App Store - Authed", () => {
|
||||
await page.click('[data-testid="app-store-app-card-apple-calendar"]');
|
||||
await page.click('[data-testid="install-app-button"]');
|
||||
await expect(page.locator(`text=Connect to Apple Server`)).toBeVisible();
|
||||
await pro.delete();
|
||||
});
|
||||
|
||||
test("Installed Apps - Navigation", async ({ page, users }) => {
|
||||
|
||||
@@ -2,6 +2,8 @@ import { expect } from "@playwright/test";
|
||||
|
||||
import { test } from "../lib/fixtures";
|
||||
|
||||
test.afterEach(({ users }) => users.deleteAll());
|
||||
|
||||
test("Can delete user account", async ({ page, users }) => {
|
||||
const user = await users.create({
|
||||
username: "delete-me",
|
||||
|
||||
@@ -2,6 +2,8 @@ import { expect } from "@playwright/test";
|
||||
|
||||
import { test } from "../lib/fixtures";
|
||||
|
||||
test.afterEach(({ users }) => users.deleteAll());
|
||||
|
||||
test("Can reset forgotten password", async ({ page, users }) => {
|
||||
test.skip(process.env.NEXT_PUBLIC_IS_E2E !== "1", "It shouldn't if we can't skip email");
|
||||
const user = await users.create();
|
||||
@@ -47,6 +49,4 @@ test("Can reset forgotten password", async ({ page, users }) => {
|
||||
await page.waitForSelector("[data-testid=dashboard-shell]");
|
||||
|
||||
await expect(page.locator("[data-testid=dashboard-shell]")).toBeVisible();
|
||||
|
||||
await users.deleteAll();
|
||||
});
|
||||
|
||||
@@ -10,15 +10,13 @@ import {
|
||||
} from "./lib/testUtils";
|
||||
|
||||
test.describe.configure({ mode: "parallel" });
|
||||
test.afterEach(async ({ users }) => users.deleteAll());
|
||||
|
||||
test.describe("free user", () => {
|
||||
test.beforeEach(async ({ page, users }) => {
|
||||
const free = await users.create();
|
||||
await page.goto(`/${free.username}`);
|
||||
});
|
||||
test.afterEach(async ({ users }) => {
|
||||
await users.deleteAll();
|
||||
});
|
||||
|
||||
test("cannot book same slot multiple times", async ({ page }) => {
|
||||
// Click first event type
|
||||
@@ -58,9 +56,6 @@ test.describe("pro user", () => {
|
||||
const pro = await users.create();
|
||||
await page.goto(`/${pro.username}`);
|
||||
});
|
||||
test.afterEach(async ({ users }) => {
|
||||
await users.deleteAll();
|
||||
});
|
||||
|
||||
test("pro user's page has at least 2 visible events", async ({ page }) => {
|
||||
// await page.pause();
|
||||
|
||||
@@ -24,6 +24,6 @@ test.describe("Change Password Test", () => {
|
||||
|
||||
const toast = await page.waitForSelector("div[class*='data-testid-toast-success']");
|
||||
|
||||
await expect(toast).toBeTruthy();
|
||||
expect(toast).toBeTruthy();
|
||||
});
|
||||
});
|
||||
|
||||
@@ -7,9 +7,14 @@ import {
|
||||
selectSecondAvailableTimeSlotNextMonth,
|
||||
} from "./lib/testUtils";
|
||||
|
||||
test("dynamic booking", async ({ page, users }) => {
|
||||
test.afterEach(({ users }) => users.deleteAll());
|
||||
|
||||
// Due to some reason for Dynamic booking cancellation, daily video api_key is not set which causes cancellation to fail.
|
||||
// This test is skipped until the issue is resolved in GH actions.
|
||||
test.skip("dynamic booking", async ({ page, users }) => {
|
||||
const pro = await users.create();
|
||||
await pro.login();
|
||||
|
||||
const free = await users.create({ username: "free" });
|
||||
await page.goto(`/${pro.username}+${free.username}`);
|
||||
|
||||
@@ -55,8 +60,6 @@ test("dynamic booking", async ({ page, users }) => {
|
||||
|
||||
const cancelledHeadline = await page.locator('[data-testid="cancelled-headline"]').innerText();
|
||||
|
||||
await expect(cancelledHeadline).toBe("This event is cancelled");
|
||||
expect(cancelledHeadline).toBe("This event is cancelled");
|
||||
});
|
||||
|
||||
await users.deleteAll();
|
||||
});
|
||||
|
||||
@@ -88,6 +88,8 @@ async function expectToContainValidPreviewIframe(
|
||||
|
||||
test.describe.configure({ mode: "parallel" });
|
||||
|
||||
test.afterEach(({ users }) => users.deleteAll());
|
||||
|
||||
test.describe("Embed Code Generator Tests", () => {
|
||||
test.beforeEach(async ({ users }) => {
|
||||
const pro = await users.create();
|
||||
|
||||
@@ -139,6 +139,8 @@ test.describe("Event Types tests", () => {
|
||||
const fillLocation = async (inputText: string) => {
|
||||
await page.locator("#location-select").click();
|
||||
await page.locator("text=In Person (Organizer Address)").click();
|
||||
// eslint-disable-next-line playwright/no-wait-for-timeout
|
||||
await page.waitForTimeout(250);
|
||||
await page.locator('input[name="locationAddress"]').fill(inputText);
|
||||
await page.locator("[data-testid=display-location]").check();
|
||||
await page.locator("[data-testid=update-location]").click();
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import type { Page, WorkerInfo } from "@playwright/test";
|
||||
import type Prisma from "@prisma/client";
|
||||
import { MembershipRole, Prisma as PrismaType } from "@prisma/client";
|
||||
import { hash } from "bcryptjs";
|
||||
import { hashSync as hash } from "bcryptjs";
|
||||
|
||||
import dayjs from "@calcom/dayjs";
|
||||
import { DEFAULT_SCHEDULE, getAvailabilityFromSchedule } from "@calcom/lib/availability";
|
||||
@@ -10,8 +10,8 @@ import { prisma } from "@calcom/prisma";
|
||||
import type { TimeZoneEnum } from "./types";
|
||||
|
||||
// Don't import hashPassword from app as that ends up importing next-auth and initializing it before NEXTAUTH_URL can be updated during tests.
|
||||
export async function hashPassword(password: string) {
|
||||
const hashedPassword = await hash(password, 12);
|
||||
export function hashPassword(password: string) {
|
||||
const hashedPassword = hash(password, 12);
|
||||
return hashedPassword;
|
||||
}
|
||||
|
||||
@@ -74,11 +74,33 @@ export const createUsersFixture = (page: Page, workerInfo: WorkerInfo) => {
|
||||
});
|
||||
await prisma.eventType.create({
|
||||
data: {
|
||||
owner: {
|
||||
connect: {
|
||||
id: _user.id,
|
||||
},
|
||||
},
|
||||
users: {
|
||||
connect: {
|
||||
id: _user.id,
|
||||
},
|
||||
},
|
||||
title: "30 min",
|
||||
slug: "30-min",
|
||||
length: 30,
|
||||
},
|
||||
});
|
||||
await prisma.eventType.create({
|
||||
data: {
|
||||
users: {
|
||||
connect: {
|
||||
id: _user.id,
|
||||
},
|
||||
},
|
||||
owner: {
|
||||
connect: {
|
||||
id: _user.id,
|
||||
},
|
||||
},
|
||||
title: "Paid",
|
||||
slug: "paid",
|
||||
length: 30,
|
||||
@@ -92,6 +114,11 @@ export const createUsersFixture = (page: Page, workerInfo: WorkerInfo) => {
|
||||
id: _user.id,
|
||||
},
|
||||
},
|
||||
owner: {
|
||||
connect: {
|
||||
id: _user.id,
|
||||
},
|
||||
},
|
||||
title: "Opt in",
|
||||
slug: "opt-in",
|
||||
requiresConfirmation: true,
|
||||
@@ -270,17 +297,14 @@ type CustomUserOptsKeys = "username" | "password" | "completedOnboarding" | "loc
|
||||
type CustomUserOpts = Partial<Pick<Prisma.User, CustomUserOptsKeys>> & { timeZone?: TimeZoneEnum };
|
||||
|
||||
// creates the actual user in the db.
|
||||
const createUser = async (
|
||||
workerInfo: WorkerInfo,
|
||||
opts?: CustomUserOpts | null
|
||||
): Promise<PrismaType.UserCreateInput> => {
|
||||
const createUser = (workerInfo: WorkerInfo, opts?: CustomUserOpts | null): PrismaType.UserCreateInput => {
|
||||
// build a unique name for our user
|
||||
const uname = `${opts?.username || "user"}-${workerInfo.workerIndex}-${Date.now()}`;
|
||||
return {
|
||||
username: uname,
|
||||
name: opts?.name,
|
||||
email: `${uname}@example.com`,
|
||||
password: await hashPassword(uname),
|
||||
password: hashPassword(uname),
|
||||
emailVerified: new Date(),
|
||||
completedOnboarding: opts?.completedOnboarding ?? true,
|
||||
timeZone: opts?.timeZone ?? dayjs.tz.guess(),
|
||||
@@ -298,13 +322,6 @@ const createUser = async (
|
||||
},
|
||||
}
|
||||
: undefined,
|
||||
eventTypes: {
|
||||
create: {
|
||||
title: "30 min",
|
||||
slug: "30-min",
|
||||
length: 30,
|
||||
},
|
||||
},
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
@@ -4,6 +4,7 @@ import { test } from "./lib/fixtures";
|
||||
import { selectFirstAvailableTimeSlotNextMonth, todo } from "./lib/testUtils";
|
||||
|
||||
test.describe.configure({ mode: "parallel" });
|
||||
test.afterEach(({ users }) => users.deleteAll());
|
||||
|
||||
const IS_STRIPE_ENABLED = !!(
|
||||
process.env.STRIPE_CLIENT_ID &&
|
||||
@@ -32,9 +33,6 @@ test.describe("Stripe integration", () => {
|
||||
await expect(
|
||||
page.locator(`li:has-text("Stripe") >> [data-testid="stripe_payment-integration-disconnect-button"]`)
|
||||
).toContainText("");
|
||||
|
||||
// Cleanup
|
||||
await users.deleteAll();
|
||||
});
|
||||
});
|
||||
|
||||
@@ -70,9 +68,6 @@ test.describe("Stripe integration", () => {
|
||||
|
||||
// Make sure we're navigated to the success page
|
||||
await expect(page.locator("[data-testid=success-page]")).toBeVisible();
|
||||
|
||||
// Cleanup
|
||||
await users.deleteAll();
|
||||
});
|
||||
|
||||
todo("Pending payment booking should not be confirmed by default");
|
||||
|
||||
@@ -159,6 +159,7 @@ test.afterEach(() => requestInterceptor.resetHandlers());
|
||||
|
||||
// Disable API mocking after the tests are done.
|
||||
test.afterAll(() => requestInterceptor.close());
|
||||
test.afterEach(({ users }) => users.deleteAll());
|
||||
|
||||
// TODO: Fix MSW mocking
|
||||
test.fixme("Integrations", () => {
|
||||
@@ -210,17 +211,6 @@ test.fixme("Integrations", () => {
|
||||
});
|
||||
};
|
||||
test.describe("Zoom App", () => {
|
||||
test.afterEach(async () => {
|
||||
await prisma?.credential.deleteMany({
|
||||
where: {
|
||||
user: {
|
||||
email: "pro@example.com",
|
||||
},
|
||||
type: "zoom_video",
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
test("Can add integration", async ({ page, users }) => {
|
||||
const user = await users.create();
|
||||
await user.login();
|
||||
|
||||
@@ -1 +1 @@
|
||||
{"triggerEvent":"BOOKING_CREATED","createdAt":"[redacted/dynamic]","payload":{"type":"30 min","title":"30 min between PRO and Test Testson","description":"","additionalNotes":"","customInputs":{},"startTime":"[redacted/dynamic]","endTime":"[redacted/dynamic]","organizer":{"name":"PRO","email":"[redacted/dynamic]","timeZone":"[redacted/dynamic]","language":"[redacted/dynamic]"},"attendees":[{"email":"test@example.com","name":"Test Testson","timeZone":"[redacted/dynamic]","language":"[redacted/dynamic]"}],"location":"[redacted/dynamic]","destinationCalendar":null,"hideCalendarNotes":false,"requiresConfirmation":"[redacted/dynamic]","eventTypeId":"[redacted/dynamic]","seatsShowAttendees":false,"uid":"[redacted/dynamic]","bookingId":"[redacted/dynamic]","metadata":{},"additionalInformation":"[redacted/dynamic]"}}
|
||||
{"triggerEvent":"BOOKING_CREATED","createdAt":"[redacted/dynamic]","payload":{"type":"30 min","title":"30 min between PRO and Test Testson","description":"","additionalNotes":"","customInputs":{},"startTime":"[redacted/dynamic]","endTime":"[redacted/dynamic]","organizer":{"name":"PRO","email":"[redacted/dynamic]","timeZone":"[redacted/dynamic]","language":"[redacted/dynamic]"},"attendees":[{"email":"test@example.com","name":"Test Testson","timeZone":"[redacted/dynamic]","language":"[redacted/dynamic]"}],"location":"[redacted/dynamic]","destinationCalendar":null,"hideCalendarNotes":false,"requiresConfirmation":"[redacted/dynamic]","eventTypeId":"[redacted/dynamic]","seatsShowAttendees":true,"uid":"[redacted/dynamic]","videoCallData":"[redacted/dynamic]","appsStatus":"[redacted/dynamic]","bookingId":"[redacted/dynamic]","metadata":{},"additionalInformation":"[redacted/dynamic]"}}
|
||||
|
||||
@@ -1,9 +1,11 @@
|
||||
import type { Page } from "@playwright/test";
|
||||
import { expect, test } from "@playwright/test";
|
||||
import { expect } from "@playwright/test";
|
||||
import type { IncomingMessage, ServerResponse } from "http";
|
||||
import { createServer } from "http";
|
||||
import noop from "lodash/noop";
|
||||
|
||||
import { test } from "./fixtures";
|
||||
|
||||
export function todo(title: string) {
|
||||
// eslint-disable-next-line playwright/no-skipped-test
|
||||
test.skip(title, noop);
|
||||
|
||||
@@ -5,6 +5,8 @@ import { test } from "./lib/fixtures";
|
||||
|
||||
test.describe.configure({ mode: "serial" });
|
||||
|
||||
test.afterEach(({ users }) => users.deleteAll());
|
||||
|
||||
test.describe("Onboarding", () => {
|
||||
test.describe("Onboarding v2", () => {
|
||||
test("Onboarding Flow", async ({ page, users }) => {
|
||||
|
||||
@@ -14,10 +14,9 @@ const IS_STRIPE_ENABLED = !!(
|
||||
|
||||
test.describe.configure({ mode: "parallel" });
|
||||
|
||||
test.afterEach(({ users }) => users.deleteAll());
|
||||
|
||||
test.describe("Reschedule Tests", async () => {
|
||||
test.afterEach(async ({ users }) => {
|
||||
await users.deleteAll();
|
||||
});
|
||||
test("Should do a booking request reschedule from /bookings", async ({ page, users, bookings }) => {
|
||||
const user = await users.create();
|
||||
|
||||
|
||||
@@ -1,14 +1,14 @@
|
||||
import { expect } from "@playwright/test";
|
||||
|
||||
import { prisma } from "@calcom/prisma";
|
||||
|
||||
import { test } from "./lib/fixtures";
|
||||
|
||||
test.describe.configure({ mode: "parallel" });
|
||||
|
||||
test.describe("Teams", () => {
|
||||
test.afterEach(async ({ users }) => {
|
||||
await users.deleteAll();
|
||||
});
|
||||
test.afterEach(({ users }) => users.deleteAll());
|
||||
|
||||
test.describe("Teams", () => {
|
||||
test("Can create teams via Wizard", async ({ page, users }) => {
|
||||
const user = await users.create();
|
||||
const inviteeEmail = `${user.username}+invitee@example.com`;
|
||||
@@ -44,6 +44,8 @@ test.describe("Teams", () => {
|
||||
await removeMemberButton.click();
|
||||
await removeMemberButton.waitFor({ state: "hidden" });
|
||||
expect(await page.locator('[data-testid="pending-member-item"]').count()).toBe(1);
|
||||
// Cleanup here since this user is created without our fixtures.
|
||||
await prisma.user.delete({ where: { email: inviteeEmail } });
|
||||
});
|
||||
|
||||
await test.step("Can publish team", async () => {
|
||||
|
||||
@@ -3,6 +3,8 @@ import { expect } from "@playwright/test";
|
||||
import { test } from "./lib/fixtures";
|
||||
import { createHttpServer, selectFirstAvailableTimeSlotNextMonth, waitFor } from "./lib/testUtils";
|
||||
|
||||
test.afterEach(({ users }) => users.deleteAll());
|
||||
|
||||
test("add webhook & test that creating an event triggers a webhook call", async ({
|
||||
page,
|
||||
users,
|
||||
@@ -70,11 +72,53 @@ test("add webhook & test that creating an event triggers a webhook call", async
|
||||
body.payload.appsStatus = dynamic;
|
||||
body.payload.metadata.videoCallUrl = dynamic;
|
||||
|
||||
// if we change the shape of our webhooks, we can simply update this by clicking `u`
|
||||
// console.log("BODY", body);
|
||||
// Text files shouldn't have platform specific suffixes
|
||||
testInfo.snapshotSuffix = "";
|
||||
expect(JSON.stringify(body)).toMatchSnapshot(`webhookResponse.txt`);
|
||||
expect(body).toMatchObject({
|
||||
triggerEvent: "BOOKING_CREATED",
|
||||
createdAt: "[redacted/dynamic]",
|
||||
payload: {
|
||||
type: "30 min",
|
||||
title: "30 min between Nameless and Test Testson",
|
||||
description: "",
|
||||
additionalNotes: "",
|
||||
customInputs: {},
|
||||
startTime: "[redacted/dynamic]",
|
||||
endTime: "[redacted/dynamic]",
|
||||
organizer: {
|
||||
id: "[redacted/dynamic]",
|
||||
name: "Nameless",
|
||||
email: "[redacted/dynamic]",
|
||||
timeZone: "[redacted/dynamic]",
|
||||
language: "[redacted/dynamic]",
|
||||
},
|
||||
responses: { email: "test@example.com", name: "Test Testson" },
|
||||
userFieldsResponses: {},
|
||||
attendees: [
|
||||
{
|
||||
email: "test@example.com",
|
||||
name: "Test Testson",
|
||||
timeZone: "[redacted/dynamic]",
|
||||
language: "[redacted/dynamic]",
|
||||
},
|
||||
],
|
||||
location: "[redacted/dynamic]",
|
||||
destinationCalendar: null,
|
||||
hideCalendarNotes: false,
|
||||
requiresConfirmation: "[redacted/dynamic]",
|
||||
eventTypeId: "[redacted/dynamic]",
|
||||
seatsShowAttendees: true,
|
||||
seatsPerTimeSlot: null,
|
||||
uid: "[redacted/dynamic]",
|
||||
eventTitle: "30 min",
|
||||
eventDescription: null,
|
||||
price: 0,
|
||||
currency: "usd",
|
||||
length: 30,
|
||||
bookingId: "[redacted/dynamic]",
|
||||
metadata: { videoCallUrl: "[redacted/dynamic]" },
|
||||
status: "ACCEPTED",
|
||||
additionalInformation: "[redacted/dynamic]",
|
||||
},
|
||||
});
|
||||
|
||||
webhookReceiver.close();
|
||||
});
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
{"triggerEvent":"BOOKING_CREATED","createdAt":"[redacted/dynamic]","payload":{"type":"30 min","title":"30 min between Nameless and Test Testson","description":"","additionalNotes":"","customInputs":{},"startTime":"[redacted/dynamic]","endTime":"[redacted/dynamic]","organizer":{"id":"[redacted/dynamic]","name":"Nameless","email":"[redacted/dynamic]","timeZone":"[redacted/dynamic]","language":"[redacted/dynamic]"},"attendees":[{"email":"test@example.com","name":"Test Testson","timeZone":"[redacted/dynamic]","language":"[redacted/dynamic]"}],"location":"[redacted/dynamic]","destinationCalendar":null,"hideCalendarNotes":false,"requiresConfirmation":"[redacted/dynamic]","eventTypeId":"[redacted/dynamic]","seatsShowAttendees":false,"seatsPerTimeSlot":null,"uid":"[redacted/dynamic]","videoCallData":"[redacted/dynamic]","appsStatus":"[redacted/dynamic]","eventTitle":"30 min","eventDescription":null,"price":0,"currency":"usd","length":30,"bookingId":"[redacted/dynamic]","metadata":{"videoCallUrl":"[redacted/dynamic]"},"status":"ACCEPTED","additionalInformation":"[redacted/dynamic]"}}
|
||||
@@ -7,6 +7,8 @@ import { test } from "./lib/fixtures";
|
||||
|
||||
test.describe.configure({ mode: "parallel" });
|
||||
|
||||
test.afterEach(({ users }) => users.deleteAll());
|
||||
|
||||
test.describe("Wipe my Cal App Test", () => {
|
||||
test("Browse upcoming bookings and validate button shows and triggering wipe my cal button", async ({
|
||||
page,
|
||||
@@ -47,7 +49,5 @@ test.describe("Wipe my Cal App Test", () => {
|
||||
page.locator("data-testid=send_request").click();
|
||||
// There will not be any today-bookings
|
||||
await expect(page.locator('[data-testid="today-bookings"]')).toBeHidden();
|
||||
|
||||
await users.deleteAll();
|
||||
});
|
||||
});
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
"upgrade_now": "تحديث الآن",
|
||||
"accept_invitation": "اقبل الدعوة",
|
||||
"calcom_explained": "يوفر {{appName}} بنية أساسية للجدولة للجميع.",
|
||||
"calcom_explained_new_user": "إنهاء إعداد حسابك في {{appName}}! تبقت لك فقط بضع خطوات فقط لحل جميع مشاكل الجدولة لديك.",
|
||||
"have_any_questions": "هل لديك أسئلة؟ نحن هنا للمساعدة.",
|
||||
"reset_password_subject": "{{appName}}: إرشادات إعادة تعيين كلمة المرور",
|
||||
"event_declined_subject": "تم الرفض: {{title}} في {{date}}",
|
||||
@@ -23,6 +24,8 @@
|
||||
"rejection_reason_description": "هل أنت متأكد من رغبتك في رفض الحجز؟ سنقوم بإبلاغ الشخص الذي حاول الحجز. يمكنك تقديم سبب أدناه.",
|
||||
"rejection_confirmation": "رفض الحجز",
|
||||
"manage_this_event": "قم بإدارة هذا الحدث",
|
||||
"invite_team_member": "دعوة عضو في الفريق",
|
||||
"invite_team_notifcation_badge": "استثمر.",
|
||||
"your_event_has_been_scheduled": "تم جدولة الحدث الخاص بك",
|
||||
"your_event_has_been_scheduled_recurring": "تم جدولة الحدث المتكرر الخاص بك",
|
||||
"accept_our_license": "اقبل ترخيصنا من خلال تغيير متغير .env المسمى <1>NEXT_PUBLIC_LICENSE_CONSENT</1> إلى '{{agree}}'.",
|
||||
@@ -410,6 +413,8 @@
|
||||
"password_updated_successfully": "تم تحديث كلمة المرور بنجاح",
|
||||
"password_has_been_changed": "تم تغيير كلمة المرور بنجاح.",
|
||||
"error_changing_password": "خطأ في تغيير كلمة المرور",
|
||||
"session_timeout_changed": "تم تحديث ملفك الشخصي بنجاح.",
|
||||
"session_timeout_change_error": "خطأ في تحديث تكوين الجلسة",
|
||||
"something_went_wrong": "حدث خطأ ما.",
|
||||
"something_doesnt_look_right": "هل يوجد شيء ما لا يبدو صحيحًا؟",
|
||||
"please_try_again": "يُرجى المحاولة مجددًا.",
|
||||
@@ -428,6 +433,7 @@
|
||||
"password_hint_num": "يحتوي على رقم واحد على الأقل",
|
||||
"invalid_password_hint": "يجب أن تتألف كلمة المرور على الأقل من {{passwordLength}} أحرف، ورقم واحد على الأقل، ومزيج من الحروف الكبيرة والصغيرة",
|
||||
"incorrect_password": "كلمة المرور غير صحيحة.",
|
||||
"incorrect_username_password": "اسم المستخدم أو كلمة المرور غير صحيحة.",
|
||||
"24_h": "24 ساعة",
|
||||
"use_setting": "استخدام الإعداد",
|
||||
"am_pm": "صباحًا/مساءً",
|
||||
@@ -455,6 +461,7 @@
|
||||
"slots_load_fail": "تعذر تحميل الفترات الزمنية المتاحة.",
|
||||
"additional_guests": "إضافة ضيوف",
|
||||
"your_name": "اسمك",
|
||||
"your_full_name": "اسمك الكامل",
|
||||
"email_address": "عنوان البريد الإلكتروني",
|
||||
"enter_valid_email": "يرجى إدخال بريد إلكتروني صالح",
|
||||
"location": "الموقع",
|
||||
@@ -508,6 +515,8 @@
|
||||
"admin": "المشرف",
|
||||
"administrator_user": "المستخدم المسؤول",
|
||||
"lets_create_first_administrator_user": "لنقم بإنشاء المستخدم المسؤول الأول.",
|
||||
"admin_user_created": "إعداد المستخدم المسؤول",
|
||||
"admin_user_created_description": "لقد أنشأت بالفعل مستخدم مسؤول. يمكنك الآن تسجيل الدخول إلى حسابك.",
|
||||
"new_member": "العضو الجديد",
|
||||
"invite": "دعوة",
|
||||
"add_team_members": "إضافة أعضاء الفريق",
|
||||
@@ -589,7 +598,6 @@
|
||||
"new_event_type_heading": "إنشاء نوع الحدث الأول لديك",
|
||||
"new_event_type_description": "تتيح لك أنواع الأحداث مشاركة الروابط التي تعرض الأوقات المتاحة في تقويمك وتسمح للأشخاص بالحجز معك.",
|
||||
"new_event_title": "إضافة نوع حدث جديد",
|
||||
"new_event_subtitle": "قم بإنشاء نوع حدث يندرج تحت اسمك أو أحد الفرق.",
|
||||
"new_team_event": "إضافة نوع حدث جديد لفريق",
|
||||
"new_event_description": "قم بإنشاء نوع حدث جديد ليحجز الأشخاص من خلاله.",
|
||||
"event_type_created_successfully": "تم إنشاء نوع الحدث {{eventTypeTitle}} بنجاح",
|
||||
@@ -658,6 +666,7 @@
|
||||
"edit_availability": "تعديل الإتاحة",
|
||||
"configure_availability": "اضبط الأوقات التي تكون متاحًا فيها للحجز.",
|
||||
"copy_times_to": "نسخ الأوقات إلى",
|
||||
"copy_times_to_tooltip": "نسخ الأوقات إلى…",
|
||||
"change_weekly_schedule": "تغيير جدولك الأسبوعي",
|
||||
"logo": "الشعار",
|
||||
"error": "خطأ",
|
||||
@@ -669,6 +678,7 @@
|
||||
"add_attendees": "إضافة الحضور",
|
||||
"show_advanced_settings": "عرض الإعدادات المتقدمة",
|
||||
"event_name": "اسم الحدث",
|
||||
"event_name_in_calendar": "اسم الحدث في الرزنامة",
|
||||
"event_name_tooltip": "الاسم الذي سيظهر في التقاويم",
|
||||
"meeting_with_user": "الاجتماع مع {{attendeeName}}",
|
||||
"additional_inputs": "مدخلات إضافية",
|
||||
@@ -787,6 +797,7 @@
|
||||
"number_apps_one": "{{count}} تطبيق",
|
||||
"number_apps_other": "{{count}} من التطبيقات",
|
||||
"trending_apps": "التطبيقات الرائجة",
|
||||
"most_popular": "الأكثر شعبية",
|
||||
"explore_apps": "تطبيقات {{category}}",
|
||||
"installed_apps": "التطبيقات المثبتة",
|
||||
"free_to_use_apps": "متاح",
|
||||
@@ -797,12 +808,14 @@
|
||||
"no_category_apps_description_analytics": "إضافة تطبيق تحليلات لصفحات الحجز الخاصة بك",
|
||||
"no_category_apps_description_automation": "إضافة تطبيق أتمتة لاستخدامه",
|
||||
"no_category_apps_description_other": "أضف أي نوع آخر من التطبيقات للقيام بأي شيء",
|
||||
"no_category_apps_description_web3": "إضافة تطبيق web3 لصفحات الحجز لديك",
|
||||
"installed_app_calendar_description": "قم بتعيين التقويمات للتحقق من وجود تعارضات لمنع الحجوزات المزدوجة.",
|
||||
"installed_app_conferencing_description": "أضف تطبيقات مؤتمرات الفيديو المفضلة لديك لاجتماعاتك",
|
||||
"installed_app_payment_description": "قم بإعداد أي خدمات معالجة دفع تود استخدامها عند التحصيل من العملاء.",
|
||||
"installed_app_analytics_description": "تهيئة أي تطبيقات تستخدم لصفحات الحجز الخاصة بك",
|
||||
"installed_app_other_description": "جميع تطبيقاتك المثبتة من الفئات الأخرى.",
|
||||
"installed_app_automation_description": "تهيئة تطبيقات الأتمتة التي سيتم استخدامها",
|
||||
"installed_app_web3_description": "تهيئة تطبيقات web3 التي يمكن استخدامها لصفحات الحجز لديك",
|
||||
"analytics": "التحليلات",
|
||||
"empty_installed_apps_headline": "لم يتم تثبيت أي تطبيق",
|
||||
"empty_installed_apps_description": "تعطيك التطبيقات القدرة على تعزيز سير عملك وتحسين الجدولة في حياتك بشدة.",
|
||||
@@ -930,6 +943,11 @@
|
||||
"current_location": "الموقع الحالي",
|
||||
"user_phone": "رقم هاتفك",
|
||||
"new_location": "الموقع الجديد",
|
||||
"session": "الجلسة",
|
||||
"session_description": "التحكم في جلسة حسابك",
|
||||
"session_timeout_after": "مهلة الجلسة بعد",
|
||||
"session_timeout": "مهلة الجلسة",
|
||||
"session_timeout_description": "أبطل جلسة عملك بعد مدة معينة من الوقت.",
|
||||
"no_location": "لم يتم تحديد موقع",
|
||||
"set_location": "تعيين الموقع",
|
||||
"update_location": "تحديث الموقع",
|
||||
@@ -1073,6 +1091,7 @@
|
||||
"broken_video_action": "لم نتمكن من إضافة رابط <1>{{location}}</1> الاجتماع إلى الحدث المجدول. يرجى الاتصال بالمدعوين أو تحديث حدث التقويم الخاص بك لإضافة التفاصيل. يمكنك إما <3> تغيير موقعك في نوع الحدث </3> أو محاولة <5>إزالة التطبيق وتثبيته مرة أخرى.</5>",
|
||||
"broken_calendar_action": "لم نتمكن من تحديث <1>{{calendar}}</1>. <2> يرجى التحقق من إعدادات التقويم أو إزالة التقويم وإضافته مرة أخرى</2>",
|
||||
"attendee_name": "اسم الحاضر",
|
||||
"scheduler_full_name": "الاسم الكامل للشخص الذي يحجز",
|
||||
"broken_integration": "تكامل تالف",
|
||||
"problem_adding_video_link": "حدثت مشكلة أثناء إضافة رابط فيديو",
|
||||
"problem_updating_calendar": "حدثت مشكلة أثناء تحديث التقويم الخاص بك",
|
||||
@@ -1215,6 +1234,7 @@
|
||||
"connect_automation_apps": "توصيل تطبيقات الأتمتة",
|
||||
"connect_analytics_apps": "توصيل تطبيقات التحليلات",
|
||||
"connect_other_apps": "ربط تطبيقات أخرى",
|
||||
"connect_web3_apps": "ربط تطبيقات web3",
|
||||
"current_step_of_total": "الخطوة {{currentStep}} من {{maxSteps}}",
|
||||
"add_variable": "إضافة متغير",
|
||||
"custom_phone_number": "رقم هاتف مخصص",
|
||||
@@ -1231,6 +1251,7 @@
|
||||
"to": "إلى",
|
||||
"workflow_turned_on_successfully": "تم تشغيل {{offOn}} سير العمل {{workflowName}} بنجاح",
|
||||
"download_responses": "تنزيل الردود",
|
||||
"download_responses_description": "تحميل جميع الردود على نموذجك بتنسيق CSV.",
|
||||
"download": "التنزيل",
|
||||
"create_your_first_form": "إنشاء أول استمارة",
|
||||
"create_your_first_form_description": "باستخدام نماذج المسارات، يمكنك طرح أسئلة التأهيل والتوجيه إلى الشخص/نوع الحدث المناسب.",
|
||||
@@ -1272,6 +1293,8 @@
|
||||
"routing_forms_send_email_owner": "إرسال رسالة إلكترونية إلى المالك",
|
||||
"routing_forms_send_email_owner_description": "يرسل رسالة بريد إلكتروني إلى المالك عند إرسال النموذج",
|
||||
"add_new_form": "إضافة استمارة جديدة",
|
||||
"create_your_first_route": "إنشاء مسارك الأول",
|
||||
"route_to_the_right_person": "التوجه إلى الشخص المناسب بناء على الإجابات على النموذج لديك",
|
||||
"form_description": "قم بإنشاء النموذج الخاص بك لتوجيه صاحب حجز",
|
||||
"copy_link_to_form": "نسخ الرابط إلى النموذج",
|
||||
"theme": "السمة",
|
||||
@@ -1302,6 +1325,7 @@
|
||||
"password_reset_leading": "إذا لم تستلم رسالة بريد إلكتروني قريبًا، تحقق من أن عنوان البريد الإلكتروني الذي أدخلته صحيح، وتحقق من مجلد البريد المزعج أو اتصل بالدعم إذا استمرت المشكلة.",
|
||||
"password_updated": "تم تحديث كلمة المرور!",
|
||||
"pending_payment": "في انتظار الدفع",
|
||||
"pending_invites": "دعوات معلقة",
|
||||
"confirmation_page_rainbow": "قم بتعيين رمز مميز لفتح الحدث الخاص بك باستخدام الرموز أو NFTs على Ethereum وPolygon وغيرها.",
|
||||
"not_on_cal": "غير موجود على {{appName}}",
|
||||
"no_calendar_installed": "لا يوجد تقويم مثبت",
|
||||
@@ -1428,6 +1452,9 @@
|
||||
"disabled_calendar": "إذا كان لديك تقويم آخر مثبت، ستُضاف الحجوزات الجديدة إليه. إذا لم يكن الأمر كذلك، قم بتوصيل تقويم جديد حتى لا تفوت أي حجوزات جديدة.",
|
||||
"enable_apps": "تمكين التطبيقات",
|
||||
"enable_apps_description": "تمكين التطبيقات التي يمكن للمستخدمين دمجها مع Cal.com",
|
||||
"purchase_license": "شراء ترخيص",
|
||||
"already_have_key": "لدي بالفعل مفتاح:",
|
||||
"already_have_key_suggestion": "يرجى نسخ متغير البيئة الحالي CALCOM_LICENSE_KEY هنا.",
|
||||
"app_is_enabled": "تم تمكين {{appName}}",
|
||||
"app_is_disabled": "تم تعطيل {{appName}}",
|
||||
"keys_have_been_saved": "تم حفظ المفاتيح",
|
||||
@@ -1448,6 +1475,7 @@
|
||||
"individual": "فردي",
|
||||
"all_bookings_filter_label": "جميع الحجوزات",
|
||||
"all_users_filter_label": "جميع المستخدمين",
|
||||
"your_bookings_filter_label": "الحجوزات لديك",
|
||||
"meeting_url_variable": "رابط الاجتماع",
|
||||
"meeting_url_info": "رابط فعالية اجتماع المؤتمر",
|
||||
"date_overrides": "تجاوز التاريخ",
|
||||
@@ -1486,6 +1514,7 @@
|
||||
"round_robin_hosts": "مضيفون بنظام دوار",
|
||||
"minimum_round_robin_hosts_count": "عدد المضيفين المطلوب حضورهم",
|
||||
"hosts": "المضيفون",
|
||||
"upgrade_to_enable_feature": "تحتاج إلى إنشاء فريق لتمكين هذه الميزة. انقر لإنشاء فريق.",
|
||||
"new_attendee": "حضور جديد",
|
||||
"awaiting_approval": "في انتظار الموافقة",
|
||||
"requires_google_calendar": "يتطلب هذا التطبيق اتصال تقويم Google",
|
||||
@@ -1494,9 +1523,99 @@
|
||||
"continue_to_install_google_calendar": "متابعة تثبيت تقويم Google",
|
||||
"install_google_meet": "تثبيت Google Meet",
|
||||
"install_google_calendar": "تثبيت تقويم Google",
|
||||
"sender_name": "اسم المرسل",
|
||||
"already_invited": "تمت دعوة هذا الحاضر بالفعل",
|
||||
"no_recordings_found": "لم يتم العثور على تسجيلات",
|
||||
"reporting": "تقديم التقارير",
|
||||
"reporting_feature": "عرض كل ما هو وارد من بيانات وتحميلها بصيغة CSV",
|
||||
"teams_plan_required": "خطة الفرق مطلوبة",
|
||||
"routing_forms_are_a_great_way": "نماذج التوجيه هي طريقة رائعة لتوجيه الوارد إليك إلى الشخص الصحيح. قم بالترقية إلى خطة \"الفرق\" للوصول إلى هذه الميزة.",
|
||||
"choose_a_license": "اختر ترخيص",
|
||||
"choose_license_description": "يأتي Cal.com مع رخصة AGPLv3 متاحة ومجانية والتي يمكن ترقيتها إلى رخصة \"المؤسسة\" في أي وقت. يمكنك الترقية في أي وقت لاحق.",
|
||||
"license": "الترخيص",
|
||||
"agplv3_license": "ترخيص AGPLv3",
|
||||
"ee_enterprise_license": "رخصة المؤسسة \"/ee\"",
|
||||
"enterprise_booking_fee": "يبدأ في {{enterprise_booking_fee}}/ الشهر",
|
||||
"enterprise_license_includes": "كل شيء لأغراض الاستخدام التجاري",
|
||||
"no_need_to_keep_your_code_open_source": "لا حاجة للحفاظ على تعليماتك البرمجية مفتوحة المصدر",
|
||||
"repackage_rebrand_resell": "إعادة التعبئة وإعادة الترويج وإعادة البيع بسهولة",
|
||||
"a_vast_suite_of_enterprise_features": "مجموعة كبيرة من سمات المشاريع",
|
||||
"free_license_fee": "$0.00/شهر",
|
||||
"forever_open_and_free": "مفتوح و مجاني إلى الأبد",
|
||||
"required_to_keep_your_code_open_source": "مطلوب للإبقاء على تعليماتك البرمجية مفتوحة المصدر",
|
||||
"cannot_repackage_and_resell": "لا يمكن إعادة التعبئة وإعادة العلامة التجارية وإعادة البيع بسهولة",
|
||||
"no_enterprise_features": "ميزات \"المؤسسة\" غير موجودة",
|
||||
"step_enterprise_license": "ترخيص المؤسسة",
|
||||
"step_enterprise_license_description": "كل شيء موجود ضمن الرخصة التجارية مع الاستضافة الخاصة وإعادة التغليف وإعادة التوسيم وإعادة البيع والوصول إلى مكونات المؤسسة الحصرية.",
|
||||
"setup": "الإعداد",
|
||||
"setup_description": "إعداد مثال Cal.com",
|
||||
"configure": "تهيئة",
|
||||
"sso_configuration": "تسجيل الدخول لمرة واحدة",
|
||||
"sso_configuration_description": "إعداد SAML/OIDC SSO والسماح لأعضاء الفريق بتسجيل الدخول باستخدام \"موفر الهوية\"",
|
||||
"sso_oidc_heading": "SSO مع OIDC",
|
||||
"sso_oidc_description": "تكوين OIDC SSO مع موفر هوية من اختيارك.",
|
||||
"sso_oidc_configuration_title": "تكوين OIDC",
|
||||
"sso_oidc_configuration_description": "قم بتكوين اتصال OIDC مع موفر هويتك الشخصية. يمكنك العثور على المعلومات المطلوبة في موفر هويتك الشخصية.",
|
||||
"sso_oidc_callback_copied": "تم نسخ رابط رد اتصال URL",
|
||||
"sso_saml_heading": "SSO مع SAML",
|
||||
"sso_saml_description": "تكوين SAML SSO مع موفر هوية من اختيارك.",
|
||||
"sso_saml_configuration_title": "تكوين SAML",
|
||||
"sso_saml_configuration_description": "تكوين اتصال SAML مع مزود هويتك الشخصية. يمكنك العثور على المعلومات المطلوبة في مزود هويتك الشخصية.",
|
||||
"sso_saml_acsurl_copied": "تم نسخ رابط ACS",
|
||||
"sso_saml_entityid_copied": "تم نسخ معرف الكيان",
|
||||
"sso_connection_created_successfully": "تم إنشاء تكوين {{connectionType}} بنجاح",
|
||||
"sso_connection_deleted_successfully": "تم حذف تكوين {{connectionType}} بنجاح",
|
||||
"delete_sso_configuration": "حذف اعدادات {{connectionType}}",
|
||||
"delete_sso_configuration_confirmation": "نعم، احذف اعدادات {{connectionType}}",
|
||||
"delete_sso_configuration_confirmation_description": "هل أنت متأكد من أنك تريد حذف تكوين {{connectionType}}؟ لن يكون لأعضاء فريقك الذين يستخدمون {{connectionType}} لتسجيل الدخول القدرة بعد الآن على الوصول إلى Cal.com.",
|
||||
"organizer_timezone": "منظم المناطق الزمنية",
|
||||
"email_no_user_cta": "إنشاء حسابك",
|
||||
"email_user_cta": "عرض الدعوة",
|
||||
"email_no_user_invite_heading": "لقد تمت دعوتك للانضمام إلى فريق في {{appName}}",
|
||||
"email_no_user_invite_subheading": "قام {{invitedBy}} بدعوتك للانضمام إلى فريقهم على {{appName}}. {{appName}} هو أداة لجدولة الأحداث تعطيك أنت وفريقك القدرة على جدولة اجتماعات من دون الحاجة إلى البريد الإلكتروني.",
|
||||
"email_no_user_invite_steps_intro": "سنقطع معك بضع خطوات قصيرة وستستمتع بالجدولة المجانية مع فريقك في أي وقت.",
|
||||
"email_no_user_step_one": "اختر اسم المستخدم الخاص بك",
|
||||
"email_no_user_step_two": "ربط حساب التقويم الخاص بك",
|
||||
"email_no_user_step_three": "تعيين توافرك",
|
||||
"email_no_user_step_four": "انضم إلى {{teamName}}",
|
||||
"email_no_user_signoff": "جدولة سعيدة من فريق {{appName}}",
|
||||
"impersonation_user_tip": "أنت على وشك انتحال شخصية مستخدم، مما يعني أنه يمكنك إجراء تغييرات نيابة عنهم. يرجى توخي الحذر.",
|
||||
"available_variables": "المتغيرات المتوفرة",
|
||||
"scheduler": "{Scheduler}",
|
||||
"recommended_next_steps": "الخطوات التالية الموصى بها",
|
||||
"create_a_managed_event": "إنشاء نوع من الأحداث المُدارة",
|
||||
"meetings_are_better_with_the_right": "الاجتماعات أفضل مع أعضاء الفريق الصحيحين. ادعوهم الآن.",
|
||||
"collective_or_roundrobin": "جماعية أو ذهاب وإياب",
|
||||
"book_your_team_members": "احجز أعضاء فريقك مع الأحداث الجماعية أو الدورة للحصول على الشخص المناسب مع خيار الذهاب والإياب.",
|
||||
"default_app_link_title": "تعيين رابط تطبيق افتراضي",
|
||||
"default_app_link_description": "إعداد رابط التطبيق الافتراضي يسمح لجميع أنواع الأحداث التي تم إنشاؤها حديثا باستخدام رابط التطبيق الذي قمت بتعيينه.",
|
||||
"change_default_conferencing_app": "تعيين كافتراضي",
|
||||
"booking_confirmation_failed": "فشل تأكيد الحجز"
|
||||
"under_maintenance": "معطل للصيانة",
|
||||
"under_maintenance_description": "فريق {{appName}} يقوم بأعمال الصيانة المجدولة. إذا كان لديك أي أسئلة، يرجى الاتصال بالدعم.",
|
||||
"event_type_seats": "{{numberOfSeats}} مقعد",
|
||||
"booking_with_payment_cancelled": "الدفع لهذا الحدث لم يعد ممكناً",
|
||||
"booking_with_payment_cancelled_already_paid": "جاري العمل على استرداد دفعة الحجز هذه.",
|
||||
"booking_with_payment_cancelled_refunded": "تم استرداد هذه الدفعة للحجز.",
|
||||
"booking_confirmation_failed": "فشل تأكيد الحجز",
|
||||
"get_started_zapier_templates": "ابدأ مع قوالب Zapier",
|
||||
"a_routing_form": "نموذج توجيه",
|
||||
"form_description_placeholder": "وصف النموذج",
|
||||
"keep_me_connected_with_form": "ابقني متصلاً بالنموذج",
|
||||
"fields_in_form_duplicated": "سيعكس التكرار أية تغييرات تطرأ على التدوير والحقول المكررة في النموذج.",
|
||||
"form_deleted": "تم حذف النموذج",
|
||||
"delete_form": "حذف النموذج",
|
||||
"delete_form_action": "نعم، احذف النموذج",
|
||||
"delete_form_confirmation": "هل أنت متأكد من أنك تريد حذف هذا النموذج؟ لن يتمكن أي شخص تشارك الرابط معه من الحجز بعد الآن. كما ستحذف جميع الردود المرتبطة بذلك.",
|
||||
"typeform_redirect_url_copied": "تم نسخ عنوان URL في Typeform Redirect! يمكنك الذهاب وتعيين عنوان URL في نموذج Typeform.",
|
||||
"modifications_in_fields_warning": "سيعكس هذا الشكل التعديلات التي ستطرأ على الحقول والطرق التي تسلكها النماذج اللاحقة.",
|
||||
"connected_forms": "النماذج المتصلة",
|
||||
"form_modifications_warning": "ستتأثر النماذج التالية عند تعديل الحقول أو المسارات هنا.",
|
||||
"responses_collection_waiting_description": "انتظر لبعض الوقت لجمع الردود. يمكنك الذهاب وتقديم النموذج بنفسك أيضاً.",
|
||||
"this_is_what_your_users_would_see": "هذا ما سيراه المستخدمون لديك",
|
||||
"identifies_name_field": "تحديد الحقل بهذا الاسم.",
|
||||
"add_1_option_per_line": "إضافة خيار واحد لكل سطر",
|
||||
"select_a_router": "حدد مساراً",
|
||||
"add_a_new_route": "إضافة مسار جديد",
|
||||
"no_responses_yet": "لا توجد ردود بعد",
|
||||
"this_will_be_the_placeholder": "هذا سيكون العنصر النائب"
|
||||
}
|
||||
|
||||
@@ -589,7 +589,6 @@
|
||||
"new_event_type_heading": "Vytvořte svůj první typ události",
|
||||
"new_event_type_description": "Typy událostí vám umožňují sdílet odkazy, které ukazují časy v kalendáři, kdy jste dostupní, a lidí skrz ně mohou rezervovat váš čas.",
|
||||
"new_event_title": "Přidat nový typ události",
|
||||
"new_event_subtitle": "Vytvořit nový typ události pod vaším jménem nebo týmem.",
|
||||
"new_team_event": "Přidat nový typ týmové události",
|
||||
"new_event_description": "Vytvořit nový typ události, ve které si lidé mohou rezervovat časy.",
|
||||
"event_type_created_successfully": "Typ události {{eventTypeTitle}} byl úspěšně vytvořen",
|
||||
|
||||
@@ -166,7 +166,7 @@
|
||||
"optional": "Valgfrit",
|
||||
"input_type": "Input type",
|
||||
"rejected": "Afvist",
|
||||
"unconfirmed": "Ubekræftet",
|
||||
"unconfirmed": "Ubekræftede",
|
||||
"guests": "Gæster",
|
||||
"guest": "Gæst",
|
||||
"web_conferencing_details_to_follow": "Webkonference detaljer følger i bekræftelses-e-mailen.",
|
||||
@@ -189,8 +189,8 @@
|
||||
"check_spelling_mistakes_or_go_back": "Tjek for stavefejl eller gå tilbage til forrige side.",
|
||||
"404_page_not_found": "404: Denne side blev ikke fundet.",
|
||||
"getting_started": "Kom I Gang",
|
||||
"15min_meeting": "15 min Møde",
|
||||
"30min_meeting": "30 min Møde",
|
||||
"15min_meeting": "15 min. Møde",
|
||||
"30min_meeting": "30 min. Møde",
|
||||
"secret": "Hemmeligt",
|
||||
"leave_blank_to_remove_secret": "Lad feltet stå tomt for at fjerne hemmelig",
|
||||
"webhook_secret_key_description": "Sørg for, at din server kun modtager de forventede {{appName}} anmodninger af sikkerhedsmæssige årsager",
|
||||
@@ -437,7 +437,7 @@
|
||||
"24_h": "24h",
|
||||
"use_setting": "Brug indstilling",
|
||||
"am_pm": "am/pm",
|
||||
"time_options": "Tidsindstillinger",
|
||||
"time_options": "Tidsmuligheder",
|
||||
"january": "Januar",
|
||||
"february": "Februar",
|
||||
"march": "Marts",
|
||||
@@ -527,7 +527,7 @@
|
||||
"invite_new_team_member": "Invitér nogen til dit team.",
|
||||
"change_member_role": "Skift teammedlems rolle",
|
||||
"disable_cal_branding": "Deaktivér {{appName}} branding",
|
||||
"disable_cal_branding_description": "Skjul alle {{appName}} branding fra dine offentlige sider.",
|
||||
"disable_cal_branding_description": "Skjul al {{appName}} branding fra dine offentlige sider.",
|
||||
"hide_book_a_team_member": "Skjul Book et Team Medlem-knap",
|
||||
"hide_book_a_team_member_description": "Skjul Book et Team medlem-knap på dine offentlige sider.",
|
||||
"danger_zone": "Farezone",
|
||||
@@ -548,12 +548,12 @@
|
||||
"manage_your_team": "Administrér dit team",
|
||||
"no_teams": "Du har ikke nogen teams endnu.",
|
||||
"no_teams_description": "Teams giver andre mulighed for at booke begivenheder, der deles mellem dine kolleger.",
|
||||
"submit": "Send",
|
||||
"submit": "Videre",
|
||||
"delete": "Slet",
|
||||
"update": "Opdatér",
|
||||
"save": "Gem",
|
||||
"pending": "Afventer",
|
||||
"open_options": "Åbn indstillinger",
|
||||
"open_options": "Åbn muligheder",
|
||||
"copy_link": "Kopiér link til begivenhed",
|
||||
"share": "Del",
|
||||
"share_event": "Kan du booke min Cal eller sende mig dit link?",
|
||||
@@ -598,7 +598,6 @@
|
||||
"new_event_type_heading": "Opret din første begivenhedstype",
|
||||
"new_event_type_description": "Begivenhedstyper gør det muligt for dig at dele links, der viser tilgængelige tider i din kalender, og give folk mulighed for at foretage bookinger med dig.",
|
||||
"new_event_title": "Tilføj en ny begivenhedstype",
|
||||
"new_event_subtitle": "Opret en begivenhedstype under dit navn eller et team.",
|
||||
"new_team_event": "Tilføj en ny team begivenhedstype",
|
||||
"new_event_description": "Opret en ny begivenhedstype for folk til at booke tider med.",
|
||||
"event_type_created_successfully": "{{eventTypeTitle}} begivenhedstype blev oprettet",
|
||||
@@ -647,6 +646,15 @@
|
||||
"team_billing_description": "Administrér fakturering for dit team",
|
||||
"upgrade_to_flexible_pro_title": "Vi har ændret faktureringen for teams",
|
||||
"upgrade_to_flexible_pro_message": "Der er medlemmer i dit team uden en plads. Opgradér din pro plan for at dække manglende pladser.",
|
||||
"changed_team_billing_info": "Fra januar 2022 opkræver vi pr. plads for teammedlemmer. Medlemmer af Deres team, der havde PRO gratis, er nu på en 14 dages prøveperiode. Når deres prøveperiode udløber, vil disse medlemmer blive skjult fra dit team, medmindre du opgraderer nu.",
|
||||
"create_manage_teams_collaborative": "Opret og administrer teams for at bruge samarbejdsfunktioner.",
|
||||
"only_available_on_pro_plan": "Denne funktion er kun tilgængelig i Pro plan",
|
||||
"remove_cal_branding_description": "For at fjerne {{appName}} branding fra dine bookingsider, skal du opgradere til en Pro-konto.",
|
||||
"edit_profile_info_description": "Redigér dine profiloplysninger, der vises på dit planlægningslink.",
|
||||
"change_email_tip": "Det kan være nødvendigt at logge ud og ind igen for at se ændringerne træde i kraft.",
|
||||
"little_something_about": "Lidt om dig selv.",
|
||||
"profile_updated_successfully": "Profilen blev opdateret",
|
||||
"your_user_profile_updated_successfully": "Din brugerprofil er blevet opdateret.",
|
||||
"user_cannot_found_db": "Bruger ser ud til at være logget ind, men kan ikke findes i db",
|
||||
"embed_and_webhooks": "Indlejr & Webhooks",
|
||||
"enabled": "Aktiveret",
|
||||
@@ -656,7 +664,7 @@
|
||||
"manage_your_billing_info": "Administrer dine faktureringsoplysninger og annuller dit abonnement.",
|
||||
"availability": "Tilgængelighed",
|
||||
"edit_availability": "Redigér tilgængelighed",
|
||||
"configure_availability": "Konfigurér tidspunkter, hvor du er tilgængelig for bookinger.",
|
||||
"configure_availability": "Indstil tidspunkter, hvor du er tilgængelig for bookinger.",
|
||||
"copy_times_to": "Kopiér tidspunkter til",
|
||||
"copy_times_to_tooltip": "Kopiér tidspunkter til …",
|
||||
"change_weekly_schedule": "Redigér din ugentlige tidsplan",
|
||||
@@ -754,7 +762,7 @@
|
||||
"embed_your_calendar": "Indlejr din kalender på din hjemmeside",
|
||||
"connect_your_favourite_apps": "Tilslut dine foretrukne apps.",
|
||||
"automation": "Automatisering",
|
||||
"configure_how_your_event_types_interact": "Konfigurér hvordan dine begivenhedstyper skal interagere med dine kalendere.",
|
||||
"configure_how_your_event_types_interact": "Indstil hvordan dine begivenhedstyper skal interagere med dine kalendere.",
|
||||
"toggle_calendars_conflict": "Skift mellem de kalendere du vil tjekke for konflikter, for at forhindre dobbeltbookinger.",
|
||||
"select_destination_calendar": "Opret begivenheder på",
|
||||
"connect_additional_calendar": "Forbind yderligere kalender",
|
||||
@@ -803,11 +811,11 @@
|
||||
"no_category_apps_description_web3": "Tilføj en web3 app til dine bookingsider",
|
||||
"installed_app_calendar_description": "Indstil kalenderne til at tjekke for konflikter, for at forhindre dobbeltbookinger.",
|
||||
"installed_app_conferencing_description": "Tilføj dine foretrukne videokonference apps til dine møder",
|
||||
"installed_app_payment_description": "Konfigurer hvilke betalingsbehandlings tjenester der skal bruges, når du opkræver betaling fra dine kunder.",
|
||||
"installed_app_analytics_description": "Konfigurer hvilke analyseapps der skal bruges til dine bookingsider",
|
||||
"installed_app_payment_description": "Indstil hvilke betalingsbehandlingstjenester der skal bruges, når du opkræver betaling fra dine kunder.",
|
||||
"installed_app_analytics_description": "Indstil hvilke analyseapps der skal bruges til dine bookingsider",
|
||||
"installed_app_other_description": "Alle dine installerede apps fra andre kategorier.",
|
||||
"installed_app_automation_description": "Konfigurer hvilke automatiserings apps der skal bruges",
|
||||
"installed_app_web3_description": "Konfigurer hvilke web3 apps der skal bruges til dine bookingsider",
|
||||
"installed_app_automation_description": "Indstil hvilke automatiseringsapps der skal bruges",
|
||||
"installed_app_web3_description": "Indstil hvilke web3 apps der skal bruges til dine bookingsider",
|
||||
"analytics": "Analyser",
|
||||
"empty_installed_apps_headline": "Ingen apps installeret",
|
||||
"empty_installed_apps_description": "Apps giver dig mulighed for at forbedre din arbejdsgang og forbedre dit planlægningsliv betydeligt.",
|
||||
@@ -867,6 +875,7 @@
|
||||
"24_hour_short": "24h",
|
||||
"redirect_success_booking": "Omdirigér ved booking ",
|
||||
"you_are_being_redirected": "Du bliver omdirigeret til {{ url }} om $t(second, {\"count\": {{seconds}} }).",
|
||||
"external_redirect_url": "https://eksempel.com/omdiriger-til-min-succes-side",
|
||||
"redirect_url_description": "Omdiriger til en brugerdefineret URL efter en vellykket booking",
|
||||
"duplicate": "Duplikér",
|
||||
"offer_seats": "Tilbyd pladser",
|
||||
@@ -1006,7 +1015,7 @@
|
||||
"new_event_trigger": "når ny begivenhed er booket",
|
||||
"email_host_action": "send e-mail til vært",
|
||||
"email_attendee_action": "send e-mail til deltager",
|
||||
"sms_attendee_action": "send SMS til deltager",
|
||||
"sms_attendee_action": "Send SMS til deltager",
|
||||
"sms_number_action": "send SMS til et specifikt nummer",
|
||||
"workflows": "Workflows",
|
||||
"new_workflow_btn": "Nyt Workflow",
|
||||
@@ -1092,6 +1101,24 @@
|
||||
"new_seat_subject": "Ny Deltager {{name}} på {{eventType}} den {{date}}",
|
||||
"new_seat_title": "Nogen har tilføjet sig selv til en begivenhed",
|
||||
"variable": "Variabel",
|
||||
"event_name_variable": "Begivenhedsnavn",
|
||||
"organizer_name_variable": "Arrangør",
|
||||
"attendee_name_variable": "Deltager",
|
||||
"event_date_variable": "Dato for begivenhed",
|
||||
"event_time_variable": "Tidspunkt for begivenhed",
|
||||
"location_variable": "Placering",
|
||||
"additional_notes_variable": "Yderligere bemærkninger",
|
||||
"app_upgrade_description": "For at bruge denne funktion skal du opgradere til en Pro-konto.",
|
||||
"invalid_number": "Ugyldigt telefonnummer",
|
||||
"navigate": "Navigér",
|
||||
"open": "Åbn",
|
||||
"close": "Luk",
|
||||
"upgrade": "Opgradér",
|
||||
"upgrade_to_access_recordings_title": "Opgradér for at tilgå optagelser",
|
||||
"upgrade_to_access_recordings_description": "Optagelser er kun tilgængelige som en del af vores teams plan. Opgradér for at begynde at optage dine opkald",
|
||||
"recordings_are_part_of_the_teams_plan": "Optagelser er en del af teams planen",
|
||||
"team_feature_teams": "Dette er en Team funktion. Opgradér til Team for at se dit teams tilgængelighed.",
|
||||
"team_feature_workflows": "Dette er en Team funktion. Opgradér til Team for at automatisere dine begivenhedsnotifikationer og påmindelser med Workflows.",
|
||||
"show_eventtype_on_profile": "Vis på profil",
|
||||
"embed": "Indlejr",
|
||||
"new_username": "Nyt brugernavn",
|
||||
@@ -1161,7 +1188,37 @@
|
||||
"profile_picture": "Profilbillede",
|
||||
"upload": "Upload",
|
||||
"add_profile_photo": "Tilføj profilbillede",
|
||||
"web3": "Web3",
|
||||
"rainbow_token_gated": "Denne begivenhedstype er token gated.",
|
||||
"rainbow_connect_wallet_gate": "Forbind din wallet, hvis du ejer <1>{{name}}</1> (<3>{{symbol}}</3>).",
|
||||
"rainbow_insufficient_balance": "Din tilsluttede wallet indeholder ikke nok <1>{{symbol}}</1>.",
|
||||
"rainbow_sign_message_request": "Signér beskedanmodningen på din wallet.",
|
||||
"rainbow_signature_error": "Fejl ved anmodning om signatur fra din wallet.",
|
||||
"token_address": "Token Adresse",
|
||||
"blockchain": "Blockchain",
|
||||
"old_password": "Gammel adgangskode",
|
||||
"secure_password": "Din nye super sikre adgangskode",
|
||||
"error_updating_password": "Fejl under opdatering af adgangskode",
|
||||
"two_factor_auth": "To-faktor autentificering",
|
||||
"recurring_event_tab_description": "Opret en gentagende tidsplan",
|
||||
"today": "i dag",
|
||||
"appearance": "Udseende",
|
||||
"appearance_subtitle": "Administrér indstillinger for din booking visning",
|
||||
"my_account": "Min konto",
|
||||
"general": "Generelt",
|
||||
"calendars": "Kalendere",
|
||||
"2fa_auth": "To-faktor aut",
|
||||
"invoices": "Fakturaer",
|
||||
"embeds": "Indlejringer",
|
||||
"impersonation": "Impersonation",
|
||||
"impersonation_description": "Indstillinger til håndtering af bruger-impersonation",
|
||||
"users": "Brugere",
|
||||
"profile_description": "Administrér indstillinger for din {{appName}} profil",
|
||||
"users_description": "Her kan du finde en liste over alle brugere",
|
||||
"users_listing": "Bruger liste",
|
||||
"general_description": "Administrér indstillinger for dit sprog og tidszone",
|
||||
"calendars_description": "Indstil hvordan dine begivenhedstyper interagerer med dine kalendere",
|
||||
"appearance_description": "Administrér indstillinger for din booking visning",
|
||||
"conferencing_description": "Tilføj dine foretrukne videokonference apps til dine møder",
|
||||
"password_description": "Administrér indstillinger for dine kontoadgangskoder",
|
||||
"2fa_description": "Administrér indstillinger for dine kontoadgangskoder",
|
||||
@@ -1337,7 +1394,7 @@
|
||||
"saml_sp_entity_id": "SP Entity ID",
|
||||
"saml_sp_acs_url_copied": "ACS URL kopieret!",
|
||||
"saml_sp_entity_id_copied": "SP Entity ID kopieret!",
|
||||
"saml_btn_configure": "Konfigurér",
|
||||
"saml_btn_configure": "Indstil",
|
||||
"add_calendar": "Tilføj Kalender",
|
||||
"limit_future_bookings": "Begræns fremtidige bookinger",
|
||||
"limit_future_bookings_description": "Begræns hvor langt i fremtiden denne begivenhed kan bookes",
|
||||
@@ -1378,7 +1435,7 @@
|
||||
"edit_event_type": "Redigér begivenhedstype",
|
||||
"collective_scheduling": "Kollektiv Planlægning",
|
||||
"make_it_easy_to_book": "Gør det nemt at booke dit team, når alle er tilgængelige.",
|
||||
"find_the_best_person": "Find den bedste tilgængelige person, og cykl gennem dit team.",
|
||||
"find_the_best_person": "Find den bedste person tilgængelig, og cykl gennem dit team.",
|
||||
"fixed_round_robin": "Fast round robin",
|
||||
"add_one_fixed_attendee": "Tilføj en fast deltager og round robin gennem en række deltagere.",
|
||||
"calcom_is_better_with_team": "Cal.com er bedre med teams",
|
||||
@@ -1389,6 +1446,41 @@
|
||||
"disable_payment_app": "Administratoren har deaktiveret {{appName}}, hvilket påvirker din begivenhedstype {{title}}. Deltagere er stadig i stand til at booke denne type begivenhed, men vil ikke blive bedt om at betale. Du kan skjule begivenhedstypen for at forhindre dette, indtil din administrator genaktiverer din betalingsmetode.",
|
||||
"payment_disabled_still_able_to_book": "Deltagere kan stadig booke denne type begivenhed, men vil ikke blive bedt om at betale. Du kan skjule begivenhedstypen for at forhindre dette, indtil din administrator genaktiverer din betalingsmetode.",
|
||||
"app_disabled_with_event_type": "Administratoren har deaktiveret {{appName}}, hvilket påvirker din begivenhedstype {{title}}.",
|
||||
"app_disabled_video": "Administratoren har deaktiveret {{appName}}, hvilket kan påvirke dine begivenhedstyper. Hvis du har begivenhedstyper med {{appName}} som placering, vil den som standard gå til Cal Video.",
|
||||
"app_disabled_subject": "{{appName}} er blevet deaktiveret",
|
||||
"navigate_installed_apps": "Gå til installerede apps",
|
||||
"disabled_calendar": "Hvis du har en anden kalender installeret vil nye bookinger blive tilføjet til den. Hvis ikke, så forbind en ny kalender, så du ikke går glip af nye bookinger.",
|
||||
"enable_apps": "Aktivér Apps",
|
||||
"enable_apps_description": "Aktivér apps, som brugere kan integrere med Cal.com",
|
||||
"purchase_license": "Køb en licens",
|
||||
"already_have_key": "Jeg har allerede en nøgle:",
|
||||
"already_have_key_suggestion": "Kopiér venligst din eksisterende CALCOM_LICENSE_KEY environment variabel her.",
|
||||
"app_is_enabled": "{{appName}} er aktiveret",
|
||||
"app_is_disabled": "{{appName}} er deaktiveret",
|
||||
"keys_have_been_saved": "Nøgler er blevet gemt",
|
||||
"disable_app": "Deaktivér App",
|
||||
"disable_app_description": "Deaktivering af denne app kan forårsage problemer med, hvordan dine brugere interagerer med Cal",
|
||||
"edit_keys": "Redigér Nøgler",
|
||||
"admin_apps_description": "Aktivér apps for din instans af Cal",
|
||||
"no_available_apps": "Der er ingen tilgængelige apps",
|
||||
"no_available_apps_description": "Sørg for, at der er apps i din implementering under 'packages/app-store'",
|
||||
"no_apps": "Der er ingen apps aktiveret i denne instans af Cal",
|
||||
"apps_settings": "Indstillinger for apps",
|
||||
"fill_this_field": "Udfyld venligst dette felt",
|
||||
"options": "Muligheder",
|
||||
"enter_option": "Angiv Mulighed {{index}}",
|
||||
"add_an_option": "Tilføj en mulighed",
|
||||
"radio": "Radio",
|
||||
"google_meet_warning": "For at kunne bruge Google Meet skal du indstille din destinationskalender til en Google-kalender",
|
||||
"individual": "Individuel",
|
||||
"all_bookings_filter_label": "Alle Bookinger",
|
||||
"all_users_filter_label": "Alle Brugere",
|
||||
"your_bookings_filter_label": "Dine Bookinger",
|
||||
"meeting_url_variable": "Møde url",
|
||||
"meeting_url_info": "Begivenhedens mødekonference url",
|
||||
"date_overrides": "Overskrivning af dato",
|
||||
"date_overrides_subtitle": "Tilføj datoer, når din tilgængelighed skifter fra dine daglige timer.",
|
||||
"date_overrides_info": "Overskrivninger af dato arkiveres automatisk efter datoen er passeret",
|
||||
"date_overrides_dialog_which_hours": "Hvilke timer er du ledig?",
|
||||
"date_overrides_dialog_which_hours_unavailable": "Hvilke timer er du optaget?",
|
||||
"date_overrides_dialog_title": "Vælg de datoer der skal tilsidesættes",
|
||||
@@ -1434,15 +1526,31 @@
|
||||
"sender_name": "Afsenders navn",
|
||||
"already_invited": "Deltager allerede inviteret",
|
||||
"no_recordings_found": "Ingen optagelser fundet",
|
||||
"new_workflow_subtitle": "Nyt Workflow for...",
|
||||
"reporting": "Indberetning",
|
||||
"reporting_feature": "Se alt indkommende fra data og download det som en CSV",
|
||||
"teams_plan_required": "Teams plan påkrævet",
|
||||
"routing_forms_are_a_great_way": "Routingformularer er en fantastisk måde at dirigere dine indgående leads til den rigtige person. Opgradér til en Teams-plan for at få adgang til denne funktion.",
|
||||
"choose_a_license": "Vælg en licens",
|
||||
"choose_license_description": "Cal.com kommer med en tilgængelig og gratis AGPLv3-licens med nogle begrænsninger, som til enhver tid kan opgraderes til en Enterprise-licens. Du kan opgradere når som helst senere.",
|
||||
"license": "Licens",
|
||||
"agplv3_license": "AGPLv3 Licens",
|
||||
"ee_enterprise_license": "“/ee” Virksomhedslicens",
|
||||
"enterprise_booking_fee": "Fra {{enterprise_booking_fee}}/måned",
|
||||
"enterprise_license_includes": "Alt til en kommerciel brugssag",
|
||||
"no_need_to_keep_your_code_open_source": "Ingen grund til at holde din kode open source",
|
||||
"repackage_rebrand_resell": "Ompak, rebrand og videresælg nemt",
|
||||
"a_vast_suite_of_enterprise_features": "En bred vifte af virksomhedsfunktioner",
|
||||
"free_license_fee": "0,00kr./måned",
|
||||
"forever_open_and_free": "Åbent og Gratis for altid",
|
||||
"required_to_keep_your_code_open_source": "Påkrævet for at holde din kode open source",
|
||||
"cannot_repackage_and_resell": "Kan ikke ompakke, rebrande og videresælge nemt",
|
||||
"no_enterprise_features": "Ingen virksomhedsfunktioner",
|
||||
"step_enterprise_license": "Virksomhedslicens",
|
||||
"step_enterprise_license_description": "Alt til en kommerciel brugssag med privat hosting, ompakning, rebranding og videresalg, og adgang til eksklusive virksomhedskomponenter.",
|
||||
"setup": "Opsætning",
|
||||
"setup_description": "Opsæt Cal.com instans",
|
||||
"configure": "Konfigurér",
|
||||
"configure": "Indstil",
|
||||
"sso_configuration": "Enkelt Log På",
|
||||
"sso_configuration_description": "Konfigurer SAML/OIDC SSO og tillad teammedlemmer at logge ind ved hjælp af en Identitetsudbyder",
|
||||
"sso_oidc_heading": "SSO med OIDC",
|
||||
@@ -1473,14 +1581,17 @@
|
||||
"email_no_user_step_four": "Tilmeld dig {{teamName}}",
|
||||
"email_no_user_signoff": "Glædelig planlægning fra {{appName}} teamet",
|
||||
"impersonation_user_tip": "Du er ved at efterligne en bruger, hvilket betyder, at du kan foretage ændringer på deres vegne. Vær venligst forsigtig.",
|
||||
"scheduler": "{Scheduler}",
|
||||
"available_variables": "Tilgængelige variabler",
|
||||
"scheduler": "{Scheduler}",
|
||||
"no_workflows": "Ingen workflows",
|
||||
"change_filter": "Skift filter for at se dine personlige- og team workflows.",
|
||||
"recommended_next_steps": "Anbefalede næste trin",
|
||||
"create_a_managed_event": "Opret en administreret begivenhedstype",
|
||||
"meetings_are_better_with_the_right": "Møder er bedre med de rigtige teammedlemmer. Invitér dem nu.",
|
||||
"create_a_one_one_template": "Opret en one-one skabelon for en begivenhedstype og distribuér den til flere medlemmer.",
|
||||
"collective_or_roundrobin": "Kollektiv eller round-robin",
|
||||
"book_your_team_members": "Book dine teammedlemmer sammen med kollektive arrangementer eller cykl igennem for at få den rigtige person med round-robin.",
|
||||
"create_event_on": "Opret begivenhed den",
|
||||
"default_app_link_title": "Angiv et standard app-link",
|
||||
"default_app_link_description": "Indstilling af et standard app-link gør det muligt for alle nyoprettede begivenhedstyper at bruge det app-link, du har angivet.",
|
||||
"change_default_conferencing_app": "Angiv som standard",
|
||||
@@ -1492,6 +1603,7 @@
|
||||
"booking_with_payment_cancelled_refunded": "Denne booking betaling er blevet refunderet.",
|
||||
"booking_confirmation_failed": "Reservationsbekræftelse mislykkedes",
|
||||
"get_started_zapier_templates": "Kom i gang med Zapier skabeloner",
|
||||
"team_member": "Teammedlem",
|
||||
"a_routing_form": "En Routing Formular",
|
||||
"form_description_placeholder": "Formular Beskrivelse",
|
||||
"keep_me_connected_with_form": "Hold mig i forbindelse med formularen",
|
||||
@@ -1511,5 +1623,7 @@
|
||||
"select_a_router": "Vælg en router",
|
||||
"add_a_new_route": "Tilføj en ny rute",
|
||||
"no_responses_yet": "Ingen svar endnu",
|
||||
"this_will_be_the_placeholder": "Dette vil være pladsholderen"
|
||||
"this_will_be_the_placeholder": "Dette vil være pladsholderen",
|
||||
"verification_code": "Bekræftelseskode",
|
||||
"verify": "Bekræft"
|
||||
}
|
||||
|
||||
@@ -25,7 +25,7 @@
|
||||
"rejection_confirmation": "Buchung ablehnen",
|
||||
"manage_this_event": "Diesen Termin verwalten",
|
||||
"invite_team_member": "Teammitglied einladen",
|
||||
"invite_team_notifcation_badge": "Inv.",
|
||||
"invite_team_notifcation_badge": "Eing.",
|
||||
"your_event_has_been_scheduled": "Ihr Termin wurde gebucht",
|
||||
"your_event_has_been_scheduled_recurring": "Ihr wiederkehrender Termin wurde gebucht",
|
||||
"accept_our_license": "Akzeptieren Sie unsere Lizenz, indem Sie die .env-Variable <1>NEXT_PUBLIC_LICENSE_CONSENT</1> auf '{{agree}} ' ändern.",
|
||||
@@ -413,8 +413,8 @@
|
||||
"password_updated_successfully": "Passwort erfolgreich aktualisiert",
|
||||
"password_has_been_changed": "Ihr Passwort wurde erfolgreich geändert.",
|
||||
"error_changing_password": "Fehler beim Ändern des Passworts",
|
||||
"session_timeout_changed": "Ihre Session Konfiguration wurde erfolgreich aktualisiert.",
|
||||
"session_timeout_change_error": "Fehler beim Aktualisieren der Session Konfiguration",
|
||||
"session_timeout_changed": "Ihre Sitzungskonfiguration wurde erfolgreich aktualisiert.",
|
||||
"session_timeout_change_error": "Fehler beim Aktualisieren der Sitzungskonfiguration",
|
||||
"something_went_wrong": "Etwas ist schief gelaufen",
|
||||
"something_doesnt_look_right": "Irgendwas sieht nicht richtig aus?",
|
||||
"please_try_again": "Bitte erneut versuchen",
|
||||
@@ -515,7 +515,7 @@
|
||||
"admin": "Administrator",
|
||||
"administrator_user": "Administrator Benutzer",
|
||||
"lets_create_first_administrator_user": "Lass uns als erstes den Administrator Benutzer anlegen.",
|
||||
"admin_user_created": "Administrator-Benutzereinstellungen",
|
||||
"admin_user_created": "Administrator-Benutzereinrichtung",
|
||||
"admin_user_created_description": "Sie haben bereits einen Administrator-Benutzer erstellt. Sie können sich nun in Ihr Konto einloggen.",
|
||||
"new_member": "Neues Mitglied",
|
||||
"invite": "Einladen",
|
||||
@@ -598,7 +598,6 @@
|
||||
"new_event_type_heading": "Erstellen Sie Ihren ersten Ereignistyp",
|
||||
"new_event_type_description": "Mit Ereignistypen kann man verfügbare Zeiten im Kalendar freigeben, die andere Personen dann buchen können.",
|
||||
"new_event_title": "Neuen Ereignistyp hinzufügen",
|
||||
"new_event_subtitle": "Erstellen Sie einen Ereignistyp unter Ihrem Namen oder einem Team.",
|
||||
"new_team_event": "Neuen Ereignistyp hinzufügen",
|
||||
"new_event_description": "Erstellen Sie einen neuen Ereignistyp, mit dem Personen Zeiten buchen können.",
|
||||
"event_type_created_successfully": "{{eventTypeTitle}} Ereignistyp erfolgreich erstellt",
|
||||
@@ -944,11 +943,11 @@
|
||||
"current_location": "Aktueller Ort",
|
||||
"user_phone": "Ihre Telefonnummer",
|
||||
"new_location": "Neuer Ort",
|
||||
"session": "Session",
|
||||
"session_description": "Verwalten Sie Ihre Account-Session",
|
||||
"session": "Sitzung",
|
||||
"session_description": "Verwalten Sie Ihre Kontositzung",
|
||||
"session_timeout_after": "Timeout Session nach",
|
||||
"session_timeout": "Session Timeout",
|
||||
"session_timeout_description": "Nach einer bestimmten Zeit die Session löschen.",
|
||||
"session_timeout_description": "Erklärt nach einer bestimmten Zeit Ihre Sitzung für ungültig.",
|
||||
"no_location": "Kein Ort definiert",
|
||||
"set_location": "Ort festlegen",
|
||||
"update_location": "Ort aktualisieren",
|
||||
@@ -1295,7 +1294,7 @@
|
||||
"routing_forms_send_email_owner_description": "Sendet eine E-Mail an den Eigentümer, wenn das Formular abgeschickt wird",
|
||||
"add_new_form": "Neues Formular hinzufügen",
|
||||
"create_your_first_route": "Erstellen Sie Ihre erste Route",
|
||||
"route_to_the_right_person": "Route an die richtige Person anhand der Formularantworten",
|
||||
"route_to_the_right_person": "Anhand der Formularantworten an die richtige Person weiterleiten",
|
||||
"form_description": "Erstellen Sie Ihr Formular, um einen Bucher zu anzuleiten",
|
||||
"copy_link_to_form": "Link in Formular kopieren",
|
||||
"theme": "Theme",
|
||||
@@ -1454,8 +1453,8 @@
|
||||
"enable_apps": "Apps aktivieren",
|
||||
"enable_apps_description": "Apps aktivieren, die Benutzer mit Cal.com integrieren können",
|
||||
"purchase_license": "Lizenz kaufen",
|
||||
"already_have_key": "Ich habe bereits einen Key:",
|
||||
"already_have_key_suggestion": "Bitte fügen Sie Ihre vorhandene CALCOM_LICENSE_KEY Lizenz hier ein.",
|
||||
"already_have_key": "Ich habe bereits einen Schlüssel:",
|
||||
"already_have_key_suggestion": "Bitte fügen Sie Ihre vorhandene CALCOM_LICENSE_KEY Umgebungsvariable hier ein.",
|
||||
"app_is_enabled": "{{appName}} ist aktiviert",
|
||||
"app_is_disabled": "{{appName}} ist deaktiviert",
|
||||
"keys_have_been_saved": "Schlüssel wurden gespeichert",
|
||||
@@ -1526,28 +1525,28 @@
|
||||
"install_google_calendar": "Google Calendar installieren",
|
||||
"sender_name": "Absendername",
|
||||
"already_invited": "Teilnehmer bereits eingeladen",
|
||||
"no_recordings_found": "Keine Aufzeichnungen gefunden",
|
||||
"reporting": "Berichte",
|
||||
"reporting_feature": "Alle Daten anzeigen und als CSV herunterladen",
|
||||
"teams_plan_required": "Teamplan benötigt",
|
||||
"routing_forms_are_a_great_way": "Routing-Formulare sind eine gute Möglichkeit, Ihre eingehenden Leads zur richtigen Person zu leiten. Upgrade auf einen Teamplan, um auf diese Funktion zuzugreifen.",
|
||||
"no_recordings_found": "Keine Aufnahmen gefunden",
|
||||
"reporting": "Meldungen",
|
||||
"reporting_feature": "Alle eingehenden Daten anzeigen und als CSV herunterladen",
|
||||
"teams_plan_required": "Teams-Plan benötigt",
|
||||
"routing_forms_are_a_great_way": "Routing-Formulare sind eine gute Möglichkeit, Ihre eingehenden Leads zur richtigen Person zu leiten. Upgraden Sie auf einen Teamplan, um auf diese Funktion zuzugreifen.",
|
||||
"choose_a_license": "Wählen Sie eine Lizenz",
|
||||
"choose_license_description": "Cal.com enthält eine kostenlose AGPLv3-Lizenz, die einige Einschränkungen enthält, die jederzeit auf eine Enterprise-Lizenz aktualisiert werden können. Sie können später jederzeit upgraden.",
|
||||
"choose_license_description": "Cal.com enthält eine kostenlose AGPLv3-Lizenz, mit einigen Einschränkungen, die jederzeit auf eine Enterprise-Lizenz aufgerüstet werden können. Sie können später jederzeit upgraden.",
|
||||
"license": "Lizenz",
|
||||
"agplv3_license": "AGPLv3 Lizenz",
|
||||
"ee_enterprise_license": "„/ee“ Enterprise-Lizenz",
|
||||
"enterprise_booking_fee": "Ab {{enterprise_booking_fee}}/Monat",
|
||||
"enterprise_license_includes": "Alles für einen kommerziellen Anwendungsfall",
|
||||
"no_need_to_keep_your_code_open_source": "Sie müssen Ihren Code nicht Open-Source lassen",
|
||||
"repackage_rebrand_resell": "Einfaches neuverpacken, rebranding und weiterverkaufen",
|
||||
"no_need_to_keep_your_code_open_source": "Ihr Code muss nicht open-source bleiben",
|
||||
"repackage_rebrand_resell": "Einfaches Neuverpacken, Rebranding und Weiterverkaufen",
|
||||
"a_vast_suite_of_enterprise_features": "Eine große Auswahl an Enterprise-Funktionen",
|
||||
"free_license_fee": "0.00€/Monat",
|
||||
"free_license_fee": "0,00€/Monat",
|
||||
"forever_open_and_free": "Für immer offen & kostenlos",
|
||||
"required_to_keep_your_code_open_source": "Ihr Code muss Open-Source bleiben",
|
||||
"cannot_repackage_and_resell": "Kann nicht einfach neu verpackt, gerebrandet und weiterverkauft werden",
|
||||
"required_to_keep_your_code_open_source": "Ihr Code muss open-source bleiben",
|
||||
"cannot_repackage_and_resell": "Kann nicht einfach neuverpackt, rebrandet und weiterverkauft werden",
|
||||
"no_enterprise_features": "Keine Enterprise-Funktionen",
|
||||
"step_enterprise_license": "Enterprise-Lizenz",
|
||||
"step_enterprise_license_description": "Alles für einen kommerziellen Einsatzfall mit privatem Hosting, Umverpackung, Rebranding, Wiederverkauf und Zugriff auf exklusive Enterprise Komponenten.",
|
||||
"step_enterprise_license_description": "Alles für einen kommerziellen Einsatzfall mit privatem Hosting, Umverpacken, Rebranding, Wiederverkauf und Zugriff auf exklusive Enterprise-Komponenten.",
|
||||
"setup": "Einrichtung",
|
||||
"setup_description": "Cal.com Instanz einrichten",
|
||||
"configure": "Konfigurieren",
|
||||
@@ -1566,28 +1565,28 @@
|
||||
"sso_saml_entityid_copied": "Entitäts-ID kopiert",
|
||||
"sso_connection_created_successfully": "{{connectionType}} Konfiguration erfolgreich erstellt",
|
||||
"sso_connection_deleted_successfully": "{{connectionType}} Konfiguration erfolgreich gelöscht",
|
||||
"delete_sso_configuration": "Lösche {{connectionType}} Konfiguration",
|
||||
"delete_sso_configuration": "{{connectionType}}-Konfiguration löschen",
|
||||
"delete_sso_configuration_confirmation": "Ja, {{connectionType}} Konfiguration löschen",
|
||||
"delete_sso_configuration_confirmation_description": "Sind Sie sicher, dass Sie die {{connectionType}} -Konfiguration löschen möchten? Ihre Teammitglieder, die {{connectionType}} anmelden, werden keinen Zugriff mehr auf Cal.com haben.",
|
||||
"delete_sso_configuration_confirmation_description": "Sind Sie sicher, dass Sie die {{connectionType}}-Konfiguration löschen möchten? Ihre Teammitglieder, die sich über {{connectionType}} anmelden, werden keinen Zugriff mehr auf Cal.com haben.",
|
||||
"organizer_timezone": "Zeitzone des Veranstalters",
|
||||
"email_no_user_cta": "Erstellen Sie Ihr Konto",
|
||||
"email_user_cta": "Einladung anzeigen",
|
||||
"email_no_user_invite_heading": "Sie wurden eingeladen dem Team {{appName}} beizutreten",
|
||||
"email_no_user_invite_subheading": "{{invitedBy}} hat Sie eingeladen, dem Team {{appName}} beizutreten. {{appName}} ist der Event-Planer, der es Ihnen und Ihrem Team ermöglicht, Meetings ohne E-Mail Tennis zu planen.",
|
||||
"email_no_user_invite_steps_intro": "Wir begleiten Sie durch ein paar Schritte und Sie genießen stressfreie Planung mit Ihrem Team in kürzester Zeit.",
|
||||
"email_no_user_step_one": "Benutzernamen auswählen",
|
||||
"email_no_user_step_two": "Kalenderkonto verbinden",
|
||||
"email_no_user_step_three": "Verfügbarkeit festlegen",
|
||||
"email_no_user_step_four": "{{teamName}} beitreten",
|
||||
"email_no_user_signoff": "Glückliche Terminplanung wünscht das {{appName}} Team",
|
||||
"impersonation_user_tip": "Sie sind dabei einen Benutzer zu identifizieren, was bedeutet, dass Sie Änderungen in ihrem Namen vornehmen können. Bitte seien Sie vorsichtig.",
|
||||
"scheduler": "{Scheduler}",
|
||||
"email_no_user_invite_heading": "Sie wurden eingeladen, dem Team in {{appName}} beizutreten",
|
||||
"email_no_user_invite_subheading": "{{invitedBy}} hat Sie eingeladen, dem Team {{appName}} beizutreten. {{appName}} ist der Event-Planer, der es Ihnen und Ihrem Team ermöglicht, Meetings ohne ständiges hin und her zu planen.",
|
||||
"email_no_user_invite_steps_intro": "Wir begleiten Sie durch ein paar Schritte, danach können Sie stressfreie Planung mit Ihrem Team in kürzester Zeit genießen.",
|
||||
"email_no_user_step_one": "Wählen Sie Ihren Benutzernamen",
|
||||
"email_no_user_step_two": "Verbinden Sie Ihr Kalenderkonto",
|
||||
"email_no_user_step_three": "Legen Sie Ihre Verfügbarkeit fest",
|
||||
"email_no_user_step_four": "Treten Sie {{teamName}} bei",
|
||||
"email_no_user_signoff": "Fröhliche Terminplanung wünscht das {{appName}} Team",
|
||||
"impersonation_user_tip": "Sie sind dabei einen Benutzer zu identifizieren, was bedeutet, dass Sie Änderungen an ihrem Namen vornehmen können. Bitte seien Sie vorsichtig.",
|
||||
"available_variables": "Verfügbare Variablen",
|
||||
"scheduler": "{Scheduler}",
|
||||
"recommended_next_steps": "Empfohlene nächste Schritte",
|
||||
"create_a_managed_event": "Erstellen Sie ein verwalteten Ereignistyp",
|
||||
"meetings_are_better_with_the_right": "Treffen sind besser mit den richtigen Teammitgliedern. Laden Sie sie jetzt ein.",
|
||||
"create_a_managed_event": "Einen verwalteten Ereignistyp erstellen",
|
||||
"meetings_are_better_with_the_right": "Meetings sind mit den richtigen Teammitgliedern besser. Laden Sie sie jetzt ein.",
|
||||
"collective_or_roundrobin": "Kollektiv oder Round-Robin",
|
||||
"book_your_team_members": "Buchen Sie Ihre Teammitglieder zusammen mit Kollektivveranstaltungen oder wählen Sie anhand Round-Robin die richtige Person.",
|
||||
"book_your_team_members": "Buchen Sie Ihre Teammitglieder zusammen mit Kollektivveranstaltungen oder wählen Sie mit Round-Robin die richtige Person.",
|
||||
"default_app_link_title": "Standard-App-Link festlegen",
|
||||
"default_app_link_description": "Mit dem Festlegen eines Standard-App-Links können alle neu erstellten Ereignistypen den App-Link verwenden, den Sie gesetzt haben.",
|
||||
"change_default_conferencing_app": "Als Standard festlegen",
|
||||
@@ -1598,15 +1597,15 @@
|
||||
"booking_with_payment_cancelled_already_paid": "Eine Rückerstattung für diese Buchungszahlung ist auf dem Weg.",
|
||||
"booking_with_payment_cancelled_refunded": "Diese Buchungszahlung wurde zurückerstattet.",
|
||||
"booking_confirmation_failed": "Buchungsbestätigung fehlgeschlagen",
|
||||
"get_started_zapier_templates": "Beginnen Sie mit Zapier-Templates",
|
||||
"get_started_zapier_templates": "Legen Sie mit Zapier-Templates los",
|
||||
"a_routing_form": "Ein Routing-Formular",
|
||||
"form_description_placeholder": "Formularbeschreibung",
|
||||
"keep_me_connected_with_form": "Mich mit dem Formular verbunden lassen",
|
||||
"fields_in_form_duplicated": "Alle Änderungen in Router und Felder des Formulars, die dupliziert werden, werden auch im Duplikat wiedergegeben.",
|
||||
"keep_me_connected_with_form": "Behalte mich mit dem Formular verbunden",
|
||||
"fields_in_form_duplicated": "Alle Änderungen in Router und in den Feldern des Formulars, die dupliziert werden, werden auch im Duplikat wiedergegeben.",
|
||||
"form_deleted": "Formular gelöscht",
|
||||
"delete_form": "Formular löschen",
|
||||
"delete_form_action": "Ja, Formular löschen",
|
||||
"delete_form_confirmation": "Sind Sie sicher, dass Sie dieses Formular löschen möchten? Jede Person, mit dem Link kann nicht mehr mit dem Formular buchen. Außerdem wurden alle zugehörigen Antworten gelöscht.",
|
||||
"delete_form_confirmation": "Sind Sie sicher, dass Sie dieses Formular löschen möchten? Jede Person, mit der Sie den Link geteilt haben, kann nicht mehr über das Formular buchen. Außerdem würden alle zugehörigen Antworten gelöscht werden.",
|
||||
"typeform_redirect_url_copied": "Typeform Umleitungs-URL kopiert! Sie können die URL in Typeform einstellen.",
|
||||
"modifications_in_fields_warning": "Änderungen in den Feldern und Routen der folgenden Formulare werden in diesem Formular reflektiert.",
|
||||
"connected_forms": "Verbundene Formulare",
|
||||
|
||||
@@ -598,7 +598,6 @@
|
||||
"new_event_type_heading": "Create your first event type",
|
||||
"new_event_type_description": "Event types enable you to share links that show available times on your calendar and allow people to make bookings with you.",
|
||||
"new_event_title": "Add a new event type",
|
||||
"new_event_subtitle": "Create an event type under your name or a team.",
|
||||
"new_team_event": "Add a new team event type",
|
||||
"new_event_description": "Create a new event type for people to book times with.",
|
||||
"event_type_created_successfully": "{{eventTypeTitle}} event type created successfully",
|
||||
@@ -861,6 +860,7 @@
|
||||
"add_new_calendar": "Add a new calendar",
|
||||
"set_calendar": "Set where to add new events to when you're booked.",
|
||||
"delete_schedule": "Delete schedule",
|
||||
"delete_schedule_description":"Deleting a schedule will remove it from all event types. This action cannot be undone.",
|
||||
"schedule_created_successfully": "{{scheduleName}} schedule created successfully",
|
||||
"availability_updated_successfully": "{{scheduleName}} schedule updated successfully",
|
||||
"schedule_deleted_successfully": "Schedule deleted successfully",
|
||||
@@ -1527,6 +1527,7 @@
|
||||
"sender_name": "Sender name",
|
||||
"already_invited": "Attendee already invited",
|
||||
"no_recordings_found": "No recordings found",
|
||||
"new_workflow_subtitle": "New workflow for...",
|
||||
"reporting": "Reporting",
|
||||
"reporting_feature": "See all incoming from data and download it as a CSV",
|
||||
"teams_plan_required": "Teams plan required",
|
||||
@@ -1581,25 +1582,37 @@
|
||||
"email_no_user_step_four":"Join {{teamName}}",
|
||||
"email_no_user_signoff":"Happy Scheduling from the {{appName}} team",
|
||||
"impersonation_user_tip": "You are about to impersonate a user, which means you can make changes on their behalf. Please be careful.",
|
||||
"scheduler": "{Scheduler}",
|
||||
"available_variables": "Available variables",
|
||||
"scheduler": "{Scheduler}",
|
||||
"no_workflows": "No workflows",
|
||||
"change_filter": "Change filter to see your personal and team workflows.",
|
||||
"recommended_next_steps": "Recommended next steps",
|
||||
"create_a_managed_event": "Create a managed event type",
|
||||
"meetings_are_better_with_the_right": "Meetings are better with the right team members there. Invite them now.",
|
||||
"create_a_one_one_template": "Create a one-one one template for an event type and distribute it to multiple members.",
|
||||
"collective_or_roundrobin": "Collective or round-robin",
|
||||
"book_your_team_members": "Book your team members together with collective events or cycle through to get the right person with round-robin.",
|
||||
"create_event_on": "Create event on",
|
||||
"default_app_link_title":"Set a default app link",
|
||||
"default_app_link_description":"Setting a default app link allows all newly created event types to use the app link you set.",
|
||||
"change_default_conferencing_app":"Set as default",
|
||||
"under_maintenance": "Down for maintenance",
|
||||
"under_maintenance_description": "The {{appName}} team are performing scheduled maintenance. If you have any questions, please contact support.",
|
||||
"event_type_seats": "{{numberOfSeats}} seats",
|
||||
"booking_questions_title": "Booking questions",
|
||||
"booking_questions_description": "Customize the questions asked on the booking page",
|
||||
"add_a_booking_question": "Add a question",
|
||||
"duplicate_email": "Email is duplicate",
|
||||
"booking_with_payment_cancelled": "Paying for this event is no longer possible",
|
||||
"booking_with_payment_cancelled_already_paid": "A refund for this booking payment it's on the way.",
|
||||
"booking_with_payment_cancelled_refunded": "This booking payment has been refunded.",
|
||||
"booking_confirmation_failed": "Booking confirmation failed",
|
||||
"form_builder_field_already_exists": "A field with this name already exists",
|
||||
"form_builder_field_add_subtitle": "Customize the questions asked on the booking page",
|
||||
"form_builder_system_field_cant_delete": "This system field can't be removed.",
|
||||
"form_builder_system_field_cant_toggle": "This system field can't be toggled.",
|
||||
"get_started_zapier_templates": "Get started with Zapier templates",
|
||||
"team_member": "Team member",
|
||||
"a_routing_form": "A Routing Form",
|
||||
"form_description_placeholder": "Form Description",
|
||||
"keep_me_connected_with_form": "Keep me connected with the form",
|
||||
@@ -1619,5 +1632,11 @@
|
||||
"select_a_router": "Select a router",
|
||||
"add_a_new_route": "Add a new Route",
|
||||
"no_responses_yet": "No responses yet",
|
||||
"this_will_be_the_placeholder": "This will be the placeholder"
|
||||
"this_will_be_the_placeholder": "This will be the placeholder",
|
||||
"verification_code": "Verification code",
|
||||
"verify": "Verify",
|
||||
"select_all": "Select All",
|
||||
"default_conferencing_bulk_title": "Bulk update existing event types",
|
||||
"default_conferencing_bulk_description": "Update the locations for the selected event types",
|
||||
"invalid_event_name_variables": "There is an invalid variable in your event name"
|
||||
}
|
||||
|
||||
@@ -589,7 +589,6 @@
|
||||
"new_event_type_heading": "Crea tu primer tipo de evento",
|
||||
"new_event_type_description": "Los tipos de eventos te permiten compartir enlaces que muestran las horas disponibles en tu calendario y permitir que la gente haga reservas contigo.",
|
||||
"new_event_title": "Crear Nuevo Tipo de Evento",
|
||||
"new_event_subtitle": "Crea un tipo de evento bajo tu nombre o equipo.",
|
||||
"new_team_event": "Crear Nuevo Tipo de Evento de Equipo",
|
||||
"new_event_description": "Crea un nuevo tipo de evento con el que la gente pueda hacer reservas.",
|
||||
"event_type_created_successfully": "{{eventTypeTitle}} tipo de evento creado con éxito",
|
||||
|
||||
@@ -598,7 +598,6 @@
|
||||
"new_event_type_heading": "Créez votre premier type d'événement",
|
||||
"new_event_type_description": "Les types d'événements vous permettent de partager des liens qui affichent vos disponibilités sur votre calendrier et permettent aux personnes de réserver des créneaux.",
|
||||
"new_event_title": "Ajouter un nouveau type d'événement",
|
||||
"new_event_subtitle": "Créez un type d'événement pour vous ou votre équipe.",
|
||||
"new_team_event": "Ajouter un nouveau type d'événement d'équipe",
|
||||
"new_event_description": "Créez un nouveau type d'événement avec lequel les personnes peuvent réserver des créneaux.",
|
||||
"event_type_created_successfully": "Type d'événement {{eventTypeTitle}} créé avec succès",
|
||||
@@ -861,6 +860,7 @@
|
||||
"add_new_calendar": "Ajouter un nouveau calendrier",
|
||||
"set_calendar": "Définissez où ajouter les nouveaux événements après une réservation.",
|
||||
"delete_schedule": "Supprimer le planning",
|
||||
"delete_schedule_description": "La suppression d'un planning l'enlèvera de tous les types d'événements. Cette action ne peut pas être annulée.",
|
||||
"schedule_created_successfully": "Planning {{scheduleName}} créé avec succès",
|
||||
"availability_updated_successfully": "Planning {{scheduleName}} mis à jour avec succès",
|
||||
"schedule_deleted_successfully": "Planning supprimé avec succès",
|
||||
@@ -1527,6 +1527,7 @@
|
||||
"sender_name": "Nom de l'expéditeur",
|
||||
"already_invited": "Participant déjà invité",
|
||||
"no_recordings_found": "Aucun enregistrement trouvé",
|
||||
"new_workflow_subtitle": "Nouveau workflow pour...",
|
||||
"reporting": "Rapports",
|
||||
"reporting_feature": "Voir toutes les données entrantes et les télécharger au format CSV.",
|
||||
"teams_plan_required": "Plan Équipes requis",
|
||||
@@ -1581,25 +1582,37 @@
|
||||
"email_no_user_step_four": "Rejoignez {{teamName}}",
|
||||
"email_no_user_signoff": "Bonne planification de la part de l'équipe {{appName}}",
|
||||
"impersonation_user_tip": "Vous êtes sur le point d'emprunter l'identité d'un utilisateur, ce qui signifie que vous pouvez effectuer des modifications en son nom. S'il vous plaît, soyez prudent(e).",
|
||||
"scheduler": "{Scheduler}",
|
||||
"available_variables": "Variables disponibles",
|
||||
"scheduler": "{Scheduler}",
|
||||
"no_workflows": "Aucun workflow",
|
||||
"change_filter": "Changez le filtre pour voir vos workflows personnels et d'équipe.",
|
||||
"recommended_next_steps": "Étapes suivantes recommandées",
|
||||
"create_a_managed_event": "Créer un type d'événement géré",
|
||||
"meetings_are_better_with_the_right": "Les rendez-vous sont meilleurs avec les bons membres d'équipe. Invitez-les maintenant.",
|
||||
"create_a_one_one_template": "Créez un modèle unique pour un type d'événement et distribuez-le à plusieurs membres.",
|
||||
"collective_or_roundrobin": "Collective ou round-robin",
|
||||
"book_your_team_members": "Réservez les membres de votre équipe entre eux avec des événements collectifs ou mettez en place un cycle pour obtenir la bonne personne avec le round-robin.",
|
||||
"create_event_on": "Créer un événement dans",
|
||||
"default_app_link_title": "Définir un lien d'application par défaut",
|
||||
"default_app_link_description": "Définir un lien d'application par défaut permet à tous les nouveaux types d'événements d'utiliser le lien d'application que vous avez défini.",
|
||||
"change_default_conferencing_app": "Définir par défaut",
|
||||
"under_maintenance": "En cours de maintenance",
|
||||
"under_maintenance_description": "L'équipe {{appName}} effectue une maintenance planifiée. Si vous avez des questions, veuillez contacter l'assistance.",
|
||||
"event_type_seats": "{{numberOfSeats}} places",
|
||||
"booking_questions_title": "Questions de réservation",
|
||||
"booking_questions_description": "Personnalisez les questions posées sur la page de réservation.",
|
||||
"add_a_booking_question": "Ajouter une question",
|
||||
"duplicate_email": "L'adresse e-mail existe déjà",
|
||||
"booking_with_payment_cancelled": "Payer pour cet événement n'est plus possible",
|
||||
"booking_with_payment_cancelled_already_paid": "Un remboursement pour ce paiement de réservation est en route.",
|
||||
"booking_with_payment_cancelled_refunded": "Ce paiement de réservation a été remboursé.",
|
||||
"booking_confirmation_failed": "Échec de la confirmation de la réservation",
|
||||
"form_builder_field_already_exists": "Un champ avec ce nom existe déjà",
|
||||
"form_builder_field_add_subtitle": "Personnalisez les questions posées sur la page de réservation.",
|
||||
"form_builder_system_field_cant_delete": "Ce champ système ne peut pas être supprimé.",
|
||||
"form_builder_system_field_cant_toggle": "Ce champ système ne peut pas être activé.",
|
||||
"get_started_zapier_templates": "Démarrer avec les modèles Zapier",
|
||||
"team_member": "Membre d'équipe",
|
||||
"a_routing_form": "Un formulaire de routage",
|
||||
"form_description_placeholder": "Description du formulaire",
|
||||
"keep_me_connected_with_form": "Rester connecté avec le formulaire",
|
||||
@@ -1619,5 +1632,11 @@
|
||||
"select_a_router": "Sélectionner un routeur",
|
||||
"add_a_new_route": "Ajouter une nouvelle route",
|
||||
"no_responses_yet": "Aucune réponse pour l'instant",
|
||||
"this_will_be_the_placeholder": "Ce sera le texte de substitution"
|
||||
"this_will_be_the_placeholder": "Ce sera le texte de substitution",
|
||||
"verification_code": "Code de vérification",
|
||||
"verify": "Vérifier",
|
||||
"select_all": "Tout sélectionner",
|
||||
"default_conferencing_bulk_title": "Mise à jour multiple des types d'événements existants",
|
||||
"default_conferencing_bulk_description": "Mettez à jour les emplacements pour les types d'événements sélectionnés.",
|
||||
"invalid_event_name_variables": "Il y a une variable invalide dans le nom de votre événement"
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
{
|
||||
"trial_days_left": "נותרו לך $t(day, {\"count\": {{days}} }) לשימוש בגרסת הניסיון של גרסת ה-PRO",
|
||||
"trial_days_left": "נותרו לך $t(day, {\"count\": {{days}} }) לשימוש בגרסת הניסיון של רישוי PRO",
|
||||
"day_one": "יום {{count}}",
|
||||
"day_other": "{{count}} ימים",
|
||||
"second_one": "שנייה {{count}}",
|
||||
@@ -7,10 +7,11 @@
|
||||
"upgrade_now": "לשדרג עכשיו",
|
||||
"accept_invitation": "אישור הזמנה",
|
||||
"calcom_explained": "{{appName}} מספקת תשתית ליצירת לוחות זמנים שתתאים לכולם.",
|
||||
"calcom_explained_new_user": "סיים להגדיר את החשבון של {{appName}}! אתה רק מספר צעדים מפתרון כל בעיות התזמון שלך.",
|
||||
"have_any_questions": "יש לך שאלות? אנחנו כאן כדי לעזור.",
|
||||
"reset_password_subject": "{{appName}}: הנחיות לאיפוס סיסמה",
|
||||
"event_declined_subject": "נדחה: {{title}} בתאריך {{date}}",
|
||||
"event_cancelled_subject": "בוטל: {{title}} בתאריך {{date}}",
|
||||
"event_declined_subject": "נדחה: {{title}} ב- {{date}}",
|
||||
"event_cancelled_subject": "בוטל: {{title}} ב- {{date}}",
|
||||
"event_request_declined": "בקשת האירוע שלך נדחתה",
|
||||
"event_request_declined_recurring": "בקשת האירוע החוזר שלך נדחתה",
|
||||
"event_request_cancelled": "האירוע המתוכנן בוטל",
|
||||
@@ -23,6 +24,8 @@
|
||||
"rejection_reason_description": "בטוח שברצונך לדחות את ההזמנה? אנחנו ניידע את האדם שניסה להזמין. יש לך אפשרות להוסיף את הסיבה לדחייה למטה.",
|
||||
"rejection_confirmation": "לדחות את ההזמנה",
|
||||
"manage_this_event": "נהל את האירוע הזה",
|
||||
"invite_team_member": "הזמן חבר צוות",
|
||||
"invite_team_notifcation_badge": "הזמנה",
|
||||
"your_event_has_been_scheduled": "נקבע מועד לאירוע שלך",
|
||||
"your_event_has_been_scheduled_recurring": "נקבע מועד לאירוע החוזר שלך",
|
||||
"accept_our_license": "יש לאשר את תנאי הרישיון שלנו על ידי שינוי המשתנה מסוג .env בשם <1>NEXT_PUBLIC_LICENSE_CONSENT</1> ל-'{{agree}}'.",
|
||||
@@ -32,7 +35,7 @@
|
||||
"refund_failed": "ההחזר הכספי עבור האירוע {{eventType}} עם {{userName}} בתאריך {{date}} נכשל.",
|
||||
"check_with_provider_and_user": "יש לברר עם ספק התשלום ועם {{user}} כיצד לטפל בעניין.",
|
||||
"a_refund_failed": "ההחזר הכספי נכשל",
|
||||
"awaiting_payment_subject": "בהמתנה לתשלום: {{title}} בתאריך {{date}}",
|
||||
"awaiting_payment_subject": "ממתין לתשלום: {{title}} ב- {{date}}",
|
||||
"meeting_awaiting_payment": "התשלום על הפגישה שלך טרם בוצע",
|
||||
"help": "עזרה",
|
||||
"price": "מחיר",
|
||||
@@ -63,11 +66,11 @@
|
||||
"someone_requested_an_event": "מישהו ביקש לקבוע מועד לאירוע בלוח השנה שלך.",
|
||||
"someone_requested_password_reset": "מישהו ביקש קישור כדי לשנות את הסיסמה שלך.",
|
||||
"password_reset_instructions": "אם הבקשה לא היתה שלך, ניתן להתעלם מהודעת הדוא\"ל הזו בבטחה, והסיסמה שלך לא תשתנה.",
|
||||
"event_awaiting_approval_subject": "בהמתנה לאישור: {{title}} בתאריך {{date}}",
|
||||
"event_awaiting_approval_subject": "ממתין לאישור: {{title}} ב- {{date}}",
|
||||
"event_still_awaiting_approval": "אירוע עדיין ממתין לאישורך",
|
||||
"booking_submitted_subject": "ההזמנה נשלחה: {{title}} בתאריך {{date}}",
|
||||
"booking_submitted_subject": "ההזמנה נשלחה: {{title}} ב- {{date}}",
|
||||
"your_meeting_has_been_booked": "הפגישה שלך הוזמנה",
|
||||
"event_type_has_been_rescheduled_on_time_date": "{{title}} הועבר לתאריך {{date}}.",
|
||||
"event_type_has_been_rescheduled_on_time_date": "{{title}} תוזמן מחדש לתאריך {{date}}.",
|
||||
"event_has_been_rescheduled": "עודכן – מועד האירוע שלך השתנה",
|
||||
"request_reschedule_title_attendee": "בקשה לשינוי מועד ההזמנה",
|
||||
"request_reschedule_subtitle": "{{organizer}} ביטל/ה את ההזמנה וביקש/ה שתבחר/י מועד אחר.",
|
||||
@@ -101,7 +104,7 @@
|
||||
"team_info": "מידע על הצוות",
|
||||
"request_another_invitation_email": "אם אתה מעדיף לא להשתמש בכתובת {{toEmail}} ככתובת הדוא\"ל שלך עבור {{appName}} או שכבר יש לך חשבון {{appName}}, יש לבקש לקבל הזמנה נוספת לכתובת הדוא\"ל הרצויה.",
|
||||
"you_have_been_invited": "הוזמנת להצטרף לצוות {{teamName}}",
|
||||
"user_invited_you": "{{user}} הזמין/ה אותך להצטרף לצוות {{team}} ב-{{appName}}",
|
||||
"user_invited_you": "{{user}} הזמין אותך להצטרף לצוות {{team}} ב-{{appName}}",
|
||||
"hidden_team_member_title": "אתה מוסתר בצוות זה",
|
||||
"hidden_team_member_message": "לא בוצע תשלום עבור המקום שלך. ניתן לשדרג ל-PRO או ליידע את הבעלים של הצוות שהוא או היא יכולים לשלם עבור המקום שלך.",
|
||||
"hidden_team_owner_message": "נדרש חשבון Pro כדי להשתמש בתכונות הצוותים. תהיה מוסתר עד שתבצע שידרוג.",
|
||||
@@ -240,7 +243,7 @@
|
||||
"credentials_stored_and_encrypted": "פרטי הכניסה שלך יישמרו ויוצפנו.",
|
||||
"connect": "להתחבר",
|
||||
"try_for_free": "לנסות בחינם",
|
||||
"create_booking_link_with_calcom": "צור קישור הזמנה משלך ב-{{appName}}",
|
||||
"create_booking_link_with_calcom": "צור קישור תזמון משלך עם {{appName}}",
|
||||
"who": "מי",
|
||||
"what": "מה",
|
||||
"when": "מתי",
|
||||
@@ -410,6 +413,8 @@
|
||||
"password_updated_successfully": "עדכון הסיסמה בוצע בהצלחה",
|
||||
"password_has_been_changed": "שינוי הסיסמה בוצע בהצלחה.",
|
||||
"error_changing_password": "שגיאה בעת שינוי הסיסמה",
|
||||
"session_timeout_changed": "הגדרות החיבור שלך עודכנו בהצלחה.",
|
||||
"session_timeout_change_error": "שגיאה בעדכון הגדרות החיבור",
|
||||
"something_went_wrong": "משהו השתבש.",
|
||||
"something_doesnt_look_right": "משהו נראה לא כשורה?",
|
||||
"please_try_again": "נא לנסות שוב.",
|
||||
@@ -418,16 +423,17 @@
|
||||
"your_old_password": "הסיסמה הקודמת",
|
||||
"current_password": "הסיסמה הנוכחית",
|
||||
"change_password": "שינוי סיסמה",
|
||||
"change_secret": "שינוי הסוד",
|
||||
"change_secret": "שנה סוד",
|
||||
"new_password_matches_old_password": "הסיסמה החדשה זהה לישנה. יש לבחור סיסמה אחרת.",
|
||||
"forgotten_secret_description": "אם שכחת או איבדת את הסוד, יש לך אפשרות לשנות אותו, אבל חשוב לזכור שיהיה צורך לעדכן את כל השילובים שבהם נעשה שימוש בסוד זה",
|
||||
"current_incorrect_password": "הסיסמה הנוכחית שגויה",
|
||||
"password_hint_caplow": "שילוב של אותיות רישיות וקטנות",
|
||||
"password_hint_min": "באורך 7 תווים לפחות",
|
||||
"password_hint_admin_min": "באורך של 15 תווים לפחות",
|
||||
"password_hint_admin_min": "באורך 15 תווים לפחות",
|
||||
"password_hint_num": "לכלול לפחות ספרה אחת",
|
||||
"invalid_password_hint": "הסיסמה חייבת להיות באורך של {{passwordLength}} תווים לפחות ולכלול לפחות ספרה אחת ושילוב של אותיות רישיות וקטנות",
|
||||
"incorrect_password": "הסיסמה שגויה.",
|
||||
"incorrect_username_password": "שם משתמש או סיסמה שגויים.",
|
||||
"24_h": "24 שעות",
|
||||
"use_setting": "השתמש בהגדרה",
|
||||
"am_pm": "לפנה\"צ/אחה\"צ",
|
||||
@@ -455,12 +461,13 @@
|
||||
"slots_load_fail": "לא ניתן לטעון את חלונות הזמן הזמינים.",
|
||||
"additional_guests": "הוספת אורחים",
|
||||
"your_name": "שמך",
|
||||
"your_full_name": "שמך המלא",
|
||||
"email_address": "כתובת דוא\"ל",
|
||||
"enter_valid_email": "יש להזין כתובת דוא״ל תקינה",
|
||||
"location": "מיקום",
|
||||
"address": "כתובת",
|
||||
"enter_address": "יש להזין כתובת",
|
||||
"in_person_attendee_address": "פנים-אל-פנים (הכתובת של המשתתף/ת)",
|
||||
"in_person_attendee_address": "פנים-אל-פנים (בכתובת של המשתתף)",
|
||||
"yes": "כן",
|
||||
"no": "לא",
|
||||
"additional_notes": "הערות נוספות",
|
||||
@@ -470,14 +477,14 @@
|
||||
"booking_confirmation": "אשר את ה{{eventTypeTitle}} עם {{profileName}}",
|
||||
"booking_reschedule_confirmation": "שנה את המועד של ה{{eventTypeTitle}} עם {{profileName}}",
|
||||
"in_person_meeting": "פגישה אישית",
|
||||
"attendeeInPerson": "פנים-אל-פנים (הכתובת של המשתתף/ת)",
|
||||
"inPerson": "פנים-אל-פנים (הכתובת של המארגן/ת)",
|
||||
"attendeeInPerson": "פנים-אל-פנים (בכתובת של המשתתף)",
|
||||
"inPerson": "פנים-אל-פנים (בכתובת של המארגן)",
|
||||
"link_meeting": "פגישה עם קישור",
|
||||
"phone_call": "מספר הטלפון של המשתתף/ת",
|
||||
"your_number": "מספר הטלפון שלך",
|
||||
"phone_number": "מספר טלפון",
|
||||
"attendee_phone_number": "מספר הטלפון של המשתתף/ת",
|
||||
"organizer_phone_number": "מספר הטלפון של המארגן/ת",
|
||||
"organizer_phone_number": "מספר הטלפון של המארגן",
|
||||
"host_phone_number": "מספר הטלפון שלך",
|
||||
"enter_phone_number": "נא להזין מספר טלפון",
|
||||
"reschedule": "שינוי המועד שנקבע",
|
||||
@@ -508,6 +515,8 @@
|
||||
"admin": "מנהל/ת מערכת",
|
||||
"administrator_user": "משתמש המוגדר כמנהל מערכת",
|
||||
"lets_create_first_administrator_user": "עכשיו ניצור את המשתמש הראשון המוגדר כמנהל מערכת.",
|
||||
"admin_user_created": "הגדרת משתמש מנהל",
|
||||
"admin_user_created_description": "כבר יצרת משתמש מנהל. אתה יכול לבצע כניסה לחשבונך.",
|
||||
"new_member": "חבר/ה חדש/ה",
|
||||
"invite": "להזמין",
|
||||
"add_team_members": "הוספת חברי צוות",
|
||||
@@ -517,8 +526,8 @@
|
||||
"invite_new_member_description": "הערה: פעולה זו <1>תחייב את המינוי שלך במקום נוסף ($15 לחודש)</1>.",
|
||||
"invite_new_team_member": "להזמין מישהו לצוות שלך.",
|
||||
"change_member_role": "לשנות את תפקיד החבר/ה בצוות",
|
||||
"disable_cal_branding": "להשבית את מיתוג {{appName}}",
|
||||
"disable_cal_branding_description": "הסתר את כל מיתוגי {{appName}} מהדפים הציבוריים שלך.",
|
||||
"disable_cal_branding": "הסר מיתוג {{appName}}",
|
||||
"disable_cal_branding_description": "הסתר את כל המיתוג של {{appName}} מהדפים הציבוריים שלך.",
|
||||
"hide_book_a_team_member": "הסתרת הלחצן לשריון זמן של חבר/ת צוות",
|
||||
"hide_book_a_team_member_description": "הסתר/י את הלחצן לשריון זמן של חבר/ת צוות מהדפים הציבוריים שלך.",
|
||||
"danger_zone": "אזור מסוכן",
|
||||
@@ -568,7 +577,7 @@
|
||||
"duration": "משך זמן",
|
||||
"available_durations": "משכי זמן זמינים",
|
||||
"default_duration": "משך הזמן המוגדר כברירת מחדל",
|
||||
"default_duration_no_options": "יש לבחור תחילה משכי זמן זמינים",
|
||||
"default_duration_no_options": "ראשית, אנא בחר משך זמינות",
|
||||
"multiple_duration_mins": "{{count}} $t(minute_timeUnit)",
|
||||
"minutes": "דקות",
|
||||
"round_robin": "לפי תורות",
|
||||
@@ -589,7 +598,6 @@
|
||||
"new_event_type_heading": "צור את סוג האירוע הראשון שלך",
|
||||
"new_event_type_description": "סוגי אירועים מאפשרים לך לשתף קישורים המציגים את המועדים הפנויים בלוח השנה שלך ומאפשרים לאנשים לשריין זמן איתך.",
|
||||
"new_event_title": "הוסף סוג אירוע חדש",
|
||||
"new_event_subtitle": "צור סוג אירוע בשמך או עבור צוות.",
|
||||
"new_team_event": "הוסף סוג אירוע חדש עבור הצוות",
|
||||
"new_event_description": "צור סוג אירוע חדש שאנשים יוכלו לקבוע באמצעותו מועדים.",
|
||||
"event_type_created_successfully": "יצירת האירוע מסוג {{eventTypeTitle}} בוצעה בהצלחה",
|
||||
@@ -641,7 +649,7 @@
|
||||
"changed_team_billing_info": "החל מינואר 2022, התחלנו לגבות תשלום עבור כל חבר צוות שמשתתף בפגישה. חברי צוות שעבדו עם גרסת PRO בחינם, הועברו לגרסת ניסיון למשך 14 יום. ברגע שהתוקף של גרסת הניסיון יסתיים, חברי צוות אלה יוסתרו מהצוות, אלא אם תשדרג כעת.",
|
||||
"create_manage_teams_collaborative": "צור ונהל צוותים כדי להשתמש בתכונות של שיתוף פעולה.",
|
||||
"only_available_on_pro_plan": "תכונה זו זמינה רק בחבילת Pro",
|
||||
"remove_cal_branding_description": "כדי להסיר את המיתוג של {{appName}} מדפי ההזמנות שלך, עליך לשדרג לחשבון Pro.",
|
||||
"remove_cal_branding_description": "כדי להסיר את המיתוג של {{appName}} מדפי הזימון שלך, עליך לשדרג לחשבון Pro.",
|
||||
"edit_profile_info_description": "ערוך את פרטי הפרופיל שלך שיופיעו בקישור לקביעת מועד.",
|
||||
"change_email_tip": "ייתכן שיהיה צורך לצאת ולהיכנס שוב כדי לראות את השינויים.",
|
||||
"little_something_about": "משהו קטן אודותיך.",
|
||||
@@ -658,6 +666,7 @@
|
||||
"edit_availability": "עריכת נתוני זמינות",
|
||||
"configure_availability": "הגדר מועדים שבהם תהיה זמין להזמנות.",
|
||||
"copy_times_to": "להעתיק שעות ל",
|
||||
"copy_times_to_tooltip": "העתק שעות אל …",
|
||||
"change_weekly_schedule": "שינוי לוח הזמנים השבועי שלך",
|
||||
"logo": "לוגו",
|
||||
"error": "שגיאה",
|
||||
@@ -669,10 +678,11 @@
|
||||
"add_attendees": "הוסף משתתפים",
|
||||
"show_advanced_settings": "הצגת הגדרות מתקדמות",
|
||||
"event_name": "שם האירוע",
|
||||
"event_name_in_calendar": "שם הארוע בלוח השנה",
|
||||
"event_name_tooltip": "השם שיופיע בלוחות השנה",
|
||||
"meeting_with_user": "פגישה עם {{attendeeName}}",
|
||||
"meeting_with_user": "{Event type title} פגישה בין {Organiser} ו- {Scheduler}",
|
||||
"additional_inputs": "אפשרויות קלט נוספות",
|
||||
"additional_input_description": "לדרוש מכלי התזמון להוסיף פרטים לפני אישור ההזמנה",
|
||||
"additional_input_description": "דרוש מהמתזמן להזין נתונים נוספים לפני אישור התזמון",
|
||||
"label": "תווית",
|
||||
"placeholder": "מציין מיקום",
|
||||
"type": "סוג",
|
||||
@@ -690,21 +700,21 @@
|
||||
"private_link_label": "קישור פרטי",
|
||||
"private_link_hint": "הקישור הפרטי שלך ייווצר מחדש לאחר כל שימוש",
|
||||
"copy_private_link": "העתקת קישור פרטי",
|
||||
"private_link_description": "ניתן ליצור כתובת URL פרטית על מנת לשתף את האירוע מבלי לחשוף את שם המשתמש/ת שלך ב-{{appName}}",
|
||||
"private_link_description": "ניתן ליצור כתובת קישור פרטית מבלי לחשוף את המשתמש שלך- {{appName}}",
|
||||
"invitees_can_schedule": "המוזמנים יכולים לקבוע מועד",
|
||||
"date_range": "טווח תאריכים",
|
||||
"calendar_days": "ימים קלנדריים",
|
||||
"business_days": "ימי עסקים",
|
||||
"set_address_place": "הגדר כתובת או מקום",
|
||||
"set_link_meeting": "הגדר קישור לפגישה",
|
||||
"cal_invitee_phone_number_scheduling": "{{appName}} יציג למוזמן/ת בקשה להזין מספר טלפון לפני קביעת מועד.",
|
||||
"cal_invitee_phone_number_scheduling": "{{appName}} יציג לנמען בקשה להזנת מספר טלפון לפני קביעת ביצוע התזמון.",
|
||||
"cal_provide_google_meet_location": "{{appName}} יספק מיקום Google Meet.",
|
||||
"cal_provide_zoom_meeting_url": "{{appName}} יספק כתובת URL לפגישת Zoom.",
|
||||
"cal_provide_tandem_meeting_url": "{{appName}} יספק כתובת URL לפגישת Tandem.",
|
||||
"cal_provide_video_meeting_url": "{{appName}} יספק כתובת URL לפגישת וידאו.",
|
||||
"cal_provide_zoom_meeting_url": "{{appName}} יספק קישור לפגישת Zoom.",
|
||||
"cal_provide_tandem_meeting_url": "{{appName}} יספק כתובת קישור לפגישת Tandem.",
|
||||
"cal_provide_video_meeting_url": "{{appName}} יספק כתובת קישור לפגישת וידאו.",
|
||||
"cal_provide_jitsi_meeting_url": "אנחנו ניצור עבורך כתובת URL לפגישת Jitsi Meet.",
|
||||
"cal_provide_huddle01_meeting_url": "{{appName}} יספק כתובת URL לפגישת וידאו ב-Huddle01 web3.",
|
||||
"cal_provide_teams_meeting_url": "{{appName}} יספק כתובת URL לפגישת MS Teams. הערה: חייב להיות חשבון של מקום עבודה או בית ספר",
|
||||
"cal_provide_huddle01_meeting_url": "{{appName}} יספק כתובת קישור לפגישת וידאו web3 ב- Huddle01.",
|
||||
"cal_provide_teams_meeting_url": "{{appName}} יספק כתובת קישור לפגישת MS Teams. הערה: חייב להיות חשבון של מקום עבודה או בית ספר",
|
||||
"require_payment": "דרישת תשלום",
|
||||
"commission_per_transaction": "עמלה לעסקה",
|
||||
"event_type_updated_successfully_description": "סוג האירוע שלך עודכן בהצלחה.",
|
||||
@@ -787,6 +797,7 @@
|
||||
"number_apps_one": "אפליקציה {{count}}",
|
||||
"number_apps_other": "{{count}} אפליקציות",
|
||||
"trending_apps": "אפליקציות פופולריות",
|
||||
"most_popular": "הכי פופולרי",
|
||||
"explore_apps": "אפליקציות בקטגוריה {{category}}",
|
||||
"installed_apps": "אפליקציות מותקנות",
|
||||
"free_to_use_apps": "חינם",
|
||||
@@ -797,12 +808,14 @@
|
||||
"no_category_apps_description_analytics": "להוסיף אפליקציה לניתוח נתונים עבור דפי ההזמנות שלך",
|
||||
"no_category_apps_description_automation": "להוסיף אפליקציית אוטומציה שברצונך להשתמש בה",
|
||||
"no_category_apps_description_other": "הוסף/הוסיפי אפליקציה מכל סוג אחר לביצוע פעולות שונות",
|
||||
"no_category_apps_description_web3": "הוסף אפליקצית web3 לעמודי תזמון הפגישות שלך",
|
||||
"installed_app_calendar_description": "הגדר/הגדירח את לוחות השנה כדי לבדוק אם יש התנגשויות על מנת למנוע כפל הזמנות.",
|
||||
"installed_app_conferencing_description": "הוסף/הוסיפי את האפליקציות האהובות עליך לשיחות ועידה לשימוש בפגישות שלך",
|
||||
"installed_app_payment_description": "הגדר/הגידירי את השירותים לעיבוד תשלומים שבהם יש להשתמש לחיוב הלקוחות.",
|
||||
"installed_app_analytics_description": "הגדרת האפליקציות לניתוח נתונים שבהן יש להשתמש עבור דפי ההזמנות שלך",
|
||||
"installed_app_other_description": "כל האפליקציות המותקנות שלך מקטגוריות אחרות.",
|
||||
"installed_app_automation_description": "הגדרת אפליקציות האוטומציה שבהן ברצונך להשתמש",
|
||||
"installed_app_web3_description": "הגדר באיזה אפליקציות web3 להשתמש בעמודי תזמון הפגישות שלך",
|
||||
"analytics": "ניתוח נתונים",
|
||||
"empty_installed_apps_headline": "אין אפליקציות מותקנות",
|
||||
"empty_installed_apps_description": "אפליקציות מאפשרות לך לשפר משמעותית את תהליכי העבודה שלך ואת תהליך קביעת המועדים.",
|
||||
@@ -828,11 +841,11 @@
|
||||
"verify_wallet": "אימות הארנק",
|
||||
"connect_metamask": "קישור Metamask",
|
||||
"create_events_on": "ליצור אירועים ב-",
|
||||
"enterprise_license": "תכונה זו זמינה רק במינוי ארגוני",
|
||||
"enterprise_license_description": "כדי להפעיל תכונה זו, עליך לקבל מפתח פריסה בכתובת {{consoleUrl}} ולהוסיף אותו לסביבת .env שלך בתור CALCOM_LICENSE_KEY. אם כבר יש לצוות שלך רישיון, ניתן לפנות אל {{supportMail}} לקבלת עזרה.",
|
||||
"enterprise_license": "תכונה זו זמינה רק במינוי Enterprise",
|
||||
"enterprise_license_description": "כדי להפעיל את יכולת זו, בקש ממנהל לגשת אל הקישור {{setupUrl}} והקלדת הרישיון. אם כבר יש רישיון מוגדר, צור קשר עם {{supportMail}} לעזרה.",
|
||||
"missing_license": "חסר רישיון",
|
||||
"signup_requires": "נדרש רישיון לשימוש מסחרי",
|
||||
"signup_requires_description": "בשלב זה, {{companyName}} אינה מציעה גרסת קוד פתוח חינמית של דף ההרשמה. לקבלת גישה מלאה לרכיבי ההרשמה, תצטרך לקנות רישיון לשימוש מסחרי. ליציר חשבונות המיועדים לשימוש אישי, אנחנו ממליצים על Prisma Data Platform או על כל ממשק אחר של Postgres ליצירת חשבונות.",
|
||||
"signup_requires_description": "בשלב זה, {{companyName}} אינה מציעה גרסת קוד פתוח חינמית של דף ההרשמה. לקבלת גישה מלאה לרכיבי ההרשמה, תצטרך לקנות רישיון לשימוש מסחרי. לצרכים אישיים אנו ממליצים על Prisma Data Platform או כל ממשק Postgres אחר ליצירת חשבונות.",
|
||||
"next_steps": "השלבים הבאים",
|
||||
"acquire_commercial_license": "רכישת רישיון לשימוש מסחרי",
|
||||
"the_infrastructure_plan": "חבילת הבסיס מחויבת לפי שימוש ומוצעת בהנחות למתחילים.",
|
||||
@@ -847,6 +860,7 @@
|
||||
"add_new_calendar": "הוספת לוח שנה חדש",
|
||||
"set_calendar": "הגדר/י למתי יש להוסיף אירועים חדשים כשאת/ה עסוק/ה.",
|
||||
"delete_schedule": "מחק תזמון",
|
||||
"delete_schedule_description": "מחיקת תזמון תמחק אותו מכל סוגי הארועים. לא ניתן לבטל פעולה זו.",
|
||||
"schedule_created_successfully": "יצירת התזמון {{scheduleName}} בוצעה בהצלחה",
|
||||
"availability_updated_successfully": "עדכון התזמון {{scheduleName}} בוצע בהצלחה",
|
||||
"schedule_deleted_successfully": "מחיקת התזמון בוצעה בהצלחה",
|
||||
@@ -858,7 +872,7 @@
|
||||
"time_format": "פורמט תצוגת זמן",
|
||||
"12_hour": "12 שעות",
|
||||
"24_hour": "24 שעות",
|
||||
"12_hour_short": "12 ש'",
|
||||
"12_hour_short": "12 שעות",
|
||||
"24_hour_short": "24 שעות",
|
||||
"redirect_success_booking": "הפניה מחדש בעת הזמנה ",
|
||||
"you_are_being_redirected": "אנחנו ננתב אותך אל {{ url }} בעוד $t(second, {\"count\": {{seconds}} }).",
|
||||
@@ -921,7 +935,7 @@
|
||||
"user_impersonation_heading": "התחזות למשתמשים",
|
||||
"user_impersonation_description": "מצב זה מאפשר לצוות התמיכה שלנו להתחבר באופן זמני לחשבונך כדי שנוכל לפתור במהירות את הבעיות שתדווח/י לנו עליהם.",
|
||||
"team_impersonation_description": "מאפשר לבעלים של הצוות/מנהלים להיכנס זמנית בשמך.",
|
||||
"allow_booker_to_select_duration": "אפשר/י למזמין/ה לבחור משך זמן",
|
||||
"allow_booker_to_select_duration": "אפשר למזמין לבחור את משך הזמן",
|
||||
"impersonate_user_tip": "כל השימושים בתכונה זו נבדקים.",
|
||||
"impersonating_user_warning": "בהתחזות לשם המשתמש \"{{user}}\".",
|
||||
"impersonating_stop_instructions": "לחץ/י כאן כדי להפסיק",
|
||||
@@ -930,20 +944,25 @@
|
||||
"current_location": "המיקום הנוכחי",
|
||||
"user_phone": "מספר הטלפון שלך",
|
||||
"new_location": "המיקום החדש",
|
||||
"session": "חיבור",
|
||||
"session_description": "שלוט בהגדרות החיבור של החשבון שלך",
|
||||
"session_timeout_after": "נתק חיבור לאחר",
|
||||
"session_timeout": "ניתוק חיבור לאחר",
|
||||
"session_timeout_description": "בטל הזדהות של החיבור לאחר פרק זמן מסויים.",
|
||||
"no_location": "לא הוגדר מיקום",
|
||||
"set_location": "הגדרת מיקום",
|
||||
"update_location": "עדכון מיקום",
|
||||
"location_updated": "המיקום עודכן",
|
||||
"email_validation_error": "המידע שהזנת לא נראה כמו כתובת דוא\"ל",
|
||||
"place_where_cal_widget_appear": "מקם/י את הקוד הזה בתוך דף ה-HTML במקום שבו ברצונך שהווידג'ט של {{appName}} יופיע.",
|
||||
"place_where_cal_widget_appear": "מקם את הקוד הזה בתוך דף ה-HTML במקום שבו ברצונך שהווידג'ט של {{appName}} יופיע.",
|
||||
"create_update_react_component": "צור או עדכן רכיב React קיים כפי שמוצג להלן.",
|
||||
"copy_code": "העתקת הקוד",
|
||||
"code_copied": "הקוד הועתק!",
|
||||
"how_you_want_add_cal_site": "איך ברצונך להוסיף את {{appName}} לאתר שלך?",
|
||||
"choose_ways_put_cal_site": "בחר/י אחת מהדרכים הבאות כדי להציב את {{appName}} באתר שלך.",
|
||||
"choose_ways_put_cal_site": "בחר/י אחת מהדרכים הבאות כדי לשלב את {{appName}} באתר שלך.",
|
||||
"setting_up_zapier": "המערכת מגדירה את השילוב שלך עם Zapier",
|
||||
"generate_api_key": "יצירת מפתח ממשק תכנות יישומים (API)",
|
||||
"generate_api_key_description": "יצירת מפתח ממשק תכנות יישומים (API) לשימוש עם {{appName}} ב-",
|
||||
"generate_api_key_description": "צור מפתח ממשק מפתחים, API, לשימוש עם {{appName}} ב-",
|
||||
"your_unique_api_key": "מפתח ה-API הייחודי שלך",
|
||||
"copy_safe_api_key": "העתק/י את מפתח ה-API הזה ושמור/י אותו במקום בטוח. אם תאבד/י אותו, יהיה עליך ליצור מפתח חדש.",
|
||||
"zapier_setup_instructions": "<0>התחבר/י לחשבון Zapier שלך וצור/י Zap חדש.</0><1>בחר/י את Cal.com כאפליקציית ה-Trigger. בנוסף, בחר/י אירוע Trigger.</1><2>בחר/י את החשבון שלך ולאחר מכן הזן/י את מפתח ה-API הייחודי שלך.</2><3>בדוק/י את ה-Trigger.</3><4>וזהו, הכל מוכן!</4>",
|
||||
@@ -951,7 +970,7 @@
|
||||
"connect_apple_server": "חיבור לשרת Apple",
|
||||
"connect_caldav_server": "חיבור לשרת CalDav (בטא)",
|
||||
"calendar_url": "כתובת ה-URL של לוח השנה",
|
||||
"apple_server_generate_password": "צור סיסמה ספציפית לאפליקציה כדי להשתמש ב-{{appName}} ב:",
|
||||
"apple_server_generate_password": "צור סיסמה ספציפית לאפליקציה שתשמש עבור {{appName}} ב-",
|
||||
"credentials_stored_encrypted": "פרטי הכניסה שלך יישמרו ויוצפנו.",
|
||||
"it_stored_encrypted": "הוא יאוחסן ויוצפן.",
|
||||
"go_to_app_store": "מעבר אל ה-App Store",
|
||||
@@ -995,13 +1014,13 @@
|
||||
"before_event_trigger": "לפני שהאירוע מתחיל",
|
||||
"event_cancelled_trigger": "כאשר אירוע מבוטל",
|
||||
"new_event_trigger": "כאשר אירוע חדש מוזמן",
|
||||
"email_host_action": "יש לשלוח דוא\"ל למארח/ת",
|
||||
"email_attendee_action": "יש לשלוח דוא\"ל למשתתף/ת",
|
||||
"sms_attendee_action": "יש לשלוח SMS למשתתף/ת",
|
||||
"sms_number_action": "יש לשלוח SMS למספר מסוים",
|
||||
"workflows": "תהליכי עבודה",
|
||||
"email_host_action": "שלח מייל למארח",
|
||||
"email_attendee_action": "שלח מייל למשתתף",
|
||||
"sms_attendee_action": "שלח SMS למשתתף",
|
||||
"sms_number_action": "שלח SMS למספר מסוים",
|
||||
"workflows": "תהליכים",
|
||||
"new_workflow_btn": "תהליך עבודה חדש",
|
||||
"add_new_workflow": "הוספת תהליך עבודה חדש",
|
||||
"add_new_workflow": "הוסף תהליך חדש",
|
||||
"reschedule_event_trigger": "כאשר נקבע מועד חדש לאירוע",
|
||||
"trigger": "גורם מפעיל",
|
||||
"triggers": "גורמים מפעילים",
|
||||
@@ -1026,7 +1045,7 @@
|
||||
"current": "נוכחי",
|
||||
"premium": "פרימיום",
|
||||
"standard": "רגיל",
|
||||
"confirm_username_change_dialog_title": "אישור השינוי של שם המשתמש",
|
||||
"confirm_username_change_dialog_title": "אשר את שינוי שם המשתמש",
|
||||
"change_username_standard_to_premium": "מאחר שאתה משנה את שם המשתמש מסטנדרטי לפרימיום, תועבר אל הקופה לצורך שדרוג.",
|
||||
"change_username_premium_to_standard": "מאחר שאתה משנה את שם המשתמש מפרימיום לסטנדרטי, תועבר אל הקופה לצורך שנמוך.",
|
||||
"go_to_stripe_billing": "למעבר אל דף החיוב",
|
||||
@@ -1062,37 +1081,38 @@
|
||||
"browse_our_docs": "לדפדף במסמכים שלנו",
|
||||
"choose_template": "בחירת תבנית",
|
||||
"reminder": "תזכורת",
|
||||
"custom": "בהתאמה אישית",
|
||||
"custom": "התאמה אישית",
|
||||
"reminder_email": "תזכורת: {{eventType}} עם {{name}} בתאריך {{date}}",
|
||||
"not_triggering_existing_bookings": "לא יופעל עבור הזמנות קיימות מאחר שהמשתמש יתבקש למסור מספר טלפון בעת הזמנת האירוע.",
|
||||
"minute_one": "דקה {{count}}",
|
||||
"minute_one": "{{count}} דקה",
|
||||
"minute_other": "{{count}} דקות",
|
||||
"hour_one": "שעה {{count}}",
|
||||
"hour_one": "{{count}} שעה",
|
||||
"hour_other": "{{count}} שעות",
|
||||
"invalid_input": "קלט לא חוקי",
|
||||
"broken_video_action": "לא יכולנו להוסיף לאירוע המתוכנן שלך את הקישור לפגישה ב-<1>{{location}}</1>. צור/י קשר עם המוזמנים או עדכן/י את הפרטים באירוע בלוח השנה. ניתן <3> לשנות את המיקום בסוג האירוע </3> או לנסות <5>להסיר את האפליקציה ולהוסיף אותה שוב.</5>",
|
||||
"broken_calendar_action": "לא הצלחנו לעדכן את <1>{{calendar}}</1>. <2> נא לבדוק את הגדרות לוח השנה שלך או להסיר את לוח השנה ולהוסיף אותו שוב </2>",
|
||||
"attendee_name": "שם המשתתף/ת",
|
||||
"attendee_name": "שם המשתתף",
|
||||
"scheduler_full_name": "השם המלא של האדם שמבצע את התזמון",
|
||||
"broken_integration": "שילוב מנותק",
|
||||
"problem_adding_video_link": "הייתה בעיה בהוספת קישור לסרטון",
|
||||
"problem_updating_calendar": "הייתה בעיה בעדכון לוח השנה",
|
||||
"active_on_event_types_one": "פעיל בסוג אירוע {{count}}",
|
||||
"active_on_event_types_one": "פעיל ב-{{count}} סוגי אירועים",
|
||||
"active_on_event_types_other": "פעיל ב-{{count}} סוגי אירועים",
|
||||
"no_active_event_types": "אין סוגי אירועים פעילים",
|
||||
"new_seat_subject": "משתתף/ת חדש/ה {{name}} ב{{eventType}} בתאריך {{date}}",
|
||||
"new_seat_title": "מישהו הוסיף את עצמו לאירוע",
|
||||
"variable": "משתנה",
|
||||
"event_name_variable": "שם האירוע",
|
||||
"organizer_name_variable": "שם המארגן/ת",
|
||||
"attendee_name_variable": "שם המשתתף/ת",
|
||||
"organizer_name_variable": "שם המארגן",
|
||||
"attendee_name_variable": "שם המשתתף",
|
||||
"event_date_variable": "תאריך האירוע",
|
||||
"event_time_variable": "שעת האירוע",
|
||||
"event_time_variable": "מועד האירוע",
|
||||
"location_variable": "מיקום",
|
||||
"additional_notes_variable": "הערות נוספות",
|
||||
"app_upgrade_description": "כדי להשתמש בתכונה זו, עליך לשדרג לחשבון Pro.",
|
||||
"invalid_number": "מספר טלפון לא תקין",
|
||||
"navigate": "ניווט",
|
||||
"open": "פתיחה",
|
||||
"open": "פתח",
|
||||
"close": "סגירה",
|
||||
"upgrade": "שדרוג",
|
||||
"upgrade_to_access_recordings_title": "שדרג/י כדי לגשת להקלטות",
|
||||
@@ -1110,25 +1130,25 @@
|
||||
"company_size": "גודל החברה",
|
||||
"what_help_needed": "במה דרושה לך עזרה?",
|
||||
"variable_format": "הפורמט של המשתנה",
|
||||
"webhook_subscriber_url_reserved": "כתובת ה-URL של מנוי/מנויית Webhook כבר מוגדרת",
|
||||
"webhook_subscriber_url_reserved": "כתובת ה-URL של מנוי Webhook כבר מוגדרת",
|
||||
"custom_input_as_variable_info": "התעלמות מכל התווים המיוחדים של תווית הקלט הנוספת (שימוש באותיות ובספרות בלבד), שימוש באותיות רישיות עבור כל האותיות והחלפת רווחים במקפים תחתונים.",
|
||||
"using_additional_inputs_as_variables": "איך ניתן להשתמש בסוגי קלט נוספים כמשתנים?",
|
||||
"download_desktop_app": "הורדת האפליקציה למחשבים שולחניים",
|
||||
"set_ping_link": "הגדרת קישור Ping",
|
||||
"rate_limit_exceeded": "חריגה מההגבלה",
|
||||
"rate_limit_exceeded": "חריגה מהגבלת קצב",
|
||||
"when_something_happens": "כאשר משהו קורה",
|
||||
"action_is_performed": "פעולה מבוצעת",
|
||||
"test_action": "בדיקת פעולה",
|
||||
"notification_sent": "נשלח עדכון",
|
||||
"test_action": "בדוק פעולה",
|
||||
"notification_sent": "התראה נשלחה",
|
||||
"no_input": "אין קלט",
|
||||
"test_workflow_action": "בדיקת פעולת תהליך עבודה",
|
||||
"test_workflow_action": "בדוק פעולת תהליך עבודה",
|
||||
"send_sms": "שליחת SMS",
|
||||
"send_sms_to_number": "בטוח שברצונך לשלוח SMS למספר {{number}}?",
|
||||
"missing_connected_calendar": "אף לוח שנה המוגדר כברירת מחדל לא מחובר",
|
||||
"missing_connected_calendar": "אין לוח שנה מחובר המוגדר כברירת מחדל",
|
||||
"connect_your_calendar_and_link": "ניתן לחבר את לוח השנה שלך מ<1>כאן</1>.",
|
||||
"default_calendar_selected": "לוח השנה המוגדר כברירת מחדל",
|
||||
"hide_from_profile": "להסתיר מהפרופיל",
|
||||
"event_setup_tab_title": "הגדרת האירוע",
|
||||
"hide_from_profile": "הסתר מהפרופיל",
|
||||
"event_setup_tab_title": "הגדרת ארוע",
|
||||
"event_limit_tab_title": "מגבלות",
|
||||
"event_limit_tab_description": "באיזו תדירות ניתן להזמין אותך",
|
||||
"event_advanced_tab_description": "הגדרות לוח שנה ועוד...",
|
||||
@@ -1136,36 +1156,36 @@
|
||||
"event_setup_multiple_duration_error": "הגדרת אירוע: משכי זמן מרובים מחייבים הגדרה של אפשרות אחת לפחות.",
|
||||
"event_setup_multiple_duration_default_error": "הגדרת אירוע: יש לבחור משך זמן חוקי המוגדר כברירת מחדל.",
|
||||
"event_setup_booking_limits_error": "הגבלות על הזמנות חייבות להיות מוגדרות בסדר עולה. [יום,שבוע,חודש,שנה]",
|
||||
"select_which_cal": "בחר/י את לוח השנה שאליו יש להוסיף הזמנות",
|
||||
"select_which_cal": "בחר את לוח השנה שאליו יש להוסיף הזמנות",
|
||||
"custom_event_name": "שם אירוע מותאם אישית",
|
||||
"custom_event_name_description": "ניתן ליצור שמות אירועים בהתאמה אישית שיוצגו באירוע בלוח השנה",
|
||||
"2fa_required": "נדרש אימות בשני גורמים",
|
||||
"incorrect_2fa": "קוד שגוי של אימות בשני גורמים",
|
||||
"custom_event_name_description": "צור שמות אירועים בהתאמה אישית שיוצגו באירוע בלוח השנה",
|
||||
"2fa_required": "נדרש אימות דו-גורמי",
|
||||
"incorrect_2fa": "קוד אימות דו-גורמי שגוי",
|
||||
"which_event_type_apply": "על איזה סוג אירוע זה יחול?",
|
||||
"no_workflows_description": "תהליכי עבודה מאפשרים שימוש באוטומציה פשוטה לשליחת עדכונים ותזכורות, כך שאת/ה יכול/ה לתכנן תהליכים שקשורים לאירועים שלך.",
|
||||
"no_workflows_description": "תהליכי עבודה מאפשרים שימוש באוטומציה פשוטה לשליחת התראות ותזכורות, כך שאתה יכול לתכנן תהליכים שקשורים לאירועים שלך.",
|
||||
"timeformat_profile_hint": "זוהי הגדרה פנימית שלא תשפיע על אופן התצוגה של תאריכים ושעות בדפים של הזמנות ציבוריות עבורך או עבור מי שמבצע הזמנות בשמך.",
|
||||
"create_workflow": "יצירת תהליך עבודה",
|
||||
"do_this": "יש לבצע את הפעולה הזו",
|
||||
"turn_off": "השבתה",
|
||||
"do_this": "עשה את זה",
|
||||
"turn_off": "כבה",
|
||||
"settings_updated_successfully": "עדכון ההגדרות בוצע בהצלחה",
|
||||
"error_updating_settings": "שגיאה במהלך עדכון ההגדרות",
|
||||
"personal_cal_url": "כתובת ה-URL של ה-{{appName}} האישי שלי",
|
||||
"error_updating_settings": "שגיאה בעדכון ההגדרות",
|
||||
"personal_cal_url": "כתובת ה-URL האישית שלי של {{appName}}",
|
||||
"bio_hint": "מספר משפטים אודותיך. המידע הזה יופיע בדף ה-URL האישי שלך.",
|
||||
"delete_account_modal_title": "מחיקת חשבון",
|
||||
"delete_account_modal_title": "מחיקת החשבון",
|
||||
"confirm_delete_account_modal": "בטוח שברצונך למחוק את חשבון {{appName}} שלך?",
|
||||
"delete_my_account": "מחיקת החשבון שלי",
|
||||
"start_of_week": "תחילת השבוע",
|
||||
"recordings_title": "הקלטות",
|
||||
"recording": "הקלטה",
|
||||
"select_calendars": "בחר/י את לוחות השנה שבהם ברצונך לבדוק אם יש התנגשויות כדי למנוע כפל הזמנות.",
|
||||
"select_calendars": "בחר את לוחות השנה שבהם ברצונך לבדוק אם יש התנגשויות, כדי למנוע כפל הזמנות.",
|
||||
"check_for_conflicts": "בדיקת התנגשויות",
|
||||
"view_recordings": "צפייה בהקלטות",
|
||||
"adding_events_to": "הוספת אירועים ל",
|
||||
"follow_system_preferences": "פעל לפי העדפות המערכת",
|
||||
"custom_brand_colors": "צבעי מותג בהתאמה אישית",
|
||||
"customize_your_brand_colors": "בצע/י התאמה אישית של דף ההזמנות שלך עם צבעי מותג משלך.",
|
||||
"customize_your_brand_colors": "בצע התאמה אישית של דף ההזמנות שלך עם צבעי מותג משלך.",
|
||||
"pro": "Pro",
|
||||
"removes_cal_branding": "הסרת מיתוגים הקשורים ל-{{appName}}, כלומר 'מופעל על ידי {{appName}}'.",
|
||||
"removes_cal_branding": "הסרת מיתוגים הקשורים ל-{{appName}}, כגון 'מופעל על ידי {{appName}}'",
|
||||
"profile_picture": "תמונת פרופיל",
|
||||
"upload": "העלאה",
|
||||
"add_profile_photo": "הוספת תמונת פרופיל",
|
||||
@@ -1177,11 +1197,11 @@
|
||||
"rainbow_signature_error": "שגיאה בעת בקשת חתימה מהארנק.",
|
||||
"token_address": "כתובת הטוקן",
|
||||
"blockchain": "בלוקצ'יין",
|
||||
"old_password": "הסיסמה הקודמת",
|
||||
"old_password": "סיסמה ישנה",
|
||||
"secure_password": "הסיסמה החדשה והסופר מאובטחת שלך",
|
||||
"error_updating_password": "שגיאה בעת עדכון הסיסמה",
|
||||
"two_factor_auth": "אימות בשני גורמים",
|
||||
"recurring_event_tab_description": "הגדרת לוח זמנים חוזר",
|
||||
"two_factor_auth": "אימות דו-גורמי",
|
||||
"recurring_event_tab_description": "הגדרת ארוע חוזר",
|
||||
"today": "היום",
|
||||
"appearance": "מראה",
|
||||
"appearance_subtitle": "ניהול ההגדרות של מראה ההזמנות שלך",
|
||||
@@ -1215,6 +1235,7 @@
|
||||
"connect_automation_apps": "קישור אפליקציות אוטומציה",
|
||||
"connect_analytics_apps": "קישור אפליקציות ניתוח נתונים",
|
||||
"connect_other_apps": "חיבור אפליקציות אחרות",
|
||||
"connect_web3_apps": "חבר אפליקציות web3",
|
||||
"current_step_of_total": "שלב {{currentStep}} מתוך {{maxSteps}}",
|
||||
"add_variable": "להוסיף משתנה",
|
||||
"custom_phone_number": "מספר טלפון בהתאמה אישית",
|
||||
@@ -1231,6 +1252,7 @@
|
||||
"to": "אל",
|
||||
"workflow_turned_on_successfully": "תהליך העבודה {{workflowName}} הועבר למצב {{offOn}} בהצלחה",
|
||||
"download_responses": "להוריד תגובות",
|
||||
"download_responses_description": "הורד את כל התגובות לטופס שלך בפורמט CSV.",
|
||||
"download": "הורדה",
|
||||
"create_your_first_form": "צור/צרי את הטופס הראשון שלך",
|
||||
"create_your_first_form_description": "באמצעות טפסי ניתוב ניתן לשאול שאלות סיווג ולנתב אל האדם או אל סוג האירוע המתאימים.",
|
||||
@@ -1251,7 +1273,7 @@
|
||||
"workflow_example_4": "לשלוח למשתתף/ת תזכורת בדוא\"ל שעה אחת לפני תחילת האירועים",
|
||||
"workflow_example_5": "לשלוח דוא\"ל מותאם אישית למארח/ת כאשר המועד של אירוע משתנה",
|
||||
"workflow_example_6": "לשלוח הודעת SMS מותאמת אישית למארח/ת כאשר אירוע חדש מוזמן",
|
||||
"welcome_to_cal_header": "ברוך בואך ל-{{appName}}!",
|
||||
"welcome_to_cal_header": "ברוך הבא אל {{appName}}!",
|
||||
"edit_form_later_subtitle": "ניתן יהיה לערוך את זה מאוחר יותר.",
|
||||
"connect_calendar_later": "אקשר את לוח השנה שלי מאוחר יותר",
|
||||
"problem_saving_user_profile": "אירעה בעיה בשמירת הנתונים שלך. נסה/י שוב או פנה/י לשירות התמיכה.",
|
||||
@@ -1260,7 +1282,7 @@
|
||||
"booking_appearance": "מראה ההזמנה",
|
||||
"appearance_team_description": "ניהול ההגדרות של מראה הזמנות הצוות שלך",
|
||||
"only_owner_change": "רק הבעלים של הצוות יכולים לבצע שינויים בהזמנת הצוות ",
|
||||
"team_disable_cal_branding_description": "הסרת מיתוגים הקשורים ל-{{appName}}, כמו למשל 'מופעל על ידי {{appName}}'",
|
||||
"team_disable_cal_branding_description": "הסרת מיתוגים הקשורים ל-{{appName}}, כגון 'מופעל על ידי {{appName}}'",
|
||||
"invited_by_team": "הוזמנת על ידי {{teamName}} להצטרף לצוות בתפקיד {{role}}",
|
||||
"token_invalid_expired": "הטוקן לא חוקי או שתוקפו פג.",
|
||||
"exchange_add": "התחבר/י אל Microsoft Exchange",
|
||||
@@ -1272,6 +1294,8 @@
|
||||
"routing_forms_send_email_owner": "שליחת דוא\"ל לבעלים",
|
||||
"routing_forms_send_email_owner_description": "דוא\"ל נשלח לבעלים לאחר שליחת הטופס",
|
||||
"add_new_form": "הוספת טופס חדש",
|
||||
"create_your_first_route": "צור את המסלול הראשון שלך",
|
||||
"route_to_the_right_person": "מסלל לאדם הנכון בהתאם לתשובות בטופס שלך",
|
||||
"form_description": "צור/י טופס משלך כדי לנתב אל מזמין/ה",
|
||||
"copy_link_to_form": "להעתיק את הקישור לטופס",
|
||||
"theme": "ערכת נושא",
|
||||
@@ -1299,9 +1323,10 @@
|
||||
"back_to_signin": "חזרה לדף הכניסה",
|
||||
"reset_link_sent": "נשלח קישור לאיפוס",
|
||||
"password_reset_email": "שלחנו לך הודעת דוא\"ל עם הוראות לאיפוס הסיסמה לכתובת {{email}}.",
|
||||
"password_reset_leading": "אם הודעת הדוא\"ל לא תגיע בקרוב, ודא/י שכתובת הדוא\"ל שהזנת נכונה, בדוק/י אם ההודעה הגיעה לתיקיית דואר הזבל או פנה/י לתמיכה אם הבעיה נמשכת.",
|
||||
"password_reset_leading": "אם הודעת המייל לא תגיע בקרוב, ודא שכתובת הדוא\"ל שהזנת נכונה, בדוק אם ההודעה הגיעה לתיקיית דואר הזבל או פנה לתמיכה אם הבעיה נמשכת.",
|
||||
"password_updated": "הסיסמה עודכנה!",
|
||||
"pending_payment": "המתנה לתשלום",
|
||||
"pending_invites": "הזמנות ממתינות",
|
||||
"confirmation_page_rainbow": "הגן/י על האירוע שלך באמצעות טוקנים או אסימוני NFT במטבע Ethereum, Polygon ועוד.",
|
||||
"not_on_cal": "לא ב-{{appName}}",
|
||||
"no_calendar_installed": "לא מותקן לוח שנה",
|
||||
@@ -1315,7 +1340,7 @@
|
||||
"limit_booking_frequency": "הגבלת תדירות ההזמנות",
|
||||
"limit_booking_frequency_description": "הגבלת מספר הפעמים שבהן ניתן להזמין את האירוע הזה",
|
||||
"add_limit": "הוספת הגבלה",
|
||||
"team_name_required": "שם הצוות נדרש",
|
||||
"team_name_required": "נדרש שם צוות",
|
||||
"show_attendees": "שיתוף האורחים בפרטי המשתתפים",
|
||||
"how_additional_inputs_as_variables": "איך ניתן להשתמש בסוגי קלט נוספים כמשתנים",
|
||||
"format": "פורמט",
|
||||
@@ -1372,7 +1397,7 @@
|
||||
"saml_sp_entity_id_copied": "המזהה של ישות SP הועתק!",
|
||||
"saml_btn_configure": "הגדרה",
|
||||
"add_calendar": "הוספת לוח שנה",
|
||||
"limit_future_bookings": "הגבלת הזמנות עתידיות",
|
||||
"limit_future_bookings": "הגבלת תזמונים עתידיים",
|
||||
"limit_future_bookings_description": "הגבלת התאריך הרחוק ביותר בעתיד שעד אליו ניתן להזמין את האירוע הזה",
|
||||
"no_event_types": "לא הוגדר אף סוג אירוע",
|
||||
"no_event_types_description": "לא הוגדר על ידי {{name}} אף סוג אירוע שבאפשרותך להזמין.",
|
||||
@@ -1391,8 +1416,8 @@
|
||||
"team_url_required": "יש להזין כתובת URL של הצוות",
|
||||
"team_url_taken": "כתובת ה-URL הזו כבר תפוסה",
|
||||
"team_publish": "פרסום צוות",
|
||||
"number_sms_notifications": "מספר טלפון (הודעות SMS)",
|
||||
"attendee_email_variable": "כתובת הדוא\"ל של המשתתף/ת",
|
||||
"number_sms_notifications": "מספר טלפון (התראות SMS)",
|
||||
"attendee_email_variable": "כתובת הדוא\"ל של המשתתף",
|
||||
"attendee_email_info": "כתובת הדוא\"ל של האדם שביצע את ההזמנה",
|
||||
"kbar_search_placeholder": "הקלד/י פקודה או חפש/י...",
|
||||
"invalid_credential": "נראה שתוקף ההרשאה פג או שההרשאה בוטלה. יש להתקין מחדש שוב.",
|
||||
@@ -1428,6 +1453,9 @@
|
||||
"disabled_calendar": "אם התקנת לוח שנה אחר, ההזמנות החדשות יתווספו אליו. אם לא, קשר/י לוח שנה חדש כדי לא להחמיץ הזמנות חדשות.",
|
||||
"enable_apps": "הפעלת אפליקציות",
|
||||
"enable_apps_description": "להפעיל אפליקציות שמשתמשים יכולים לשלב עם Cal.com",
|
||||
"purchase_license": "רכוש רישיון",
|
||||
"already_have_key": "כבר יש לי מפתח:",
|
||||
"already_have_key_suggestion": "אנא העתק את משתנה הסביבה CALCOM_LICENSE_KEY הקיים שלך לכאן.",
|
||||
"app_is_enabled": "האפליקציה {{appName}} מופעלת",
|
||||
"app_is_disabled": "האפליקציה {{appName}} מושבתת",
|
||||
"keys_have_been_saved": "המפתחות נשמרו",
|
||||
@@ -1439,18 +1467,19 @@
|
||||
"no_available_apps_description": "ודא/י שיש אפליקציות בפריסה שלך בנתיב 'packages/app-store'",
|
||||
"no_apps": "אף אפליקציה לא מופעלת במופע הזה של Cal",
|
||||
"apps_settings": "הגדרות אפליקציות",
|
||||
"fill_this_field": "יש להזין מידע בשדה הזה",
|
||||
"fill_this_field": "נא מלא שדה זה",
|
||||
"options": "אפשרויות",
|
||||
"enter_option": "הזנת ה-{{index}} של האפשרות",
|
||||
"add_an_option": "הוספת אפשרות",
|
||||
"radio": "לחצן אפשרויות",
|
||||
"radio": "רדיו",
|
||||
"google_meet_warning": "כדי להשתמש ב-Google Meet, יש להגדיר את Google Calendar כלוח השנה של המארח",
|
||||
"individual": "משתמש בודד",
|
||||
"all_bookings_filter_label": "כל ההזמנות",
|
||||
"all_users_filter_label": "כל המשתמשים",
|
||||
"your_bookings_filter_label": "התזמונים שלך",
|
||||
"meeting_url_variable": "כתובת ה-URL של הפגישה",
|
||||
"meeting_url_info": "כתובת ה-URL של שיחת הוועידה באירוע",
|
||||
"date_overrides": "חפיפת תאריכים",
|
||||
"date_overrides": "תאריכים חופפים",
|
||||
"date_overrides_subtitle": "הוסף/י תאריכים שבהם הזמינות שלך שונה משעות העבודה הרגילות שלך מדי יום.",
|
||||
"date_overrides_info": "תאריכים שסומנו למעקף מועברים לארכיון באופן אוטומטי לאחר שהתאריך חולף",
|
||||
"date_overrides_dialog_which_hours": "באילו שעות את/ה פנוי/ה?",
|
||||
@@ -1486,6 +1515,7 @@
|
||||
"round_robin_hosts": "מארחים לפי סבב",
|
||||
"minimum_round_robin_hosts_count": "מספר המארחים שחייבים להשתתף",
|
||||
"hosts": "מארחים",
|
||||
"upgrade_to_enable_feature": "אתה צריך לייצר צוות כדי להפעיל את היכולת. לחץ ליצירת צוות.",
|
||||
"new_attendee": "משתתף/ת חדש/ה",
|
||||
"awaiting_approval": "בהמתנה לאישור",
|
||||
"requires_google_calendar": "האפליקציה הזו מחייבת חיבור ל-Google Calendar",
|
||||
@@ -1494,9 +1524,119 @@
|
||||
"continue_to_install_google_calendar": "המשך להתקנת Google Calendar",
|
||||
"install_google_meet": "התקנת Google Meet",
|
||||
"install_google_calendar": "התקנת Google Calendar",
|
||||
"sender_name": "שם השולח",
|
||||
"already_invited": "הנמען כבר הוזמן",
|
||||
"no_recordings_found": "לא נמצאו הקלטות",
|
||||
"new_workflow_subtitle": "צור תהליך חדש עבור...",
|
||||
"reporting": "דוחות",
|
||||
"reporting_feature": "ראה את כל המידע הנכנס והורד אותו כ- CSV",
|
||||
"teams_plan_required": "נדרש תוכנית צוותים",
|
||||
"routing_forms_are_a_great_way": "טפסי ניתוב הם דרך מעולה לנתב לידים נכנסים לאדם המתאים. שדרג לתוכנית צוותים לגישה ליכולת זו.",
|
||||
"choose_a_license": "בחר רישיון",
|
||||
"choose_license_description": "Cal.com מגיע עם רישיון AGPLv3 נגיש וחינמי עם כמה מגבלות שניתן לשדרג לתוכנית Enterprise בכל עת לקבלת גישה אליהן. אתה יכול לשדרג בכל מועד עתידי.",
|
||||
"license": "רישיון",
|
||||
"agplv3_license": "רישיון AGPLv3",
|
||||
"ee_enterprise_license": "\"ee/\" רישיון Enterprise",
|
||||
"enterprise_booking_fee": "החל מ- {{enterprise_booking_fee}}/לחודש",
|
||||
"enterprise_license_includes": "הכל לשימוש מסחרי",
|
||||
"no_need_to_keep_your_code_open_source": "אין צורך לשמור את הקוד שלך כקוד פתוח",
|
||||
"repackage_rebrand_resell": "אריזה מחדש, מיתוג מחדש ומכירה בקלות",
|
||||
"a_vast_suite_of_enterprise_features": "מגוון יכולות Enterprise עצום",
|
||||
"free_license_fee": "$0.00/לחודש",
|
||||
"forever_open_and_free": "פתוח וחינם לתמיד",
|
||||
"required_to_keep_your_code_open_source": "נדרש על מנת לשמור את הקוד שלך כקוד פתוח",
|
||||
"cannot_repackage_and_resell": "לא ניתן לבצע אריזה מחדש, מיתוג מחדש ומכירה בקלות",
|
||||
"no_enterprise_features": "אין יכולות Enterprise",
|
||||
"step_enterprise_license": "רישיון Enterprise",
|
||||
"step_enterprise_license_description": "כל מה שמימוש מסחרי צריך עם אחסון פרטי, אריזה מחדש, מיתוג מחדש ומכירה עם גישה בלעדית ליכולות Enterprise.",
|
||||
"setup": "התקנה",
|
||||
"setup_description": "התקנת מופע Cal.com",
|
||||
"configure": "הגדרה",
|
||||
"sso_configuration": "כניסה בודדת",
|
||||
"sso_configuration": "כניסת הזדהות אחידה SSO",
|
||||
"sso_configuration_description": "הגדר SSO מסוג SAML/OIDC ואפשר לחברי הצוות לבצע כניסה עם ספק הזדהות",
|
||||
"sso_oidc_heading": "SSO עם OIDC",
|
||||
"sso_oidc_description": "הגדר SSO מסוג OIDC עם ספק ההזדהות שאתה רוצה.",
|
||||
"sso_oidc_configuration_title": "הגדרות OIDC",
|
||||
"sso_oidc_configuration_description": "הגדרת חיבור OIDC לספק ההזדהות שלך. אתה יכול למצוא את כל המידע הדרוש אצל ספק ההזדהות שלך.",
|
||||
"sso_oidc_callback_copied": "הועתק כתובת קישור Callback",
|
||||
"sso_saml_heading": "SSO עם SAML",
|
||||
"sso_saml_description": "הגדר SSO מסוג SAML עם ספק ההזדהות שאתה רוצה.",
|
||||
"sso_saml_configuration_title": "הגדרות SAML",
|
||||
"sso_saml_configuration_description": "הגדרת חיבור SAML לספק ההזדהות שלך. אתה יכול למצוא את כל המידע הדרוש אצל ספק ההזדהות שלך.",
|
||||
"sso_saml_acsurl_copied": "הועתק כתובת קישור ACS",
|
||||
"sso_saml_entityid_copied": "הועתק Entity ID",
|
||||
"sso_connection_created_successfully": "הגדרות {{connectionType}} נוצרו בהצלחה",
|
||||
"sso_connection_deleted_successfully": "הגדרות {{connectionType}} נמחקו בהצלחה",
|
||||
"delete_sso_configuration": "מחק את הגדרות {{connectionType}}",
|
||||
"delete_sso_configuration_confirmation": "כן, מחק את הגדרות {{connectionType}}",
|
||||
"delete_sso_configuration_confirmation_description": "אתה בטוח שאתה רוצה למחוק את הגדרות {{connectionType}}? חברי הצוות שלך שמשתמשים ב- {{connectionType}} להזדהות לא יוכלו להשתמש בו להכנס ל- Cal.com.",
|
||||
"organizer_timezone": "מארגן אזורי זמן",
|
||||
"email_no_user_cta": "צור את החשבון שלך",
|
||||
"email_user_cta": "צפה בהזמנה",
|
||||
"email_no_user_invite_heading": "הוזמנת להצטרף לצוות ב- {{appName}}",
|
||||
"email_no_user_invite_subheading": "{{invitedBy}} הזמין אותך להצטרף לצוות שלו ב- {{appName}}. {{appName}} הינה מתזמן זימונים שמאפשר לך ולצוות שלך לזמן פגישות בלי כל הפינג פונג במיילים.",
|
||||
"email_no_user_invite_steps_intro": "אנחנו נדריך אותך במספר צעדים קצרים ואתה תהנה תזמון נטול מתח עם הצוות שלך כהרף עין.",
|
||||
"email_no_user_step_one": "בחר שם משתמש",
|
||||
"email_no_user_step_two": "קשר את לוח השנה שלך",
|
||||
"email_no_user_step_three": "הגדר את הזמינות שלך",
|
||||
"email_no_user_step_four": "הצטרף ל- {{teamName}}",
|
||||
"email_no_user_signoff": "תזמון פגישות נעים מצוות {{appName}}",
|
||||
"impersonation_user_tip": "אתה עומד להתחזות למשתמש, זה אומר שאתה יכול לעשות שינויים בשמו. אנא הזהר.",
|
||||
"available_variables": "משתנים זמינים",
|
||||
"scheduler": "{Scheduler}",
|
||||
"no_workflows": "אין תהליכים",
|
||||
"change_filter": "שנה את הסנן כדי לראות תהליכים אישיים וצוותים.",
|
||||
"recommended_next_steps": "הצעדים הבאים המומלצים",
|
||||
"create_a_managed_event": "צור ארוע מנוהל",
|
||||
"meetings_are_better_with_the_right": "פגישות טובות יותר עם אנשי הצוות הנכונים נמצאים בו. הזמן אותם עכשיו.",
|
||||
"create_a_one_one_template": "צור תבנית לתזמון פגישות אחד על אחד והפץ אותם למספר משתמשים.",
|
||||
"collective_or_roundrobin": "כולם או טורי",
|
||||
"book_your_team_members": "הזמן את אנשי הצוות שלך ביחד עם ארועים מסוג כולם או עבור על פניהם לבחירת האדם הנכון עם טורי.",
|
||||
"create_event_on": "צור ארוע ב-",
|
||||
"default_app_link_title": "צור קישור אפליקציה ברירת מחדל",
|
||||
"default_app_link_description": "הגדרת קישור אפליקציה ברירת מחדל מאפשר לכל הארועים החדשים להשתמש בקישור שהגדרת.",
|
||||
"change_default_conferencing_app": "להגדיר כברירת מחדל",
|
||||
"booking_confirmation_failed": "אישור ההזמנה נכשל"
|
||||
"under_maintenance": "אינו זמין עקב תחזוקה",
|
||||
"under_maintenance_description": "צוות {{appName}} מבצע עבודות תחזוקה שתוכננו מראש. אם יש לך שאלות, נא צור קשר עם התמיכה.",
|
||||
"event_type_seats": "{{numberOfSeats}} מושבים",
|
||||
"booking_questions_title": "שאלות תזמון",
|
||||
"booking_questions_description": "התאמת השאלות שנשאלות בדף התזמון",
|
||||
"add_a_booking_question": "הוסף שאלה",
|
||||
"duplicate_email": "מייל כבר קיים",
|
||||
"booking_with_payment_cancelled": "תשלום עבור ארוע זה כבר אינו נתמך",
|
||||
"booking_with_payment_cancelled_already_paid": "זיכוי עבור התשלום של תזמון זה כבר בדרך.",
|
||||
"booking_with_payment_cancelled_refunded": "התשלום עבור תזמון זה זוכה.",
|
||||
"booking_confirmation_failed": "אישור ההזמנה נכשל",
|
||||
"form_builder_field_already_exists": "שדה עם שם זה כבר קיים",
|
||||
"form_builder_field_add_subtitle": "התאמת השאלות שנשאלות בדף התזמון",
|
||||
"form_builder_system_field_cant_delete": "שדה מערכת זה לא ניתן להסרה.",
|
||||
"form_builder_system_field_cant_toggle": "שדה מערכת זה לא ניתן לשינוי.",
|
||||
"get_started_zapier_templates": "התחל עם תבניות Zapier",
|
||||
"team_member": "חבר צוות",
|
||||
"a_routing_form": "טופס ניתוב",
|
||||
"form_description_placeholder": "תיאור הטופס",
|
||||
"keep_me_connected_with_form": "שמור אותי מחובר לטופס",
|
||||
"fields_in_form_duplicated": "כל שינוי בניתוב ובשדות הטופס שמשוכפל, ישפיעו על הטופס המשוכפל.",
|
||||
"form_deleted": "הטופס נמחק",
|
||||
"delete_form": "מחק טופס",
|
||||
"delete_form_action": "כן, מחק את הטופס",
|
||||
"delete_form_confirmation": "אתה בטוח שאתה רוצה למחוק את הטופס? כל מי ששיתפת עמו את הקישור לא יוכל יותר לתזמן באמצעותו. בנוסף, כל התגובות הקשורות אליו ימחקו.",
|
||||
"typeform_redirect_url_copied": "קישור הפניה TypeForm הועתק! אתה יכול ללכת ולהגדיר את הקישור בטופס ה- Typeform שלך.",
|
||||
"modifications_in_fields_warning": "שינויים בשדות וניתובים של הטפסים הבאים ישפיעו על טופס זה.",
|
||||
"connected_forms": "טפסים מחוברים",
|
||||
"form_modifications_warning": "הטפסים הבאים יושפעו כשאתה משנה שדות או ניתובים כאן.",
|
||||
"responses_collection_waiting_description": "חכה זמן מה עד לאיסוף תגובות. אתה גם יכול ללכת ולשלוח טופס בעצמך.",
|
||||
"this_is_what_your_users_would_see": "זה מה שהמשתמשים שלך היו רואים",
|
||||
"identifies_name_field": "מזהה שדה לפי שם זה.",
|
||||
"add_1_option_per_line": "הוסף אפשרות 1 לכל שורה",
|
||||
"select_a_router": "בחר נתב",
|
||||
"add_a_new_route": "הוסף נתיב חדש",
|
||||
"no_responses_yet": "אין עדיין תגובות",
|
||||
"this_will_be_the_placeholder": "זה יהיה הממלא מקום",
|
||||
"verification_code": "קוד אימות",
|
||||
"verify": "אמת",
|
||||
"select_all": "בחר הכל",
|
||||
"default_conferencing_bulk_title": "בצע עדכון אצווה של סוגי הארועים הקיימים",
|
||||
"default_conferencing_bulk_description": "עדכן את המיקומים עבור סוגי הארועים שנבחרו",
|
||||
"invalid_event_name_variables": "יש משתנה שגוי בשם הארוע שלך"
|
||||
}
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
"upgrade_now": "Upgrade sekarang",
|
||||
"accept_invitation": "Terima undangan",
|
||||
"calcom_explained": "{{appName}} menyediakan infrastruktur penjadwalan untuk semua orang.",
|
||||
"calcom_explained_new_user": "Selesaikan pengaturan akun {{appName}}! Tinggal selangkah lagi untuk solusi penjadwalan kamu.",
|
||||
"have_any_questions": "Punya pertanyaan? Kami siap membantu.",
|
||||
"reset_password_subject": "{{appName}}: Petunjuk pengaturan ulang kata sandi",
|
||||
"event_declined_subject": "Ditolak: {{title}} pada {{date}}",
|
||||
@@ -23,6 +24,7 @@
|
||||
"rejection_reason_description": "Kamu yakin menolak pemesanan? Kami akan memberitahu orang yang memesan. Kamu bisa menyediakan alasan di bawah ini.",
|
||||
"rejection_confirmation": "Tolak pesanan",
|
||||
"manage_this_event": "Kelola acara ini",
|
||||
"invite_team_member": "Undang anggota tim",
|
||||
"your_event_has_been_scheduled": "Acara kamu telah terjadwal",
|
||||
"your_event_has_been_scheduled_recurring": "Acara berulang kamu telah terjadwal",
|
||||
"accept_our_license": "Setujui lisensi dengan mengganti variabel .env <1>NEXT_PUBLIC_LICENSE_CONSENT</1> menjadi {{agree}}.",
|
||||
@@ -48,6 +50,32 @@
|
||||
"open_env": "Buka .env dan setujui lisensi kami",
|
||||
"env_changed": "Saya telah mengubah .env saya",
|
||||
"accept_license": "Terima Lisensi",
|
||||
"still_waiting_for_approval": "Satu acara menunggu persetujuan",
|
||||
"event_is_still_waiting": "Permintaan acara masih menunggu: {{attendeeName}} - {{date}} - {{eventType}}",
|
||||
"no_more_results": "Tidak ada lagi",
|
||||
"no_results": "Tidak ada hasil",
|
||||
"load_more_results": "Muat lagi",
|
||||
"integration_meeting_id": "{{integrationName}} ID pertemuan: {{meetingId}}",
|
||||
"confirmed_event_type_subject": "Terkonfirmasi: {{eventType}} dengan {{name}} pada {{date}}",
|
||||
"new_event_request": "Permintaan acara baru: {{attendeeName}} - {{date}} - {{eventType}}",
|
||||
"confirm_or_reject_request": "Konfirmasi atau tolak permintaan",
|
||||
"check_bookings_page_to_confirm_or_reject": "Periksa halaman penjadwalan untuk mengkonfirmasi atau menolak.",
|
||||
"event_awaiting_approval": "Sebuah acara menunggu persetujuanmu",
|
||||
"event_awaiting_approval_recurring": "Acara berulang menunggu persetujuanmu",
|
||||
"someone_requested_an_event": "Sesorang mengirimkan permintaan penjadwalan acara di kalender kamu.",
|
||||
"someone_requested_password_reset": "Seseorang mengirimkan link permintaan penggantian kata sandi.",
|
||||
"password_reset_instructions": "Jika kamu tidak meminta ini, hiraukan email ini dan kata sandi tidak akan diganti.",
|
||||
"event_awaiting_approval_subject": "Menunggu persetujuan: {{title}} pada {{date}}",
|
||||
"event_still_awaiting_approval": "Sebuah acara masih menunggu persetujuanmu",
|
||||
"booking_submitted_subject": "Pendaftaran Terkirim: {{title}} pada {{date}}",
|
||||
"your_meeting_has_been_booked": "Pertemuanmu telah terdaftar",
|
||||
"event_type_has_been_rescheduled_on_time_date": "{{title}} kamu telah dijadwalkan ulang menjadi {{date}}.",
|
||||
"event_has_been_rescheduled": "Terkini - Acara kamu telah dijadwalkan ulang",
|
||||
"request_reschedule_title_attendee": "Minta untuk penjadwalan ulang",
|
||||
"request_reschedule_subtitle": "{{organizer}} telah membatalkan acara dan meminta kamu untuk memilih waktu lain.",
|
||||
"request_reschedule_title_organizer": "Kamu telah meminta {{attendee}} untuk menjadwalkan ulang",
|
||||
"request_reschedule_subtitle_organizer": "Kamu telah membatalkan acara dan {{attendee}} akan memilih waktu lain.",
|
||||
"rescheduled_event_type_subject": "Permintaan penjadwalan ulang terkirim: {{eventType}} dengan {{name}} pada {{date}}",
|
||||
"team_info": "Informasi Tim",
|
||||
"request_another_invitation_email": "Jika kamu lebih suka tidak menggukan {{toEmail}} sebagai email {{appName}} atau telah memiliki akun {{appName}} silakan membuat permintaan lain kepada email tersebut.",
|
||||
"you_have_been_invited": "Kamu telah diundang untuk bergabung ke tim {{teamName}}",
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
"upgrade_now": "Cambia piano",
|
||||
"accept_invitation": "Accetta Invito",
|
||||
"calcom_explained": "{{appName}} fornisce un'infrastruttura di panificazione aperta a tutti.",
|
||||
"calcom_explained_new_user": "Completa la configurazione del tuo account {{appName}}! Mancano solo pochi passi per risolvere tutti i problemi di pianificazione.",
|
||||
"have_any_questions": "Hai domande? Siamo qui per aiutare.",
|
||||
"reset_password_subject": "{{appName}}: istruzioni per reimpostare la password",
|
||||
"event_declined_subject": "Rifiutato: {{title}} il {{date}}",
|
||||
@@ -23,6 +24,8 @@
|
||||
"rejection_reason_description": "Sei sicuro di voler rifiutare la prenotazione? Informeremo la persona che ha cercato di prenotare. Puoi indicare il motivo qui sotto.",
|
||||
"rejection_confirmation": "Rifiuta la prenotazione",
|
||||
"manage_this_event": "Gestisci questo evento",
|
||||
"invite_team_member": "Invia un membro del team",
|
||||
"invite_team_notifcation_badge": "Inv.",
|
||||
"your_event_has_been_scheduled": "Il tuo evento è stato programmato",
|
||||
"your_event_has_been_scheduled_recurring": "Il tuo evento ricorrente è stato programmato",
|
||||
"accept_our_license": "Accetta la nostra licenza cambiando la variabile .env <1>NEXT_PUBLIC_LICENSE_CONSENT</1> a '{{agree}}'.",
|
||||
@@ -410,6 +413,8 @@
|
||||
"password_updated_successfully": "Webhook aggiornato con successo",
|
||||
"password_has_been_changed": "La password è stata cambiata con successo.",
|
||||
"error_changing_password": "Errore nel cambiare la password",
|
||||
"session_timeout_changed": "La configurazione della sessione è stata aggiornata correttamente.",
|
||||
"session_timeout_change_error": "Errore durante l'aggiornamento della configurazione della sessione",
|
||||
"something_went_wrong": "Qualcosa è andato storto.",
|
||||
"something_doesnt_look_right": "Qualcosa non sembra giusto?",
|
||||
"please_try_again": "Per favore riprova.",
|
||||
@@ -428,6 +433,7 @@
|
||||
"password_hint_num": "Deve contenere almeno 1 numero",
|
||||
"invalid_password_hint": "La password deve avere una lunghezza minima di {{passwordLength}} caratteri e deve contenere almeno 1 numero e una combinazione di caratteri maiuscoli e minuscoli",
|
||||
"incorrect_password": "La password non è corretta.",
|
||||
"incorrect_username_password": "Nome utente o password errati.",
|
||||
"24_h": "24 ore",
|
||||
"use_setting": "Usa impostazione",
|
||||
"am_pm": "am/pm",
|
||||
@@ -455,6 +461,7 @@
|
||||
"slots_load_fail": "Impossibile caricare gli intervalli di tempo disponibili.",
|
||||
"additional_guests": "Aggiungi ospiti",
|
||||
"your_name": "Il tuo nome",
|
||||
"your_full_name": "Nome completo",
|
||||
"email_address": "Indirizzo email",
|
||||
"enter_valid_email": "Immettere un indirizzo e-mail valido",
|
||||
"location": "Luogo",
|
||||
@@ -508,6 +515,8 @@
|
||||
"admin": "Amministratore",
|
||||
"administrator_user": "Utente amministratore",
|
||||
"lets_create_first_administrator_user": "Creiamo il primo utente amministratore.",
|
||||
"admin_user_created": "Impostazione utente amministratore",
|
||||
"admin_user_created_description": "Hai già creato un utente amministratore. Puoi effettuare l'accesso al tuo account.",
|
||||
"new_member": "Nuovo Membro",
|
||||
"invite": "Invita",
|
||||
"add_team_members": "Aggiungi membri del team",
|
||||
@@ -589,7 +598,6 @@
|
||||
"new_event_type_heading": "Crea il tuo primo tipo di evento",
|
||||
"new_event_type_description": "I tipi di eventi ti permettono di condividere i link che mostrano gli orari disponibili sul tuo calendario e consentire alle persone di effettuare prenotazioni con te.",
|
||||
"new_event_title": "Aggiungi un nuovo tipo di evento",
|
||||
"new_event_subtitle": "Crea un tipo di evento sotto il tuo nome o un team.",
|
||||
"new_team_event": "Aggiungi un nuovo tipo di evento del team",
|
||||
"new_event_description": "Crea un nuovo tipo di evento per le persone con cui prenotare.",
|
||||
"event_type_created_successfully": "{{eventTypeTitle}} tipo di evento creato con successo",
|
||||
@@ -658,6 +666,7 @@
|
||||
"edit_availability": "Modifica disponibilità",
|
||||
"configure_availability": "Cambia quando sei disponibile per le prenotazioni.",
|
||||
"copy_times_to": "Copia orari in",
|
||||
"copy_times_to_tooltip": "Copia orari in…",
|
||||
"change_weekly_schedule": "Cambia il tuo programma settimanale",
|
||||
"logo": "Logo",
|
||||
"error": "Errore",
|
||||
@@ -669,6 +678,7 @@
|
||||
"add_attendees": "Aggiungi partecipanti",
|
||||
"show_advanced_settings": "Mostra impostazioni avanzate",
|
||||
"event_name": "Nome Dell'Evento",
|
||||
"event_name_in_calendar": "Nome dell'evento nel calendario",
|
||||
"event_name_tooltip": "Il nome che apparirà nei calendari",
|
||||
"meeting_with_user": "Riunione con {{attendeeName}}",
|
||||
"additional_inputs": "Input Aggiuntivi",
|
||||
@@ -787,6 +797,7 @@
|
||||
"number_apps_one": "{{count}} App",
|
||||
"number_apps_other": "{{count}} app",
|
||||
"trending_apps": "App di tendenza",
|
||||
"most_popular": "Più popolari",
|
||||
"explore_apps": "App {{category}}",
|
||||
"installed_apps": "App installate",
|
||||
"free_to_use_apps": "Gratuito",
|
||||
@@ -797,12 +808,14 @@
|
||||
"no_category_apps_description_analytics": "Aggiungi un'app di analisi per le tue pagine di prenotazione",
|
||||
"no_category_apps_description_automation": "Aggiungi un'app di automazione da usare",
|
||||
"no_category_apps_description_other": "Aggiungi qualsiasi altra app per fare altre attività",
|
||||
"no_category_apps_description_web3": "Aggiungi un'app Web3 per le tue pagine di prenotazione",
|
||||
"installed_app_calendar_description": "Imposta uno o più calendari per controllare i conflitti ed evitare doppie prenotazioni.",
|
||||
"installed_app_conferencing_description": "Aggiungi le tue app di videoconferenza preferite per le tue riunioni",
|
||||
"installed_app_payment_description": "Configura quale servizio di elaborazione dei pagamenti usare per addebitare i clienti.",
|
||||
"installed_app_analytics_description": "Imposta quali app di analisi usare per le tue pagine di prenotazione",
|
||||
"installed_app_other_description": "Tutte le app installate appartenenti ad altre categorie.",
|
||||
"installed_app_automation_description": "Imposta quali app di automazione usare",
|
||||
"installed_app_web3_description": "Imposta quali app Web3 usare per le tue pagine di prenotazione",
|
||||
"analytics": "Analisi",
|
||||
"empty_installed_apps_headline": "Nessuna app installata",
|
||||
"empty_installed_apps_description": "Le app consentono di ottimizzare il flusso di lavoro e di migliorare significativamente la pianificazione.",
|
||||
@@ -930,6 +943,11 @@
|
||||
"current_location": "Luogo corrente",
|
||||
"user_phone": "Il tuo numero di telefono",
|
||||
"new_location": "Nuovo luogo",
|
||||
"session": "Sessione",
|
||||
"session_description": "Controlla la sessione del tuo account",
|
||||
"session_timeout_after": "Timeout sessione dopo",
|
||||
"session_timeout": "Timeout sessione",
|
||||
"session_timeout_description": "Invalida la sessione dopo un determinato periodo di tempo.",
|
||||
"no_location": "Nessun luogo definito",
|
||||
"set_location": "Imposta luogo",
|
||||
"update_location": "Aggiorna luogo",
|
||||
@@ -1073,6 +1091,7 @@
|
||||
"broken_video_action": "Non è stato possibile aggiungere il link della riunione di <1>{{location}}</1> al tuo evento programmato. Contatta gli invitati o aggiorna l'evento sul tuo calendario per aggiungere i dettagli. È possibile <3> cambiare il luogo del tipo di evento </3> oppure provare a <5>rimuovere l'app e aggiungerla nuovamente.</5>",
|
||||
"broken_calendar_action": "Non è stato possibile aggiornare il tuo <1>{{calendar}}</1>. <2> Controlla le impostazioni del tuo calendario oppure rimuovi il calendario e aggiungilo nuovamente </2>",
|
||||
"attendee_name": "Nome del partecipante",
|
||||
"scheduler_full_name": "Nome completo della persona che prenota",
|
||||
"broken_integration": "Integrazione non funzionante",
|
||||
"problem_adding_video_link": "Si è verificato un problema durante l'aggiunta di un collegamento video",
|
||||
"problem_updating_calendar": "Si è verificato un problema durante l'aggiornamento del calendario",
|
||||
@@ -1215,6 +1234,7 @@
|
||||
"connect_automation_apps": "Connetti app di automazione",
|
||||
"connect_analytics_apps": "Connetti app di analisi",
|
||||
"connect_other_apps": "Connetti altre app",
|
||||
"connect_web3_apps": "Connetti app Web3",
|
||||
"current_step_of_total": "Passo {{currentStep}} di {{maxSteps}}",
|
||||
"add_variable": "Aggiungi variabile",
|
||||
"custom_phone_number": "Numero di telefono personalizzato",
|
||||
@@ -1231,6 +1251,7 @@
|
||||
"to": "A",
|
||||
"workflow_turned_on_successfully": "Il flusso di lavoro {{workflowName}} è stato impostato come {{offOn}}",
|
||||
"download_responses": "Scarica risposte",
|
||||
"download_responses_description": "Scarica tutte le risposte al tuo modulo in formato CSV.",
|
||||
"download": "Scarica",
|
||||
"create_your_first_form": "Crea il tuo primo modulo",
|
||||
"create_your_first_form_description": "I Moduli di instradamento consentono di porre domande qualificanti agli utenti per indirizzarli a persone o eventi pertinenti.",
|
||||
@@ -1272,6 +1293,8 @@
|
||||
"routing_forms_send_email_owner": "Invia e-mail al proprietario",
|
||||
"routing_forms_send_email_owner_description": "Invia un'e-mail al proprietario quando il modulo viene inviato",
|
||||
"add_new_form": "Aggiungi nuovo modulo",
|
||||
"create_your_first_route": "Crea il tuo primo percorso",
|
||||
"route_to_the_right_person": "Instrada gli utenti alla persona giusta in base alle risposte al modulo",
|
||||
"form_description": "Crea un modulo per instradare le persone che prenotano",
|
||||
"copy_link_to_form": "Copia il link del modulo",
|
||||
"theme": "Tema",
|
||||
@@ -1302,6 +1325,7 @@
|
||||
"password_reset_leading": "Se un'e-mail non ti dovesse arrivare a breve, assicurati che l'indirizzo specificato sia corretto e controlla la cartella della posta indesiderata. Se il problema persiste, contatta l'assistenza clienti.",
|
||||
"password_updated": "Password aggiornata!",
|
||||
"pending_payment": "Pagamento in sospeso",
|
||||
"pending_invites": "Inviti in sospeso",
|
||||
"confirmation_page_rainbow": "Proteggi i tuoi eventi con token o NFT su Ethereum, Polygon e altri.",
|
||||
"not_on_cal": "Non presente su {{appName}}",
|
||||
"no_calendar_installed": "Nessun calendario installato",
|
||||
@@ -1428,6 +1452,9 @@
|
||||
"disabled_calendar": "Se hai un altro calendario installato, le nuove prenotazioni saranno aggiunte a quel calendario. Altrimenti, collega un nuovo calendario in modo da non perdere nessuna nuova prenotazione.",
|
||||
"enable_apps": "Abilita app",
|
||||
"enable_apps_description": "Abilita le app che gli utenti possono integrare con Cal.com",
|
||||
"purchase_license": "Acquista una licenza",
|
||||
"already_have_key": "Ho già una chiave:",
|
||||
"already_have_key_suggestion": "Copia qui la variabile di ambiente CALCOM_LICENSE_KEY esistente.",
|
||||
"app_is_enabled": "{{appName}} è abilitato",
|
||||
"app_is_disabled": "{{appName}} è disabilitato",
|
||||
"keys_have_been_saved": "Le chiavi sono state salvate",
|
||||
@@ -1448,6 +1475,7 @@
|
||||
"individual": "Persona",
|
||||
"all_bookings_filter_label": "Tutte le prenotazioni",
|
||||
"all_users_filter_label": "Tutti gli utenti",
|
||||
"your_bookings_filter_label": "Le tue prenotazioni",
|
||||
"meeting_url_variable": "URL della riunione",
|
||||
"meeting_url_info": "URL dell'evento, dell'incontro o della conferenza",
|
||||
"date_overrides": "Configurazione date specifiche",
|
||||
@@ -1486,6 +1514,7 @@
|
||||
"round_robin_hosts": "Organizzatori round robin",
|
||||
"minimum_round_robin_hosts_count": "Numero di organizzatori necessario per partecipare",
|
||||
"hosts": "Organizzatori",
|
||||
"upgrade_to_enable_feature": "Per abilitare questa funzione, è necessario creare un team. Fai clic per creare un team.",
|
||||
"new_attendee": "Nuovo partecipante",
|
||||
"awaiting_approval": "In attesa di approvazione",
|
||||
"requires_google_calendar": "L'app richiede una connessione a Google Calendar",
|
||||
@@ -1494,9 +1523,106 @@
|
||||
"continue_to_install_google_calendar": "Continua e installa Google Calendar",
|
||||
"install_google_meet": "Installa Google Meet",
|
||||
"install_google_calendar": "Installa Google Calendar",
|
||||
"sender_name": "Nome mittente",
|
||||
"already_invited": "Partecipante già invitato",
|
||||
"no_recordings_found": "Nessuna registrazione trovata",
|
||||
"new_workflow_subtitle": "Nuovo flusso di lavoro per...",
|
||||
"reporting": "Reporting",
|
||||
"reporting_feature": "Visualizza tutti i dati in arrivo e scaricali in formato CSV",
|
||||
"teams_plan_required": "Piano Team richiesto",
|
||||
"routing_forms_are_a_great_way": "I moduli di instradamento sono un ottimo strumento per instradare i lead in arrivo alle persone giuste. Per accedere a questa funzione, effettuare l'upgrade al piano Team.",
|
||||
"choose_a_license": "Scegli una licenza",
|
||||
"choose_license_description": "Cal.com viene fornito con una licenza AGPLv3 accessibile e gratuita che ha alcune limitazioni e può essere aggiornata a Enterprise in qualsiasi momento. È possibile effettuare l'upgrade in un secondo tempo.",
|
||||
"license": "Licenza",
|
||||
"agplv3_license": "Licenza AGPLv3",
|
||||
"ee_enterprise_license": "Licenza Enterprise “/ee”",
|
||||
"enterprise_booking_fee": "A partire da {{enterprise_booking_fee}}/mese",
|
||||
"enterprise_license_includes": "Tutto il necessario per l'utilizzo commerciale",
|
||||
"no_need_to_keep_your_code_open_source": "Non c'è bisogno di mantenere il codice open-source",
|
||||
"repackage_rebrand_resell": "Rimonta e rivendi sotto un nuovo marchio",
|
||||
"a_vast_suite_of_enterprise_features": "Un'estesa suite di funzionalità enterprise",
|
||||
"free_license_fee": "0,00 $/mese",
|
||||
"forever_open_and_free": "Aperto e gratuito per sempre",
|
||||
"required_to_keep_your_code_open_source": "È necessario mantenere il codice open-source",
|
||||
"cannot_repackage_and_resell": "Impossibile rimontare e rivendere sotto un nuovo marchio",
|
||||
"no_enterprise_features": "Nessuna funzionalità enterprise",
|
||||
"step_enterprise_license": "Licenza Enterprise",
|
||||
"step_enterprise_license_description": "Tutto il necessario per l'utilizzo commerciale con hosting privato, rimontaggio, rebranding e rivendita e accesso ai componenti enterprise esclusivi.",
|
||||
"setup": "Impostazione",
|
||||
"setup_description": "Imposta istanza Cal.com",
|
||||
"configure": "Configura",
|
||||
"sso_configuration": "Configurazione SAML",
|
||||
"sso_configuration_description": "Configura accesso SSO tramite SAML/OIDC e consenti ai membri del team di accedere utilizzando un provider di identità",
|
||||
"sso_oidc_heading": "SSO con OIDC",
|
||||
"sso_oidc_description": "Configura accesso SSO tramite OIDC con un provider di identità di tua scelta.",
|
||||
"sso_oidc_configuration_title": "Configurazione OIDC",
|
||||
"sso_oidc_configuration_description": "Configura la connessione OIDC al tuo provider di identità. Puoi trovare le informazioni necessarie presso il tuo provider di identità.",
|
||||
"sso_oidc_callback_copied": "URL di callback copiato",
|
||||
"sso_saml_heading": "SSO con SAML",
|
||||
"sso_saml_description": "Configura accesso SSO tramite SAML con un provider di identità di tua scelta.",
|
||||
"sso_saml_configuration_title": "Configurazione SAML",
|
||||
"sso_saml_configuration_description": "Configura la connessione SAML al tuo provider di identità. Puoi trovare le informazioni necessarie presso il tuo provider di identità.",
|
||||
"sso_saml_acsurl_copied": "URL dell'ACS copiato",
|
||||
"sso_saml_entityid_copied": "ID entità copiato",
|
||||
"sso_connection_created_successfully": "Configurazione {{connectionType}} creata correttamente",
|
||||
"sso_connection_deleted_successfully": "Configurazione {{connectionType}} eliminata correttamente",
|
||||
"delete_sso_configuration": "Eliminare la configurazione {{connectionType}}",
|
||||
"delete_sso_configuration_confirmation": "Sì, elimina la configurazione {{connectionType}}",
|
||||
"delete_sso_configuration_confirmation_description": "Eliminare la configurazione {{connectionType}}? I membri del tuo team che utilizzano l'accesso {{connectionType}} non saranno più in grado di accedere a Cal.com.",
|
||||
"organizer_timezone": "Fuso orario organizzatore",
|
||||
"email_no_user_cta": "Crea il tuo account",
|
||||
"email_user_cta": "Visualizza invito",
|
||||
"email_no_user_invite_heading": "Sei stato invitato a unirti al team su {{appName}}",
|
||||
"email_no_user_invite_subheading": "{{invitedBy}} ti ha invitato a unirti al suo team su {{appName}}. {{appName}} è uno strumento di pianificazione di eventi che permette al tuo team di pianificare le riunioni senza scambiare decine di e-mail.",
|
||||
"email_no_user_invite_steps_intro": "Ti assisteremo nei passaggi iniziali in modo che tu possa pianificare eventi per il tuo team senza stress e in pochissimo tempo.",
|
||||
"email_no_user_step_one": "Scegli il tuo nome utente",
|
||||
"email_no_user_step_two": "Collega il tuo account di calendario",
|
||||
"email_no_user_step_three": "Imposta la tua disponibilità",
|
||||
"email_no_user_step_four": "Unirsi a {{teamName}}",
|
||||
"email_no_user_signoff": "Il team {{appName}} ti augura una piacevole esperienza di pianificazione",
|
||||
"impersonation_user_tip": "Stai per effettuare l'accesso con altra identità, vuol dire che potrai apportare modifiche a nome di un altro utente. Sei pregato di farlo con cautela.",
|
||||
"available_variables": "Variabili disponibili",
|
||||
"scheduler": "{Scheduler}",
|
||||
"no_workflows": "Nessun flusso di lavoro",
|
||||
"change_filter": "Modifica il filtro per vedere i flussi di lavoro personali e di squadra.",
|
||||
"recommended_next_steps": "Passaggi successivi consigliati",
|
||||
"create_a_managed_event": "Crea un tipo di evento gestito",
|
||||
"meetings_are_better_with_the_right": "Le riunioni sono efficaci quando sono presenti le persone giuste. Invitale adesso.",
|
||||
"create_a_one_one_template": "Crea un modello di incontro uno a uno per un tipo di evento e distribuiscilo a più membri.",
|
||||
"collective_or_roundrobin": "Di gruppo o round robin",
|
||||
"book_your_team_members": "Usa eventi di gruppo per riunire tutti i membri del team o eventi round robin per farli intervenire a turno e individuare la persona giusta.",
|
||||
"create_event_on": "Crea evento in data",
|
||||
"default_app_link_title": "Imposta il link dell'app predefinita",
|
||||
"default_app_link_description": "L'impostazione di un link dell'app predefinita permette a tutti i nuovi tipi di eventi di usare il link dell'app impostato.",
|
||||
"change_default_conferencing_app": "Imposta come predefinito",
|
||||
"booking_confirmation_failed": "Conferma prenotazione non riuscita"
|
||||
"under_maintenance": "Inattivo per manutenzione",
|
||||
"under_maintenance_description": "Il team di {{appName}} sta eseguendo la manutenzione programmata. Per qualsiasi domanda, contattare il supporto.",
|
||||
"event_type_seats": "{{numberOfSeats}} posti",
|
||||
"booking_with_payment_cancelled": "Non è più possibile pagare per questo evento",
|
||||
"booking_with_payment_cancelled_already_paid": "È in corso il rimborso del pagamento per questa prenotazione.",
|
||||
"booking_with_payment_cancelled_refunded": "Il pagamento per questa prenotazione è stato rimborsato.",
|
||||
"booking_confirmation_failed": "Conferma prenotazione non riuscita",
|
||||
"get_started_zapier_templates": "Inizia con i modelli Zapier",
|
||||
"a_routing_form": "Un modulo di instradamento",
|
||||
"form_description_placeholder": "Descrizione modulo",
|
||||
"keep_me_connected_with_form": "Mantieni la connessione con il modulo",
|
||||
"fields_in_form_duplicated": "Le eventuali modifiche al router e ai campi del modulo da duplicare si rifletteranno nel duplicato.",
|
||||
"form_deleted": "Modulo eliminato",
|
||||
"delete_form": "Elimina modulo",
|
||||
"delete_form_action": "Sì, elimina modulo",
|
||||
"delete_form_confirmation": "Eliminare questo modulo? Gli utenti con cui hai condiviso il link non saranno più in grado di usarlo per prenotare. Inoltre, verranno eliminate tutte le risposte a esso associate.",
|
||||
"typeform_redirect_url_copied": "URL di reindirizzamento Typeform copiato! È possibile andare a impostare l'URL ne modulo Typeform.",
|
||||
"modifications_in_fields_warning": "Le eventuali modifiche apportate ai campi e ai percorsi dei seguenti moduli si rifletteranno in questo modulo.",
|
||||
"connected_forms": "Moduli connessi",
|
||||
"form_modifications_warning": "Le modifiche qui apportate a campi e percorsi si rifletteranno nei seguenti moduli.",
|
||||
"responses_collection_waiting_description": "Attendere che vengano raccolte alcune risposte. È possibile anche compilare e inviare il modulo personalmente.",
|
||||
"this_is_what_your_users_would_see": "Ecco cosa vedranno gli utenti",
|
||||
"identifies_name_field": "Identifica il campo con questo nome.",
|
||||
"add_1_option_per_line": "Aggiungi 1 opzione per riga",
|
||||
"select_a_router": "Seleziona un router",
|
||||
"add_a_new_route": "Aggiungi un nuovo percorso",
|
||||
"no_responses_yet": "Per ora non ci sono risposte",
|
||||
"this_will_be_the_placeholder": "Questo sarà un segnaposto",
|
||||
"verification_code": "Codice di verifica",
|
||||
"verify": "Verifica"
|
||||
}
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
"upgrade_now": "今すぐアップグレード",
|
||||
"accept_invitation": "招待を受け入れる",
|
||||
"calcom_explained": "{{appName}} は、すべての人が使えるスケジュール管理インフラを提供します。",
|
||||
"calcom_explained_new_user": "{{appName}} アカウントの設定を完了してください!あと数ステップでスケジューリングの問題をすべて解決できます。",
|
||||
"have_any_questions": "ご不明な点があれば、お気軽にお問い合わせください。",
|
||||
"reset_password_subject": "{{appName}}: パスワードのリセット手順",
|
||||
"event_declined_subject": "却下: {{title}} {{date}}",
|
||||
@@ -23,6 +24,8 @@
|
||||
"rejection_reason_description": "この予約を拒否してよろしいですか?予約を試みたユーザーに通知を送ります。拒否の理由は、下にご記入いただけます。",
|
||||
"rejection_confirmation": "予約を拒否する",
|
||||
"manage_this_event": "このイベントを管理する",
|
||||
"invite_team_member": "チームメンバーを招待",
|
||||
"invite_team_notifcation_badge": "招待済み",
|
||||
"your_event_has_been_scheduled": "イベントがスケジュールされました",
|
||||
"your_event_has_been_scheduled_recurring": "繰り返しイベントがスケジュールされています",
|
||||
"accept_our_license": ".env 変数 <1>NEXT_PUBLIC_LICENSE_CONSENT</1> を '{{agree}} ' に変更することで、ライセンスに同意してください。",
|
||||
@@ -410,6 +413,8 @@
|
||||
"password_updated_successfully": "パスワードが正常に更新されました",
|
||||
"password_has_been_changed": "パスワードが正常に変更されました。",
|
||||
"error_changing_password": "パスワードの変更中にエラーが発生しました",
|
||||
"session_timeout_changed": "セッションの構成が正常に更新されました。",
|
||||
"session_timeout_change_error": "セッションの構成の更新中にエラーが発生しました",
|
||||
"something_went_wrong": "問題が発生しました。",
|
||||
"something_doesnt_look_right": "何かおかしいことがありますか?",
|
||||
"please_try_again": "もう一度お試しください",
|
||||
@@ -428,6 +433,7 @@
|
||||
"password_hint_num": "少なくとも 1 文字は数字を含めてください",
|
||||
"invalid_password_hint": "パスワードには少なくとも 1 文字以上数字を含め、アルファベットの大文字と小文字を両方使用した上で {{passwordLength}} 文字以上の長さに設定してください",
|
||||
"incorrect_password": "パスワードが正しくありません。",
|
||||
"incorrect_username_password": "ユーザー名またはパスワードが正しくありません。",
|
||||
"24_h": "24時間",
|
||||
"use_setting": "設定を使用",
|
||||
"am_pm": "午前/午後",
|
||||
@@ -455,6 +461,7 @@
|
||||
"slots_load_fail": "利用可能な時間帯を読み込めませんでした。",
|
||||
"additional_guests": "ゲストを追加",
|
||||
"your_name": "あなたの名前",
|
||||
"your_full_name": "あなたのフルネーム",
|
||||
"email_address": "メールアドレス",
|
||||
"enter_valid_email": "有効なメールアドレスを入力してください",
|
||||
"location": "所在地",
|
||||
@@ -508,6 +515,8 @@
|
||||
"admin": "管理者",
|
||||
"administrator_user": "管理者ユーザー",
|
||||
"lets_create_first_administrator_user": "最初の管理者ユーザーを作成しましょう。",
|
||||
"admin_user_created": "管理者ユーザー設定",
|
||||
"admin_user_created_description": "すでに管理者ユーザーを作成しています。アカウントにログインできます。",
|
||||
"new_member": "新しいメンバー",
|
||||
"invite": "招待する",
|
||||
"add_team_members": "チームメンバーを追加",
|
||||
@@ -589,7 +598,6 @@
|
||||
"new_event_type_heading": "最初のイベントタイプを作成する",
|
||||
"new_event_type_description": "イベントタイプを使用すると、カレンダーに利用可能な時間を表示し、人々があなたの時間の予約を行うことができるリンクを共有できます。",
|
||||
"new_event_title": "新しいイベント種別を追加",
|
||||
"new_event_subtitle": "あなたの名前またはチームの下にイベントタイプを作成します。",
|
||||
"new_team_event": "新しいイベント種別を追加",
|
||||
"new_event_description": "人々が時間を予約できる新しいイベントタイプを作成します。",
|
||||
"event_type_created_successfully": "{{eventTypeTitle}} イベント種別が正常に作成されました",
|
||||
@@ -658,6 +666,7 @@
|
||||
"edit_availability": "参加可能な時間を編集",
|
||||
"configure_availability": "予約が可能な時間を設定する。",
|
||||
"copy_times_to": "時間を以下にコピー",
|
||||
"copy_times_to_tooltip": "時間を…にコピー",
|
||||
"change_weekly_schedule": "ウィークリースケジュールを変更する",
|
||||
"logo": "ロゴ",
|
||||
"error": "エラー",
|
||||
@@ -669,6 +678,7 @@
|
||||
"add_attendees": "出席者を追加",
|
||||
"show_advanced_settings": "詳細設定を表示",
|
||||
"event_name": "イベント名",
|
||||
"event_name_in_calendar": "カレンダーのイベント名",
|
||||
"event_name_tooltip": "カレンダーに表示される名前",
|
||||
"meeting_with_user": "{{attendeeName}} とのミーティング",
|
||||
"additional_inputs": "追加入力",
|
||||
@@ -787,6 +797,7 @@
|
||||
"number_apps_one": "{{count}} 個のアプリ",
|
||||
"number_apps_other": "{{count}} 個のアプリ",
|
||||
"trending_apps": "人気のアプリ",
|
||||
"most_popular": "最も人気",
|
||||
"explore_apps": "{{category}} アプリ",
|
||||
"installed_apps": "インストールされているアプリ",
|
||||
"free_to_use_apps": "無料",
|
||||
@@ -797,12 +808,14 @@
|
||||
"no_category_apps_description_analytics": "予約ページに分析アプリを追加する",
|
||||
"no_category_apps_description_automation": "使用する自動化アプリを追加する",
|
||||
"no_category_apps_description_other": "その他のアプリを追加して、様々なことを実現しましょう",
|
||||
"no_category_apps_description_web3": "予約ページに Web3 アプリを追加",
|
||||
"installed_app_calendar_description": "ダブルブッキングを防ぐために、カレンダーの重複をチェックするように設定します。",
|
||||
"installed_app_conferencing_description": "会議用にお気に入りのビデオ会議アプリを追加しましょう",
|
||||
"installed_app_payment_description": "顧客に請求をする際に使用する決済処理サービスを設定しましょう。",
|
||||
"installed_app_analytics_description": "予約ページでどの分析アプリを使用するかを構成する",
|
||||
"installed_app_other_description": "その他のカテゴリーからインストールしたすべてのアプリ。",
|
||||
"installed_app_automation_description": "どの自動化アプリを使用するかを構成する",
|
||||
"installed_app_web3_description": "予約ページでどの Web3 アプリを使用するかを設定します",
|
||||
"analytics": "分析",
|
||||
"empty_installed_apps_headline": "アプリがインストールされていません",
|
||||
"empty_installed_apps_description": "アプリを使えば、ワークフローの質を高め、スケジュールライフを大幅に改善することができます。",
|
||||
@@ -930,6 +943,11 @@
|
||||
"current_location": "現在の場所",
|
||||
"user_phone": "あなたの電話番号",
|
||||
"new_location": "新しい場所",
|
||||
"session": "セッション",
|
||||
"session_description": "アカウントのセッションを管理します",
|
||||
"session_timeout_after": "後にセッションをタイムアウト",
|
||||
"session_timeout": "セッションタイムアウト",
|
||||
"session_timeout_description": "一定時間後にセッションを無効にする",
|
||||
"no_location": "場所が定義されていません",
|
||||
"set_location": "場所を設定",
|
||||
"update_location": "場所を更新",
|
||||
@@ -1073,6 +1091,7 @@
|
||||
"broken_video_action": "スケジュールされたイベントに<1>{{location}}</1>ミーティングへのリンクを追加できませんでした。招待者に連絡するか、カレンダーのイベントを更新して詳細を追加してください。 <3>イベントタイプで場所を変更するか</3>、<5>アプリを削除して再度追加</5>してください。",
|
||||
"broken_calendar_action": "<1>{{calendar}}</1>を更新できませんでした。<2>カレンダーの設定を確認するか、カレンダーを削除してもう一度追加してください</2>",
|
||||
"attendee_name": "出席者の名前",
|
||||
"scheduler_full_name": "予約者のフルネーム",
|
||||
"broken_integration": "連携が切断されています",
|
||||
"problem_adding_video_link": "動画リンクの追加中に問題が発生しました",
|
||||
"problem_updating_calendar": "カレンダーの更新中に問題が発生しました",
|
||||
@@ -1215,6 +1234,7 @@
|
||||
"connect_automation_apps": "自動化アプリを接続する",
|
||||
"connect_analytics_apps": "分析アプリを接続する",
|
||||
"connect_other_apps": "その他のアプリを接続",
|
||||
"connect_web3_apps": "Web3 アプリを接続",
|
||||
"current_step_of_total": "ステップ {{currentStep}}/{{maxSteps}}",
|
||||
"add_variable": "変数を追加",
|
||||
"custom_phone_number": "カスタム電話番号",
|
||||
@@ -1231,6 +1251,7 @@
|
||||
"to": "送信先",
|
||||
"workflow_turned_on_successfully": "{{workflowName}} ワークフローが正常に {{offOn}} になりました",
|
||||
"download_responses": "回答をダウンロード",
|
||||
"download_responses_description": "CSV形式ですべての回答をフォームにダウンロードします。",
|
||||
"download": "ダウンロード",
|
||||
"create_your_first_form": "最初のフォームを作成",
|
||||
"create_your_first_form_description": "ルーティングフォームを使用すれば、絞り込みの質問を通して適切な人物やイベントの種類へとルーティングを行うことができます。",
|
||||
@@ -1272,6 +1293,8 @@
|
||||
"routing_forms_send_email_owner": "所有者にメールを送信",
|
||||
"routing_forms_send_email_owner_description": "フォームの送信時に所有者にメールを送信します",
|
||||
"add_new_form": "新しいフォームを追加",
|
||||
"create_your_first_route": "最初のルートを作成",
|
||||
"route_to_the_right_person": "フォームへの回答に基づいて適切な人にルーティングする",
|
||||
"form_description": "予約者をルーティングするフォームを作成します",
|
||||
"copy_link_to_form": "フォームへのリンクをコピー",
|
||||
"theme": "テーマ",
|
||||
@@ -1302,6 +1325,7 @@
|
||||
"password_reset_leading": "すぐにメールが届かない場合は、入力したメールアドレスが正しいかや迷惑メールフォルダを確認し、それでも問題が解決しない場合はサポートにご連絡ください。",
|
||||
"password_updated": "パスワードが更新されました!",
|
||||
"pending_payment": "支払い待ち",
|
||||
"pending_invites": "保留中の招待",
|
||||
"confirmation_page_rainbow": "Ethereum や Polygon などのトークンや NFT を使用してイベントに参加しましょう。",
|
||||
"not_on_cal": "{{appName}} にはいません",
|
||||
"no_calendar_installed": "カレンダーがインストールされていません",
|
||||
@@ -1428,6 +1452,9 @@
|
||||
"disabled_calendar": "他のカレンダーがインストールされている場合、新しい予約はそのカレンダーに追加されます。そうでない場合には、新しいカレンダーへと接続します。そのため、新しい予約を見逃すことはなくなります。",
|
||||
"enable_apps": "アプリを有効にする",
|
||||
"enable_apps_description": "ユーザーが Cal.com と統合可能なアプリを有効にします",
|
||||
"purchase_license": "ライセンスを購入",
|
||||
"already_have_key": "すでにキーを持っています:",
|
||||
"already_have_key_suggestion": "ここに既存の CALCOM_LICENSE_KEY 環境変数をコピーしてください。",
|
||||
"app_is_enabled": "{{appName}} は有効です",
|
||||
"app_is_disabled": "{{appName}} は無効です",
|
||||
"keys_have_been_saved": "キーが保存されました",
|
||||
@@ -1448,6 +1475,7 @@
|
||||
"individual": "個人",
|
||||
"all_bookings_filter_label": "すべての予約",
|
||||
"all_users_filter_label": "すべてのユーザー",
|
||||
"your_bookings_filter_label": "あなたの予約",
|
||||
"meeting_url_variable": "ミーティング URL",
|
||||
"meeting_url_info": "イベントミーティング会議 URL",
|
||||
"date_overrides": "日付の上書き",
|
||||
@@ -1486,6 +1514,7 @@
|
||||
"round_robin_hosts": "ラウンドロビンホスト",
|
||||
"minimum_round_robin_hosts_count": "出席が必要なホストの数",
|
||||
"hosts": "ホスト",
|
||||
"upgrade_to_enable_feature": "この機能を有効にするにはチームを作成する必要があります。クリックしてチームを作成してください。",
|
||||
"new_attendee": "新規参加者",
|
||||
"awaiting_approval": "承認を待っています",
|
||||
"requires_google_calendar": "このアプリは Google カレンダーとの接続が必要です",
|
||||
@@ -1494,9 +1523,99 @@
|
||||
"continue_to_install_google_calendar": "Google カレンダーのインストールを続行",
|
||||
"install_google_meet": "Google Meet をインストール",
|
||||
"install_google_calendar": "Google カレンダーをインストール",
|
||||
"sender_name": "送信者名",
|
||||
"already_invited": "出席者はすでに招待されています",
|
||||
"no_recordings_found": "録音が見つかりません",
|
||||
"reporting": "報告",
|
||||
"reporting_feature": "データからの受信情報をすべて表示し、CSV形式でダウンロード",
|
||||
"teams_plan_required": "チームプランが必要です",
|
||||
"routing_forms_are_a_great_way": "ルーティングフォームは入ってきたリードを適切な人にルーティングするのに最適な方法です。この機能にアクセスするにはチームプランにアップグレードしてください。",
|
||||
"choose_a_license": "ライセンスを選択する",
|
||||
"choose_license_description": "Cal.com にはアクセス可能な無料の AGPLv3 ライセンスが付属していますが、これにはいくつか制限があり、いつでも企業向けライセンスにアップグレードすることができます。後でいつでもアップグレード可能です。",
|
||||
"license": "ライセンス",
|
||||
"agplv3_license": "AGPLv3 ライセンス",
|
||||
"ee_enterprise_license": "「/ee」企業向けライセンス",
|
||||
"enterprise_booking_fee": "{{enterprise_booking_fee}}/月で開始",
|
||||
"enterprise_license_includes": "商用ユースケースのためのあらゆるもの",
|
||||
"no_need_to_keep_your_code_open_source": "コードをオープンソースにしておく必要はありません",
|
||||
"repackage_rebrand_resell": "再パッケージ、リブランド、再販が簡単です",
|
||||
"a_vast_suite_of_enterprise_features": "膨大な企業向け機能のパッケージ",
|
||||
"free_license_fee": "0.00ドル/月",
|
||||
"forever_open_and_free": "永久にオープンかつ無料です",
|
||||
"required_to_keep_your_code_open_source": "コードをオープンソースにしておく必要があります",
|
||||
"cannot_repackage_and_resell": "再パッケージ、リブランド、再販が簡単ではありません",
|
||||
"no_enterprise_features": "企業向け機能がありません",
|
||||
"step_enterprise_license": "企業向けライセンス",
|
||||
"step_enterprise_license_description": "プライベートホスティング、再パッケージ、リブラディング、再販、専用の企業向けコンポーネントなど、商用ユースケース用のあらゆるものが備わっています。",
|
||||
"setup": "設定",
|
||||
"setup_description": "Cal.com インスタンスを設定します",
|
||||
"configure": "構成する",
|
||||
"sso_configuration": "シングルサインオン",
|
||||
"sso_configuration_description": "SAML/OIDC SSO を設定し、チームメンバーが ID プロバイダーを使ってログインできるようにします",
|
||||
"sso_oidc_heading": "OIDCでのSSO",
|
||||
"sso_oidc_description": "好みの ID プロバイダーを使用して OIDCでのSSO を設定します。",
|
||||
"sso_oidc_configuration_title": "OIDC 設定",
|
||||
"sso_oidc_configuration_description": "ID プラバイダーへの OIDC 接続を設定します。必要な情報は ID プロバイダーで見つけることができます。",
|
||||
"sso_oidc_callback_copied": "コールバックURLがコピーされました",
|
||||
"sso_saml_heading": "SAMLでのSSO",
|
||||
"sso_saml_description": "好みの ID プロバイダーを使用して SAMLでのSSO を設定します。",
|
||||
"sso_saml_configuration_title": "SAML 設定",
|
||||
"sso_saml_configuration_description": "ID プロバイダーへの SAML 接続を設定します。必要な情報は ID プロバイダーで見つけることができます。",
|
||||
"sso_saml_acsurl_copied": "ACS URL をコピーしました",
|
||||
"sso_saml_entityid_copied": "エンティティ ID をコピーしました",
|
||||
"sso_connection_created_successfully": "{{connectionType}} の設定が正常に作成されました",
|
||||
"sso_connection_deleted_successfully": "{{connectionType}} の設定が正常に削除されました",
|
||||
"delete_sso_configuration": "{{connectionType}} の設定を削除",
|
||||
"delete_sso_configuration_confirmation": "はい、{{connectionType}} の設定を削除します",
|
||||
"delete_sso_configuration_confirmation_description": "{{connectionType}} の設定を削除してもよろしいですか?{{connectionType}} でのログインを使用しているチームメンバーは Cal.com にアクセスすることができなくなります。",
|
||||
"organizer_timezone": "主催者のタイムゾーン",
|
||||
"email_no_user_cta": "アカウントを作成",
|
||||
"email_user_cta": "招待を表示",
|
||||
"email_no_user_invite_heading": "{{appName}} のチームに参加するよう招待されました",
|
||||
"email_no_user_invite_subheading": "{{invitedBy}} は {{appName}} のチームに参加するようあなたを招待しました。{{appName}} はイベント調整スケジューラーで、あなたとチームは延々とメールをやりとりすることなくミーティングをスケジューリングできます。",
|
||||
"email_no_user_invite_steps_intro": "いくつかの短い手順を踏むだけで、すぐにチームとのストレスフリーなスケジューリングをお楽しみいただけます。",
|
||||
"email_no_user_step_one": "ユーザー名を選択する",
|
||||
"email_no_user_step_two": "カレンダーアカウントを接続する",
|
||||
"email_no_user_step_three": "空き状況を設定する",
|
||||
"email_no_user_step_four": "{{teamName}} に参加する",
|
||||
"email_no_user_signoff": "スケジューリングをお楽しみください {{appName}} チームより",
|
||||
"impersonation_user_tip": "あるユーザーになりすまし、その人に代わって変更を加えることが可能になろうとしています。ご注意ください。",
|
||||
"available_variables": "利用可能な変数",
|
||||
"scheduler": "{Scheduler}",
|
||||
"recommended_next_steps": "推奨される次のステップ",
|
||||
"create_a_managed_event": "管理イベントタイプを作成",
|
||||
"meetings_are_better_with_the_right": "ミーティングは適切なチームメンバーの参加でより良いものになります。今すぐ彼らを招待しましょう。",
|
||||
"collective_or_roundrobin": "全体またはラウンドロビン",
|
||||
"book_your_team_members": "全体イベントでチームメンバー全員を予約するか、ラウンドロビンで持ち回りにして適切な人を獲得します。",
|
||||
"default_app_link_title": "デフォルトのアプリリンクを設定",
|
||||
"default_app_link_description": "デフォルトのアプリリンクを設定すると、新たに作成したすべてのイベントタイプがそのアプリリンクを使用することができます。",
|
||||
"change_default_conferencing_app": "デフォルトとして設定",
|
||||
"booking_confirmation_failed": "予約の確認に失敗しました"
|
||||
"under_maintenance": "メンテナンスのためダウン",
|
||||
"under_maintenance_description": "{{appName}} チームが定期メンテナンスを行っています。ご質問がある場合は、サポートにお問い合わせください。",
|
||||
"event_type_seats": "{{numberOfSeats}} 席",
|
||||
"booking_with_payment_cancelled": "このイベントの支払いはもうできません",
|
||||
"booking_with_payment_cancelled_already_paid": "この予約の支払いに対する払い戻しは処理中です。",
|
||||
"booking_with_payment_cancelled_refunded": "この予約の支払いは返金されました。",
|
||||
"booking_confirmation_failed": "予約の確認に失敗しました",
|
||||
"get_started_zapier_templates": "Zapier テンプレートを使い始める",
|
||||
"a_routing_form": "ルーティングフォーム",
|
||||
"form_description_placeholder": "フォームの説明",
|
||||
"keep_me_connected_with_form": "フォームに接続したままにする",
|
||||
"fields_in_form_duplicated": "フォームのルーターとフィールドの変更は複製され、複製に反映されます。",
|
||||
"form_deleted": "フォームが削除されました",
|
||||
"delete_form": "フォームを削除",
|
||||
"delete_form_action": "はい、フォームを削除します",
|
||||
"delete_form_confirmation": "このフォームを削除してもよろしいですか?これまでにリンクを共有した相手の人はリンクを使って予約することができなくなります。また、関連する回答はすべて削除されます。",
|
||||
"typeform_redirect_url_copied": "Typeform のリダイレクト URL をコピーしました!URL は Typeform のフォームで設定できます。",
|
||||
"modifications_in_fields_warning": "以下のフォームのフィールドとルートの変更がこのフォームに反映されます。",
|
||||
"connected_forms": "接続されているフォーム",
|
||||
"form_modifications_warning": "ここでフィールドまたはルートを変更すると、以下のフォームが影響を受けます。",
|
||||
"responses_collection_waiting_description": "回答が集められるまでしばらく待ってください。あなた自身でフォームを送信してくることもできます。",
|
||||
"this_is_what_your_users_would_see": "これがユーザーに表示される内容です",
|
||||
"identifies_name_field": "この名前でフィールドを識別します。",
|
||||
"add_1_option_per_line": "1 行に 1 つのオプションを追加",
|
||||
"select_a_router": "ルーターを選択",
|
||||
"add_a_new_route": "新しいルートを追加",
|
||||
"no_responses_yet": "回答はまだありません",
|
||||
"this_will_be_the_placeholder": "これがプレースホルダーになります"
|
||||
}
|
||||
|
||||
@@ -598,7 +598,6 @@
|
||||
"new_event_type_heading": "첫 번째 이벤트 타입 만들기",
|
||||
"new_event_type_description": "이벤트 타입을 사용하면 캘린더에서 사용 가능한 시간을 표시하는 링크를 공유하고, 사람들이 당신과 함께 예약할 수 있습니다.",
|
||||
"new_event_title": "새 이벤트 타입 추가하기",
|
||||
"new_event_subtitle": "귀당신의 이름 또는 팀 아래 이벤트 타입을 작성하십시오.",
|
||||
"new_team_event": "새 팀 이벤트 타입 추가",
|
||||
"new_event_description": "사람들이 시간을 예약할 수 있는 새 이벤트 타입을 만듭니다.",
|
||||
"event_type_created_successfully": "{{eventTypeTitle}} 이벤트 타입이 성공적으로 생성되었습니다.",
|
||||
@@ -1581,8 +1580,8 @@
|
||||
"email_no_user_step_four": "{{teamName}} 가입",
|
||||
"email_no_user_signoff": "{{appName}} 팀의 행복한 일정",
|
||||
"impersonation_user_tip": "사용자를 가장하려고 합니다. 즉, 사용자를 대신하여 변경할 수 있는 것입니다. 조심하세요.",
|
||||
"scheduler": "{Scheduler}",
|
||||
"available_variables": "사용 가능 변수",
|
||||
"scheduler": "{Scheduler}",
|
||||
"recommended_next_steps": "추천 다음 단계",
|
||||
"create_a_managed_event": "관리형 이벤트 유형 작성",
|
||||
"meetings_are_better_with_the_right": "회의는 그곳에서 올바른 팀원과 함께 하는 것이 더 낫습니다. 지금 초대하세요.",
|
||||
|
||||
@@ -589,7 +589,6 @@
|
||||
"new_event_type_heading": "Maak uw eerste evenement aan",
|
||||
"new_event_type_description": "Evenementen stellen u in staat om links te delen die beschikbare tijden tonen op uw agenda en bezoekers hiervan kunnen deze gebruiken om afspraken te maken.",
|
||||
"new_event_title": "Een evenement toevoegen",
|
||||
"new_event_subtitle": "Maak een evenement aan onder uw profiel of team.",
|
||||
"new_team_event": "Een nieuw type vergadering toevoegen",
|
||||
"new_event_description": "Maak een nieuw evenement voor bezoekers om afspraken te maken.",
|
||||
"event_type_created_successfully": "{{eventTypeTitle}} evenement met succes aangemaakt",
|
||||
|
||||
@@ -588,7 +588,6 @@
|
||||
"new_event_type_heading": "Opprett din første hendelsestype",
|
||||
"new_event_type_description": "Hendelsestyper lar deg dele lenker som viser tilgjengelige tider i kalenderen din og lar folk gjøre bookinger med deg.",
|
||||
"new_event_title": "Legg til en ny hendelsestype",
|
||||
"new_event_subtitle": "Opprett en hendelsestype under navnet ditt eller et team.",
|
||||
"new_team_event": "Legg til en ny hendelsestype for team",
|
||||
"new_event_description": "Opprett en ny hendelsestype som folk kan booke tider med.",
|
||||
"event_type_created_successfully": "{{eventTypeTitle}} hendelsestype opprettet",
|
||||
|
||||
@@ -589,7 +589,6 @@
|
||||
"new_event_type_heading": "Utwórz swój typ pierwszego wydarzenia",
|
||||
"new_event_type_description": "Typy wydarzeń umożliwiają udostępnianie linków, które pokazują dostępne czasy w kalendarzu i pozwalają ludziom na dokonywanie rezerwacji.",
|
||||
"new_event_title": "Dodaj nowy typ wydarzenia",
|
||||
"new_event_subtitle": "Utwórz typ wydarzenia pod Twoim imieniem lub zespołem.",
|
||||
"new_team_event": "Dodaj nowy typ wydarzenia drużynowego",
|
||||
"new_event_description": "Utwórz nowy typ wydarzenia, z którym ludzie mogą rezerwować czasy.",
|
||||
"event_type_created_successfully": "Utworzono {{eventTypeTitle}} typ wydarzenia pomyślnie",
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user