Compare commits

...
101 Commits
Author SHA1 Message Date
Omar López 7f13fc58b9 v2.9.7
release.yml / release (push) Canceled after 0s
2023-06-07 16:02:32 -07:00
alannncandAlex van Andel 527d1f6c93 fix: remove bg-color (#9408)
* remove bg-color

* Update packages/app-store/_components/AppCard.tsx

Fix lint error trailing ,

---------

Co-authored-by: Alex van Andel <me@alexvanandel.com>
2023-06-07 16:02:32 -07:00
Omar López 0ec3c496d8 fix: missing company name in emails (#9409) 2023-06-07 16:02:32 -07:00
Jeroen Reumkens 62ec3de0b1 Recurring event doesn't neccessarily mean an event that requires confirmation. We need to show the recurring option nevertheless. (#9393) 2023-06-07 16:02:32 -07:00
Jeroen Reumkens 2c47cb6a3b Only take owner data we need in public event api, instead of everything. Saves bandwidth. (#9394) 2023-06-07 16:02:32 -07:00
Jeroen Reumkens dc2b145843 Show header layout in large views even if theres only one layout enable. Don't show toggle though. (#9398) 2023-06-07 16:02:32 -07:00
Nafees Nazik c958e1578a feat: use the correct locale for the title (#9286) 2023-06-07 16:02:32 -07:00
Crowdin Bot 1e857e5c0a New Crowdin translations by Github Action 2023-06-07 20:08:38 +00:00
Peer Richelsen 9bc8d48415 fix: leading none in shell (#9404) 2023-06-07 19:57:10 +00:00
f86c6734a7 fix: Wrong padding on "Invite Team Members" modal (CALCOM-8414-FIX) (#9273)
* Fix margin from invitation modal content

* Change margin to padding in Dialog component, so the divider absolute property works properly

* Update Dialog.tsx padding from the button top from 24px to 16px

* Change Dialog content padding to match figma design, having the padding bottom 16px

* Update FormBuilder.tsx to match figma

* Update FormBuilder.tsx Dialog content inner div paddings

* Update FormBuilder.tsx, remove relative to fix divider

* Fixing padding across dialogs

* nit

* Fixes e2e

* undo wrong padding

* fixed footer with divider

---------

Co-authored-by: gitstart-calcom <gitstart@users.noreply.github.com>
Co-authored-by: Peer Richelsen <peeroke@gmail.com>
Co-authored-by: Peer Richelsen <peer@cal.com>
Co-authored-by: zomars <zomars@me.com>
2023-06-07 19:55:47 +00:00
HitenandPeer Richelsen 3d5ff82062 Fix width issue in general setting (#9388)
Co-authored-by: Peer Richelsen <peeroke@gmail.com>
2023-06-07 11:08:29 +00:00
Crowdin Bot 8b63483e2e New Crowdin translations by Github Action 2023-06-07 10:56:44 +00:00
TheOnlyWayUpandPeer Richelsen c97d4288c0 typo(README): 'concent' -> 'consent' (#9356)
Co-authored-by: Peer Richelsen <peeroke@gmail.com>
2023-06-07 11:55:45 +01:00
Hariom Balhara ff75364f22 Fix embed detection (#9385) 2023-06-07 08:43:12 +00:00
Crowdin Bot 7f1b028099 New Crowdin translations by Github Action 2023-06-07 07:40:33 +00:00
9e70a985e4 feat: email verification (#9081)
* Verify - inital email commit

* Add token type - api redirect - migration

* Redirect and valid api callback route

* Update email design

* Change signup URL to redirect to verify-email

* Add feature flag - add a11y text to email - add top banner

* Shell shouldnt redirect to onboarding if the user needs to verify account

* Move flag check to server

* Cleanup

* Rate limit

* Fix redirects

* Remove api signup mess

* Double negation for forced bool

* Fix props

* Update packages/emails/templates/account-verify-email.ts

* Enable migration by default

* Fix typos

* Fix google verify issue

* Update packages/features/auth/lib/verifyEmail.ts

Co-authored-by: Hariom Balhara <hariombalhara@gmail.com>

* NITS: @harioms addressed

* Remove schema changes

* Fix NITs+ improvments

* Update apps/web/pages/api/auth/verify-email.ts

Co-authored-by: Omar López <zomars@me.com>

* Update packages/features/ee/common/components/LicenseRequired.tsx

Co-authored-by: Omar López <zomars@me.com>

* Update apps/web/pages/api/auth/verify-email.ts

Co-authored-by: Omar López <zomars@me.com>

* Always preloads feature flags

* Update verifyEmail.ts

* Update schema.prisma

* Type fix

---------

Co-authored-by: Hariom Balhara <hariombalhara@gmail.com>
Co-authored-by: Omar López <zomars@me.com>
2023-06-07 07:27:48 +00:00
Crowdin Bot 057cf273dd New Crowdin translations by Github Action 2023-06-07 02:15:50 +00:00
Omar López 9af621294d fix: Prevents undefined features flags on first render (#9374) 2023-06-07 02:03:52 +00:00
zomars bfb5a31032 Fix broken test introduced in #9085 2023-06-06 17:35:03 -07:00
Hariom BalharaandOmar López 6308955e89 fix: embed non-transparent dark background on success page (#9085)
* Fix colorscheme dark on success page due to embed not detected properly there

* Use calNamespace in getEmbediframe

* Fix missing variable

* Update basic.e2e.ts

---------

Co-authored-by: Omar López <zomars@me.com>
2023-06-06 23:52:13 +00:00
Crowdin Bot b0c5b629d7 New Crowdin translations by Github Action 2023-06-06 23:52:45 +00:00
10f965570b feat: Add copy invite link (#8355)
* feat: Add shared invite link

* refactor: Rename Invite to Team Invite model

* feat: add admin check for team invite link procedures

* Replace TeamInvite with VerificationToken

* Add team invite null checks

* Migrates tRPC procedures to new format

* Type fixes

* Update common.json

---------

Co-authored-by: zomars <zomars@me.com>
Co-authored-by: Peer Richelsen <peeroke@gmail.com>
Co-authored-by: Joe Au-Yeung <65426560+joeauyeung@users.noreply.github.com>
Co-authored-by: alannnc <alannnc@gmail.com>
Co-authored-by: Efraín Rochín <roae.85@gmail.com>
Co-authored-by: Keith Williams <keithwillcode@gmail.com>
2023-06-06 23:34:14 +00:00
Udit TakkarandPeer Richelsen c24f5200f5 fix: opt in booking from email (#9358)
* fix: opt in booking from email

Signed-off-by: Udit Takkar <udit.07814802719@cse.mait.ac.in>

* fix: undo this

Signed-off-by: Udit Takkar <udit.07814802719@cse.mait.ac.in>

* fix: type error

Signed-off-by: Udit Takkar <udit.07814802719@cse.mait.ac.in>

* fix: type error

Signed-off-by: Udit Takkar <udit.07814802719@cse.mait.ac.in>

* fix: Avada Kedavra type errors

Signed-off-by: Udit Takkar <udit.07814802719@cse.mait.ac.in>

---------

Signed-off-by: Udit Takkar <udit.07814802719@cse.mait.ac.in>
Co-authored-by: Peer Richelsen <peeroke@gmail.com>
2023-06-06 21:04:06 +00:00
zomars f922692a1a Sync yarn.lock with website 2023-06-06 12:07:37 -07:00
Crowdin Bot 65c137f67d New Crowdin translations by Github Action 2023-06-06 18:44:00 +00:00
Efraín Rochínandzomars 585679969a perf: Avoid useless dependencies in calendar cache page (#9290)
* increases the time range to cover all time zones

* it isolates the getCachedResults and rename to getCalendarsEvents

* remove unrelated changes

* remove unrelated changes

---------

Co-authored-by: zomars <zomars@me.com>
2023-06-06 18:30:29 +00:00
Crowdin Bot 893b67b6c4 New Crowdin translations by Github Action 2023-06-06 18:16:49 +00:00
Crowdin Bot 3c296b440e New Crowdin translations by Github Action 2023-06-06 18:15:56 +00:00
Crowdin Bot f8a59b52f7 New Crowdin translations by Github Action 2023-06-06 18:14:59 +00:00
Efraín RochínandKeith Williams 17d106cfda chore: Replace UI login with api login on e2e tests (#9344)
* Replace the ui login with api login

* test api login

* go to first page after login in some tests

---------

Co-authored-by: Keith Williams <keithwillcode@gmail.com>
2023-06-06 18:02:32 +00:00
Crowdin Bot dcf9d30382 New Crowdin translations by Github Action 2023-06-06 17:48:34 +00:00
eafd7f6b77 fix: Disabled pinch to zoom on mobile devices#9155 (#9163)
* Disabled pinch to zoom on mobile devices#9155

* Modified the better fix to the feature

* Update apps/web/pages/_document.tsx

* Update apps/web/pages/_document.tsx

* Update apps/web/styles/globals.css

* Update apps/web/pages/_document.tsx

* Update apps/web/pages/_document.tsx

* Update apps/web/pages/_document.tsx

---------

Co-authored-by: Peer Richelsen <peeroke@gmail.com>
Co-authored-by: Peer Richelsen <peer@cal.com>
Co-authored-by: Keith Williams <keithwillcode@gmail.com>
2023-06-06 17:35:19 +00:00
f31165b442 feat: event settings booker layout toggle (#9082)
* WIP for adding booker layout toggle in event settings pages

* Prevent form error from getting form stuck in loading state

* Fixed types for bookerlayouts settings and preselect correct layout in booker

* Added defaultlayout settings to profile too, and use that in booker plus as default for events.

* Made layout settings responsive

* Added feature toggle for new layout settings

* Fixed user builder for tests by adding defaultlyotu

* Show toggles on booker for layout switch based on selected layouts. Also added a small fix for the settings toggles to preselect the correct toggle for defaultlayout when user profile settings are used.

* Used zod parse to fix type errors.

* Fix unit test

* Set selected date to today in datepicker when week or column view is default layout. It uses that date to show in the title bar.

* Moved booker layout settings to event and user meta data instead of new db column.

* Converted booker layout strings into an enum.

* Renamed booker layouts feature flag and deleted unused v2 booker feature flag.

* Update packages/trpc/server/routers/viewer/eventTypes/update.handler.ts

Co-authored-by: Omar López <zomars@me.com>

* Fix import

* Fix lint warnings in EventTypeSingleLayout

* Fixed bug where when selected date was passed via query param page booking form wouldn't automatically show up. It would still serve you the date selection. This should fix e2e tests.

* Fixed layout header.

* Enabled booking layout toggle feature flag.

---------

Co-authored-by: Peer Richelsen <peeroke@gmail.com>
Co-authored-by: Omar López <zomars@me.com>
Co-authored-by: Alex van Andel <me@alexvanandel.com>
2023-06-06 15:31:43 +00:00
Crowdin Bot 40c5d5871e New Crowdin translations by Github Action 2023-06-06 14:09:06 +00:00
Jeroen Reumkensandsean-brydon 2362754356 feat: CAL-1674 Added new header layout for new booker. (#9227)
* CAL-1674: Added new header layout for new booker.

* Removed unneccesary bg style for toggle group, since it's already the default bg color.

* Fixed types

* Gave minwidth to booker header date title, to prevent arrows for switching weeks from jumping around.

* Push small calendar down

* Fixed overflow in small calendar view

* Added booker modal padding underneath badges

* Fixed grid area name causing broken animation. Also use setstyle directly instead of using animate for non animated properties. Performs better and removes some errors by framer motion for non animatable units like 'auto'.

---------

Co-authored-by: sean-brydon <55134778+sean-brydon@users.noreply.github.com>
2023-06-06 13:55:27 +00:00
Crowdin Bot 8ccf3b589e New Crowdin translations by Github Action 2023-06-06 12:14:47 +00:00
2dbc73c75b chore: fix all Typescript warnings (#8618)
* [CAL-1517] fix all Typescript warnings

* solve conflicts

* Update stripeCheckoutSession.handler.ts

Parse is a guard, so even though the variable is unused the parse itself is needed.

* Update ToolbarPlugin.tsx

Don't change dependency tree

---------

Co-authored-by: gitstart-calcom <gitstart@users.noreply.github.com>
Co-authored-by: Peer Richelsen <peeroke@gmail.com>
Co-authored-by: Alex van Andel <me@alexvanandel.com>
2023-06-06 11:59:57 +00:00
Ben Hybert 87e1ad7115 chore: switch over to use variable for app/companyName (#9334)
* switch over to use variable for app/companyName
* enable_apps_description - appName
* recording_from_your_recent_call - appName
* the_calcom_team - companyName
* calcom_is_better_with_team - appName

* capitalise 'S' in teams page.
2023-06-06 11:58:05 +00:00
il3ven 2e9895aceb add telegramvideo to packages/app-tore/index.ts (#9324)
`telegramvideo` seems to be missing and causing issue #9308
2023-06-06 11:24:54 +00:00
fbbc573f33 chore: remove deprecated metamask and rainbow (#9299)
* Remove deprecated code related to rainbow

* Remove translations for rainbow specific features

* Remove english translations for metamask

* Remove translations for metamask

* Fix lint issues

* Fix prettier issues

* update yarn lock

* Generated yarn.lock with submodules

* Added auth submodule deps

---------

Co-authored-by: Peer Richelsen <peeroke@gmail.com>
Co-authored-by: alannnc <alannnc@gmail.com>
Co-authored-by: Alex van Andel <me@alexvanandel.com>
2023-06-06 11:18:44 +00:00
Piyush GargandPeer Richelsen 8bc8a045b6 feat: email undefined value (#9240)
* Fix: #9210

* Fix: #9215 Added Password Validation to App Signup

* FIX #9216 Fixed the Update Button Allignment

* Fix #9238: Don't render descripiton in email template if undefined

* Remove Prev Changes

* Remove unwanted space

* Revert yarn.lock

---------

Co-authored-by: Peer Richelsen <peeroke@gmail.com>
2023-06-06 10:03:40 +00:00
Crowdin Bot 8c049b29b3 New Crowdin translations by Github Action 2023-06-06 09:47:49 +00:00
ravi kunwarandUdit Takkar f1e783f047 fix: Availability Name does Not Update (#9322)
* fix: Availability Name does Not Update

* fix: use i18n in navigation

Signed-off-by: Udit Takkar <udit.07814802719@cse.mait.ac.in>

---------

Signed-off-by: Udit Takkar <udit.07814802719@cse.mait.ac.in>
Co-authored-by: Udit Takkar <udit.07814802719@cse.mait.ac.in>
2023-06-06 09:33:34 +00:00
Crowdin Bot 3baa6c7145 New Crowdin translations by Github Action 2023-06-06 07:17:36 +00:00
dd28bb46db fix: title (#9055)
Co-authored-by: alannnc <alannnc@gmail.com>
Co-authored-by: Peer Richelsen <peeroke@gmail.com>
2023-06-06 07:04:54 +00:00
c182091fa9 fix: /event-type /apps - doesn't match designs (#9317)
* updated AppCard comp for design changes

* updated rainfallForm for design changes

* Fix:: event-type/apps design issues

* Update apps/web/components/eventtype/EventAppsTab.tsx

* Update packages/app-store/_components/AppCard.tsx

* Update packages/app-store/_components/AppCard.tsx

* Fix lint

---------

Co-authored-by: Peer Richelsen <peer@cal.com>
Co-authored-by: Peer Richelsen <peeroke@gmail.com>
Co-authored-by: Bailey Pumfleet <bailey@pumfleet.co.uk>
Co-authored-by: alannnc <alannnc@gmail.com>
2023-06-05 22:49:27 +00:00
Crowdin Bot d061572ed6 New Crowdin translations by Github Action 2023-06-05 22:34:31 +00:00
Ujwal Kumarandalannnc 3a943fbc81 Fix background colour for show on booking page switch on event types page (#9318)
Co-authored-by: alannnc <alannnc@gmail.com>
2023-06-05 22:24:10 +00:00
Crowdin Bot 8a58a51a2c New Crowdin translations by Github Action 2023-06-05 12:20:39 +00:00
Crowdin Bot e92265ceaa New Crowdin translations by Github Action 2023-06-05 12:19:41 +00:00
Udit Takkar b7b1fff1c0 fix: hide 2fa tab when using google as identity provider (#9333)
Signed-off-by: Udit Takkar <udit.07814802719@cse.mait.ac.in>
2023-06-05 12:04:48 +00:00
Crowdin Bot 886f7021f4 New Crowdin translations by Github Action 2023-06-05 10:13:18 +00:00
Alex van Andel 2b17188087 Fixup tsconfig.json in packaged embed-react (#9330) 2023-06-05 09:57:53 +00:00
Ayush Mainali d498988bd4 fix: fixes page rendering comments initially (#9270) 2023-06-05 09:55:10 +00:00
Hariom Balhara 785a08ba2c Fix duplicate query param missing issue (#9328) 2023-06-05 09:50:34 +00:00
Hariom BalharaandBailey Pumfleet 6aa83102e4 Add stricter self-review guideline (#9327)
Co-authored-by: Bailey Pumfleet <bailey@pumfleet.co.uk>
2023-06-05 11:00:04 +01:00
Ujwal Kumar 97fe41f3ba Fix hardcoded label of identifier label in form builder (#9249) 2023-06-05 09:47:08 +00:00
Piyush GargandPeer Richelsen b7cecfbb66 fix: Skeleton Padding and Width Issue (#9310)
* Fixed the Skeleton Padding and Width Issue

* Fix the Icon Bounce on Skeleton

---------

Co-authored-by: Peer Richelsen <peeroke@gmail.com>
2023-06-05 09:24:16 +00:00
Anwar Sadath 7f7d80e653 fix: /getting-started/connected-calendar Toggle the first calendar on (#9028)
* [CAL-115] /getting-started/connected-calendar Toggle the first calendar on

* Fix lint error

* Fix error shown after completion of onboarding by connecting to calendars and playing around with toggle

* Fix type errors

* Fix first calendar selected even in all the screens wherever connectedCalendars is used
2023-06-05 09:21:50 +00:00
Ujwal Kumarandsean-brydon 64796a96fc Fix alignment of update and cancel button on sign up flow (#9218)
Co-authored-by: sean-brydon <55134778+sean-brydon@users.noreply.github.com>
2023-06-05 09:16:28 +00:00
Crowdin Bot 83cc7dc86e New Crowdin translations by Github Action 2023-06-05 09:23:16 +00:00
Nafees Nazik 75c9145558 feat: add disable signup feature flag (#9274)
* feat: add feature flag

* feat: use the feature flag
2023-06-05 09:08:16 +00:00
Nafees Nazik 869f459d98 fix: title in booking submitted page (#9326) 2023-06-05 07:28:03 +00:00
Crowdin Bot e00008b663 New Crowdin translations by Github Action 2023-06-05 06:04:16 +00:00
175f2482e1 fix: Update forms UI (#8093)
* Routing Forms: Update forms UI

* fix failing test

* fix: Routing Forms forms UI Update

* fix: Routing Forms forms UI Update

* Apply suggestions from code review

---------

Co-authored-by: gitstart-calcom <gitstart@users.noreply.github.com>
Co-authored-by: Peer Richelsen <peeroke@gmail.com>
Co-authored-by: Omar López <zomars@me.com>
Co-authored-by: Hariom Balhara <hariombalhara@gmail.com>
2023-06-05 05:51:19 +00:00
Crowdin Bot 9d91d72a72 New Crowdin translations by Github Action 2023-06-04 18:58:28 +00:00
Ujwal Kumar fd9cd1b98b fix: background colour for disabled select option (#9320)
* Fix disabled bg colour in CheckedTeamSelect

* Fix disabled bg colour in CheckedSelect, CheckedUserSelect, ChildrenEventTypeSelect
2023-06-04 18:46:19 +00:00
Crowdin Bot 2640040359 New Crowdin translations by Github Action 2023-06-03 11:13:34 +00:00
alannnc dec8f8e896 add team validations (#9300) 2023-06-03 11:02:23 +00:00
Efraín RochínandOmar López b4eff25636 fix: Issues with calendar sync at the beginning and end of month (#9282)
* increases the time range to cover all time zones

* remove console.log

---------

Co-authored-by: Omar López <zomars@me.com>
2023-06-02 20:17:53 +00:00
Alex van Andel 2a752e5358 v2.9.6
release.yml / release (push) Canceled after 0s
2023-06-02 22:18:28 +02:00
Syed Ali Shahbaz b2684837c1 Remove end as mandatory property (#9297) 2023-06-02 20:01:30 +00:00
Crowdin Bot 2fed2133a5 New Crowdin translations by Github Action 2023-06-02 19:44:04 +00:00
Alex van Andel 7fc0877c26 Set reqBody.end to start + eventType.length (#9296) 2023-06-02 19:29:52 +00:00
Crowdin Bot f7ce774ddc New Crowdin translations by Github Action 2023-06-02 18:42:40 +00:00
174c730f1f chore: add canonical to the document via PageWrapper (#8639)
* add canonical to the document via `PageWrapper`

* use WEBSITE_URL constant to create the canonical url value

---------

Co-authored-by: Keith Williams <keithwillcode@gmail.com>
Co-authored-by: Efraín Rochín <roae.85@gmail.com>
Co-authored-by: Peer Richelsen <peeroke@gmail.com>
2023-06-02 18:28:03 +00:00
Syed Ali Shahbaz 8ad513e4ec fix typo in swagger (#9278) 2023-06-01 21:09:18 +00:00
a0bf5b4067 test: Smoke Tests for packaged embeds and build improvements (#9169)
* Fix 2 Factor Auth

* Add a sandbox to verify types of embed-react

* Add fault types location

* Fix type location again

* Break types

* Ensure that builds are done again when doing pbublish

* Debug failure in CI

* Make sure unit test files arent used by playwright

* Fix embed-react test description

* Update .github/workflows/e2e-embed-react.yml

Co-authored-by: Omar López <zomars@me.com>

* Remove unnecessary log

---------

Co-authored-by: Alex van Andel <me@alexvanandel.com>
Co-authored-by: Omar López <zomars@me.com>
2023-06-01 20:41:30 +00:00
Hariom BalharaandOmar López 484f603c9e fix: Routing Forms, Number operators were using string operands (#9182)
* Fix operators for number

* Add number operator unit tests

* Fixes and remove between operators

---------

Co-authored-by: Omar López <zomars@me.com>
2023-06-01 20:29:13 +00:00
zomars 94b16fb327 Update yarn.lock 2023-06-01 12:29:49 -07:00
Jeroen Reumkens 55db7bdf76 Make new booker work with private links (#9260) 2023-06-01 18:55:43 +00:00
Crowdin Bot 14af241d5f New Crowdin translations by Github Action 2023-06-01 18:57:05 +00:00
Keith Williams 4efa90e42f chore: Upgrade turbo (#9271)
* chore: Upgrade turbo

* Pinned turbo version

* Revert "Pinned turbo version"

This reverts commit ae263009ee4750943e25efe62052152b40655844.

* Upgraded to 1.10.1
2023-06-01 18:43:21 +00:00
Peer Richelsen 581e1759c4 chore: prevent merge conflicts in common.json (#9268) 2023-06-01 15:47:43 +00:00
Crowdin Bot 61cdac321e New Crowdin translations by Github Action 2023-06-01 15:09:08 +00:00
Ayush MainaliandPeer Richelsen 59a04137a1 fix: fixed width resizing of colorpicker (#9233)
Co-authored-by: Peer Richelsen <peeroke@gmail.com>
2023-06-01 14:53:39 +00:00
Crowdin Bot eba1a1ffff New Crowdin translations by Github Action 2023-06-01 12:30:28 +00:00
Nafees Nazik df25b179d7 fix: use skeleton loader (#9264) 2023-06-01 12:17:11 +00:00
Ted Spare ff2d9ad67d Use github-script to safely label PRs from forks (#9256) 2023-06-01 11:48:36 +00:00
Crowdin Bot 485b72cd0d New Crowdin translations by Github Action 2023-06-01 11:56:48 +00:00
Jeroen ReumkensandPeer Richelsen 57eb5a4328 Fix for booker colors in dark mode, we can't use bg-default in both places because we use a custom background in dark mode. Otherwise it would be a similar color in dark. So we need to supply a custom dark mode color. (#9259)
Co-authored-by: Peer Richelsen <peeroke@gmail.com>
2023-06-01 11:38:52 +00:00
Peer Richelsen 2c4954e31c Update package.json
release.yml / release (push) Canceled after 0s
2023-06-01 12:43:56 +01:00
Alex van Andel 748f2b42e8 Remove debugger; calls (#9262) 2023-06-01 11:28:59 +00:00
Nafees NazikandKeith Williams 6bc713bc2e feat: add additional parameters for QR code generator app (#9177)
* fix: add i18n key

* fix: add additional parameters

* fix: query params

---------

Co-authored-by: Keith Williams <keithwillcode@gmail.com>
2023-06-01 10:13:54 +00:00
Hariom Balhara b1019d6bab fix: [Hotfix]No phone number is valid (#9258)
* Fix invalid phone number always

* Fix countrycode detection
2023-06-01 09:47:18 +00:00
Nafees Nazik 268f1872e4 fix: layout effect hook warning (#9226)
* feat: add isomorphic hook

* feat: use useIsomorphicLayoutEffect hook
2023-06-01 09:45:24 +00:00
Efraín RochínandKeith Williams 60d439cc32 prevents revalidation errors from reaching the when editing an event type (#9191)
Co-authored-by: Keith Williams <keithwillcode@gmail.com>
2023-06-01 09:16:30 +00:00
Crowdin Bot 36d201ac20 New Crowdin translations by Github Action 2023-06-01 08:01:31 +00:00
d6644bc232 feat: Customise JITSI Url path (#8835)
* Closes #1847 - adds an environment variable `JITSI_HOST_URL` to configure the Host URL for self hosted instances

* Closes #1847 - adds an environment variable `JITSI_HOST_URL` to configure the Host URL for self hosted instances

* Closes #1847 - adds an environment variable `JITSI_HOST_URL` to configure the Host URL for self hosted instances

* Replace Tab with spaces

* Add JITSI_HOST_URL env

* Remote Tabs for Spaces

* Support jitsi_host key

* Remove ENV, add Interface jitsi host URL and fallback

* Fix linting issues

* Clean code

* add missing await

* Add configurable meeting slug

* Refactor to jitsiHost, remove slug generator

* zod default doesnt work right now. So remove it

* Add replacement values and url encoding

* Change Placeholder to unified values.

---------

Co-authored-by: Udit Takkar <53316345+Udit-takkar@users.noreply.github.com>
Co-authored-by: Hariom Balhara <hariombalhara@gmail.com>
Co-authored-by: Peer Richelsen <peeroke@gmail.com>
2023-06-01 07:48:01 +00:00
alannnc 7a9b893931 Add startOf endOf day for date range (#9252) 2023-05-31 22:12:04 +00:00
Crowdin Bot 235c314e68 New Crowdin translations by Github Action 2023-05-31 21:02:11 +00:00
348 changed files with 5331 additions and 4755 deletions
-6
View File
@@ -106,12 +106,6 @@ LARK_OPEN_APP_ID=""
LARK_OPEN_APP_SECRET=""
LARK_OPEN_VERIFICATION_TOKEN=""
# - WEB3
# Used for the Web3 plugin
# @see https://github.com/calcom/cal.com/blob/main/packages/app-store/rainbow/README.md
ALCHEMY_API_KEY=""
INFURA_API_KEY=""
# - SALESFORCE
# Used for the Salesforce (Sales Cloud) app
SALESFORCE_CONSUMER_KEY=""
+3 -4
View File
@@ -8,8 +8,6 @@ Fixes # (issue)
Loom Video: https://www.loom.com/
-->
**Environment**: Staging(main branch) / Production
## Type of change
<!-- Please delete bullets that are not relevant. -->
@@ -27,13 +25,14 @@ Fixes # (issue)
- [ ] Test A
- [ ] Test B
## Mandatory Tasks
- [ ] Make sure you have self-reviewed the code. A decent size PR without self-review might be rejected.
## Checklist
<!-- Please remove all the irrelevant bullets to your PR -->
- I haven't read the [contributing guide](https://github.com/calcom/cal.com/blob/main/CONTRIBUTING.md)
- My code doesn't follow the style guidelines of this project
- I haven't performed a self-review of my own code and corrected any misspellings
- I haven't commented my code, particularly in hard-to-understand areas
- I haven't checked if my PR needs changes to the documentation
- I haven't checked if my changes generate no new warnings
+64 -16
View File
@@ -1,27 +1,75 @@
name: "Apply issue labels to PR"
on:
pull_request:
types: [opened]
pull_request_target:
types:
- opened
jobs:
label_on_pr:
runs-on: ubuntu-latest
permissions:
contents: none
issues: read
pull-requests: write
steps:
- name: Checkout repository
uses: actions/checkout@v2
- name: Setup Node.js
uses: actions/setup-node@v2
with:
node-version: 16
- name: Apply labels from linked issue to PR
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
PR_DATA: ${{ toJson(github.event.pull_request) }}
run: node ./.github/workflows/scripts/apply-issue-labels-to-pr.ts
uses: actions/github-script@v5
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
script: |
async function getLinkedIssues(owner, repo, prNumber) {
const query = `query GetLinkedIssues($owner: String!, $repo: String!, $prNumber: Int!) {
repository(owner: $owner, name: $repo) {
pullRequest(number: $prNumber) {
closingIssuesReferences(first: 10) {
nodes {
number
labels(first: 10) {
nodes {
name
}
}
}
}
}
}
}`;
const variables = {
owner: owner,
repo: repo,
prNumber: prNumber,
};
const result = await github.graphql(query, variables);
return result.repository.pullRequest.closingIssuesReferences.nodes;
}
const pr = context.payload.pull_request;
const linkedIssues = await getLinkedIssues(
context.repo.owner,
context.repo.repo,
pr.number
);
const labelsToAdd = new Set();
for (const issue of linkedIssues) {
if (issue.labels && issue.labels.nodes) {
for (const label of issue.labels.nodes) {
labelsToAdd.add(label.name);
}
}
}
if (labelsToAdd.size) {
await github.rest.issues.addLabels({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: pr.number,
labels: Array.from(labelsToAdd),
});
}
+3 -1
View File
@@ -25,7 +25,9 @@ jobs:
- uses: ./.github/actions/cache-db
- uses: ./.github/actions/cache-build
- name: Run Tests
run: yarn test-e2e:embed-react
run: |
yarn test-e2e:embed-react
yarn workspace @calcom/embed-react packaged:tests
env:
DEPLOYSENTINEL_API_KEY: ${{ secrets.DEPLOYSENTINEL_API_KEY }}
- name: Upload Test Results
@@ -1,139 +0,0 @@
const https = require("https");
async function applyLabelFromLinkedIssueToPR(pr, token) {
// Get the labels from issues linked to the PR
const query = `
query GetLinkedIssues($owner: String!, $repo: String!, $prNumber: Int!) {
repository(owner: $owner, name: $repo) {
pullRequest(number: $prNumber) {
closingIssuesReferences(first: 10) {
nodes {
number
labels(first: 10) {
nodes {
name
}
}
}
}
}
}
}
`;
const graphqlData = JSON.stringify({
query,
variables: {
owner: pr.base.repo.owner.login,
repo: pr.base.repo.name,
prNumber: pr.number,
},
});
const requestOptions = {
hostname: "api.github.com",
path: "/graphql",
method: "POST",
headers: {
"Content-Type": "application/json",
"Content-Length": graphqlData.length,
Authorization: "Bearer " + token,
"User-Agent": "Node.js",
},
};
// Use the native Node.js request library to make the request
let linkedIssues;
linkedIssues = await new Promise((resolve, reject) => {
const request = https.request(requestOptions, (response) => {
let responseBody = "";
response.on("data", (chunk) => {
responseBody += chunk;
});
response.on("end", () => {
resolve(JSON.parse(responseBody)?.data?.repository?.pullRequest?.closingIssuesReferences?.nodes);
});
});
request.on("error", (error) => {
reject(error);
});
request.write(graphqlData);
request.end();
});
if (!linkedIssues || linkedIssues.length === 0) {
console.log("No issue linked.");
return;
}
// Iterate over linked issues and apply labels to PR
for (const issue of linkedIssues) {
const labels = issue?.labels?.nodes?.map((label) => label.name);
if (!labels || labels.length === 0) {
console.log(`No labels found on the linked issue #${issue.number}.`);
continue;
}
const labelsData = JSON.stringify({
labels: labels,
});
const requestOptions = {
hostname: "api.github.com",
path: `/repos/${pr.base.repo.owner.login}/${pr.base.repo.name}/issues/${pr.number}/labels`,
method: "POST",
headers: {
"Content-Type": "application/json",
"Content-Length": labelsData.length,
Authorization: "Bearer " + token,
"User-Agent": "Node.js",
},
};
let labelResult;
labelResult = await new Promise((resolve, reject) => {
const request = https.request(requestOptions, (response) => {
let responseBody = "";
response.on("data", (chunk) => {
responseBody += chunk;
});
response.on("data", () => {});
response.on("end", () => {
resolve(JSON.parse(responseBody));
});
});
request.on("error", (error) => {
reject(error);
});
request.write(labelsData);
request.end();
});
if (labelResult.message) {
console.log(`Error labelling PR: ${labelResult.message}`);
continue;
}
console.log(
`Applied labels: ${labels.join(", ")} to PR #${pr.number} from linked issue #${issue.number}`
);
}
}
// Pass the PR data and GitHub token to the script
(async () => {
if (!process.env.PR_DATA) {
console.log("No PR data found.");
return;
}
const prData = JSON.parse(process.env.PR_DATA);
const token = process.env.GITHUB_TOKEN;
await applyLabelFromLinkedIssueToPR(prData, token);
})();
+1 -1
View File
@@ -416,7 +416,7 @@ Make sure to complete section "Obtaining the Google API Credentials". After the
following
1. Add extra redirect URL `<Cal.com URL>/api/auth/callback/google`
1. Under 'OAuth concent screen', click "PUBLISH APP"
1. Under 'OAuth consent screen', click "PUBLISH APP"
### Obtaining Microsoft Graph Client ID and Secret
+1 -1
View File
@@ -33,7 +33,7 @@ import { schemaQuerySingleOrMultipleUserIds } from "~/lib/validations/shared/que
* type: integer
* example: [2, 3, 4]
* - in: query
* name: attendeeEmails
* name: attendeeEmail
* required: false
* schema:
* oneOf:
-1
View File
@@ -26,7 +26,6 @@ import { defaultResponder } from "@calcom/lib/server";
* required:
* - eventTypeId
* - start
* - end
* - name
* - email
* - timeZone
+1 -1
View File
@@ -30,7 +30,7 @@ export const SnippedGenerator = {
// extend some internals to gain information about current path, method and spec in the generator function metioned later
spec: {
wrapSelectors: {
requestFor: (ori, system) => (state, path, method) => {
requestFor: (ori) => (state, path, method) => {
return ori(path, method)
?.set("spec", state.get("json", {}))
?.setIn(["oasPathMethod", "path"], path)
+1
View File
@@ -60,6 +60,7 @@ export default function AppListCard(props: AppListCardProps) {
timeoutRef.current = null;
}
};
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);
return (
+1 -6
View File
@@ -1133,12 +1133,7 @@ export const EmbedDialog = () => {
const router = useRouter();
const embedUrl: string = router.query.embedUrl as string;
return (
<Dialog
name="embed"
clearQueryParamsOnClose={queryParamsForDialog}
onOpenChange={(open) => {
if (!open) window.resetEmbedStatus();
}}>
<Dialog name="embed" clearQueryParamsOnClose={queryParamsForDialog}>
{!router.query.embedType ? (
<ChooseEmbedTypesDialogContent />
) : (
-51
View File
@@ -1,51 +0,0 @@
import dynamic from "next/dynamic";
import type { Dispatch } from "react";
import { useState, useEffect } from "react";
import type { JSONObject } from "superjson/dist/types";
export type Gate = undefined | "rainbow"; // Add more like ` | "geolocation" | "payment"`
export type GateState = {
rainbowToken?: string;
};
type GateProps = {
children: React.ReactNode;
gates: Gate[];
appData: JSONObject;
dispatch: Dispatch<Partial<GateState>>;
};
const RainbowGate = dynamic(() => import("@calcom/app-store/rainbow/components/RainbowKit"));
// To add a new Gate just add the gate logic to the switch statement
const Gates: React.FC<GateProps> = ({ children, gates, appData, dispatch }) => {
const [rainbowToken, setRainbowToken] = useState<string>();
useEffect(() => {
dispatch({ rainbowToken });
}, [rainbowToken, dispatch]);
let gateWrappers = <>{children}</>;
// Recursively wraps the `gateWrappers` with new gates allowing for multiple gates
for (const gate of gates) {
switch (gate) {
case "rainbow":
if (appData.blockchainId && appData.smartContractAddress && !rainbowToken) {
gateWrappers = (
<RainbowGate
setToken={setRainbowToken}
chainId={appData.blockchainId as number}
tokenAddress={appData.smartContractAddress as string}>
{gateWrappers}
</RainbowGate>
);
}
}
}
return gateWrappers;
};
export default Gates;
+19 -2
View File
@@ -5,6 +5,8 @@ import Script from "next/script";
import "@calcom/embed-core/src/embed-iframe";
import LicenseRequired from "@calcom/features/ee/common/components/LicenseRequired";
import { WEBAPP_URL } from "@calcom/lib/constants";
import { buildCanonical } from "@calcom/lib/next-seo.config";
import type { AppProps } from "@lib/app-providers";
import AppProviders from "@lib/app-providers";
@@ -13,7 +15,7 @@ import { seoConfig } from "@lib/config/next-seo.config";
import I18nLanguageHandler from "@components/I18nLanguageHandler";
export interface CalPageWrapper {
(props?: any): JSX.Element;
(props?: AppProps): JSX.Element;
PageWrapper?: AppProps["Component"]["PageWrapper"];
}
@@ -49,9 +51,24 @@ function PageWrapper(props: AppProps) {
};
// Use the layout defined at the page level, if available
const getLayout = Component.getLayout ?? ((page) => page);
// Canonical: Check if the URL is from cal.com so that we set the canonical conditionally
const isCalcom =
WEBAPP_URL &&
(new URL(WEBAPP_URL).hostname.endsWith("cal.com") || new URL(WEBAPP_URL).hostname.endsWith("cal.dev"));
const path = router.asPath;
return (
<AppProviders {...providerProps}>
<DefaultSeo {...seoConfig.defaultNextSeo} />
<DefaultSeo
// Set canonical to https://cal.com or self-hosted URL
canonical={
isCalcom
? buildCanonical({ path, origin: "https://cal.com" }) // cal.com & .dev
: buildCanonical({ path, origin: WEBAPP_URL }) // self-hosted
}
{...seoConfig.defaultNextSeo}
/>
<I18nLanguageHandler />
<Script
nonce={nonce}
@@ -1,3 +1,5 @@
import type { FunctionComponent, SVGProps } from "react";
import { InstallAppButton } from "@calcom/app-store/components";
import { useLocale } from "@calcom/lib/hooks/useLocale";
import { trpc } from "@calcom/trpc/react";
@@ -55,7 +57,7 @@ const AdditionalCalendarSelector = ({ isLoading }: AdditionalCalendarSelectorPro
<InstallAppButton
type={data.type}
render={(installProps) => {
const props = { ...installProps } as any;
const props = { ...installProps } as FunctionComponent<SVGProps<SVGSVGElement>>;
return (
<DropdownItem {...props} color="minimal" type="button">
<span className="flex items-center gap-x-2">
@@ -2,60 +2,12 @@ import type { ComponentProps } from "react";
import React from "react";
import AppCategoryNavigation from "@calcom/app-store/_components/AppCategoryNavigation";
import type { InstalledAppVariants } from "@calcom/app-store/utils";
import Shell from "@calcom/features/shell/Shell";
import { trpc } from "@calcom/trpc/react";
import type { HorizontalTabItemProps, VerticalTabItemProps } from "@calcom/ui";
import { BarChart, Calendar, CreditCard, Grid, Share2, Video } from "@calcom/ui/components/icon";
const tabs: (VerticalTabItemProps | HorizontalTabItemProps)[] = [
{
name: "calendar",
href: "/apps/installed/calendar",
icon: Calendar,
},
{
name: "conferencing",
href: "/apps/installed/conferencing",
icon: Video,
},
{
name: "payment",
href: "/apps/installed/payment",
icon: CreditCard,
},
{
name: "automation",
href: "/apps/installed/automation",
icon: Share2,
},
{
name: "analytics",
href: "/apps/installed/analytics",
icon: BarChart,
},
{
name: "other",
href: "/apps/installed/other",
icon: Grid,
},
];
export default function InstalledAppsLayout({
children,
...rest
}: { children: React.ReactNode } & ComponentProps<typeof Shell>) {
const variant: (typeof InstalledAppVariants)[number] = "payment";
const query = trpc.viewer.integrations.useQuery({
variant,
onlyInstalled: true,
});
let actualTabs = tabs;
if (query.data?.items.length === 0) {
actualTabs = tabs.filter((tab) => tab.name !== variant);
}
return (
<Shell {...rest} hideHeadingOnMobile>
<AppCategoryNavigation baseURL="/apps/installed" containerClassname="min-w-0 w-full">
@@ -28,7 +28,6 @@ type AvailableTimesProps = {
bookingAttendees?: number | null;
slots?: Slot[];
isLoading: boolean;
ethSignature?: string;
duration: number;
};
@@ -43,7 +42,6 @@ const AvailableTimes: FC<AvailableTimesProps> = ({
onTimeFormatChange,
seatsPerTimeSlot,
bookingAttendees,
ethSignature,
duration,
}) => {
const reserveSlotMutation = trpc.viewer.public.slots.reserveSlot.useMutation();
@@ -119,7 +117,6 @@ const AvailableTimes: FC<AvailableTimesProps> = ({
timeFormat,
/** Treat as recurring only when a count exist and it's not a rescheduling workflow */
count: recurringCount && !rescheduleUid ? recurringCount : undefined,
...(ethSignature ? { ethSignature } : {}),
},
};
@@ -80,7 +80,6 @@ export const SlotPicker = ({
seatsPerTimeSlot,
bookingAttendees,
weekStart = 0,
ethSignature,
}: {
eventType: Pick<
EventType & { metadata: z.infer<typeof EventTypeMetaDataSchema> },
@@ -94,7 +93,6 @@ export const SlotPicker = ({
recurringEventCount?: number;
users: string[];
weekStart?: 0 | 1 | 2 | 3 | 4 | 5 | 6;
ethSignature?: string;
}) => {
const [selectedDate, setSelectedDate] = useState<Dayjs>();
const [browsingDate, setBrowsingDate] = useState<Dayjs>();
@@ -193,7 +191,6 @@ export const SlotPicker = ({
seatsPerTimeSlot={seatsPerTimeSlot}
bookingAttendees={bookingAttendees}
recurringCount={recurringEventCount}
ethSignature={ethSignature}
duration={parseInt(duration)}
/>
</>
@@ -1,10 +1,9 @@
import dynamic from "next/dynamic";
import { useRouter } from "next/router";
import { useEffect, useMemo, useReducer, useState } from "react";
import { useEffect, useMemo, useState } from "react";
import { z } from "zod";
import BookingPageTagManager from "@calcom/app-store/BookingPageTagManager";
import { getEventTypeAppData } from "@calcom/app-store/utils";
import dayjs from "@calcom/dayjs";
import {
useEmbedNonStylesConfig,
@@ -27,8 +26,6 @@ import { CreditCard, User, RefreshCcw } from "@calcom/ui/components/icon";
import { timeZone as localStorageTimeZone } from "@lib/clock";
import type { Gate, GateState } from "@components/Gates";
import Gates from "@components/Gates";
import BookingDescription from "@components/booking/BookingDescription";
import { SlotPicker } from "@components/booking/SlotPicker";
@@ -89,14 +86,6 @@ const AvailabilityPage = ({ profile, eventType, ...restProps }: Props) => {
setIs24hClockInLocalStorage(is24Hours);
};
const [gateState, gateDispatcher] = useReducer(
(state: GateState, newState: Partial<GateState>) => ({
...state,
...newState,
}),
{}
);
useEffect(() => {
setTimeZone(localStorageTimeZone() || dayjs.tz.guess());
}, []);
@@ -124,20 +113,11 @@ const AvailabilityPage = ({ profile, eventType, ...restProps }: Props) => {
);
const paymentAppData = getPaymentAppData(eventType);
const rainbowAppData = getEventTypeAppData(eventType, "rainbow") || {};
const rawSlug = profile.slug ? profile.slug.split("/") : [];
if (rawSlug.length > 1) rawSlug.pop(); //team events have team name as slug, but user events have [user]/[type] as slug.
const showEventTypeDetails = (isEmbed && !embedUiConfig.hideEventTypeDetails) || !isEmbed;
// Define conditional gates here
const gates = [
// Rainbow gate is only added if the event has both a `blockchainId` and a `smartContractAddress`
rainbowAppData && rainbowAppData.blockchainId && rainbowAppData.smartContractAddress
? ("rainbow" as Gate)
: undefined,
];
const { data: bookingAttendees } = trpc.viewer.bookings.getBookingAttendees.useQuery(
{
seatReferenceUid: rescheduleUid,
@@ -148,7 +128,7 @@ const AvailabilityPage = ({ profile, eventType, ...restProps }: Props) => {
);
return (
<Gates gates={gates} appData={rainbowAppData} dispatch={gateDispatcher}>
<>
<HeadSeo
title={`${rescheduleUid ? t("reschedule") : ""} ${eventType.title} | ${profile.name}`}
description={`${rescheduleUid ? t("reschedule") : ""} ${eventType.title}`}
@@ -296,7 +276,6 @@ const AvailabilityPage = ({ profile, eventType, ...restProps }: Props) => {
seatsPerTimeSlot={eventType.seatsPerTimeSlot || undefined}
bookingAttendees={bookingAttendees || undefined}
recurringEventCount={recurringEventCount}
ethSignature={gateState.rainbowToken}
/>
</div>
</div>
@@ -306,7 +285,7 @@ const AvailabilityPage = ({ profile, eventType, ...restProps }: Props) => {
</main>
</div>
<Toaster position="bottom-right" />
</Gates>
</>
);
};
@@ -4,7 +4,7 @@ import { useSession } from "next-auth/react";
import dynamic from "next/dynamic";
import Head from "next/head";
import { useRouter } from "next/router";
import { useEffect, useMemo, useReducer, useState } from "react";
import { useEffect, useMemo, useState } from "react";
import { useForm, useFormContext } from "react-hook-form";
import { v4 as uuidv4 } from "uuid";
import { z } from "zod";
@@ -12,7 +12,6 @@ import { z } from "zod";
import BookingPageTagManager from "@calcom/app-store/BookingPageTagManager";
import type { EventLocationType } from "@calcom/app-store/locations";
import { createPaymentLink } from "@calcom/app-store/stripepayment/lib/client";
import { getEventTypeAppData } from "@calcom/app-store/utils";
import type { LocationObject } from "@calcom/core/location";
import dayjs from "@calcom/dayjs";
import {
@@ -51,8 +50,6 @@ import { AlertTriangle, Calendar, RefreshCw, User } from "@calcom/ui/components/
import { timeZone } from "@lib/clock";
import useRouterQuery from "@lib/hooks/useRouterQuery";
import type { Gate, GateState } from "@components/Gates";
import Gates from "@components/Gates";
import BookingDescription from "@components/booking/BookingDescription";
import type { BookPageProps } from "../../../pages/[user]/book";
@@ -224,13 +221,6 @@ const BookingPage = ({
const { data: session } = useSession();
const isBackgroundTransparent = useIsBackgroundTransparent();
const telemetry = useTelemetry();
const [gateState, gateDispatcher] = useReducer(
(state: GateState, newState: Partial<GateState>) => ({
...state,
...newState,
}),
{}
);
const { timezone } = useTimePreferences();
@@ -488,7 +478,6 @@ const BookingPage = ({
metadata,
hasHashedBookingLink,
hashedLink,
ethSignature: gateState.rainbowToken,
}));
recurringMutation.mutate(recurringBookings);
} else {
@@ -506,25 +495,15 @@ const BookingPage = ({
metadata,
hasHashedBookingLink,
hashedLink,
ethSignature: gateState.rainbowToken,
seatReferenceUid: router.query.seatReferenceUid as string,
});
}
};
const showEventTypeDetails = (isEmbed && !embedUiConfig.hideEventTypeDetails) || !isEmbed;
const rainbowAppData = getEventTypeAppData(eventType, "rainbow") || {};
// Define conditional gates here
const gates = [
// Rainbow gate is only added if the event has both a `blockchainId` and a `smartContractAddress`
rainbowAppData && rainbowAppData.blockchainId && rainbowAppData.smartContractAddress
? ("rainbow" as Gate)
: undefined,
];
return (
<Gates gates={gates} appData={rainbowAppData} dispatch={gateDispatcher}>
<>
<Head>
<title>
{rescheduleUid
@@ -686,7 +665,7 @@ const BookingPage = ({
</div>
</main>
<Toaster position="bottom-right" />
</Gates>
</>
);
};
@@ -16,6 +16,7 @@ import {
allowDisablingHostConfirmationEmails,
} from "@calcom/features/ee/workflows/lib/allowDisablingStandardEmails";
import { FormBuilder } from "@calcom/features/form-builder/FormBuilder";
import { BookerLayoutSelector } from "@calcom/features/settings/BookerLayoutSelector";
import { classNames } from "@calcom/lib";
import { APP_NAME, CAL_URL } from "@calcom/lib/constants";
import { useLocale } from "@calcom/lib/hooks/useLocale";
@@ -65,7 +66,7 @@ export const EventAdvancedTab = ({ eventType, team }: Pick<EventTypeSetupProps,
const [requiresConfirmation, setRequiresConfirmation] = useState(eventType.requiresConfirmation);
const placeholderHashedLink = `${CAL_URL}/d/${hashedUrl}/${eventType.slug}`;
const seatsEnabled = formMethods.watch("seatsPerTimeSlotEnabled");
const noShowFeeEnabled = eventType.metadata.apps?.stripe?.paymentOption === "HOLD";
const noShowFeeEnabled = eventType.metadata?.apps?.stripe?.paymentOption === "HOLD";
useEffect(() => {
!hashedUrl && setHashedUrl(generateHashedLink(eventType.users[0]?.id ?? team?.id));
@@ -159,6 +160,10 @@ export const EventAdvancedTab = ({ eventType, team }: Pick<EventTypeSetupProps,
}
/>
</div>
<hr className="border-subtle [&:has(+div:empty)]:hidden" />
<div>
<BookerLayoutSelector fallbackToUserSettings />
</div>
<hr className="border-subtle" />
<FormBuilder
title={t("booking_questions_title")}
@@ -104,9 +104,9 @@ export const EventAppsTab = ({ eventType }: { eventType: EventType }) => {
</div>
</div>
{!shouldLockDisableProps("apps").disabled && (
<div>
<div className="bg-muted rounded-md p-8">
{!isLoading && notInstalledApps?.length ? (
<h2 className="text-emphasis my-2 text-lg font-semibold">{t("available_apps")}</h2>
<h2 className="text-emphasis text-lg font-semibold">{t("available_apps")}</h2>
) : null}
<div className="before:border-0">
{notInstalledApps?.map((app) => (
@@ -115,7 +115,7 @@ export const EventSetupTab = (
const [showLocationModal, setShowLocationModal] = useState(false);
const [editingLocationType, setEditingLocationType] = useState<string>("");
const [selectedLocation, setSelectedLocation] = useState<LocationOption | undefined>(undefined);
const [multipleDuration, setMultipleDuration] = useState(eventType.metadata.multipleDuration);
const [multipleDuration, setMultipleDuration] = useState(eventType.metadata?.multipleDuration);
const locationOptions = props.locationOptions.filter((option) => {
return !team ? option.label !== "Conferencing" : true;
@@ -75,8 +75,7 @@ function getNavigation(props: {
installedAppsNumber: number;
availability: AvailabilityOption | undefined;
}) {
const { eventType, t, enabledAppsNumber, installedAppsNumber, enabledWorkflowsNumber, availability } =
props;
const { eventType, t, enabledAppsNumber, installedAppsNumber, enabledWorkflowsNumber } = props;
const duration =
eventType.metadata?.multipleDuration?.map((duration) => ` ${duration}`) || eventType.length;
@@ -178,6 +177,7 @@ function EventTypeSingleLayout({
enabledWorkflowsNumber,
availability,
});
navigation.splice(1, 0, {
name: "availability",
href: `/event-types/${eventType.id}?tabName=availability`,
@@ -185,7 +185,7 @@ function EventTypeSingleLayout({
info:
isManagedEventType || isChildrenManagedEventType
? eventType.schedule === null
? "Member's default schedule"
? "member_default_schedule"
: isChildrenManagedEventType
? `${
eventType.scheduleName
@@ -193,7 +193,7 @@ function EventTypeSingleLayout({
: `default_schedule_name`
}`
: eventType.scheduleName ?? `default_schedule_name`
: `default_schedule_name`,
: eventType.scheduleName ?? `default_schedule_name`,
});
// If there is a team put this navigation item within the tabs
if (team) {
@@ -220,7 +220,18 @@ function EventTypeSingleLayout({
});
}
return navigation;
}, [t, eventType, installedAppsNumber, enabledAppsNumber, enabledWorkflowsNumber, team, availability]);
}, [
t,
eventType,
enabledAppsNumber,
installedAppsNumber,
enabledWorkflowsNumber,
availability,
isManagedEventType,
isChildrenManagedEventType,
team,
formMethods,
]);
const permalink = `${CAL_URL}/${team ? `team/${team.slug}` : eventType.users[0].username}/${
eventType.slug
@@ -236,7 +247,7 @@ function EventTypeSingleLayout({
heading={eventType.title}
CTA={
<div className="flex items-center justify-end">
{!eventType.metadata.managedEventConfig && (
{!eventType.metadata?.managedEventConfig && (
<>
<div
className={classNames(
@@ -379,7 +390,7 @@ function EventTypeSingleLayout({
<Button
className="ml-4 lg:ml-0"
type="submit"
loading={formMethods.formState.isSubmitting || isUpdateMutationLoading}
loading={isUpdateMutationLoading}
data-testid="update-eventtype"
form="event-type-form">
{t("save")}
@@ -39,6 +39,7 @@ export default function RequiresConfirmationController({
if (!requiresConfirmation) {
formMethods.setValue("metadata.requiresConfirmationThreshold", undefined);
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [requiresConfirmation]);
const { shouldLockDisableProps } = useLockedFieldsManager(
@@ -15,7 +15,7 @@ interface IConnectCalendarsProps {
const ConnectedCalendars = (props: IConnectCalendarsProps) => {
const { nextStep } = props;
const queryConnectedCalendars = trpc.viewer.connectedCalendars.useQuery();
const queryConnectedCalendars = trpc.viewer.connectedCalendars.useQuery({ onboarding: true });
const { t } = useLocale();
const queryIntegrations = trpc.viewer.integrations.useQuery({ variant: "calendar", onlyInstalled: false });
@@ -24,7 +24,7 @@ interface IUserProfileProps {
const UserProfile = (props: IUserProfileProps) => {
const { user } = props;
const { t } = useLocale();
const avatarRef = useRef<HTMLInputElement>(null!);
const avatarRef = useRef<HTMLInputElement>(null);
const { setValue, handleSubmit, getValues } = useForm<FormData>({
defaultValues: { bio: user?.bio || "" },
});
@@ -76,7 +76,7 @@ const UserProfile = (props: IUserProfileProps) => {
async function updateProfileHandler(event: FormEvent<HTMLFormElement>) {
event.preventDefault();
const enteredAvatar = avatarRef.current.value;
const enteredAvatar = avatarRef.current?.value;
mutation.mutate({
avatar: enteredAvatar,
});
@@ -127,14 +127,16 @@ const UserProfile = (props: IUserProfileProps) => {
id="avatar-upload"
buttonMsg={t("add_profile_photo")}
handleAvatarChange={(newAvatar) => {
avatarRef.current.value = newAvatar;
if (avatarRef.current) {
avatarRef.current.value = newAvatar;
}
const nativeInputValueSetter = Object.getOwnPropertyDescriptor(
window.HTMLInputElement.prototype,
"value"
)?.set;
nativeInputValueSetter?.call(avatarRef.current, newAvatar);
const ev2 = new Event("input", { bubbles: true });
avatarRef.current.dispatchEvent(ev2);
avatarRef.current?.dispatchEvent(ev2);
updateProfileHandler(ev2 as unknown as FormEvent<HTMLFormElement>);
setImageSrc(newAvatar);
}}
@@ -79,7 +79,7 @@ const UsernameTextfield = (props: ICustomUsernameProps) => {
const ActionButtons = () => {
return usernameIsAvailable && currentUsername !== inputUsernameValue ? (
<div className="ms-2 me-2 mt-px flex flex-row space-x-2">
<div className="ms-2 me-2 flex flex-row space-x-2">
<Button
type="button"
onClick={() => setOpenDialogSaveUsername(true)}
@@ -142,7 +142,7 @@ const UsernameTextfield = (props: ICustomUsernameProps) => {
</div>
)}
</div>
<div className="mt-5 hidden md:inline">
<div className="mt-7 hidden md:inline">
<ActionButtons />
</div>
</div>
@@ -26,12 +26,6 @@ export const CheckedSelect = ({
return (
<>
<Select
styles={{
option: (styles, { isDisabled }) => ({
...styles,
backgroundColor: isDisabled ? "#F5F5F5" : "inherit",
}),
}}
name={props.name}
placeholder={props.placeholder || t("select")}
isSearchable={false}
+4 -2
View File
@@ -66,6 +66,7 @@ export function QueryCell<TData, TError extends ErrorLike>(
if ("empty" in opts && (query.data == null || (Array.isArray(query.data) && query.data.length === 0))) {
return opts.empty(query);
}
// eslint-disable-next-line @typescript-eslint/no-explicit-any
return opts.success(query as any);
}
@@ -88,9 +89,10 @@ const withQuery = <
TInput = inferProcedureInput<TQuery>,
TOutput = inferProcedureOutput<TQuery>
>(
queryProcedure: DecorateProcedure<TQuery, any, any>,
queryProcedure: DecorateProcedure<TQuery, inferProcedureInput<TQuery>, inferProcedureOutput<TQuery>>,
input?: TInput,
params?: UseTRPCQueryOptions<any, TInput, TOutput, TOutput, TError>
params?: UseTRPCQueryOptions<TQuery, TInput, TOutput, TOutput, TError>
) => {
return function WithQuery(
opts: Omit<
+19 -1
View File
@@ -5,7 +5,25 @@ export default function useRouterQuery<T extends string>(name: T) {
const existingQueryParams = router.asPath.split("?")[1];
const urlParams = new URLSearchParams(existingQueryParams);
const query = Object.fromEntries(urlParams);
const query: Record<string, string | string[]> = {};
// Following error is thrown by Typescript:
// 'Type 'URLSearchParams' can only be iterated through when using the '--downlevelIteration' flag or with a '--target' of 'es2015' or higher'
// We should change the target to higher ES2019 atleast maybe
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-expect-error
for (const [key, value] of urlParams) {
if (!query[key]) {
query[key] = value;
} else {
let queryValue = query[key];
if (queryValue instanceof Array) {
queryValue.push(value);
} else {
queryValue = query[key] = [queryValue];
queryValue.push(value);
}
}
}
const setQuery = (newValue: string | number | null | undefined) => {
router.replace({ query: { ...router.query, [name]: newValue } }, undefined, { shallow: true });
+2 -1
View File
@@ -1,6 +1,7 @@
/* eslint-disable @typescript-eslint/no-explicit-any */
type GetSSRResult<TProps> =
//
{ props: TProps } | { redirect: any } | { notFound: boolean };
{ props: TProps } | { redirect: { destination: string; permanent: boolean } } | { notFound: boolean };
type GetSSRFn<TProps> = (...args: any[]) => Promise<GetSSRResult<TProps>>;
+5
View File
@@ -215,6 +215,11 @@ const nextConfig = {
destination: "/new-booker/team/:slug/:type",
has: [{ type: "cookie", key: "new-booker-enabled" }],
},
{
source: "/d/:link/:slug",
destination: "/new-booker/d/:link/:slug",
has: [{ type: "cookie", key: "new-booker-enabled" }],
},
];
},
async headers() {
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@calcom/web",
"version": "2.9.5",
"version": "2.9.7",
"private": true,
"scripts": {
"analyze": "ANALYZE=true next build",
@@ -3,18 +3,16 @@
* caching system that NextJS uses SSG pages.
* TODO: Redirect to user profile on browser
*/
import type { GetStaticPaths, GetStaticProps } from "next";
import type { GetStaticPaths, GetStaticProps, InferGetStaticPropsType } from "next";
import { z } from "zod";
import { getCachedResults } from "@calcom/core";
import getCalendarsEvents from "@calcom/core/getCalendarsEvents";
import dayjs from "@calcom/dayjs";
import prisma from "@calcom/prisma";
const CalendarCache = () => <div />;
const paramsSchema = z.object({ user: z.string(), month: z.string() });
export const getStaticProps: GetStaticProps<
{ results: Awaited<ReturnType<typeof getCachedResults>> },
{ results: Awaited<ReturnType<typeof getCalendarsEvents>> },
{ user: string }
> = async (context) => {
const { user: username, month } = paramsSchema.parse(context.params);
@@ -29,16 +27,16 @@ export const getStaticProps: GetStaticProps<
selectedCalendars: true,
},
});
const startDate = (
dayjs(month, "YYYY-MM").isSame(dayjs(), "month") ? dayjs.utc() : dayjs.utc(month, "YYYY-MM")
).startOf("day");
const endDate = startDate.endOf("month");
// Subtract 11 hours from the start date to avoid problems in UTC- time zones.
const startDate = dayjs.utc(month, "YYYY-MM").startOf("day").subtract(11, "hours").format();
// Add 14 hours from the start date to avoid problems in UTC+ time zones.
const endDate = dayjs.utc(month, "YYYY-MM").endOf("month").add(14, "hours").format();
try {
const results = userWithCredentials?.credentials
? await getCachedResults(
? await getCalendarsEvents(
userWithCredentials?.credentials,
startDate.format(),
endDate.format(),
startDate,
endDate,
userWithCredentials?.selectedCalendars
)
: [];
@@ -64,5 +62,8 @@ export const getStaticPaths: GetStaticPaths = () => {
fallback: "blocking",
};
};
type Props = InferGetStaticPropsType<typeof getStaticProps>;
const CalendarCache = (props: Props) =>
process.env.NODE_ENV === "development" ? <pre>{JSON.stringify(props, null, " ")}</pre> : <div />;
export default CalendarCache;
+4
View File
@@ -48,6 +48,10 @@ class MyDocument extends Document<Props> {
<meta name="msapplication-TileColor" content="#ff0000" />
<meta name="theme-color" media="(prefers-color-scheme: light)" content="#f9fafb" />
<meta name="theme-color" media="(prefers-color-scheme: dark)" content="#1C1C1C" />
<meta
name="viewport"
content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0"
/>
</Head>
<body
+17 -11
View File
@@ -1,11 +1,20 @@
import type { NextApiRequest, NextApiResponse } from "next";
import { z } from "zod";
import { hashPassword } from "@calcom/features/auth/lib/hashPassword";
import { sendEmailVerification } from "@calcom/features/auth/lib/verifyEmail";
import slugify from "@calcom/lib/slugify";
import { closeComUpsertTeamUser } from "@calcom/lib/sync/SyncServiceManager";
import prisma from "@calcom/prisma";
import { IdentityProvider } from "@calcom/prisma/enums";
const signupSchema = z.object({
username: z.string(),
email: z.string().email(),
password: z.string().min(7),
language: z.string().optional(),
});
export default async function handler(req: NextApiRequest, res: NextApiResponse) {
if (req.method !== "POST") {
return;
@@ -17,7 +26,8 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse)
}
const data = req.body;
const { email, password } = data;
const { email, password, language } = signupSchema.parse(data);
const username = slugify(data.username);
const userEmail = email.toLowerCase();
@@ -26,16 +36,6 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse)
return;
}
if (!userEmail || !userEmail.includes("@")) {
res.status(422).json({ message: "Invalid email" });
return;
}
if (!password || password.trim().length < 7) {
res.status(422).json({ message: "Invalid input - password should be at least 7 characters long." });
return;
}
// There is an existingUser if the username matches
// OR if the email matches AND either the email is verified
// or both username and password are set
@@ -106,5 +106,11 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse)
}
}
await sendEmailVerification({
email: userEmail,
username,
language,
});
res.status(201).json({ message: "Created user" });
}
+48
View File
@@ -0,0 +1,48 @@
import type { NextApiRequest, NextApiResponse } from "next";
import { z } from "zod";
import dayjs from "@calcom/dayjs";
import { WEBAPP_URL } from "@calcom/lib/constants";
import { prisma } from "@calcom/prisma";
const verifySchema = z.object({
token: z.string(),
});
export default async function handler(req: NextApiRequest, res: NextApiResponse) {
const { token } = verifySchema.parse(req.query);
const foundToken = await prisma.verificationToken.findFirst({
where: {
token,
},
});
if (!foundToken) {
return res.status(401).json({ message: "No token found" });
}
if (dayjs(foundToken?.expires).isBefore(dayjs())) {
return res.status(401).json({ message: "Token expired" });
}
const user = await prisma.user.update({
where: {
email: foundToken?.identifier,
},
data: {
emailVerified: new Date(),
},
});
// Delete token from DB after it has been used
await prisma.verificationToken.delete({
where: {
id: foundToken?.id,
},
});
const hasCompletedOnboarding = user.completedOnboarding;
res.redirect(`${WEBAPP_URL}/${hasCompletedOnboarding ? "/event-types" : "/getting-started"}`);
}
+8 -3
View File
@@ -60,9 +60,14 @@ const handler = async (req: NextApiRequest, res: NextApiResponse) => {
res.setHeader("Content-Type", "text/html");
res.setHeader("Cache-Control", "no-cache, no-store, private, must-revalidate");
res.write(
renderEmail("OrganizerRequestEmail", {
calEvent: evt,
attendee: evt.organizer,
renderEmail("VerifyAccountEmail", {
language: t,
user: {
name: "Pro Example",
email: "pro@example.com",
},
verificationEmailLink:
"http://localhost:3000/api/auth/verify-email?token=b91af0eee5a9a24a8d83a3d3d6a58c1606496e94ced589441649273c66100f5b",
})
);
res.end();
+11 -2
View File
@@ -26,7 +26,7 @@ const decryptedSchema = z.object({
async function handler(req: NextApiRequest, res: NextApiResponse<Response>) {
const { action, token, reason } = querySchema.parse(req.query);
const { bookingUid } = decryptedSchema.parse(
const { bookingUid, userId } = decryptedSchema.parse(
JSON.parse(symmetricDecrypt(decodeURIComponent(token), process.env.CALENDSO_ENCRYPTION_KEY || ""))
);
@@ -34,10 +34,19 @@ async function handler(req: NextApiRequest, res: NextApiResponse<Response>) {
where: { uid: bookingUid },
});
const user = await prisma.user.findUniqueOrThrow({
where: { id: userId },
});
try {
/** @see https://trpc.io/docs/server-side-calls */
const ctx = await createContext({ req, res });
const caller = viewerRouter.createCaller({ ...ctx, req, res });
const caller = viewerRouter.createCaller({
...ctx,
req,
res,
user: { ...user, locale: user?.locale ?? "en" },
});
await caller.bookings.confirm({
bookingId: booking.id,
recurringEventId: booking.recurringEventId || undefined,
-4
View File
@@ -1,4 +0,0 @@
import ethRouter from "@calcom/app-store/rainbow/trpc/router";
import { createNextApiHandler } from "@calcom/trpc/server/createNextApiHandler";
export default createNextApiHandler(ethRouter);
+1
View File
@@ -19,6 +19,7 @@ export default function Page() {
callbackUrl: "/",
code,
});
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);
return null;
+2 -1
View File
@@ -5,6 +5,7 @@ import { useState } from "react";
import AdminAppsList from "@calcom/features/apps/AdminAppsList";
import { getServerSession } from "@calcom/features/auth/lib/getServerSession";
import { getDeploymentKey } from "@calcom/features/ee/deployment/lib/getDeploymentKey";
import { APP_NAME } from "@calcom/lib/constants";
import { useLocale } from "@calcom/lib/hooks/useLocale";
import prisma from "@calcom/prisma";
import { UserPermissionRole } from "@calcom/prisma/enums";
@@ -95,7 +96,7 @@ export function Setup(props: inferSSRProps<typeof getServerSideProps>) {
steps.push({
title: t("enable_apps"),
description: t("enable_apps_description"),
description: t("enable_apps_description", { appName: APP_NAME }),
contentClassname: "!pb-0 mb-[-1px]",
content: (setIsLoading) => {
const currentStep = isFreeLicense ? 3 : 4;
+4 -2
View File
@@ -111,8 +111,10 @@ export const getServerSideProps = async (context: GetServerSidePropsContext) =>
const ret = await samlTenantProduct(prisma, emailParam);
tenant = ret.tenant;
product = ret.product;
} catch (e: any) {
error = e.message;
} catch (e) {
if (e instanceof Error) {
error = e.message;
}
}
}
}
+2
View File
@@ -18,6 +18,7 @@ export default function Page({ samlTenantID, samlProductID }: inferSSRProps<type
if (HOSTED_CAL_FEATURES) {
router.push("/auth/login");
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);
useEffect(() => {
@@ -29,6 +30,7 @@ export default function Page({ samlTenantID, samlProductID }: inferSSRProps<type
},
{ tenant: samlTenantID, product: samlProductID }
);
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);
return null;
+60
View File
@@ -0,0 +1,60 @@
import { MailOpenIcon } from "lucide-react";
import { useSession } from "next-auth/react";
import { useRouter } from "next/router";
import { useEffect } from "react";
import { APP_NAME } from "@calcom/lib/constants";
import { useLocale } from "@calcom/lib/hooks/useLocale";
import { trpc } from "@calcom/trpc";
import useEmailVerifyCheck from "@calcom/trpc/react/hooks/useEmailVerifyCheck";
import { Button, EmptyScreen, showToast } from "@calcom/ui";
import PageWrapper from "@components/PageWrapper";
function VerifyEmailPage() {
const { data } = useEmailVerifyCheck();
const { data: session } = useSession();
const router = useRouter();
const { t } = useLocale();
const mutation = trpc.viewer.auth.resendVerifyEmail.useMutation();
useEffect(() => {
if (data?.isVerified) {
router.replace("/getting-started");
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [data?.isVerified]);
return (
<div className="h-[100vh] w-full ">
<div className="flex h-full w-full flex-col items-center justify-center">
<div className="max-w-3xl">
<EmptyScreen
border
dashedBorder={false}
Icon={MailOpenIcon}
headline={t("check_your_email")}
description={t("verify_email_page_body", { email: session?.user?.email, appName: APP_NAME })}
className="bg-default"
buttonRaw={
<Button
color="minimal"
className="underline"
loading={mutation.isLoading}
onClick={() => {
showToast("Send email", "success");
mutation.mutate();
}}>
Resend Email
</Button>
}
/>
</div>
</div>
</div>
);
}
export default VerifyEmailPage;
VerifyEmailPage.PageWrapper = PageWrapper;
+2 -1
View File
@@ -105,7 +105,8 @@ export function AvailabilityList({ schedules }: RouterOutputs["viewer"]["availab
);
}
const WithQuery = withQuery(trpc.viewer.availability.list);
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const WithQuery = withQuery(trpc.viewer.availability.list as any);
export default function AvailabilityPage() {
const { t } = useLocale();
+1 -1
View File
@@ -26,7 +26,7 @@ const AvailabilityView = ({ user }: { user: User }) => {
const { data, isLoading } = trpc.viewer.availability.user.useQuery(
{
username: user.username!,
username: user.username || "",
dateFrom: selectedDate.startOf("day").utc().format(),
dateTo: selectedDate.endOf("day").utc().format(),
withSource: true,
+3 -5
View File
@@ -102,7 +102,6 @@ export default function Success(props: SuccessProps) {
allRemainingBookings,
isSuccessBookingPage,
cancel: isCancellationMode,
changes,
formerTime,
email,
seatReferenceUid,
@@ -222,6 +221,7 @@ export default function Success(props: SuccessProps) {
setCalculatedDuration(
dayjs(props.bookingInfo.endTime).diff(dayjs(props.bookingInfo.startTime), "minutes")
);
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);
function eventLink(): string {
@@ -279,9 +279,7 @@ export default function Success(props: SuccessProps) {
darkBrandColor: props.profile.darkBrandColor,
});
const title = t(
`booking_${needsConfirmation ? "booking_submitted" : "confirmed"}${
props.recurringBookings ? "_recurring" : ""
}`
`booking_${needsConfirmation ? "submitted" : "confirmed"}${props.recurringBookings ? "_recurring" : ""}`
);
const locationToDisplay = getSuccessPageLocationMessage(
@@ -402,7 +400,7 @@ export default function Success(props: SuccessProps) {
</>
)}
<div className="font-medium">{t("what")}</div>
<div className="col-span-2 mb-6 last:mb-0">{props.bookingInfo.title}</div>
<div className="col-span-2 mb-6 last:mb-0">{eventName}</div>
<div className="font-medium">{t("when")}</div>
<div className="col-span-2 mb-6 last:mb-0">
{reschedule && !!formerTime && (
+56 -43
View File
@@ -3,7 +3,7 @@ import { useAutoAnimate } from "@formkit/auto-animate/react";
import { zodResolver } from "@hookform/resolvers/zod";
import type { GetServerSidePropsContext } from "next";
import { Trans } from "next-i18next";
import { useEffect, useState } from "react";
import { useEffect, useMemo, useState } from "react";
import { useForm } from "react-hook-form";
import { z } from "zod";
@@ -17,9 +17,14 @@ import { useLocale } from "@calcom/lib/hooks/useLocale";
import { useTypedQuery } from "@calcom/lib/hooks/useTypedQuery";
import { HttpError } from "@calcom/lib/http-error";
import { telemetryEventTypes, useTelemetry } from "@calcom/lib/telemetry";
import { validateBookerLayouts } from "@calcom/lib/validateBookerLayouts";
import type { Prisma } from "@calcom/prisma/client";
import type { PeriodType, SchedulingType } from "@calcom/prisma/enums";
import type { customInputSchema, EventTypeMetaDataSchema } from "@calcom/prisma/zod-utils";
import type {
BookerLayoutSettings,
customInputSchema,
EventTypeMetaDataSchema,
} from "@calcom/prisma/zod-utils";
import { eventTypeBookingFields } from "@calcom/prisma/zod-utils";
import type { RouterOutputs } from "@calcom/trpc/react";
import { trpc } from "@calcom/trpc/react";
@@ -96,6 +101,7 @@ export type FormValues = {
hosts: { userId: number; isFixed: boolean }[];
bookingFields: z.infer<typeof eventTypeBookingFields>;
availability?: AvailabilityOption;
bookerLayouts: BookerLayoutSettings;
};
export type CustomInputParsed = typeof customInputSchema._output;
@@ -184,17 +190,17 @@ const EventTypePage = (props: EventTypeSetupProps) => {
const metadata = eventType.metadata;
// fallback to !!eventType.schedule when 'useHostSchedulesForTeamEvent' is undefined
if (!!team) {
if (!!team && metadata !== null) {
metadata.config = {
...metadata.config,
useHostSchedulesForTeamEvent:
typeof eventType.metadata.config?.useHostSchedulesForTeamEvent !== "undefined"
? eventType.metadata.config?.useHostSchedulesForTeamEvent === true
typeof eventType.metadata?.config?.useHostSchedulesForTeamEvent !== "undefined"
? eventType.metadata?.config?.useHostSchedulesForTeamEvent === true
: !!eventType.schedule,
};
} else {
// Make sure non-team events NEVER have this config key;
delete metadata.config?.useHostSchedulesForTeamEvent;
delete metadata?.config?.useHostSchedulesForTeamEvent;
}
const bookingFields: Prisma.JsonObject = {};
@@ -203,41 +209,43 @@ const EventTypePage = (props: EventTypeSetupProps) => {
bookingFields[name] = name;
});
const defaultValues = {
title: eventType.title,
locations: eventType.locations || [],
recurringEvent: eventType.recurringEvent || null,
description: eventType.description ?? undefined,
schedule: eventType.schedule || undefined,
bookingLimits: eventType.bookingLimits || undefined,
durationLimits: eventType.durationLimits || undefined,
length: eventType.length,
offsetStart: eventType.offsetStart,
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,
children: eventType.children.map((ch) => ({
...ch,
created: true,
owner: {
...ch.owner,
eventTypeSlugs:
eventType.team?.members
.find((mem) => mem.user.id === ch.owner.id)
?.user.eventTypes.map((evTy) => evTy.slug)
.filter((slug) => slug !== eventType.slug) ?? [],
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const defaultValues: any = useMemo(() => {
return {
title: eventType.title,
locations: eventType.locations || [],
recurringEvent: eventType.recurringEvent || null,
description: eventType.description ?? undefined,
schedule: eventType.schedule || undefined,
bookingLimits: eventType.bookingLimits || undefined,
durationLimits: eventType.durationLimits || undefined,
length: eventType.length,
hidden: eventType.hidden,
periodDates: {
startDate: periodDates.startDate,
endDate: periodDates.endDate,
},
})),
} as const;
bookingFields: eventType.bookingFields,
periodType: eventType.periodType,
periodCountCalendarDays: eventType.periodCountCalendarDays ? "1" : "0",
schedulingType: eventType.schedulingType,
minimumBookingNotice: eventType.minimumBookingNotice,
metadata,
hosts: eventType.hosts,
children: eventType.children.map((ch) => ({
...ch,
created: true,
owner: {
...ch.owner,
eventTypeSlugs:
eventType.team?.members
.find((mem) => mem.user.id === ch.owner.id)
?.user.eventTypes.map((evTy) => evTy.slug)
.filter((slug) => slug !== eventType.slug) ?? [],
},
})),
};
}, [eventType, periodDates, metadata]);
const formMethods = useForm<FormValues>({
defaultValues,
@@ -270,6 +278,7 @@ const EventTypePage = (props: EventTypeSetupProps) => {
//TODO: What's the best way to sync the form with backend
formMethods.setValue("bookingFields", defaultValues.bookingFields);
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [defaultValues]);
const appsMetadata = formMethods.getValues("metadata")?.apps;
@@ -332,6 +341,7 @@ const EventTypePage = (props: EventTypeSetupProps) => {
seatsPerTimeSlotEnabled,
// eslint-disable-next-line @typescript-eslint/no-unused-vars
minimumBookingNoticeInDurationType,
bookerLayouts,
...input
} = values;
@@ -345,6 +355,9 @@ const EventTypePage = (props: EventTypeSetupProps) => {
if (!isValid) throw new Error(t("event_setup_duration_limits_error"));
}
const layoutError = validateBookerLayouts(metadata?.bookerLayouts || null);
if (layoutError) throw new Error(t(layoutError));
if (metadata?.multipleDuration !== undefined) {
if (metadata?.multipleDuration.length < 1) {
throw new Error(t("event_setup_multiple_duration_error"));
@@ -415,9 +428,6 @@ const EventTypePage = (props: EventTypeSetupProps) => {
// We don't need to send send these values to the backend
// eslint-disable-next-line @typescript-eslint/no-unused-vars
seatsPerTimeSlotEnabled,
// eslint-disable-next-line @typescript-eslint/no-unused-vars
minimumBookingNoticeInDurationType,
availability,
...input
} = values;
@@ -431,6 +441,9 @@ const EventTypePage = (props: EventTypeSetupProps) => {
if (!isValid) throw new Error(t("event_setup_duration_limits_error"));
}
const layoutError = validateBookerLayouts(metadata?.bookerLayouts || null);
if (layoutError) throw new Error(t(layoutError));
if (metadata?.multipleDuration !== undefined) {
if (metadata?.multipleDuration.length < 1) {
throw new Error(t("event_setup_multiple_duration_error"));
+11 -7
View File
@@ -393,11 +393,13 @@ export const EventTypeList = ({ group, groupIndex, readOnly, types }: EventTypeL
className="relative top-1 right-3"
size="sm"
truncateAfter={4}
items={type.users.map((organizer: { name: any; username: any }) => ({
alt: organizer.name || "",
image: `${WEBAPP_URL}/${organizer.username}/avatar.png`,
title: organizer.name || "",
}))}
items={type.users.map(
(organizer: { name: string | null; username: string | null }) => ({
alt: organizer.name || "",
image: `${WEBAPP_URL}/${organizer.username}/avatar.png`,
title: organizer.name || "",
})
)}
/>
)}
{isManagedEventType && (
@@ -780,7 +782,8 @@ const CTA = () => {
);
};
const WithQuery = withQuery(trpc.viewer.eventTypes.getByViewer);
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const WithQuery = withQuery(trpc.viewer.eventTypes.getByViewer as any);
const EventTypesPage = () => {
const { t } = useLocale();
@@ -793,6 +796,7 @@ const EventTypesPage = () => {
if (query?.openIntercom && query?.openIntercom === "true") {
open();
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);
return (
@@ -816,7 +820,7 @@ const EventTypesPage = () => {
{isMobile ? (
<MobileTeamsTab eventTypeGroups={data.eventTypeGroups} />
) : (
data.eventTypeGroups.map((group, index) => (
data.eventTypeGroups.map((group: EventTypeGroup, index: number) => (
<div className="flex flex-col" key={group.profile.slug}>
<EventTypeListHeading
profile={group.profile}
@@ -117,9 +117,7 @@ const OnboardingPage = (props: IOnboardingPageProps) => {
}
key={router.asPath}>
<Head>
<title>
{APP_NAME} - {t("getting_started")}
</title>
<title>{`${APP_NAME} - ${t("getting_started")}`}</title>
<link rel="icon" href="/favicon.ico" />
</Head>
@@ -0,0 +1,120 @@
import type { GetServerSidePropsContext } from "next";
import { z } from "zod";
import { Booker } from "@calcom/atoms";
import { BookerSeo } from "@calcom/features/bookings/components/BookerSeo";
import { getBookingByUidOrRescheduleUid } from "@calcom/features/bookings/lib/get-booking";
import type { GetBookingType } from "@calcom/features/bookings/lib/get-booking";
import prisma from "@calcom/prisma";
import type { inferSSRProps } from "@lib/types/inferSSRProps";
import PageWrapper from "@components/PageWrapper";
type PageProps = inferSSRProps<typeof getServerSideProps>;
export default function Type({ slug, user, booking, away, isBrandingHidden }: PageProps) {
return (
<main className="flex h-full min-h-[100dvh] items-center justify-center">
<BookerSeo
username={user}
eventSlug={slug}
rescheduleUid={booking?.uid}
hideBranding={isBrandingHidden}
/>
<Booker
username={user}
eventSlug={slug}
rescheduleBooking={booking}
isAway={away}
hideBranding={isBrandingHidden}
/>
</main>
);
}
Type.PageWrapper = PageWrapper;
async function getUserPageProps(context: GetServerSidePropsContext) {
const { link, slug } = paramsSchema.parse(context.params);
const { rescheduleUid } = context.query;
const { ssrInit } = await import("@server/lib/ssr");
const ssr = await ssrInit(context);
const hashedLink = await prisma.hashedLink.findUnique({
where: {
link,
},
select: {
eventTypeId: true,
eventType: {
select: {
users: {
select: {
username: true,
},
},
},
},
},
});
const username = hashedLink?.eventType.users[0]?.username;
if (!hashedLink || !username) {
return {
notFound: true,
};
}
const user = await prisma.user.findUnique({
where: {
username,
},
select: {
away: true,
hideBranding: true,
},
});
if (!user) {
return {
notFound: true,
};
}
let booking: GetBookingType | null = null;
if (rescheduleUid) {
booking = await getBookingByUidOrRescheduleUid(`${rescheduleUid}`);
}
// We use this to both prefetch the query on the server,
// as well as to check if the event exist, so we c an show a 404 otherwise.
const eventData = await ssr.viewer.public.event.fetch({ username, eventSlug: slug });
if (!eventData) {
return {
notFound: true,
};
}
return {
props: {
booking,
away: user?.away,
user: username,
slug,
trpcState: ssr.dehydrate(),
isBrandingHidden: user?.hideBranding,
},
};
}
const paramsSchema = z.object({ link: z.string(), slug: z.string() });
// Booker page fetches a tiny bit of data server side, to determine early
// whether the page should show an away state or dynamic booking not allowed.
export const getServerSideProps = async (context: GetServerSidePropsContext) => {
return await getUserPageProps(context);
};
@@ -1,12 +1,14 @@
import { useState } from "react";
import { Controller, useForm } from "react-hook-form";
import { BookerLayoutSelector } from "@calcom/features/settings/BookerLayoutSelector";
import ThemeLabel from "@calcom/features/settings/ThemeLabel";
import { getLayout } from "@calcom/features/settings/layouts/SettingsLayout";
import { APP_NAME } from "@calcom/lib/constants";
import { checkWCAGContrastColor } from "@calcom/lib/getBrandColours";
import { useHasPaidPlan } from "@calcom/lib/hooks/useHasPaidPlan";
import { useLocale } from "@calcom/lib/hooks/useLocale";
import { validateBookerLayouts } from "@calcom/lib/validateBookerLayouts";
import { trpc } from "@calcom/trpc/react";
import {
Alert,
@@ -62,6 +64,7 @@ const AppearanceView = () => {
brandColor: user?.brandColor || "#292929",
darkBrandColor: user?.darkBrandColor || "#fafafa",
hideBranding: user?.hideBranding,
defaultBookerLayouts: user?.defaultBookerLayouts,
},
});
@@ -76,8 +79,12 @@ const AppearanceView = () => {
showToast(t("settings_updated_successfully"), "success");
reset(data);
},
onError: () => {
showToast(t("error_updating_settings"), "error");
onError: (error) => {
if (error.message) {
showToast(error.message, "error");
} else {
showToast(t("error_updating_settings"), "error");
}
},
});
@@ -92,6 +99,9 @@ const AppearanceView = () => {
<Form
form={formMethods}
handleSubmit={(values) => {
const layoutError = validateBookerLayouts(values.defaultBookerLayouts || null);
if (layoutError) throw new Error(t(layoutError));
mutation.mutate({
...values,
// Radio values don't support null as values, therefore we convert an empty string
@@ -130,6 +140,13 @@ const AppearanceView = () => {
/>
</div>
<hr className="border-subtle my-8 border [&:has(+hr)]:hidden" />
<BookerLayoutSelector
name="metadata.defaultBookerLayouts"
title={t("bookerlayout_user_settings_title")}
description={t("bookerlayout_user_settings_description")}
/>
<hr className="border-subtle my-8 border" />
<div className="mb-6 flex items-center text-sm">
<div>
@@ -46,7 +46,10 @@ interface GeneralViewProps {
user: RouterOutputs["viewer"]["me"];
}
const WithQuery = withQuery(trpc.viewer.public.i18n, undefined, { trpc: { context: { skipBatch: true } } });
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const WithQuery = withQuery(trpc.viewer.public.i18n as any, undefined, {
trpc: { context: { skipBatch: true } },
});
const GeneralQueryView = () => {
const { t } = useLocale();
@@ -34,7 +34,7 @@ const PasswordView = () => {
onSettled: () => {
utils.viewer.me.invalidate();
},
onMutate: async ({ metadata }) => {
onMutate: async () => {
await utils.viewer.me.cancel();
const previousValue = utils.viewer.me.getData();
const previousMetadata = userMetadata.parse(previousValue?.metadata);
+12 -5
View File
@@ -9,10 +9,11 @@ import { z } from "zod";
import LicenseRequired from "@calcom/features/ee/common/components/LicenseRequired";
import { checkPremiumUsername } from "@calcom/features/ee/common/lib/checkPremiumUsername";
import { isSAMLLoginEnabled } from "@calcom/features/ee/sso/lib/saml";
import { useFlagMap } from "@calcom/features/flags/context/provider";
import { getFeatureFlagMap } from "@calcom/features/flags/server/utils";
import { IS_SELF_HOSTED, WEBAPP_URL } from "@calcom/lib/constants";
import { useLocale } from "@calcom/lib/hooks/useLocale";
import { collectPageParameters, telemetryEventTypes, useTelemetry } from "@calcom/lib/telemetry";
import prisma from "@calcom/prisma";
import type { inferSSRProps } from "@calcom/types/inferSSRProps";
import { Alert, Button, EmailField, HeadSeo, PasswordField, TextField } from "@calcom/ui";
@@ -29,10 +30,10 @@ type FormValues = {
};
export default function Signup({ prepopulateFormValues, token }: inferSSRProps<typeof getServerSideProps>) {
const { t } = useLocale();
const { t, i18n } = useLocale();
const router = useRouter();
const flags = useFlagMap();
const telemetry = useTelemetry();
const methods = useForm<FormValues>({
defaultValues: prepopulateFormValues,
});
@@ -52,6 +53,7 @@ export default function Signup({ prepopulateFormValues, token }: inferSSRProps<t
await fetch("/api/auth/signup", {
body: JSON.stringify({
...data,
language: i18n.language,
}),
headers: {
"Content-Type": "application/json",
@@ -61,11 +63,12 @@ export default function Signup({ prepopulateFormValues, token }: inferSSRProps<t
.then(handleErrors)
.then(async () => {
telemetry.event(telemetryEventTypes.signup, collectPageParameters());
const verifyOrGettingStarted = flags["email-verification"] ? "auth/verify-email" : "getting-started";
await signIn<"credentials">("credentials", {
...data,
callbackUrl: router.query.callbackUrl
? `${WEBAPP_URL}/${router.query.callbackUrl}`
: `${WEBAPP_URL}/getting-started`,
: `${WEBAPP_URL}/${verifyOrGettingStarted}`,
});
})
.catch((err) => {
@@ -158,6 +161,8 @@ export default function Signup({ prepopulateFormValues, token }: inferSSRProps<t
}
export const getServerSideProps = async (ctx: GetServerSidePropsContext) => {
const prisma = await import("@calcom/prisma").then((mod) => mod.default);
const flags = await getFeatureFlagMap(prisma);
const ssr = await ssrInit(ctx);
const token = z.string().optional().parse(ctx.query.token);
@@ -168,7 +173,9 @@ export const getServerSideProps = async (ctx: GetServerSidePropsContext) => {
prepopulateFormValues: undefined,
};
if (process.env.NEXT_PUBLIC_DISABLE_SIGNUP === "true") {
if (process.env.NEXT_PUBLIC_DISABLE_SIGNUP === "true" || flags["disable-signup"]) {
console.log({ flag: flags["disable-signup"] });
return {
notFound: true,
};
+2
View File
@@ -64,6 +64,7 @@ export default function JoinCall(props: JoinCallPageProps) {
return () => {
callFrame.destroy();
};
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);
const onRecordingStopped = () => {
@@ -169,6 +170,7 @@ function ProgressBar(props: ProgressBarProps) {
intervalRef.current = null;
}
};
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);
const prev = startDuration - duration;
+2 -2
View File
@@ -9,7 +9,7 @@ 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();
await pro.login();
await pro.apiLogin();
await page.goto("/apps/categories/calendar");
await page.click('[data-testid="app-store-app-card-apple-calendar"]');
await page.waitForURL("/apps/apple-calendar");
@@ -19,7 +19,7 @@ test.describe("App Store - Authed", () => {
test("Installed Apps - Navigation", async ({ page, users }) => {
const user = await users.create();
await user.login();
await user.apiLogin();
await page.goto("/apps/installed");
await page.waitForSelector('[data-testid="connect-calendar-apps"]');
await page.click('[data-testid="vertical-tab-payment"]');
+51 -51
View File
@@ -3,7 +3,7 @@ import { test } from "../lib/fixtures";
test.describe("Can signup from a team invite", async () => {
test.beforeEach(async ({ users }) => {
const proUser = await users.create();
await proUser.login();
await proUser.apiLogin();
});
test.afterEach(async ({ users }) => users.deleteAll());
@@ -33,65 +33,65 @@ test.describe("Can signup from a team invite", async () => {
// Wait for the invite to be sent
/*await page.waitForSelector(`[data-testid="member-email"][data-email="${testUser.email}"]`);
const tokenObj = await prisma.verificationToken.findFirstOrThrow({
where: { identifier: testUser.email },
select: { token: true },
});
const tokenObj = await prisma.verificationToken.findFirstOrThrow({
where: { identifier: testUser.email },
select: { token: true },
});
if (!proUser.username) throw Error("Test username is null, can't continue");
if (!proUser.username) throw Error("Test username is null, can't continue");
// Open a new user window to accept the invite
const newPage = await browser.newPage();
await newPage.goto(`/auth/signup?token=${tokenObj.token}&callbackUrl=${WEBAPP_URL}/settings/teams`);
// Open a new user window to accept the invite
const newPage = await browser.newPage();
await newPage.goto(`/auth/signup?token=${tokenObj.token}&callbackUrl=${WEBAPP_URL}/settings/teams`);
// Fill in form
await newPage.fill('input[name="username"]', proUser.username); // Invalid username
await newPage.fill('input[name="email"]', testUser.email);
await newPage.fill('input[name="password"]', testUser.password);
await newPage.fill('input[name="passwordcheck"]', testUser.password);
await newPage.press('input[name="passwordcheck"]', "Enter"); // Press Enter to submit
// Fill in form
await newPage.fill('input[name="username"]', proUser.username); // Invalid username
await newPage.fill('input[name="email"]', testUser.email);
await newPage.fill('input[name="password"]', testUser.password);
await newPage.fill('input[name="passwordcheck"]', testUser.password);
await newPage.press('input[name="passwordcheck"]', "Enter"); // Press Enter to submit
await expect(newPage.locator('text="Username already taken"')).toBeVisible();
await expect(newPage.locator('text="Username already taken"')).toBeVisible();
// Email address is already registered
// TODO: Form errors don't disappear when corrected and resubmitted, so we need to refresh
await newPage.reload();
await newPage.fill('input[name="username"]', testUser.username);
await newPage.fill('input[name="email"]', `${proUser.username}@example.com`); // Taken email
await newPage.fill('input[name="password"]', testUser.password);
await newPage.fill('input[name="passwordcheck"]', testUser.password);
await newPage.press('input[name="passwordcheck"]', "Enter"); // Press Enter to submit
await expect(newPage.locator('text="Email address is already registered"')).toBeVisible();
// Email address is already registered
// TODO: Form errors don't disappear when corrected and resubmitted, so we need to refresh
await newPage.reload();
await newPage.fill('input[name="username"]', testUser.username);
await newPage.fill('input[name="email"]', `${proUser.username}@example.com`); // Taken email
await newPage.fill('input[name="password"]', testUser.password);
await newPage.fill('input[name="passwordcheck"]', testUser.password);
await newPage.press('input[name="passwordcheck"]', "Enter"); // Press Enter to submit
await expect(newPage.locator('text="Email address is already registered"')).toBeVisible();
// Successful signup
// TODO: Form errors don't disappear when corrected and resubmitted, so we need to refresh
await newPage.reload();
await newPage.fill('input[name="username"]', testUser.username);
await newPage.fill('input[name="email"]', testUser.email);
await newPage.fill('input[name="password"]', testUser.password);
await newPage.fill('input[name="passwordcheck"]', testUser.password);
await newPage.press('input[name="passwordcheck"]', "Enter"); // Press Enter to submit
await expect(newPage.locator(`[data-testid="login-form"]`)).toBeVisible();
// Successful signup
// TODO: Form errors don't disappear when corrected and resubmitted, so we need to refresh
await newPage.reload();
await newPage.fill('input[name="username"]', testUser.username);
await newPage.fill('input[name="email"]', testUser.email);
await newPage.fill('input[name="password"]', testUser.password);
await newPage.fill('input[name="passwordcheck"]', testUser.password);
await newPage.press('input[name="passwordcheck"]', "Enter"); // Press Enter to submit
await expect(newPage.locator(`[data-testid="login-form"]`)).toBeVisible();
// We don't need the new browser anymore
await newPage.close();
// We don't need the new browser anymore
await newPage.close();
const createdUser = await prisma.user.findUniqueOrThrow({
where: { email: testUser.email },
include: { teams: { include: { team: true } } },
});
const createdUser = await prisma.user.findUniqueOrThrow({
where: { email: testUser.email },
include: { teams: { include: { team: true } } },
});
console.log("createdUser", createdUser);
console.log("createdUser", createdUser);
// Check that the user was created
expect(createdUser).not.toBeNull();
expect(createdUser.username).toBe(testUser.username);
expect(createdUser.password).not.toBeNull();
expect(createdUser.emailVerified).not.toBeNull();
// Check that the user accepted the team invite
expect(createdUser.teams).toHaveLength(1);
expect(createdUser.teams[0].team.name).toBe(teamName);
expect(createdUser.teams[0].role).toBe("MEMBER");
expect(createdUser.teams[0].accepted).toBe(true);*/
// Check that the user was created
expect(createdUser).not.toBeNull();
expect(createdUser.username).toBe(testUser.username);
expect(createdUser.password).not.toBeNull();
expect(createdUser.emailVerified).not.toBeNull();
// Check that the user accepted the team invite
expect(createdUser.teams).toHaveLength(1);
expect(createdUser.teams[0].team.name).toBe(teamName);
expect(createdUser.teams[0].role).toBe("MEMBER");
expect(createdUser.teams[0].accepted).toBe(true);*/
});
});
@@ -8,17 +8,16 @@ test("Can delete user account", async ({ page, users }) => {
const user = await users.create({
username: "delete-me",
});
await user.login();
await user.apiLogin();
await page.goto(`/settings/my-account/profile`);
await page.waitForSelector("[data-testid=dashboard-shell]");
await page.goto(`/settings/my-account/profile`);
await page.waitForLoadState("networkidle");
await page.click("[data-testid=delete-account]");
if (!user.username) throw Error(`Test user doesn't have a username`);
expect(user.username).toBeTruthy();
const $passwordField = page.locator("[data-testid=password]");
await $passwordField.fill(user.username);
await $passwordField.fill(String(user.username));
await Promise.all([
page.waitForURL((url) => url.pathname === "/auth/logout"),
@@ -5,9 +5,10 @@ import { test } from "../lib/fixtures";
test.afterEach(({ users }) => users.deleteAll());
test("Can reset forgotten password", async ({ page, users }) => {
// eslint-disable-next-line playwright/no-skipped-test
test.skip(process.env.NEXT_PUBLIC_IS_E2E !== "1", "It shouldn't if we can't skip email");
const user = await users.create();
const newPassword = `${user.username!}-123`;
const newPassword = `${user.username}-123`;
// Got to reset password flow
await page.goto("/auth/forgot-password");
@@ -17,7 +18,7 @@ test("Can reset forgotten password", async ({ page, users }) => {
// Press Enter
await Promise.all([
page.waitForURL((u) => u.pathname.startsWith("/auth/forgot-password/")),
page.waitForURL((u) => u.pathname.startsWith("/auth/forgot-password")),
page.press('input[name="email"]', "Enter"),
]);
+1 -1
View File
@@ -9,7 +9,7 @@ test.describe.configure({ mode: "parallel" });
test.describe("Availablity tests", () => {
test.beforeEach(async ({ page, users }) => {
const user = await users.create();
await user.login();
await user.apiLogin();
await page.goto("/availability");
// We wait until loading is finished
await page.waitForSelector('[data-testid="schedules"]');
+3 -3
View File
@@ -78,7 +78,7 @@ testBothBookers.describe("pro user", () => {
const [eventType] = pro.eventTypes;
await bookings.create(pro.id, pro.username, eventType.id);
await pro.login();
await pro.apiLogin();
await page.goto("/bookings/upcoming");
await page.waitForSelector('[data-testid="bookings"]');
await page.locator('[data-testid="edit_booking"]').nth(0).click();
@@ -106,7 +106,7 @@ testBothBookers.describe("pro user", () => {
await expect(page.locator(`[data-testid="attendee-name-${testName}"]`)).toHaveText(testName);
const [pro] = users.get();
await pro.login();
await pro.apiLogin();
await page.goto("/bookings/upcoming");
await page.locator('[data-testid="cancel"]').first().click();
@@ -132,7 +132,7 @@ testBothBookers.describe("pro user", () => {
}) => {
await bookOptinEvent(page);
const [pro] = users.get();
await pro.login();
await pro.apiLogin();
await page.goto("/bookings/unconfirmed");
await Promise.all([
+17 -5
View File
@@ -14,6 +14,7 @@ import {
selectFirstAvailableTimeSlotNextMonth,
} from "./lib/testUtils";
test.describe.configure({ mode: "parallel" });
test.afterEach(({ users }) => users.deleteAll());
async function createUserWithSeatedEvent(users: Fixtures["users"]) {
@@ -50,17 +51,27 @@ async function createUserWithSeatedEventAndAttendees(
testBothBookers.describe("Booking with Seats", (bookerVariant) => {
test("User can create a seated event (2 seats as example)", async ({ users, page }) => {
const user = await users.create({ name: "Seated event" });
await user.login();
await user.apiLogin();
await page.goto("/event-types");
// We wait until loading is finished
await page.waitForSelector('[data-testid="event-types"]');
const eventTitle = "My 2-seated event";
await createNewSeatedEventType(page, { eventTitle });
await expect(page.locator(`text=${eventTitle} event type updated successfully`)).toBeVisible();
});
test("Multiple Attendees can book a seated event time slot", async ({ users, page }) => {
const slug = "my-2-seated-event";
const user = await users.create({
name: "Seated event user",
eventTypes: [
{ title: "My 2-seated event", slug, length: 60, seatsPerTimeSlot: 2, seatsShowAttendees: true },
{
title: "My 2-seated event",
slug,
length: 60,
seatsPerTimeSlot: 2,
seatsShowAttendees: true,
},
],
});
await page.goto(`/${user.username}/${slug}`);
@@ -93,6 +104,7 @@ testBothBookers.describe("Booking with Seats", (bookerVariant) => {
await expect(page.locator("[data-testid=success-page]")).toBeHidden();
});
});
// TODO: Make E2E test: Attendee #1 should be able to cancel his booking
// todo("Attendee #1 should be able to cancel his booking");
// TODO: Make E2E test: Attendee #1 should be able to reschedule his booking
@@ -222,7 +234,7 @@ testBothBookers.describe("Reschedule for booking with seats", () => {
{ name: "John First", email: "first+seats@cal.com", timeZone: "Europe/Berlin" },
{ name: "Jane Second", email: "second+seats@cal.com", timeZone: "Europe/Berlin" },
]);
await user.login();
await user.apiLogin();
const oldBooking = await prisma.booking.findFirst({
where: { uid: booking.uid },
@@ -328,7 +340,7 @@ testBothBookers.describe("Reschedule for booking with seats", () => {
{ name: "John First", email: "first+seats@cal.com", timeZone: "Europe/Berlin" },
{ name: "Jane Second", email: "second+seats@cal.com", timeZone: "Europe/Berlin" },
]);
await user.login();
await user.apiLogin();
const bookingAttendees = await prisma.attendee.findMany({
where: { bookingId: booking.id },
@@ -379,7 +391,7 @@ testBothBookers.describe("Reschedule for booking with seats", () => {
{ name: "John First", email: "first+seats@cal.com", timeZone: "Europe/Berlin" },
{ name: "Jane Second", email: "second+seats@cal.com", timeZone: "Europe/Berlin" },
]);
await user.login();
await user.apiLogin();
const bookingWithEventType = await prisma.booking.findFirst({
where: { uid: booking.uid },
select: {
+4 -3
View File
@@ -7,15 +7,16 @@ test.afterEach(({ users }) => users.deleteAll());
test.describe("Change Password Test", () => {
test("change password", async ({ page, users }) => {
const pro = await users.create();
await pro.login();
await pro.apiLogin();
// Go to http://localhost:3000/settings/security
await page.goto("/settings/security/password");
if (!pro.username) throw Error("Test user doesn't have a username");
expect(pro.username).toBeTruthy();
await page.waitForLoadState("networkidle");
// Fill form
await page.locator('[name="oldPassword"]').fill(pro.username);
await page.locator('[name="oldPassword"]').fill(String(pro.username));
const $newPasswordField = page.locator('[name="newPassword"]');
$newPasswordField.fill(`${pro.username}Aa1111`);
+3 -2
View File
@@ -26,7 +26,7 @@ test.describe("Change username on settings", () => {
test.fixme("User can change username", async ({ page, users, prisma }) => {
const user = await users.create();
await user.login();
await user.apiLogin();
// Try to go homepage
await page.goto("/settings/my-account/profile");
// Change username from normal to normal
@@ -50,12 +50,13 @@ test.describe("Change username on settings", () => {
test("User can update to PREMIUM username", async ({ page, users }, testInfo) => {
// eslint-disable-next-line playwright/no-skipped-test
test.skip(!IS_STRIPE_ENABLED, "It should only run if Stripe is installed");
// eslint-disable-next-line playwright/no-skipped-test
test.skip(IS_SELF_HOSTED, "It shouldn't run on self hosted");
const user = await users.create();
await stripe.customers.create({ email: `${user?.username}@example.com` });
await user.login();
await user.apiLogin();
await page.goto("/settings/my-account/profile");
// Change username from normal to premium
@@ -11,9 +11,10 @@ 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.
// eslint-disable-next-line playwright/no-skipped-test
test.skip("dynamic booking", async ({ page, users }) => {
const pro = await users.create();
await pro.login();
await pro.apiLogin();
const free = await users.create({ username: "free" });
await page.goto(`/${pro.username}+${free.username}`);
@@ -47,7 +47,15 @@ async function expectToBeNavigatingToEmbedTypesDialog(
async function expectToBeNavigatingToEmbedCodeAndPreviewDialog(
page: Page,
{ embedUrl, embedType, basePage }: { embedUrl: string | null; embedType: string; basePage: string }
{
embedUrl,
embedType,
basePage,
}: {
embedUrl: string | null;
embedType: string;
basePage: string;
}
) {
if (!embedUrl) {
throw new Error("Couldn't find embedUrl");
@@ -89,7 +97,7 @@ test.afterEach(({ users }) => users.deleteAll());
test.describe("Embed Code Generator Tests", () => {
test.beforeEach(async ({ users }) => {
const pro = await users.create();
await pro.login();
await pro.apiLogin();
});
test.describe("Event Types Page", () => {
+2 -2
View File
@@ -13,7 +13,7 @@ test.describe("Event Types tests", () => {
testBothBookers.describe("user", (bookerVariant) => {
test.beforeEach(async ({ page, users }) => {
const user = await users.create();
await user.login();
await user.apiLogin();
await page.goto("/event-types");
// We wait until loading is finished
await page.waitForSelector('[data-testid="event-types"]');
@@ -69,7 +69,7 @@ test.describe("Event Types tests", () => {
'[data-testid="event-types"] a[href^="/event-types/"] >> nth=0'
);
const href = await firstElement.getAttribute("href");
if (!href) throw new Error("No href found for event type");
expect(href).toBeTruthy();
const [eventTypeId] = new URL(WEBAPP_URL + href).pathname.split("/").reverse();
const firstTitle = await page.locator(`[data-testid=event-type-title-${eventTypeId}]`).innerText();
const firstFullSlug = await page.locator(`[data-testid=event-type-slug-${eventTypeId}]`).innerText();
+3 -3
View File
@@ -58,7 +58,7 @@ export const createBookingsFixture = (page: Page) => {
status,
},
});
const bookingFixture = createBookingFixture(booking, store.page!);
const bookingFixture = createBookingFixture(booking, store.page);
store.bookings.push(bookingFixture);
return bookingFixture;
},
@@ -80,7 +80,7 @@ const createBookingFixture = (booking: Booking, page: Page) => {
return {
id: store.booking.id,
uid: store.booking.uid,
self: async () => (await prisma.booking.findUnique({ where: { id: store.booking.id } }))!,
delete: async () => (await prisma.booking.delete({ where: { id: store.booking.id } }))!,
self: async () => await prisma.booking.findUnique({ where: { id: store.booking.id } }),
delete: async () => await prisma.booking.delete({ where: { id: store.booking.id } }),
};
};
+3 -3
View File
@@ -36,7 +36,7 @@ export const createPaymentsFixture = (page: Page) => {
},
},
});
const paymentFixture = createPaymentFixture(payment, store.page!);
const paymentFixture = createPaymentFixture(payment, store.page);
store.payments.push(paymentFixture);
return paymentFixture;
},
@@ -57,7 +57,7 @@ const createPaymentFixture = (payment: Payment, page: Page) => {
// self is a reflective method that return the Prisma object that references this fixture.
return {
id: store.payment.id,
self: async () => (await prisma.payment.findUnique({ where: { id: store.payment.id } }))!,
delete: async () => (await prisma.payment.delete({ where: { id: store.payment.id } }))!,
self: async () => await prisma.payment.findUnique({ where: { id: store.payment.id } }),
delete: async () => await prisma.payment.delete({ where: { id: store.payment.id } }),
};
};
+34 -4
View File
@@ -233,7 +233,7 @@ export const createUsersFixture = (page: Page, workerInfo: WorkerInfo) => {
},
});
}
const userFixture = createUserFixture(user, store.page!);
const userFixture = createUserFixture(user, store.page);
store.users.push(userFixture);
return userFixture;
},
@@ -261,13 +261,18 @@ const createUserFixture = (user: UserWithIncludes, page: Page) => {
// self is a reflective method that return the Prisma object that references this fixture.
const self = async () =>
(await prisma.user.findUnique({ where: { id: store.user.id }, include: { eventTypes: true } }))!;
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
(await prisma.user.findUnique({
where: { id: store.user.id },
include: { eventTypes: true },
}))!;
return {
id: user.id,
username: user.username,
eventTypes: user.eventTypes,
routingForms: user.routingForms,
self,
apiLogin: async () => apiLogin({ ...(await self()), password: user.username }, store.page),
login: async () => login({ ...(await self()), password: user.username }, store.page),
logout: async () => {
await page.goto("/auth/logout");
@@ -275,9 +280,12 @@ const createUserFixture = (user: UserWithIncludes, page: Page) => {
getPaymentCredential: async () => getPaymentCredential(store.page),
// ths is for developemnt only aimed to inject debugging messages in the metadata field of the user
debug: async (message: string | Record<string, JSONValue>) => {
await prisma.user.update({ where: { id: store.user.id }, data: { metadata: { debug: message } } });
await prisma.user.update({
where: { id: store.user.id },
data: { metadata: { debug: message } },
});
},
delete: async () => (await prisma.user.delete({ where: { id: store.user.id } }))!,
delete: async () => await prisma.user.delete({ where: { id: store.user.id } }),
};
};
@@ -341,6 +349,28 @@ export async function login(
await page.waitForLoadState("networkidle");
}
export async function apiLogin(
user: Pick<Prisma.User, "username"> & Partial<Pick<Prisma.User, "password" | "email">>,
page: Page
) {
const csrfToken = await page
.context()
.request.get("/api/auth/csrf")
.then((response) => response.json())
.then((json) => json.csrfToken);
const data = {
email: user.email ?? `${user.username}@example.com`,
password: user.password ?? user.username!,
callbackURL: "http://localhost:3000/",
redirect: "false",
json: "true",
csrfToken,
};
return page.context().request.post("/api/auth/callback/credentials", {
data,
});
}
export async function getPaymentCredential(page: Page) {
await page.goto("/apps/stripe");
+1 -1
View File
@@ -9,7 +9,7 @@ test.describe.configure({ mode: "parallel" });
test.fixme("hash my url", () => {
test.beforeEach(async ({ users }) => {
const user = await users.create();
await user.login();
await user.apiLogin();
});
test.afterEach(async ({ users }) => {
await users.deleteAll();
@@ -24,7 +24,7 @@ test.describe("Stripe integration", () => {
test.describe("Stripe integration dashboard", () => {
test("Can add Stripe integration", async ({ page, users }) => {
const user = await users.create();
await user.login();
await user.apiLogin();
await page.goto("/apps/installed");
await user.getPaymentCredential();
@@ -38,12 +38,12 @@ test.describe("Stripe integration", () => {
test("Can book a paid booking", async ({ page, users }) => {
const user = await users.create();
const eventType = user.eventTypes.find((e) => e.slug === "paid")!;
await user.login();
const eventType = user.eventTypes.find((e) => e.slug === "paid");
await user.apiLogin();
await page.goto("/apps/installed");
await user.getPaymentCredential();
await page.goto(`${user.username}/${eventType.slug}`);
await page.goto(`${user.username}/${eventType?.slug}`);
await selectFirstAvailableTimeSlotNextMonth(page);
// --- fill form
await page.fill('[name="name"]', "Stripe Stripeson");
+9 -8
View File
@@ -1,5 +1,6 @@
import type { Page, Route } from "@playwright/test";
import { expect } from "@playwright/test";
import type { DefaultBodyType } from "msw";
import { rest } from "msw";
import { setupServer } from "msw/node";
import { v4 as uuidv4 } from "uuid";
@@ -42,7 +43,7 @@ const addOauthBasedIntegration = async function ({
// eslint-disable-next-line @typescript-eslint/no-explicit-any
verify: (config: { requestHeaders: any; params: URLSearchParams; code: string }) => {
status: number;
body: any;
body: DefaultBodyType;
};
};
}) {
@@ -213,7 +214,7 @@ test.fixme("Integrations", () => {
test.describe("Zoom App", () => {
test("Can add integration", async ({ page, users }) => {
const user = await users.create();
await user.login();
await user.apiLogin();
await addZoomIntegration({ page });
await page.waitForNavigation({
url: (url) => {
@@ -225,7 +226,7 @@ test.fixme("Integrations", () => {
test("can choose zoom as a location during booking", async ({ page, users }) => {
const user = await users.create();
await user.login();
await user.apiLogin();
const eventType = await addLocationIntegrationToFirstEvent({ user });
await addZoomIntegration({ page });
await page.waitForNavigation({
@@ -240,7 +241,7 @@ test.fixme("Integrations", () => {
// POST https://api.zoom.us/v2/users/me/meetings
// Verify Header-> Authorization: "Bearer " + accessToken,
/**
* {
* {
topic: event.title,
type: 2, // Means that this is a scheduled meeting
start_time: event.startTime,
@@ -261,15 +262,15 @@ test.fixme("Integrations", () => {
approval_type: 2,
audio: "both",
auto_recording: "none",
enforce_login: false,
enforce_apiLogin: false,
registrants_email_notification: true,
},
};
*/
*/
});
test("Can disconnect from integration", async ({ page, users }) => {
const user = await users.create();
await user.login();
await user.apiLogin();
await addZoomIntegration({ page });
await page.waitForNavigation({
url: (url) => {
@@ -298,7 +299,7 @@ test.fixme("Integrations", () => {
test.describe("Hubspot App", () => {
test("Can add integration", async ({ page, users }) => {
const user = await users.create();
await user.login();
await user.apiLogin();
await addOauthBasedIntegration({
page,
slug: "hubspot",
+1 -1
View File
@@ -40,7 +40,7 @@ declare global {
* @see https://playwright.dev/docs/test-fixtures
*/
export const test = base.extend<Fixtures>({
users: async ({ page }, use, workerInfo) => {
users: async ({ page, context }, use, workerInfo) => {
const usersFixture = createUsersFixture(page, workerInfo);
await use(usersFixture);
},
+3 -3
View File
@@ -24,11 +24,11 @@ export const deleteAllBookingsByEmail = async (
});
export const deleteEventTypeByTitle = async (title: string) => {
const event = (await prisma.eventType.findFirst({
const event = await prisma.eventType.findFirst({
select: { id: true },
where: { title: title },
}))!;
await prisma.eventType.delete({ where: { id: event.id } });
});
await prisma.eventType.delete({ where: { id: event?.id } });
};
export const deleteAllWebhooksByEmail = async (email: string) => {
+1
View File
@@ -46,6 +46,7 @@ export function createHttpServer(opts: { requestHandler?: RequestHandler } = {})
// listen on random port
server.listen(0);
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const port: number = (server.address() as any).port;
const url = `http://localhost:${port}`;
return {
+21
View File
@@ -0,0 +1,21 @@
import { expect } from "@playwright/test";
import { test } from "./lib/fixtures";
test.describe.configure({ mode: "parallel" });
test.afterEach(({ users }) => users.deleteAll());
test.describe("Login with api request", () => {
test("context request will share cookie storage with its browser context", async ({ page, users }) => {
const pro = await users.create();
await pro.apiLogin();
const contextCookies = await page.context().cookies();
const cookiesMap = new Map(contextCookies.map(({ name, value }) => [name, value]));
// The browser context will already contain all the cookies from the API response.
expect(cookiesMap.has("next-auth.csrf-token")).toBeTruthy();
expect(cookiesMap.has("next-auth.callback-url")).toBeTruthy();
expect(cookiesMap.has("next-auth.session-token")).toBeTruthy();
});
});
@@ -15,6 +15,7 @@ async function getLabelText(field: Locator) {
return await field.locator("label").first().locator("span").first().innerText();
}
test.describe.configure({ mode: "parallel" });
test.describe("Manage Booking Questions", () => {
test.afterEach(async ({ users }) => {
await users.deleteAll();
@@ -28,7 +29,7 @@ test.describe("Manage Booking Questions", () => {
}, testInfo) => {
// Considering there are many steps in it, it would need more than default test timeout
test.setTimeout(testInfo.timeout * 3);
const user = await createAndLoginUserWithEventTypes({ users });
const user = await createAndLoginUserWithEventTypes({ users, page });
const webhookReceiver = await addWebhook(user);
@@ -51,7 +52,7 @@ test.describe("Manage Booking Questions", () => {
}, testInfo) => {
// Considering there are many steps in it, it would need more than default test timeout
test.setTimeout(testInfo.timeout * 3);
const user = await createAndLoginUserWithEventTypes({ users });
const user = await createAndLoginUserWithEventTypes({ users, page });
const team = await prisma.team.findFirst({
where: {
members: {
@@ -65,7 +66,7 @@ test.describe("Manage Booking Questions", () => {
},
});
const teamId = team?.id ?? 0;
const teamId = team?.id;
const webhookReceiver = await addWebhook(undefined, teamId);
await test.step("Go to First Team Event", async () => {
@@ -86,7 +87,8 @@ async function runTestStepsCommonForTeamAndUserEventType(
webhookReceiver: {
port: number;
close: () => import("http").Server;
requestList: (import("http").IncomingMessage & { body?: unknown })[];
// eslint-disable-next-line @typescript-eslint/no-explicit-any
requestList: (import("http").IncomingMessage & { body?: any })[];
url: string;
},
bookerVariant: BookerVariants
@@ -175,7 +177,7 @@ async function runTestStepsCommonForTeamAndUserEventType(
const [request] = webhookReceiver.requestList;
const payload = (request.body as any).payload as any;
const payload = request.body.payload;
expect(payload.responses).toMatchObject({
email: {
@@ -212,7 +214,9 @@ async function runTestStepsCommonForTeamAndUserEventType(
await test.step("Do a reschedule and notice that we can't book without giving a value for rescheduleReason", async () => {
const page = previewTabPage;
await rescheduleFromTheLinkOnPage({ page, bookerVariant });
await rescheduleFromTheLinkOnPage({ page });
// eslint-disable-next-line playwright/no-page-pause
await page.pause();
await expectErrorToBeThereFor({ page, name: "rescheduleReason" });
});
}
@@ -244,6 +248,7 @@ async function bookTimeSlot({ page, name, email }: { page: Page; name: string; e
await page.fill('[name="email"]', email);
await page.press('[name="email"]', "Enter");
}
/**
* 'option' starts from 1
*/
@@ -355,11 +360,20 @@ async function toggleQuestionRequireStatusAndSave({
await saveEventType(page);
}
async function createAndLoginUserWithEventTypes({ users }: { users: ReturnType<typeof createUsersFixture> }) {
async function createAndLoginUserWithEventTypes({
users,
page,
}: {
users: ReturnType<typeof createUsersFixture>;
page: Page;
}) {
const user = await users.create(null, {
hasTeam: true,
});
await user.login();
await user.apiLogin();
await page.goto("/event-types");
// We wait until loading is finished
await page.waitForSelector('[data-testid="event-types"]');
return user;
}
@@ -368,7 +382,7 @@ async function rescheduleFromTheLinkOnPage({
bookerVariant,
}: {
page: Page;
bookerVariant: BookerVariants;
bookerVariant?: BookerVariants;
}) {
await page.locator('[data-testid="reschedule-link"]').click();
await page.waitForLoadState();
@@ -11,7 +11,8 @@ test.describe("Managed Event Types tests", () => {
// Creating the member user of the team
const memberUser = await users.create();
// First we work with owner user, logging in
await adminUser.login();
await adminUser.apiLogin();
await page.goto("/event-types");
// Making sure page loads completely
await page.waitForLoadState("networkidle");
// Let's create a team
@@ -58,7 +59,9 @@ test.describe("Managed Event Types tests", () => {
// Now we need to accept the invitation as member and come back in as admin to
// assign the member in the managed event type
await adminUser.logout();
await memberUser.login();
await memberUser.apiLogin();
await page.goto("/event-types");
// We wait until loading is finished
await page.waitForSelector('[data-testid="event-types"]');
await page.goto("/teams");
await page.waitForLoadState("networkidle");
@@ -67,7 +70,8 @@ test.describe("Managed Event Types tests", () => {
await memberUser.logout();
// Coming back as team owner to assign member user to managed event
await adminUser.login();
await adminUser.apiLogin();
await page.goto("/event-types");
await page.waitForLoadState("networkidle");
await page.locator('[data-testid="event-types"] a[title="managed"]').click();
await page.locator('[data-testid="vertical-tab-assignment"]').click();
@@ -78,7 +82,8 @@ test.describe("Managed Event Types tests", () => {
await adminUser.logout();
// Coming back as member user to see if there is a managed event present after assignment
await memberUser.login();
await memberUser.apiLogin();
await page.goto("/event-types");
await page.waitForLoadState("networkidle");
await expect(page.locator('[data-testid="event-types"] a[title="managed"]')).toBeVisible();
});
+3 -5
View File
@@ -11,8 +11,8 @@ test.describe("Onboarding", () => {
test.describe("Onboarding v2", () => {
test("Onboarding Flow", async ({ page, users }) => {
const user = await users.create({ completedOnboarding: false, name: null });
await user.login();
await user.apiLogin();
await page.goto("/getting-started");
// tests whether the user makes it to /getting-started
// after login with completedOnboarding false
await page.waitForURL("/getting-started");
@@ -76,9 +76,7 @@ test.describe("Onboarding", () => {
const userComplete = await user.self();
const userCompleteBio = userComplete.bio ? userComplete.bio : "";
expect(userCompleteBio.replace("<p><br></p>", "").length).toBe(0);
expect(userComplete.bio?.replace("<p><br></p>", "").length).toBe(0);
});
});
});
+8 -8
View File
@@ -25,7 +25,7 @@ testBothBookers.describe("Reschedule Tests", async () => {
status: BookingStatus.ACCEPTED,
});
await user.login();
await user.apiLogin();
await page.goto("/bookings/upcoming");
await page.locator('[data-testid="edit_booking"]').nth(0).click();
@@ -39,9 +39,9 @@ testBothBookers.describe("Reschedule Tests", async () => {
const updatedBooking = await booking.self();
expect(updatedBooking.rescheduled).toBe(true);
expect(updatedBooking.cancellationReason).toBe("I can't longer have it");
expect(updatedBooking.status).toBe(BookingStatus.CANCELLED);
expect(updatedBooking?.rescheduled).toBe(true);
expect(updatedBooking?.cancellationReason).toBe("I can't longer have it");
expect(updatedBooking?.status).toBe(BookingStatus.CANCELLED);
await booking.delete();
});
@@ -69,7 +69,7 @@ testBothBookers.describe("Reschedule Tests", async () => {
rescheduled: true,
});
await user.login();
await user.apiLogin();
await page.goto("/bookings/cancelled");
const requestRescheduleSentElement = page.locator('[data-testid="request_reschedule_sent"]').nth(1);
@@ -117,7 +117,7 @@ testBothBookers.describe("Reschedule Tests", async () => {
// eslint-disable-next-line playwright/no-skipped-test
test.skip(!IS_STRIPE_ENABLED, "Skipped as Stripe is not installed");
const user = await users.create();
await user.login();
await user.apiLogin();
await user.getPaymentCredential();
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
const eventType = user.eventTypes.find((e) => e.slug === "paid")!;
@@ -158,7 +158,7 @@ testBothBookers.describe("Reschedule Tests", async () => {
test("Paid rescheduling should go to success page", async ({ page, users, bookings, payments }) => {
const user = await users.create();
await user.login();
await user.apiLogin();
await user.getPaymentCredential();
await users.logout();
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
@@ -207,7 +207,7 @@ testBothBookers.describe("Reschedule Tests", async () => {
const booking = await bookings.create(user.id, user.username, eventType.id, {
status: BookingStatus.ACCEPTED,
});
await user.login();
await user.apiLogin();
await page.goto(`/${user.username}/${eventType.slug}?rescheduleUid=${booking.uid}`);
+1 -1
View File
@@ -12,7 +12,7 @@ test.describe("Teams", () => {
test("Can create teams via Wizard", async ({ page, users }) => {
const user = await users.create();
const inviteeEmail = `${user.username}+invitee@example.com`;
await user.login();
await user.apiLogin();
await page.goto("/teams");
await test.step("Can create team", async () => {
+7 -5
View File
@@ -14,11 +14,11 @@ test.describe("BOOKING_CREATED", async () => {
test("add webhook & test that creating an event triggers a webhook call", async ({
page,
users,
}, testInfo) => {
}, _testInfo) => {
const webhookReceiver = createHttpServer();
const user = await users.create();
const [eventType] = user.eventTypes;
await user.login();
await user.apiLogin();
await page.goto(`/settings/developer/webhooks`);
// --- add webhook
@@ -51,7 +51,8 @@ test.describe("BOOKING_CREATED", async () => {
});
const [request] = webhookReceiver.requestList;
const body = request.body as any;
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const body: any = request.body;
// remove dynamic properties that differs depending on where you run the tests
const dynamic = "[redacted/dynamic]";
@@ -153,7 +154,7 @@ test.describe("BOOKING_REJECTED", async () => {
await bookOptinEvent(page);
// --- login as that user
await user.login();
await user.apiLogin();
await page.goto(`/settings/developer/webhooks`);
@@ -274,7 +275,7 @@ test.describe("BOOKING_REQUESTED", async () => {
const user = await users.create();
// --- login as that user
await user.login();
await user.apiLogin();
await page.goto(`/settings/developer/webhooks`);
@@ -305,6 +306,7 @@ test.describe("BOOKING_REQUESTED", async () => {
expect(webhookReceiver.requestList.length).toBe(1);
});
const [request] = webhookReceiver.requestList;
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const body = request.body as any;
// remove dynamic properties that differs depending on where you run the tests
+1 -1
View File
@@ -35,7 +35,7 @@ test.describe("Wipe my Cal App Test", () => {
);
await bookings.create(pro.id, pro.username, eventType.id, {});
await bookings.create(pro.id, pro.username, eventType.id, {});
await pro.login();
await pro.apiLogin();
await page.goto("/bookings/upcoming");
await expect(page.locator("data-testid=wipe-today-button")).toBeVisible();
File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 18 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 17 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 19 KiB

+60 -16
View File
@@ -11,6 +11,7 @@
"calcom_explained_new_user": "قم بإنهاء إعداد حسابك في {{appName}}! متبقي بضع خطوات فقط لحل جميع مشاكل الجدولة لديك.",
"have_any_questions": "هل لديك أسئلة؟ نحن هنا للمساعدة.",
"reset_password_subject": "{{appName}}: إرشادات إعادة تعيين كلمة المرور",
"verify_email_banner_button": "إرسال بريد إلكتروني",
"event_declined_subject": "تم الرفض: {{title}} في {{date}}",
"event_cancelled_subject": "تم الإلغاء: {{title}} في {{date}}",
"event_request_declined": "تم رفض طلب الحدث الخاص بك",
@@ -26,6 +27,8 @@
"rejection_confirmation": "رفض الحجز",
"manage_this_event": "قم بإدارة هذا الحدث",
"invite_team_member": "دعوة عضو في الفريق",
"invite_team_individual_segment": "دعوة فرد",
"invite_team_bulk_segment": "استيراد بحجم جماعي",
"invite_team_notifcation_badge": "دعوة",
"your_event_has_been_scheduled": "تم جدولة الحدث الخاص بك",
"your_event_has_been_scheduled_recurring": "تم جدولة الحدث المتكرر الخاص بك",
@@ -222,6 +225,7 @@
"go_back_login": "العودة إلى صفحة تسجيل الدخول",
"error_during_login": "حدث خطأ ما أثناء تسجيل الدخول. ارجع إلى شاشة تسجيل الدخول وحاول مجددًا.",
"request_password_reset": "إرسال بريد إلكتروني لإعادة التعيين",
"send_invite": "إرسال دعوة",
"forgot_password": "هل نسيت كلمة المرور؟",
"forgot": "هل نسيت؟",
"done": "تم",
@@ -237,6 +241,8 @@
"set_availability": "تحديد الوقت الذي تكون فيه متاحًا",
"continue_without_calendar": "المتابعة من دون تقويم",
"connect_your_calendar": "ربط التقويم لديك",
"connect_your_video_app": "اربط تطبيقاتك الفيديو الخاصة بك",
"connect_your_video_app_instructions": "قم بتوصيل تطبيقات الفيديو لديك لاستخدامها في أنواع الأحداث الخاصة بك.",
"connect_your_calendar_instructions": "اربط التقويم لديك للتحقق تلقائيًا من الأوقات المشغولة والأحداث الجديدة أثناء جدولتها.",
"set_up_later": "الإعداد لاحقًا",
"current_time": "الوقت الحالي",
@@ -366,6 +372,7 @@
"create_webhook": "إنشاء الويب هوك",
"booking_cancelled": "تم إلغاء الحجز",
"booking_rescheduled": "تمت إعادة جدولة الحجز",
"recording_ready": "رابط تنزيل التسجيل جاهز",
"booking_created": "تم إنشاء الحجز",
"meeting_ended": "انتهى الاجتماع",
"form_submitted": "تم إرسال النموذج",
@@ -464,6 +471,7 @@
"friday": "الجمعة",
"saturday": "السبت",
"sunday": "الأحد",
"all_booked_today": "تم حجز الكل.",
"slots_load_fail": "تعذر تحميل الفترات الزمنية المتاحة.",
"additional_guests": "إضافة ضيوف",
"your_name": "اسمك",
@@ -623,8 +631,6 @@
"event_type_created_successfully": "تم إنشاء نوع الحدث {{eventTypeTitle}} بنجاح",
"event_type_updated_successfully": "تم تحديث نوع الحدث {{eventTypeTitle}} بنجاح",
"event_type_deleted_successfully": "تم حذف نوع الحدث بنجاح",
"web3_metamask_added": "تمت إضافة Metamask بنجاح",
"web3_metamask_disconnected": "تم فصل Metamask بنجاح",
"hours": "الساعات",
"your_email": "بريدك الإلكتروني",
"change_avatar": "تغيير الصورة الرمزية",
@@ -751,6 +757,10 @@
"new_event_type_to_book_description": "قم بإنشاء نوع حدث جديد ليحجز الأشخاص من خلاله.",
"length": "الطول",
"minimum_booking_notice": "الحد الأدنى من الوقت للحجز",
"offset_toggle": "أوقات بدء الإزاحة",
"offset_toggle_description": "إزاحة الفتحات الزمنية المعروضة للحاجزين بعدد محدد من الدقائق",
"offset_start": "إزاحة بمقدار",
"offset_start_description": "على سبيل المثال، هذا سيُظهر فتحات زمنية لمن يقوم بالحجز لديك {{ adjustedTime }} بدلاً من {{ originalTime }}",
"slot_interval": "الفترات الزمنية بين عمليات الحجز",
"slot_interval_default": "استخدام طول الحدث (الوضع الافتراضي)",
"delete_event_type": "هل تريد حذف نوع الحدث؟",
@@ -861,7 +871,6 @@
"installed_one": "تم التثبيت",
"installed_other": "{{count}} مثبت",
"verify_wallet": "تأكيد المحفظة",
"connect_metamask": "توصيل Metamask",
"create_events_on": "إنشاء أحداث في",
"enterprise_license": "هذه هي ميزة للمؤسسات",
"enterprise_license_description": "لتمكين هذه الميزة، احصل على مفتاح نشر في وحدة التحكم {{consoleUrl}} وأضفه إلى وحدة التحكم الخاصة بك. nv باسم CALCOM_LICENSE_KEY. إذا كان لدى فريقك بالفعل ترخيص، يرجى الاتصال بـ {{supportMail}} للحصول على المساعدة.",
@@ -887,6 +896,7 @@
"availability_updated_successfully": "تم تحديث جدول {{scheduleName}} بنجاح",
"schedule_deleted_successfully": "تم حذف الجدول بنجاح",
"default_schedule_name": "ساعات العمل",
"member_default_schedule": "الجدول الزمني الافتراضي للعضو",
"new_schedule_heading": "إنشاء جدول الأوقات المتاحة",
"new_schedule_description": "إن إنشاء جداول الأوقات المتاحة يتيح لك إدارة الأوقات المتاحة عبر أنواع الأحداث. يمكن تطبيقها على نوع أو أكثر من أنواع الأحداث.",
"requires_ownership_of_a_token": "يتطلب امتلاك token يخص العنوان التالي:",
@@ -903,6 +913,7 @@
"duplicate": "تكرار",
"offer_seats": "عرض مقاعد",
"offer_seats_description": "عرض مقاعد للحجز. هذا يعطل تلقائياً حجز الضيوف وحجز الاشتراك.",
"seats_available_one": "المقاعد المتاحة",
"seats_available_other": "المقاعد المتاحة",
"number_of_seats": "عدد المقاعد لكل حجز",
"enter_number_of_seats": "أدخل عدد المقاعد",
@@ -1037,7 +1048,7 @@
"event_cancelled_trigger": "متى تم إلغاء هذا الحدث",
"new_event_trigger": "متى تم حجز الحدث الجديد",
"email_host_action": "إرسال رسالة إلكترونية إلى المضيف",
"sms_attendee_action": "إرسال رسالة نصية قصيرة إلى واحد من الحضور",
"email_attendee_action": "إرسال رسالة إلكترونية إلى الحضور",
"sms_number_action": "إرسال رسالة نصية قصيرة إلى رقم محدد",
"workflows": "سير العمل",
"new_workflow_btn": "سير عمل جديد",
@@ -1189,6 +1200,7 @@
"create_workflow": "إنشاء سير عمل",
"do_this": "افعل هذا",
"turn_off": "إيقاف التشغيل",
"turn_on": "تشغيل",
"settings_updated_successfully": "تم تحديث الإعدادات بنجاح",
"error_updating_settings": "خطأ في تحديث الإعدادات",
"personal_cal_url": "عنوان {{appName}} URL الخاص بي",
@@ -1213,11 +1225,6 @@
"upload": "تحميل",
"add_profile_photo": "إضافة صورة الملف الشخصي",
"web3": "Web3",
"rainbow_token_gated": "يتم فتح هذا النوع من الأحداث برمز مميز.",
"rainbow_connect_wallet_gate": "قم بربط محفظتك إذا كنت تملك <1>{{name}}</1> (<3>{{symbol}}</3>).",
"rainbow_insufficient_balance": "لا تحتوي محفظتك المربوطة على ما يكفي من <1>{{symbol}}</1>.",
"rainbow_sign_message_request": "قم بتوقيع طلب الرسالة على محفظتك.",
"rainbow_signature_error": "خطأ في طلب التوقيع من محفظتك.",
"token_address": "عنوان الرمز المميز",
"blockchain": "سلسلة الكتل",
"old_password": "كلمة مرور قديمة",
@@ -1245,6 +1252,7 @@
"calendars_description": "قم بتهيئة كيفية تفاعل أنواع الأحداث مع التقويمات الخاصة بك",
"appearance_description": "إدارة إعدادات مظهر الحجز الخاص بك",
"conferencing_description": "أضف تطبيقات مؤتمرات الفيديو المفضلة لديك لاجتماعاتك",
"add_conferencing_app": "إضافة تطبيق عقد اجتماعات",
"password_description": "إدارة إعدادات كلمات مرور حسابك",
"2fa_description": "إدارة إعدادات كلمات مرور حسابك",
"we_just_need_basic_info": "نحتاج إلى بعض المعلومات الأساسية لإعداد ملفك الشخصي.",
@@ -1279,7 +1287,6 @@
"download_responses_description": "تنزيل جميع الردود إلى النموذج بتنسيق CSV.",
"download": "التنزيل",
"download_recording": "تنزيل التسجيل",
"recording_from_your_recent_call": "تسجيل من مكالمتك الأخيرة على Cal.com جاهز للتنزيل",
"create_your_first_form": "إنشاء أول استمارة",
"create_your_first_form_description": "باستخدام نماذج المسارات، يمكنك طرح أسئلة التأهيل والتوجيه إلى الشخص/نوع الحدث المناسب.",
"create_your_first_webhook": "إنشاء أول Webhook",
@@ -1325,7 +1332,7 @@
"exchange_version_2013_SP1": "2013 SP1",
"exchange_version_2015": "2015",
"exchange_version_2016": "2016",
"routing_forms_description": "يمكنك رؤية جميع النماذج والتوجيهات التي أنشأتها هنا.",
"routing_forms_description": "أنشئ النماذج لتوجيه الحضور إلى الوجهات الصحيحة",
"routing_forms_send_email_owner": "إرسال رسالة إلكترونية إلى المالك",
"routing_forms_send_email_owner_description": "يرسل رسالة بريد إلكتروني إلى المالك عند إرسال النموذج",
"add_new_form": "إضافة استمارة جديدة",
@@ -1362,7 +1369,6 @@
"password_updated": "تم تحديث كلمة المرور!",
"pending_payment": "في انتظار الدفع",
"pending_invites": "دعوات معلقة",
"confirmation_page_rainbow": "قم بتعيين رمز مميز لفتح الحدث الخاص بك باستخدام الرموز أو NFTs على Ethereum وPolygon وغيرها.",
"not_on_cal": "غير موجود على {{appName}}",
"no_calendar_installed": "لا يوجد تقويم مثبت",
"no_calendar_installed_description": "لم تقم بربط أي من التقويمات الخاصة بك",
@@ -1476,8 +1482,6 @@
"find_the_best_person": "ابحث عن أفضل شخص متاح وابحث بالترتيب بين أعضاء فريقك.",
"fixed_round_robin": "جدولة دوارة",
"add_one_fixed_attendee": "أضف حاضرًا ثابتًا وجدولة دوارة عبر عدد من الحاضرين.",
"calcom_is_better_with_team": "يعمل Cal.com أفضل مع الفرق",
"the_calcom_team": "فريق Cal.com",
"add_your_team_members": "أضف أعضاء فريقك إلى أنواع الأحداث الخاصة بك. استخدم الجدولة الجماعية لإدراج الجميع أو العثور على أنسب شخص باستخدام الجدولة الدوارة.",
"booking_limit_reached": "تم الوصول إلى الحد الأقصى للحجز لهذا النوع من الأحداث",
"duration_limit_reached": "تم الوصول إلى الحد الأقصى لمدة الحجز لهذا النوع من الأحداث",
@@ -1496,7 +1500,6 @@
"navigate_installed_apps": "الذهاب إلى التطبيقات المثبتة",
"disabled_calendar": "إذا كان لديك تقويم آخر مثبت، ستُضاف الحجوزات الجديدة إليه. إذا لم يكن الأمر كذلك، قم بتوصيل تقويم جديد حتى لا تفوت أي حجوزات جديدة.",
"enable_apps": "تمكين التطبيقات",
"enable_apps_description": "تمكين التطبيقات التي يمكن للمستخدمين دمجها مع Cal.com",
"purchase_license": "شراء ترخيص",
"already_have_key": "لدي مفتاح بالفعل:",
"already_have_key_suggestion": "يرجى نسخ متغير البيئة الحالي CALCOM_LICENSE_KEY هنا.",
@@ -1619,6 +1622,7 @@
"email_user_cta": "عرض الدعوة",
"email_no_user_invite_heading": "لقد تمت دعوتك للانضمام إلى فريق في {{appName}}",
"email_no_user_invite_subheading": "دعاك {{invitedBy}} للانضمام إلى فريقه على {{appName}}. إن {{appName}} هو برنامج جدولة الأحداث الذي يمكّنك أنت وفريقك من جدولة الاجتماعات دون الحاجة إلى المراسلة عبر البريد الإلكتروني.",
"email_user_invite_subheading": "دعاك {{invitedBy}} للانضمام إلى فريقه {{teamName}} على {{appName}}. إن {{appName}} هو برنامج جدولة الأحداث الذي يمكّنك أنت وفريقك من جدولة الاجتماعات دون الحاجة إلى المراسلة عبر البريد الإلكتروني.",
"email_no_user_invite_steps_intro": "سنرشدك خلال بضع خطوات قصيرة وستستمتع بجدولة خالية من الإجهاد مع فريقك وسريعة.",
"email_no_user_step_one": "اختر اسم المستخدم الخاص بك",
"email_no_user_step_two": "ربط حساب التقويم الخاص بك",
@@ -1694,6 +1698,15 @@
"spot_popular_event_types_description": "تعرف أي أنواع من الأحداث لديك تتلقى أكبر عدد من النقرات والحجوزات",
"no_responses_yet": "لا توجد ردود بعد",
"this_will_be_the_placeholder": "سيكون هذا هو العنصر النائب",
"error_booking_event": "حدث خطأ عند حجز الحدث، الرجاء تحديث الصفحة والمحاولة ثانيةً",
"timeslot_missing_title": "لم يتم تحديد مساحة زمنية",
"timeslot_missing_description": "الرجاء تحديد فترة زمنية لحجز الحدث.",
"timeslot_missing_cta": "حدد الوقت",
"switch_monthly": "التبديل إلى العرض الشهري",
"switch_weekly": "التبديل إلى العرض الأسبوعي",
"switch_multiday": "التبديل إلى العرض اليومي",
"num_locations": "خيارات الموقع {{num}}",
"select_on_next_step": "حدد في الخطوة التالية",
"this_meeting_has_not_started_yet": "لم يبدأ هذا الاجتماع بعد",
"this_app_requires_connected_account": "{{appName}} يتطلب حساب {{dependencyName}} متصل",
"connect_app": "اتصال {{dependencyName}}",
@@ -1723,6 +1736,7 @@
"locked_apps_description": "سيتمكن الأعضاء من رؤية التطبيقات النشطة، ولكن لن يتمكنوا من تعديل أي إعدادات للتطبيق",
"locked_webhooks_description": "سيكون الأعضاء قادرين على رؤية webhooks النشطة، ولكن من دون القدرة على تعديل أي إعدادات Webhook",
"locked_workflows_description": "سيكون الأعضاء قادرين على رؤية مسارات العمل النشطة، ولكن من دون القدرة على تعديل أي إعدادات لمسار العمل",
"locked_by_admin": "مقفل من قبل المشرف",
"app_not_connected": "أنت غير متصل بحساب {{appName}}.",
"connect_now": "اتصل الآن",
"managed_event_dialog_confirm_button_one": "الاستبدال وإخطار {{count}} عضو",
@@ -1780,5 +1794,35 @@
"seats_and_no_show_fee_error": "لا يمكن حاليًا تمكين المقاعد وفرض رسوم عدم الحضور",
"complete_your_booking": "أكمل الحجز",
"complete_your_booking_subject": "أكمل الحجز: {{title}} في {{date}}",
"email_invite_team": "تم دعوة {{email}}"
"confirm_your_details": "تأكيد التفاصيل الخاصة بك",
"never_expire": "لا تنتهي الصلاحية أبدًا",
"currency_string": "{{amount, currency}}",
"charge_card_dialog_body": "أنت على وشك استحصال مبلغ {{amount, currency}} من أحد الحضور. هل أنت متأكد من أنك تريد المتابعة؟",
"charge_attendee": "استحصال مبلغ {{amount, currency}} من أحد الحضور",
"payment_app_commission": "يتطلب الدفع ({{paymentFeePercentage}}% + {{fee, currency}} عمولة لكل معاملة)",
"email_invite_team": "تم دعوة {{email}}",
"email_invite_team_bulk": "{{userCount}} مستخدم تم دعوتهم",
"error_collecting_card": "خطأ في تحصيل البطاقة",
"image_size_limit_exceed": "لا ينبغي أن تتجاوز الصورة التي تم تحميلها الحد الأقصى لحجم 5 ميغابايت",
"inline_embed": "Inline Embed",
"load_inline_content": "يحمّل نوع الحدث الخاص بك مباشرة مع محتوى موقعك الأخير.",
"floating_pop_up_button": "زر منبثق عائم",
"floating_button_trigger_modal": "يضع زرًا عائمًا على موقعك يقوم بتشغيل توجيه مع نوع الحدث الخاص بك.",
"pop_up_element_click": "ينبثق عبر النقر على العنصر",
"open_dialog_with_element_click": "افتح مربع الحوار الخاص بك عندما ينقر شخص على عنصر ما.",
"need_help_embedding": "بحاجة إلى مساعدة؟ راجع أدلتنا لإدراج Cal على Wix، Squarespace، أو WordPress، تحقق من أسئلتنا المشتركة، أو استكشف خيارات متقدمة متضمنة.",
"book_my_cal": "ثبّت الحجز في رزنامتي",
"invite_as": "دعوة باسم",
"form_updated_successfully": "تم تحديث الاستمارة بنجاح.",
"email_not_cal_member_cta": "انضم إلى فريقك",
"disable_attendees_confirmation_emails": "تعطيل رسائل التأكيد الافتراضية للحضور",
"disable_attendees_confirmation_emails_description": "يوجد مسار عمل واحد على الأقل نشط في هذا النوع من الأحداث يقوم بإرسال رسائل إلكترونية إلى الحاضرين عند حجز الحدث.",
"disable_host_confirmation_emails": "تعطيل رسائل التأكيد الافتراضية لمضيف",
"disable_host_confirmation_emails_description": "يوجد مسار عمل واحد على الأقل نشط في هذا النوع من الأحداث يقوم بإرسال رسائل إلكترونية إلى المضيف عند حجز الحدث.",
"add_an_override": "إضافة تجاوز",
"import_from_google_workspace": "استيراد المستخدمين من مساحة عمل Google",
"connect_google_workspace": "ربط مساحة عمل Google",
"google_workspace_admin_tooltip": "يجب أن تكون مشرفًا على مساحة العمل لاستخدام هذه الميزة",
"first_event_type_webhook_description": "قم بإنشاء أول شبكة ويب هوك لهذا النوع من الفعاليات",
"create_for": "إنشاء من أجل"
}
@@ -0,0 +1,24 @@
{
"awaiting_payment_subject": "Esperant el pagament: {{title}} el {{date}}",
"help": "Ajuda",
"price": "Preu",
"paid": "Pagat",
"refunded": "Reembossat",
"payment": "Pagament",
"missing_card_fields": "Falten camps de la targeta",
"pay_now": "Paga ara",
"codebase_has_to_stay_opensource": "El codi font ha de seguir com codi obert, tant si s'ha modificat com si no",
"cannot_repackage_codebase": "No pots tornar a empaquetar ni vendre el codi font",
"acquire_license": "Adquireix una llicència comercial per eliminar aquests termes mitjançant un correu electrònic",
"terms_summary": "Resum dels termes",
"open_env": "Obre .env i accepta la nostra llicència",
"env_changed": "He canviat el meu .env",
"accept_license": "Accepta la llicència",
"still_waiting_for_approval": "Un esdeveniment encara està pendent d'aprovació",
"event_is_still_waiting": "La sol·licitud d'esdeveniment encara està pendent: {{attendeeName}} - {{date}} - {{eventType}}",
"no_more_results": "No hi ha més resultats",
"no_results": "No hi ha resultats",
"load_more_results": "Carrega més resultats",
"integration_meeting_id": "{{integrationName}} Identificador de la reunió: {{meetingId}}",
"confirmed_event_type_subject": "Confirmat: {{eventType}} amb {{name}} el {{date}}"
}
+59 -15
View File
@@ -11,6 +11,7 @@
"calcom_explained_new_user": "Dokončete nastavení svého účtu {{appName}}! Jste jen několik kroků od vyřešení všech svých problémů s plánováním.",
"have_any_questions": "Máte otázky? Jsme tu, abychom vám pomohli.",
"reset_password_subject": "{{appName}}: Pokyny pro obnovení hesla",
"verify_email_banner_button": "Odeslat e-mail",
"event_declined_subject": "Odmítnuto: {{title}} v {{date}}",
"event_cancelled_subject": "Zrušeno: {{title}} v {{date}}",
"event_request_declined": "Žádost o událost byla zamítnuta",
@@ -26,6 +27,8 @@
"rejection_confirmation": "Odmítnout rezervaci",
"manage_this_event": "Spravovat tuto událost",
"invite_team_member": "Pozvat člena týmu",
"invite_team_individual_segment": "Pozvat jednotlivce",
"invite_team_bulk_segment": "Hromadný import",
"invite_team_notifcation_badge": "Pozv.",
"your_event_has_been_scheduled": "Vaše událost byla naplánována",
"your_event_has_been_scheduled_recurring": "Opakovaná událost byla naplánována",
@@ -222,6 +225,7 @@
"go_back_login": "Zpět na přihlašovací stránku",
"error_during_login": "Při přihlašování došlo k chybě. Přejděte zpět na přihlašovací obrazovku a zkuste to znovu.",
"request_password_reset": "Žádost o obnovení hesla",
"send_invite": "Odeslat pozvánku",
"forgot_password": "Zapomenuté heslo",
"forgot": "Zapomněli jste?",
"done": "Hotovo",
@@ -237,6 +241,8 @@
"set_availability": "Nastavte, jak jste dostupní",
"continue_without_calendar": "Pokračovat bez kalendáře",
"connect_your_calendar": "Připojit svůj kalendář",
"connect_your_video_app": "Propojte své video aplikace",
"connect_your_video_app_instructions": "Propojte své video aplikace a používejte je v typech událostí.",
"connect_your_calendar_instructions": "Připojit kalendář pro automatickou kontrolu časů, kdy nejste dostupní, a nově naplánovaných událostí.",
"set_up_later": "Zprovoznit později",
"current_time": "Aktuální čas",
@@ -366,6 +372,7 @@
"create_webhook": "Vytvořit webhook",
"booking_cancelled": "Rezervace zrušena",
"booking_rescheduled": "Rezervace přesunuta",
"recording_ready": "Odkaz ke stažení záznamu je připraven",
"booking_created": "Rezervace vytvořena",
"meeting_ended": "Schůzka skončila",
"form_submitted": "Formulář byl odeslán",
@@ -464,6 +471,7 @@
"friday": "pátek",
"saturday": "sobota",
"sunday": "neděle",
"all_booked_today": "Vše zarezervováno.",
"slots_load_fail": "Nepodařilo se načíst dostupné časové sloty.",
"additional_guests": "Přidat hosty",
"your_name": "Vaše jméno",
@@ -623,8 +631,6 @@
"event_type_created_successfully": "Typ události {{eventTypeTitle}} byl úspěšně vytvořen",
"event_type_updated_successfully": "Typ události {{eventTypeTitle}} byl úspěšně aktualizován",
"event_type_deleted_successfully": "Typ události byl úspěšně smazán",
"web3_metamask_added": "Metamask úspěšně přidán",
"web3_metamask_disconnected": "Metamask úspěšně odpojen",
"hours": "Hodiny",
"your_email": "Váš e-mail",
"change_avatar": "Změnit avatar",
@@ -751,6 +757,10 @@
"new_event_type_to_book_description": "Vytvořit nový typ události, ve které si lidé mohou rezervovat časy.",
"length": "Doba trvání",
"minimum_booking_notice": "Minimální potřebná doba",
"offset_toggle": "Posunutí časů začátku",
"offset_toggle_description": "Posunutí časových slotů zobrazených rezervujícím osobám o zadaný počet minut",
"offset_start": "Posunutí o",
"offset_start_description": "například v tomto případě se vašim rezervujícím zobrazí časové sloty v {{ adjustedTime }} namísto {{ originalTime }}",
"slot_interval": "Časové intervaly",
"slot_interval_default": "Použít délku události (výchozí)",
"delete_event_type": "Odstranit typ události?",
@@ -861,7 +871,6 @@
"installed_one": "Nainstalováno",
"installed_other": "Nainstalováno: {{count}}",
"verify_wallet": "Ověřit peněženku",
"connect_metamask": "Připojit Metamask",
"create_events_on": "Vytvořit události v:",
"enterprise_license": "Jedná se o firemní funkci",
"enterprise_license_description": "Pokud chcete povolit tuto funkci, získejte klíč pro nasazení v konzoli {{consoleUrl}} a přidejte ho do souboru .env jako CALCOM_LICENSE_KEY. Pokud váš tým již licenci má, kontaktujte prosím {{supportMail}} a požádejte o pomoc.",
@@ -887,6 +896,7 @@
"availability_updated_successfully": "Plán {{scheduleName}} byl úspěšně aktualizován",
"schedule_deleted_successfully": "Plán byl úspěšně odstraněn",
"default_schedule_name": "Pracovní doba",
"member_default_schedule": "Výchozí rozvrh člena",
"new_schedule_heading": "Vytvořit plán dostupnosti",
"new_schedule_description": "Vytvoření plánů dostupnosti vám umožní spravovat dostupnost mezi typy událostí. Mohou být použity pro jeden nebo více typů událostí.",
"requires_ownership_of_a_token": "Vyžaduje vlastnictví tokenu, který patří následující adrese:",
@@ -903,6 +913,7 @@
"duplicate": "Duplikovat",
"offer_seats": "Nabídka míst",
"offer_seats_description": "Nabídnout místa k rezervaci. Tím se vypnou rezervace hostů a volitelné rezervace.",
"seats_available_one": "Dostupné místo",
"seats_available_other": "Dostupná místa",
"number_of_seats": "Počet míst na rezervaci",
"enter_number_of_seats": "Zadejte počet míst",
@@ -1037,7 +1048,7 @@
"event_cancelled_trigger": "při zrušení události",
"new_event_trigger": "při rezervaci nové události",
"email_host_action": "odeslání e-mailu hostiteli",
"sms_attendee_action": "odeslání SMS účastníkovi",
"email_attendee_action": "odeslat e-mail účastníkům",
"sms_number_action": "odeslání SMS na konkrétní číslo",
"workflows": "Pracovní postupy",
"new_workflow_btn": "Nový pracovní postup",
@@ -1189,6 +1200,7 @@
"create_workflow": "Vytvoření pracovního postupu",
"do_this": "Provést",
"turn_off": "Vypnout",
"turn_on": "Zapnout",
"settings_updated_successfully": "Nastavení aktualizováno",
"error_updating_settings": "Chyba při aktualizaci nastavení",
"personal_cal_url": "Moje osobní adresa URL {{appName}}",
@@ -1213,11 +1225,6 @@
"upload": "Nahrát",
"add_profile_photo": "Přidat profilovou fotku",
"web3": "Web3",
"rainbow_token_gated": "Tento typ události je uzamčený tokenem.",
"rainbow_connect_wallet_gate": "Propojte svoji peněženku, pokud vlastníte <1>{{name}}</1> (<3>{{symbol}}</3>).",
"rainbow_insufficient_balance": "Vaše propojená peněženka neobsahuje dostatek <1>{{symbol}}</1>.",
"rainbow_sign_message_request": "Podepište zprávu s požadavkem ve své peněžence.",
"rainbow_signature_error": "Chyba při vyžádání podpisu z vaší peněženky.",
"token_address": "Adresa tokenu",
"blockchain": "Blockchain",
"old_password": "Staré heslo",
@@ -1245,6 +1252,7 @@
"calendars_description": "Konfigurace způsobu interakce typů událostí s kalendáři",
"appearance_description": "Správa nastavení vzhledu rezervace",
"conferencing_description": "Přidejte si oblíbené videokonferenční pro vaše schůzky",
"add_conferencing_app": "Přidat videokonferenční aplikaci",
"password_description": "Správa nastavení hesel k vašemu účtu",
"2fa_description": "Správa nastavení hesel k vašemu účtu",
"we_just_need_basic_info": "K nastavení vašeho profilu potřebujeme jen několik základních informací.",
@@ -1279,7 +1287,6 @@
"download_responses_description": "Stáhněte si všechny odpovědi do formuláře ve formátu CSV.",
"download": "Stáhnout",
"download_recording": "Stáhnout nahrávku",
"recording_from_your_recent_call": "Nahrávka z vašeho nedávného hovoru na Cal.com je připravena ke stažení.",
"create_your_first_form": "Vytvořte svůj první formulář",
"create_your_first_form_description": "Pomocí adresných formulářů můžete klást kvalifikační otázky a adresovat je správné osobě nebo typu události.",
"create_your_first_webhook": "Vytvořte svůj první webhook",
@@ -1362,7 +1369,6 @@
"password_updated": "Heslo bylo úspěšně změněno!",
"pending_payment": "Čeká se na platbu",
"pending_invites": "Čekající pozvánky",
"confirmation_page_rainbow": "Zamkněte svoji událost pomocí tokenů nebo NFT na platformách Ethereum, Polygon a dalších.",
"not_on_cal": "Nenachází se na {{appName}}",
"no_calendar_installed": "Není nainstalován kalendář",
"no_calendar_installed_description": "Ještě jste nepropojili žádný ze svých kalendářů",
@@ -1476,8 +1482,6 @@
"find_the_best_person": "Najděte nejlepší dostupnou osobu a procházejte tým.",
"fixed_round_robin": "Pevný „round robin“",
"add_one_fixed_attendee": "Přidejte jednoho pevně stanoveného účastníka a „round robin“ přes daný počet účastníků.",
"calcom_is_better_with_team": "Cal.com je s týmy lepší",
"the_calcom_team": "Tým Cal.com",
"add_your_team_members": "Přidejte členy týmu k typům událostí. Použijte kolektivní plánování, abyste zahrnuli všechny, případně vyhledejte tu nejvhodnější osobu s plánováním „round robin“.",
"booking_limit_reached": "Byl dosažen limit rezervací pro tento typ události",
"duration_limit_reached": "Byl dosažen limit doby trvání pro tento typ události",
@@ -1496,7 +1500,6 @@
"navigate_installed_apps": "Přejděte na nainstalované aplikace",
"disabled_calendar": "Pokud máte nainstalovaný jiný kalendář, budou do něj přidány nové rezervace. Pokud ne, připojte nový kalendář, abyste nepřišli o žádné nové rezervace.",
"enable_apps": "Povolit aplikace",
"enable_apps_description": "Povolte aplikace, které mohou uživatelé integrovat s Cal.com",
"purchase_license": "Kupte si licenci",
"already_have_key": "Klíč již mám:",
"already_have_key_suggestion": "Zkopírujte sem svou stávající proměnnou prostředí CALCOM_LICENSE_KEY.",
@@ -1619,6 +1622,7 @@
"email_user_cta": "Zobrazit pozvánku",
"email_no_user_invite_heading": "Byli jste pozváni do týmu v aplikaci {{appName}}",
"email_no_user_invite_subheading": "Uživatel {{invitedBy}} vás pozval, abyste se připojili k jeho týmu v aplikaci {{appName}}. {{appName}} je plánovač událostí, který vám a vašemu týmu umožňuje plánovat schůzky bez e-mailového ping-pongu.",
"email_user_invite_subheading": "Uživatel {{invitedBy}} vás pozval, abyste se připojili k jeho týmu „{{teamName}}“ v aplikaci {{appName}}. {{appName}} je plánovač událostí, který vám a vašemu týmu umožňuje plánovat schůzky bez e-mailového pingpongu.",
"email_no_user_invite_steps_intro": "Provedeme vás několika krátkými kroky a za malou chvíli si budete se svým týmem užívat plánování bez stresu.",
"email_no_user_step_one": "Vyberte si uživatelské jméno",
"email_no_user_step_two": "Připojte svůj účet kalendáře",
@@ -1694,6 +1698,15 @@
"spot_popular_event_types_description": "Zjistěte, které typy vašich událostí získávají nejvíce kliknutí a rezervací",
"no_responses_yet": "Zatím žádné odpovědi",
"this_will_be_the_placeholder": "Toto bude zástupný znak",
"error_booking_event": "Při rezervaci události došlo k chybě, obnovte prosím stránku a zkuste to znovu",
"timeslot_missing_title": "Nebyl vybrán žádný časový slot",
"timeslot_missing_description": "Vyberte časový slot, aby mohla být událost zaregistrována.",
"timeslot_missing_cta": "Vybrat časový slot",
"switch_monthly": "Přepnout na měsíční zobrazení",
"switch_weekly": "Přepnout na týdenní zobrazení",
"switch_multiday": "Přepnout na denní zobrazení",
"num_locations": "Možná místa konání: {{num}}",
"select_on_next_step": "Vyberte v dalším kroku",
"this_meeting_has_not_started_yet": "Tato schůzka ještě nezačala",
"this_app_requires_connected_account": "{{appName}} vyžaduje připojený účet {{dependencyName}}",
"connect_app": "Připojit aplikaci {{dependencyName}}",
@@ -1723,6 +1736,7 @@
"locked_apps_description": "Členové uvidí aktivní aplikace, ale nastavení aplikací upravovat nemohou",
"locked_webhooks_description": "Členové uvidí aktivní webhooky, ale nastavení webhooků upravovat nemohou",
"locked_workflows_description": "Členové uvidí aktivní pracovní postupy, ale nastavení pracovních postupů upravovat nemohou",
"locked_by_admin": "Uzamčeno správcem týmu",
"app_not_connected": "Nemáte připojený účet {{appName}}.",
"connect_now": "Připojte se",
"managed_event_dialog_confirm_button_one": "Nahradit a upozornit {{count}} člena",
@@ -1780,5 +1794,35 @@
"seats_and_no_show_fee_error": "V současné době nelze povolit místa a strhnout poplatek za nedostavení se",
"complete_your_booking": "Dokončete svou rezervaci",
"complete_your_booking_subject": "Dokončete svou rezervaci: {{title}} dne {{date}}",
"email_invite_team": "Pozvánka pro uživatele {{email}} odeslána"
"confirm_your_details": "Potvrďte své údaje",
"never_expire": "Platnost nikdy neuplyne",
"currency_string": "{{amount, currency}}",
"charge_card_dialog_body": "Chystáte se účtovat účastníkovi {{amount, currency}}. Opravdu chcete pokračovat?",
"charge_attendee": "Naúčtovat účastníkovi {{amount, currency}}",
"payment_app_commission": "Vyžadujte platbu ({{paymentFeePercentage}} % + provizi {{fee, currency}} za transakci)",
"email_invite_team": "Pozvánka pro uživatele {{email}} odeslána",
"email_invite_team_bulk": "Počet pozvaných uživatelů: {{userCount}}",
"error_collecting_card": "Chyba při výběru karty",
"image_size_limit_exceed": "Velikost nahraného obrázku by neměla překročit limit 5 MB",
"inline_embed": "Embed inline",
"load_inline_content": "Načte váš typ události přímo „inline“ s ostatním obsahem webu.",
"floating_pop_up_button": "Plovoucí překryvné tlačítko",
"floating_button_trigger_modal": "Umístí na váš web plovoucí tlačítko, které spustí modální okno s vaším typem události.",
"pop_up_element_click": "Překryvné okno při kliknutí na prvek",
"open_dialog_with_element_click": "Otevře dialogové okno Cal, pokud někdo klikne na prvek.",
"need_help_embedding": "Potřebujete pomoc? Prohlédněte si naše průvodce pro vložení Cal do Wixu, Squarespace nebo WordPressu, podívejte se na naše nejčastější dotazy nebo prozkoumejte pokročilé možnosti vložení.",
"book_my_cal": "Book my Cal",
"invite_as": "Pozvat jako",
"form_updated_successfully": "Formulář byl aktualizován.",
"email_not_cal_member_cta": "Připojte se ke svému týmu",
"disable_attendees_confirmation_emails": "Vypnutí výchozích potvrzovacích e-mailů pro účastníky",
"disable_attendees_confirmation_emails_description": "U tohoto typu události je aktivní alespoň jeden pracovní postup, který po rezervaci události odešle účastníkům e-mail.",
"disable_host_confirmation_emails": "Vypnutí výchozích potvrzovacích e-mailů pro hostitele",
"disable_host_confirmation_emails_description": "U tohoto typu události je aktivní alespoň jeden pracovní postup, který po rezervaci události odešle hostiteli e-mail.",
"add_an_override": "Přidejte změnu",
"import_from_google_workspace": "Importovat uživatele z Google Workspace",
"connect_google_workspace": "Propojit s Google Workspace",
"google_workspace_admin_tooltip": "Používání této funkce vyžaduje, abyste byli administrátory Google Workspace",
"first_event_type_webhook_description": "Vytvořte svůj první webhook pro tento typ události",
"create_for": "Vytvořit pro"
}
+3 -14
View File
@@ -10,6 +10,7 @@
"calcom_explained_new_user": "Afslut opsætningen af din {{appName}} konto! Du er kun få skridt fra at løse alle dine planlægningsproblemer.",
"have_any_questions": "Har du spørgsmål? Vi er her for at hjælpe.",
"reset_password_subject": "{{appName}}: Nulstil adgangskodeinstruktioner",
"verify_email_banner_button": "Send e-mail",
"event_declined_subject": "Afvist: {{title}} den {{date}}",
"event_cancelled_subject": "Aflyst: {{title}} den {{date}}",
"event_request_declined": "Din begivenhedsanmodning er blevet afvist",
@@ -601,8 +602,6 @@
"event_type_created_successfully": "{{eventTypeTitle}} begivenhedstype blev oprettet",
"event_type_updated_successfully": "{{eventTypeTitle}} begivenhedstype blev opdateret",
"event_type_deleted_successfully": "Begivenhedstypen blev slettet",
"web3_metamask_added": "Metamask tilføjet",
"web3_metamask_disconnected": "Metamask blev afbrudt",
"hours": "Timer",
"your_email": "Din E-Mail",
"change_avatar": "Skift Avatar",
@@ -834,7 +833,6 @@
"installed_one": "Installeret",
"installed_other": "{{count}} installeret",
"verify_wallet": "Verificér Wallet",
"connect_metamask": "Forbind Metamask",
"create_events_on": "Opret begivenheder på",
"enterprise_license": "Dette er en virksomhedsfunktion",
"enterprise_license_description": "For at aktivere denne funktion, skal du gå til {{setupUrl}} for at indtaste en licensnøgle. Hvis en licensnøgle allerede er på plads, bedes du kontakte {{supportMail}} for hjælp.",
@@ -1009,7 +1007,6 @@
"event_cancelled_trigger": "når begivenheden er aflyst",
"new_event_trigger": "når ny begivenhed er booket",
"email_host_action": "send e-mail til vært",
"sms_attendee_action": "Send SMS til deltager",
"sms_number_action": "send SMS til et specifikt nummer",
"workflows": "Workflows",
"new_workflow_btn": "Nyt Workflow",
@@ -1181,11 +1178,6 @@
"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",
@@ -1281,7 +1273,6 @@
"exchange_authentication_standard": "Grundlæggende autentificering",
"exchange_authentication_ntlm": "NTLM autentificering",
"exchange_compression": "GZip komprimering",
"routing_forms_description": "Du kan se alle former og ruter du har oprettet her.",
"routing_forms_send_email_owner": "Send e-mail til Ejer",
"routing_forms_send_email_owner_description": "Sender en e-mail til ejeren når formularen er indsendt",
"add_new_form": "Tilføj ny formular",
@@ -1318,7 +1309,6 @@
"password_updated": "Adgangskode opdateret!",
"pending_payment": "Afventer betaling",
"pending_invites": "Afventende Invitationer",
"confirmation_page_rainbow": "Token gate din begivenhed med tokens eller NFTs på Ethereum, Polygon og flere.",
"not_on_cal": "Ikke på {{appName}}",
"no_calendar_installed": "Ingen kalender installeret",
"no_calendar_installed_description": "Du har endnu ikke tilsluttet nogen af dine kalendere",
@@ -1428,7 +1418,6 @@
"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",
"add_your_team_members": "Føj dine teammedlemmer til dine begivenhedstyper. Brug kollektiv planlægning til at inkludere alle eller finde den bedst egnede person med round robin planlægning.",
"booking_limit_reached": "Booking Grænse for denne begivenhedstype er nået",
"admin_has_disabled": "En administrator har deaktiveret {{appName}}",
@@ -1441,7 +1430,6 @@
"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.",
@@ -1613,5 +1601,6 @@
"this_will_be_the_placeholder": "Dette vil være pladsholderen",
"verification_code": "Bekræftelseskode",
"verify": "Bekræft",
"timezone_variable": "Tidszone"
"timezone_variable": "Tidszone",
"never_expire": "Udløber aldrig"
}
+60 -16
View File
@@ -11,6 +11,7 @@
"calcom_explained_new_user": "Beenden Sie die Einrichtung Ihres {{appName}} -Kontos! Sie sind nur ein paar Schritte von der Lösung aller Probleme in der Zeitplanung entfernt.",
"have_any_questions": "Haben Sie Fragen? Wir sind hier um Ihnen zu helfen.",
"reset_password_subject": "{{appName}}: Anleitung zum Zurücksetzen des Passworts",
"verify_email_banner_button": "E-Mail senden",
"event_declined_subject": "Abgelehnt: {{title}} am {{date}}",
"event_cancelled_subject": "Storniert: {{title}} um {{date}}",
"event_request_declined": "Ihre Event-Anfrage wurde abgelehnt",
@@ -26,6 +27,8 @@
"rejection_confirmation": "Buchung ablehnen",
"manage_this_event": "Diesen Termin verwalten",
"invite_team_member": "Teammitglied einladen",
"invite_team_individual_segment": "Person einladen",
"invite_team_bulk_segment": "Massenimport",
"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",
@@ -222,6 +225,7 @@
"go_back_login": "Zurück zur Login-Seite",
"error_during_login": "Beim Anmelden ist ein Fehler aufgetreten. Gehen Sie zurück zum Anmeldebildschirm und versuchen Sie es erneut.",
"request_password_reset": "Passwort zurücksetzen",
"send_invite": "Einladung senden",
"forgot_password": "Passwort vergessen",
"forgot": "Vergessen?",
"done": "Erledigt",
@@ -237,6 +241,8 @@
"set_availability": "Verfügbarkeit festlegen",
"continue_without_calendar": "Ohne Kalender fortfahren",
"connect_your_calendar": "Kalender verbinden",
"connect_your_video_app": "Verbinden Sie Ihre Video-Apps",
"connect_your_video_app_instructions": "Verbinden Sie Ihre Video-Apps, um sie für Ihre Termintypen zu verwenden.",
"connect_your_calendar_instructions": "Verbinden Sie Ihren Kalender, um automatisch zu prüfen, ob Termine verfügbar sind.",
"set_up_later": "Später einrichten",
"current_time": "Aktuelle Zeit",
@@ -366,6 +372,7 @@
"create_webhook": "Webhook erstellen",
"booking_cancelled": "Termin abgesagt",
"booking_rescheduled": "Termin verlegt",
"recording_ready": "Download-Link der Aufnahme bereit",
"booking_created": "Termin erstellt",
"meeting_ended": "Meeting beendet",
"form_submitted": "Formular gesendet",
@@ -464,6 +471,7 @@
"friday": "Freitag",
"saturday": "Samstag",
"sunday": "Sonntag",
"all_booked_today": "Alle gebucht.",
"slots_load_fail": "Die verfügbaren Zeitfenster konnten nicht geladen werden.",
"additional_guests": "+ Weitere Gäste",
"your_name": "Ihr Name",
@@ -623,8 +631,6 @@
"event_type_created_successfully": "{{eventTypeTitle}} Ereignistyp erfolgreich erstellt",
"event_type_updated_successfully": "{{eventTypeTitle}} Ereignistyp erfolgreich aktualisiert",
"event_type_deleted_successfully": "Termintyp erfolgreich gelöscht",
"web3_metamask_added": "Metamask erfolgreich hinzugefügt",
"web3_metamask_disconnected": "Metamask erfolgreich getrennt",
"hours": "Stunden",
"your_email": "Ihre E-Mail-Adresse",
"change_avatar": "Profilbild ändern",
@@ -751,6 +757,10 @@
"new_event_type_to_book_description": "Erstellen Sie einen neuen Termintyp, mit dem Personen Zeiten buchen können.",
"length": "Länge",
"minimum_booking_notice": "Mindesvorlaufzeit für eine Buchung",
"offset_toggle": "Startzeiten versetzen",
"offset_toggle_description": "Um eine bestimmte Anzahl an Minuten versetzte Zeitfenster, die Buchern angezeigt werden",
"offset_start": "Versetzt um",
"offset_start_description": "z.B. wird dies Zeitfenster für Ihre Bucher um {{ adjustedTime }} statt {{ originalTime }} anzeigen",
"slot_interval": "Zeit-Slot-Intervalle",
"slot_interval_default": "Verwende Terminlänge (Standard)",
"delete_event_type": "Ereignistyp löschen?",
@@ -861,7 +871,6 @@
"installed_one": "Installiert",
"installed_other": "{{count}} installiert",
"verify_wallet": "Wallet verifizieren",
"connect_metamask": "Metamask verbinden",
"create_events_on": "Erstelle Termine in:",
"enterprise_license": "Das ist eine Enterprise-Funktion",
"enterprise_license_description": "Um diese Funktion zu aktivieren, holen Sie sich einen Deployment-Schlüssel von der {{consoleUrl}}-Konsole und fügen Sie ihn als CALCOM_LICENSE_KEY zu Ihrer .env hinzu. Wenn Ihr Team bereits eine Lizenz hat, wenden Sie sich bitte an {{supportMail}} für Hilfe.",
@@ -887,6 +896,7 @@
"availability_updated_successfully": "{{scheduleName}} Zeitplan erfolgreich aktualisiert",
"schedule_deleted_successfully": "Verfügbarkeitsplan erfolgreich gelöscht",
"default_schedule_name": "Arbeitszeiten",
"member_default_schedule": "Standardverfügbarkeitsplan des Mitglieds",
"new_schedule_heading": "Erstelle einen Verfügbarkeitsplan",
"new_schedule_description": "Das Erstellen eines Verfügbarkeitsplan sorgt dafür, dass Ihre Verfügbarkeit bei mehreren Termintypen genutzt werden kann.",
"requires_ownership_of_a_token": "Erfordert Besitz eines Tokens, das zu der folgenden Adresse gehört:",
@@ -903,6 +913,7 @@
"duplicate": "Duplizieren",
"offer_seats": "Plätze anbieten",
"offer_seats_description": "Bieten Sie Plätze für Buchungen an (dies deaktiviert Gäste & Opt-in-Buchungen)",
"seats_available_one": "Verfügbarer Platz",
"seats_available_other": "Verfügbare Plätze",
"number_of_seats": "Anzahl der Plätze pro Termin",
"enter_number_of_seats": "Anzahl der Plätze eingeben",
@@ -1037,7 +1048,7 @@
"event_cancelled_trigger": "wenn das Ereignis abgesagt wird",
"new_event_trigger": "wenn ein neer Termin gebucht wird",
"email_host_action": "E-Mail an den Veranstalter senden",
"sms_attendee_action": "SMS an Teilnehmende senden",
"email_attendee_action": "E-Mail an Teilnehmende senden",
"sms_number_action": "SMS an eine bestimmte Nummer senden",
"workflows": "Workflows",
"new_workflow_btn": "Neuer Workflow",
@@ -1189,6 +1200,7 @@
"create_workflow": "Einen Workflow erstellen",
"do_this": "Mache dies",
"turn_off": "Abschalten",
"turn_on": "Einschalten",
"settings_updated_successfully": "Einstellungen erfolgreich aktualisiert",
"error_updating_settings": "Fehler beim Aktualisieren der Einstellungen",
"personal_cal_url": "Meine persönliche {{appName}}-URL",
@@ -1213,11 +1225,6 @@
"upload": "Upload",
"add_profile_photo": "Profilbild hinzufügen",
"web3": "Web3",
"rainbow_token_gated": "Dieser Ereignistyp ist durch einen Token geschützt.",
"rainbow_connect_wallet_gate": "Verbinden Sie Ihre Wallet, falls Sie <1>{{name}}</1> (<3>{{symbol}}</3>) besitzen.",
"rainbow_insufficient_balance": "Ihre verbundene Wallet enthält nicht genug <1>{{symbol}}</1>.",
"rainbow_sign_message_request": "Unterschreiben Sie die Nachrichtenanfrage in Ihrem Wallet.",
"rainbow_signature_error": "Fehler beim Anfordern der Signatur von Ihrer Wallet.",
"token_address": "Adresse des Token",
"blockchain": "Blockchain",
"old_password": "Altes Passwort",
@@ -1245,6 +1252,7 @@
"calendars_description": "Konfigurieren Sie, wie Ihre Event-Typen mit Ihren Kalendern interagieren sollen",
"appearance_description": "Einstellungen für Ihre Buchungsdarstellung verwalten",
"conferencing_description": "Fügen Sie Ihre favorisierten Videokonferenz-Apps für Ihre Meetings hinzu",
"add_conferencing_app": "Konferenz-App hinzufügen",
"password_description": "Einstellungen für Ihre Konto-Passwörter verwalten",
"2fa_description": "Einstellungen für Ihre Konto-Passwörter verwalten",
"we_just_need_basic_info": "Wir benötigen nur ein paar grundlegende Informationen, um Ihr Profil einzurichten.",
@@ -1279,7 +1287,6 @@
"download_responses_description": "Laden Sie alle Antworten zu Ihrem Formular im CSV-Format herunter.",
"download": "Herunterladen",
"download_recording": "Aufnahme herunterladen",
"recording_from_your_recent_call": "Eine Aufnahme von Ihrem letzten Anruf auf Cal.com steht zum Download bereit",
"create_your_first_form": "Erstellen Sie Ihr erstes Formular",
"create_your_first_form_description": "Mithilfe von Leitungsformularen können Sie qualifizierende Fragen stellen und zur richtigen Person oder zum richtigen Veranstaltungstyp weiterleiten.",
"create_your_first_webhook": "Erstellen Sie Ihren ersten Webhook",
@@ -1362,7 +1369,6 @@
"password_updated": "Passwort aktualisiert!",
"pending_payment": "Zahlung ausstehend",
"pending_invites": "Offene Einladungen",
"confirmation_page_rainbow": "Sperren Sie Ihr Ereignis hinter Tokens oder NFTs auf Ethereum, Polygon und mehr.",
"not_on_cal": "Nicht auf {{appName}}",
"no_calendar_installed": "Kein Kalender installiert",
"no_calendar_installed_description": "Sie haben noch keinen Ihrer Kalender verbunden",
@@ -1476,8 +1482,6 @@
"find_the_best_person": "Finden Sie die beste verfügbare Person und rotieren Sie durch Ihr Team.",
"fixed_round_robin": "Festgelegter Round Robin",
"add_one_fixed_attendee": "Fügen Sie einen festen Teilnehmer und einen Round Robin mit einer Reihe von Teilnehmern hinzu.",
"calcom_is_better_with_team": "Cal.com ist mit Teams besser",
"the_calcom_team": "Das Cal.com Team",
"add_your_team_members": "Fügen Sie Ihre Teammitglieder zu Ihren Termintypen hinzu. Nutzen Sie kollektive Planung, um alle einzubinden oder finden Sie die geeignetste Person mit der Round Robin Planung.",
"booking_limit_reached": "Das Buchungslimit für diesen Termintyp wurde erreicht",
"duration_limit_reached": "Das Zeitlimit für diesen Termintyp wurde erreicht",
@@ -1496,7 +1500,6 @@
"navigate_installed_apps": "Zu installierten Apps wechseln",
"disabled_calendar": "Wenn Sie einen anderen Kalender installiert haben, werden neue Buchungen zu dem Kalender hinzugefügt. Verbinden Sie andernfalls einen neuen Kalender, damit Sie keine neuen Buchungen verpassen.",
"enable_apps": "Apps aktivieren",
"enable_apps_description": "Apps aktivieren, die Benutzer mit Cal.com integrieren können",
"purchase_license": "Lizenz kaufen",
"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.",
@@ -1619,6 +1622,7 @@
"email_user_cta": "Einladung anzeigen",
"email_no_user_invite_heading": "Sie wurden eingeladen, dem Team in {{appName}} beizutreten",
"email_no_user_invite_subheading": "{{invitedBy}} hat Sie eingeladen, dem Team in {{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_user_invite_subheading": "{{invitedBy}} hat Sie eingeladen, dem Team „{{teamName}}“ beizutreten. {{appName}} ist der Event-Planer, der es Ihnen und Ihrem Team ermöglicht, Meetings ohne 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",
@@ -1694,6 +1698,15 @@
"spot_popular_event_types_description": "Sehen Sie, welche Ihrer Ereignistypen die meisten Klicks und Buchungen erhalten",
"no_responses_yet": "Noch keine Antworten",
"this_will_be_the_placeholder": "Dies wird der Platzhalter sein",
"error_booking_event": "Bei der Buchung dieses Termins ist ein Fehler aufgetreten, bitte aktualisieren Sie die Seite und versuchen Sie es erneut",
"timeslot_missing_title": "Kein Zeitfenster ausgewählt",
"timeslot_missing_description": "Bitte wählen Sie einen Zeitraum aus, um den Termin zu buchen.",
"timeslot_missing_cta": "Zeitfenster auswählen",
"switch_monthly": "Zur monatlichen Ansicht wechseln",
"switch_weekly": "Zur Wochenansicht wechseln",
"switch_multiday": "Zur Tagesansicht wechseln",
"num_locations": "{{num}} Standortoptionen",
"select_on_next_step": "Im nächsten Schritt auswählen",
"this_meeting_has_not_started_yet": "Dieses Meeting hat noch nicht begonnen",
"this_app_requires_connected_account": "{{appName}} benötigt ein verbundenes {{dependencyName}}-Konto",
"connect_app": "{{dependencyName}} verbinden",
@@ -1723,6 +1736,7 @@
"locked_apps_description": "Mitglieder können die aktiven Apps sehen, können aber keine App-Einstellungen anpassen",
"locked_webhooks_description": "Mitglieder können die aktiven Webhooks sehen, können aber keine Webhook-Einstellungen anpassen",
"locked_workflows_description": "Mitglieder können die aktiven Workflows sehen, können aber keine Workflow-Einstellungen anpassen",
"locked_by_admin": "Vom Team-Admin gesperrt",
"app_not_connected": "Sie haben kein {{appName}}-Konto verbunden.",
"connect_now": "Jetzt verbinden",
"managed_event_dialog_confirm_button_one": "{{count}} Mitglied ersetzen & benachrichtigen",
@@ -1734,7 +1748,7 @@
"managed_event_dialog_clarification": "Wenn Sie die URL ersetzen, werden wir sie benachrichtigen. Gehen Sie zurück und entfernen Sie sie, wenn Sie sie nicht überschreiben möchten.",
"review_event_type": "Ereignistyp überprüfen",
"looking_for_more_analytics": "Suchen Sie nach weiteren Analysedaten?",
"looking_for_more_insights": "Suchen Sie nach weiteren Einsichten?",
"looking_for_more_insights": "Möchten Sie mehr Insights?",
"add_filter": "Filter hinzufügen",
"select_user": "Benutzer auswählen",
"select_event_type": "Ereignistyp auswählen",
@@ -1780,5 +1794,35 @@
"seats_and_no_show_fee_error": "Aktuell können keine Plätze aktiviert oder eine Gebühr für das Nichterscheinen berechnet werden",
"complete_your_booking": "Schließen Sie Ihre Buchung ab",
"complete_your_booking_subject": "Schließen Sie Ihre Buchung ab: {{title}} am {{date}}",
"email_invite_team": "{{email}} wurde eingeladen"
"confirm_your_details": "Bestätigen Sie Ihre Daten",
"never_expire": "Läuft niemals ab",
"currency_string": "{{amount, currency}}",
"charge_card_dialog_body": "Sie sind im Begriff, den Teilnehmer {{amount, currency}} in Rechnung zu stellen. Sind Sie sicher, dass Sie fortfahren möchten?",
"charge_attendee": "Teilnehmer {{amount, currency}} berechnen",
"payment_app_commission": "Zahlung erfordern ({{paymentFeePercentage}} % + {{fee, currency}} Provision pro Transaktion)",
"email_invite_team": "{{email}} wurde eingeladen",
"email_invite_team_bulk": "{{userCount}} Benutzer wurden eingeladen",
"error_collecting_card": "Fehler beim Erfassen der Karte",
"image_size_limit_exceed": "Das hochgeladene Bild sollte die maximale Größe von 5 MB nicht überschreiten",
"inline_embed": "Inline-Einbettung",
"load_inline_content": "Laden Sie Ihren Event-Typ direkt inline mit Ihren anderen Website-Inhalten.",
"floating_pop_up_button": "Schwebende Pop-Up-Schaltfläche",
"floating_button_trigger_modal": "Erstellt einen schwebenden Button auf Ihrer Website, der einen modalen Dialog mit Ihrem Termintypen erstellt.",
"pop_up_element_click": "Pop-Up über Element-Klick",
"open_dialog_with_element_click": "Öffnet Ihren Cal-Dialog, wenn jemand ein Element anklickt.",
"need_help_embedding": "Brauchen Sie Hilfe? Sehen Sie sich unsere Anleitungen zum Einbetten von Cal auf Wix, Squarespace, oder WordPress an, schauen Sie sich unsere häufig gestellten Fragen an oder erkunden Sie erweiterte Einbettungsoptionen.",
"book_my_cal": "Mein Cal buchen",
"invite_as": "Einladen als",
"form_updated_successfully": "Formular erfolgreich aktualisiert.",
"email_not_cal_member_cta": "Treten Sie Ihrem Team bei",
"disable_attendees_confirmation_emails": "Standardmäßige Bestätigungs-E-Mails für Teilnehmer deaktivieren",
"disable_attendees_confirmation_emails_description": "Mindestens ein Workflow ist für diesen Termintyp aktiv, welcher bei Buchung eine E-Mail an die Teilnehmer sendet.",
"disable_host_confirmation_emails": "Standardmäßige Bestätigungs-E-Mails für Veranstalter deaktivieren",
"disable_host_confirmation_emails_description": "Mindestens ein Workflow ist für diesen Termintyp aktiv, welcher bei Buchung eine E-Mail an den Veranstalter sendet.",
"add_an_override": "Eine Überschreibung hinzufügen",
"import_from_google_workspace": "Benutzer aus Google Workspace importieren",
"connect_google_workspace": "Google Workspace verbinden",
"google_workspace_admin_tooltip": "Sie müssen ein Workspace-Admin sein, um diese Funktion nutzen zu können",
"first_event_type_webhook_description": "Erstellen Sie Ihren ersten Webhook für diesen Termintypen",
"create_for": "Erstellen für"
}
+45 -16
View File
@@ -11,6 +11,16 @@
"calcom_explained_new_user": "Finish setting up your {{appName}} account! You’re just a few steps away from solving all your scheduling problems.",
"have_any_questions": "Have questions? We're here to help.",
"reset_password_subject": "{{appName}}: Reset password instructions",
"verify_email_subject": "{{appName}}: Verify your account",
"check_your_email": "Check your email",
"verify_email_page_body": "We've sent an email to {{email}}. It is important to verify your email address to guarantee the best email and calendar deliverability from {{appName}}.",
"verify_email_banner_body": "Please verify your email adress to guarantee the best email and calendar deliverability from {{appName}}.",
"verify_email_banner_button": "Send email",
"verify_email_email_header": "Verify your email address",
"verify_email_email_button": "Verify email",
"verify_email_email_body": "Please verify your email address by clicking the button below.",
"verify_email_email_link_text": "Here's the link incase you don't like clicking buttons:",
"email_sent": "Email sent successfully",
"event_declined_subject": "Declined: {{title}} at {{date}}",
"event_cancelled_subject": "Cancelled: {{title}} at {{date}}",
"event_request_declined": "Your event request has been declined",
@@ -294,6 +304,18 @@
"success": "Success",
"failed": "Failed",
"password_has_been_reset_login": "Your password has been reset. You can now login with your newly created password.",
"bookerlayout_title": "Layout",
"bookerlayout_default_title": "Default view",
"bookerlayout_description": "You can select multiple and your bookers can switch views.",
"bookerlayout_user_settings_title": "Booking layout",
"bookerlayout_user_settings_description": "You can select multiple and bookers can switch views. This can be overridden on a per event basis.",
"bookerlayout_month_view": "Month",
"bookerlayout_week_view": "Weekly",
"bookerlayout_column_view": "Column",
"bookerlayout_error_min_one_enabled": "At least one layout has to be enabled.",
"bookerlayout_error_default_not_enabled": "The layout you selected as the default view is not part of the enabled layouts.",
"bookerlayout_error_unknown_layout": "The layout you selected is not a valid layout.",
"bookerlayout_override_global_settings": "You can manage this for all your event types in <2>settings / appearance</2> or <6>override for this event only</6>.",
"unexpected_error_try_again": "An unexpected error occurred. Try again.",
"sunday_time_error": "Invalid time on Sunday",
"monday_time_error": "Invalid time on Monday",
@@ -634,8 +656,6 @@
"event_type_created_successfully": "{{eventTypeTitle}} event type created successfully",
"event_type_updated_successfully": "{{eventTypeTitle}} event type updated successfully",
"event_type_deleted_successfully": "Event type deleted successfully",
"web3_metamask_added": "Metamask added successfully",
"web3_metamask_disconnected": "Metamask disconnected successfully",
"hours": "Hours",
"your_email": "Your Email",
"change_avatar": "Change Avatar",
@@ -876,7 +896,6 @@
"installed_one": "Installed",
"installed_other": "{{count}} installed",
"verify_wallet": "Verify Wallet",
"connect_metamask": "Connect Metamask",
"create_events_on": "Create events on",
"enterprise_license": "This is an enterprise feature",
"enterprise_license_description": "To enable this feature, have an administrator go to {{setupUrl}} to enter a license key. If a license key is already in place, please contact {{supportMail}} for help.",
@@ -902,6 +921,7 @@
"availability_updated_successfully": "{{scheduleName}} schedule updated successfully",
"schedule_deleted_successfully": "Schedule deleted successfully",
"default_schedule_name": "Working Hours",
"member_default_schedule":"Member's default schedule",
"new_schedule_heading": "Create an availability schedule",
"new_schedule_description": "Creating availability schedules allows you to manage availability across event types. They can be applied to one or more event types.",
"requires_ownership_of_a_token": "Requires ownership of a token belonging to the following address:",
@@ -1054,7 +1074,7 @@
"new_event_trigger": "when new event is booked",
"email_host_action": "send email to host",
"email_attendee_action": "send email to attendees",
"sms_attendee_action": "send SMS to attendee",
"sms_attendee_action": "Send SMS to attendee",
"sms_number_action": "send SMS to a specific number",
"workflows": "Workflows",
"new_workflow_btn": "New Workflow",
@@ -1231,11 +1251,6 @@
"upload": "Upload",
"add_profile_photo": "Add profile photo",
"web3": "Web3",
"rainbow_token_gated": "This event type is token gated.",
"rainbow_connect_wallet_gate": "Connect your wallet if you own <1>{{name}}</1> (<3>{{symbol}}</3>).",
"rainbow_insufficient_balance": "Your connected wallet doesn't contain enough <1>{{symbol}}</1>.",
"rainbow_sign_message_request": "Sign the message request on your wallet.",
"rainbow_signature_error": "Error requesting signature from your wallet.",
"token_address": "Token Address",
"blockchain": "Blockchain",
"old_password": "Old password",
@@ -1298,7 +1313,7 @@
"download_responses_description": "Download all responses to your form in CSV format.",
"download": "Download",
"download_recording": "Download Recording",
"recording_from_your_recent_call":"A recording from your recent call on Cal.com is ready for download",
"recording_from_your_recent_call":"A recording from your recent call on {{appName}} is ready for download",
"create_your_first_form": "Create your first form",
"create_your_first_form_description": "With Routing Forms you can ask qualifying questions and route to the correct person or event type.",
"create_your_first_webhook": "Create your first Webhook",
@@ -1381,7 +1396,6 @@
"password_updated": "Password updated!",
"pending_payment": "Pending payment",
"pending_invites": "Pending Invites",
"confirmation_page_rainbow": "Token gate your event with tokens or NFTs on Ethereum, Polygon, and more.",
"not_on_cal": "Not on {{appName}}",
"no_calendar_installed": "No calendar installed",
"no_calendar_installed_description": "You have not yet connected any of your calendars",
@@ -1495,8 +1509,8 @@
"find_the_best_person": "Find the best person available and cycle through your team.",
"fixed_round_robin": "Fixed round robin",
"add_one_fixed_attendee": "Add one fixed attendee and round robin through a number of attendees.",
"calcom_is_better_with_team": "Cal.com is better with teams",
"the_calcom_team":"The Cal.com team",
"calcom_is_better_with_team": "{{appName}} is better with teams",
"the_calcom_team":"The {{companyName}} team",
"add_your_team_members": "Add your team members to your event types. Use collective scheduling to include everyone or find the most suitable person with round robin scheduling.",
"booking_limit_reached": "Booking Limit for this event type has been reached",
"duration_limit_reached": "Duration Limit for this event type has been reached",
@@ -1515,7 +1529,7 @@
"navigate_installed_apps": "Go to installed apps",
"disabled_calendar": "If you have another calendar installed new bookings will be added to it. If not then connect a new calendar so you do not miss any new bookings.",
"enable_apps": "Enable Apps",
"enable_apps_description": "Enable apps that users can integrate with Cal.com",
"enable_apps_description": "Enable apps that users can integrate with {{appName}}",
"purchase_license": "Purchase a License",
"already_have_key": "I already have a key:",
"already_have_key_suggestion": "Please copy your existing CALCOM_LICENSE_KEY environment variable here.",
@@ -1672,6 +1686,7 @@
"booking_questions_title": "Booking questions",
"booking_questions_description": "Customize the questions asked on the booking page",
"add_a_booking_question": "Add a question",
"identifier": "Identifier",
"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.",
@@ -1680,7 +1695,7 @@
"not_enough_seats": "Not enough seats",
"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",
"show_on_booking_page":"Show on booking page",
"show_on_booking_page": "Show on booking page",
"get_started_zapier_templates": "Get started with Zapier templates",
"team_is_unpublished": "{{team}} is unpublished",
"team_is_unpublished_description": "This team link is currently not available. Please contact the team owner or ask them publish it.",
@@ -1713,6 +1728,7 @@
"spot_popular_event_types": "Spot popular event types",
"spot_popular_event_types_description": "See which of your event types are receiving the most clicks and bookings",
"no_responses_yet": "No responses yet",
"no_routes_defined": "No routes defined",
"this_will_be_the_placeholder": "This will be the placeholder",
"error_booking_event": "An error occured when booking the event, please refresh the page and try again",
"timeslot_missing_title": "No timeslot selected",
@@ -1811,6 +1827,17 @@
"complete_your_booking": "Complete your booking",
"complete_your_booking_subject": "Complete your booking: {{title}} on {{date}}",
"confirm_your_details": "Confirm your details",
"copy_invite_link": "Copy invite link",
"edit_invite_link": "Edit link settings",
"invite_link_copied": "Invite link copied",
"invite_link_deleted": "Invite link deleted",
"invite_link_updated": "Invite link settings saved",
"link_expires_after": "Links set to expire after...",
"one_day": "1 day",
"seven_days": "7 days",
"thirty_days": "30 days",
"never_expire": "Never expires",
"team_invite_received": "You have been invited to join {{teamName}}",
"currency_string": "{{amount, currency}}",
"charge_card_dialog_body": "You are about to charge the attendee {{amount, currency}}. Are you sure you want to continue?",
"charge_attendee": "Charge attendee {{amount, currency}}",
@@ -1840,5 +1867,7 @@
"connect_google_workspace":"Connect Google Workspace",
"google_workspace_admin_tooltip":"You must be a Workspace Admin to use this feature",
"first_event_type_webhook_description": "Create your first webhook for this event type",
"create_for": "Create for"
"create_for": "Create for",
"additional_url_parameters": "Additional URL parameters",
"ADD_NEW_STRINGS_ABOVE_THIS_LINE_TO_PREVENT_MERGE_CONFLICTS": "↑↑↑↑↑↑↑↑↑↑↑↑↑ Add your new strings above here ↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑"
}
+3 -14
View File
@@ -11,6 +11,7 @@
"calcom_explained_new_user": "¡Termine de configurar su cuenta de {{appName}}! Solo le faltan unos pasos para resolver todos sus problemas de programación.",
"have_any_questions": "¿Tienes preguntas? Estamos aquí para ayudar.",
"reset_password_subject": "{{appName}}: Instrucciones para restablecer la contraseña",
"verify_email_banner_button": "Enviar correo electrónico",
"event_declined_subject": "Rechazado: {{title}} en {{date}}",
"event_cancelled_subject": "Cancelado: {{title}} en {{date}}",
"event_request_declined": "Su solicitud de reunión ha sido rechazada",
@@ -630,8 +631,6 @@
"event_type_created_successfully": "{{eventTypeTitle}} tipo de evento creado con éxito",
"event_type_updated_successfully": "{{eventTypeTitle}} tipo de evento actualizado con éxito",
"event_type_deleted_successfully": "Tipo de evento eliminado con éxito",
"web3_metamask_added": "Metamask ha sido añadido exitosamente",
"web3_metamask_disconnected": "Metamask ha sido removido exitosamente",
"hours": "Horas",
"your_email": "Tu Email",
"change_avatar": "Cambiar Avatar",
@@ -872,7 +871,6 @@
"installed_one": "Instalada",
"installed_other": "{{count}} instaladas",
"verify_wallet": "Verificar billetera",
"connect_metamask": "Conectar Metamask",
"create_events_on": "Crear eventos en",
"enterprise_license": "Esta es una función empresarial",
"enterprise_license_description": "Para habilitar esta función, obtenga una clave de despliegue en la consola {{consoleUrl}} y añádala a su .env como CALCOM_LICENSE_KEY. Si su equipo ya tiene una licencia, póngase en contacto con {{supportMail}} para obtener ayuda.",
@@ -898,6 +896,7 @@
"availability_updated_successfully": "El horario de {{scheduleName}} se actualizó correctamente",
"schedule_deleted_successfully": "Programación eliminada exitosamente",
"default_schedule_name": "Horas laborables",
"member_default_schedule": "Horario predeterminado del miembro",
"new_schedule_heading": "Crear un horario de disponibilidad",
"new_schedule_description": "Crear horarios de disponibilidad le permite gestionar la disponibilidad a través de tipos de eventos. Pueden aplicarse a uno o más tipos de eventos.",
"requires_ownership_of_a_token": "Requiere la propiedad de un token perteneciente a la siguiente dirección:",
@@ -1050,7 +1049,6 @@
"new_event_trigger": "cuando se reserva un nuevo evento",
"email_host_action": "enviar correo electrónico al anfitrión",
"email_attendee_action": "enviar correo electrónico a los asistentes",
"sms_attendee_action": "enviar SMS al asistente",
"sms_number_action": "enviar SMS a un número específico",
"workflows": "Flujos de trabajo",
"new_workflow_btn": "Flujo de trabajo nuevo",
@@ -1227,11 +1225,6 @@
"upload": "Cargar",
"add_profile_photo": "Agregar foto de perfil",
"web3": "Web3",
"rainbow_token_gated": "Este tipo de evento tiene acceso cerrado por token.",
"rainbow_connect_wallet_gate": "Conecta tu billetera si posees <1>{{name}}</1> (<3>{{symbol}}</3>).",
"rainbow_insufficient_balance": "Tu billetera conectada no contiene suficiente <1>{{symbol}}</1>.",
"rainbow_sign_message_request": "Firma la solicitud de mensaje en tu billetera.",
"rainbow_signature_error": "Error al solicitar la firma desde tu billetera.",
"token_address": "Dirección del token",
"blockchain": "Blockchain",
"old_password": "Contraseña anterior",
@@ -1294,7 +1287,6 @@
"download_responses_description": "Descargue todas las respuestas de su formulario en formato CSV.",
"download": "Descargar",
"download_recording": "Descargar grabación",
"recording_from_your_recent_call": "Una grabación de su llamada reciente en Cal.com está lista para su descarga",
"create_your_first_form": "Crea tu primer formulario",
"create_your_first_form_description": "Con los formularios de orientación puedes hacer preguntas calificadoras y encaminarte hacia la persona o tipo de evento correctos.",
"create_your_first_webhook": "Crea tu primer Webhook",
@@ -1377,7 +1369,6 @@
"password_updated": "¡Contraseña actualizada!",
"pending_payment": "Pago pendiente",
"pending_invites": "Invitaciones pendientes",
"confirmation_page_rainbow": "Cierra el acceso a tu evento con tokens o NFTs en Ethereum, Polygon, etc.",
"not_on_cal": "No estás en {{appName}}",
"no_calendar_installed": "No hay ningún calendario instalado",
"no_calendar_installed_description": "Aún no has conectado ninguno de tus calendarios",
@@ -1491,8 +1482,6 @@
"find_the_best_person": "Encuentre a la mejor persona disponible y haga una rotación en su equipo.",
"fixed_round_robin": "Rotación fija por turnos",
"add_one_fixed_attendee": "Agregue un asistente fijo y realice rotación por turnos a través de un número de asistentes.",
"calcom_is_better_with_team": "Cal.com funciona mejor con equipos",
"the_calcom_team": "El equipo de Cal.com",
"add_your_team_members": "Añada los miembros de su equipo a sus tipos de eventos. Utilice la programación colectiva para incluir a todos o encuentre a la persona más adecuada con programación de rotación por turnos.",
"booking_limit_reached": "Se ha alcanzado el límite de reserva para este tipo de evento",
"duration_limit_reached": "Se ha alcanzado el límite de duración para este tipo de evento",
@@ -1511,7 +1500,6 @@
"navigate_installed_apps": "Ir a las aplicaciones instaladas",
"disabled_calendar": "Si tiene otro calendario instalado, las nuevas reservas se añadirán a él. De lo contrario, conecte un nuevo calendario para que no se pierda ninguna reserva nueva.",
"enable_apps": "Activar aplicaciones",
"enable_apps_description": "Active aplicaciones que los usuarios puedan integrar con Cal.com",
"purchase_license": "Compre una licencia",
"already_have_key": "Ya tengo una clave:",
"already_have_key_suggestion": "Copie aquí su variable de entorno CALCOM_LICENSE_KEY existente.",
@@ -1807,6 +1795,7 @@
"complete_your_booking": "Complete su reserva",
"complete_your_booking_subject": "Complete su reserva: {{title}} el {{date}}",
"confirm_your_details": "Confirme sus datos",
"never_expire": "Nunca caduca",
"currency_string": "{{amount, currency}}",
"charge_card_dialog_body": "Está a punto de cobrarle {{amount, currency}} al asistente. ¿Está seguro de que desea continuar?",
"charge_attendee": "Cobrarle al asistente {{amount, currency}}",
+62 -21
View File
@@ -11,6 +11,7 @@
"calcom_explained_new_user": "Terminez la configuration de votre compte {{appName}} ! Vous n'êtes qu'à quelques pas de résoudre tous vos problèmes de planification.",
"have_any_questions": "Vous avez des questions ? Nous sommes là pour vous aider.",
"reset_password_subject": "{{appName}} : Instructions de réinitialisation de mot de passe",
"verify_email_banner_button": "Envoyer un e-mail",
"event_declined_subject": "Refusé : {{title}} le {{date}}",
"event_cancelled_subject": "Annulé : {{title}} le {{date}}",
"event_request_declined": "Votre demande d'événement a été refusée",
@@ -26,6 +27,8 @@
"rejection_confirmation": "Refuser la réservation",
"manage_this_event": "Gérer cet événement",
"invite_team_member": "Inviter un membre d'équipe",
"invite_team_individual_segment": "Inviter une personne",
"invite_team_bulk_segment": "Importation multiple",
"invite_team_notifcation_badge": "Inv.",
"your_event_has_been_scheduled": "Votre événement a été planifié",
"your_event_has_been_scheduled_recurring": "Votre événement récurrent a été planifié",
@@ -193,6 +196,7 @@
"page_doesnt_exist": "Cette page n'existe pas.",
"check_spelling_mistakes_or_go_back": "Vérifiez s'il y a des erreurs d'orthographe ou retournez à la page précédente.",
"404_page_not_found": "404 : Cette page est introuvable.",
"booker_event_not_found": "Nous n'avons pas pu trouver l'événement que vous essayez de réserver.",
"getting_started": "Commencer",
"15min_meeting": "Rendez-vous de 15 min",
"30min_meeting": "Rendez-vous de 30 min",
@@ -222,6 +226,7 @@
"go_back_login": "Retour à la page de connexion",
"error_during_login": "Une erreur s'est produite lors de votre connexion. Retournez à l'écran de connexion et réessayez.",
"request_password_reset": "Envoyer l'email de réinitialisation",
"send_invite": "Envoyer l'invitation",
"forgot_password": "Mot de passe oublié ?",
"forgot": "Oublié ?",
"done": "Terminé",
@@ -290,6 +295,18 @@
"success": "Succès",
"failed": "Échoué",
"password_has_been_reset_login": "Votre mot de passe a été réinitialisé. Vous pouvez désormais vous connecter avec votre nouveau mot de passe.",
"bookerlayout_title": "Mise en page",
"bookerlayout_default_title": "Vue par défaut",
"bookerlayout_description": "Vous pouvez en sélectionner plusieurs, vos utilisateurs peuvent basculer entre les vues.",
"bookerlayout_user_settings_title": "Mise en page de réservation",
"bookerlayout_user_settings_description": "Vous pouvez en sélectionner plusieurs, les utilisateurs peuvent basculer entre les vues. Cela peut être remplacé individuellement pour événement.",
"bookerlayout_month_view": "Mensuelle",
"bookerlayout_week_view": "Hebdomadaire",
"bookerlayout_column_view": "Colonne",
"bookerlayout_error_min_one_enabled": "Au moins une mise en page doit être activée.",
"bookerlayout_error_default_not_enabled": "La mise en page sélectionnée comme vue par défaut ne fait pas partie des mises en page activées.",
"bookerlayout_error_unknown_layout": "La mise en page que vous avez sélectionnée n'est pas une mise en page valide.",
"bookerlayout_override_global_settings": "Vous pouvez gérer cela pour tous vos types d'événements dans <2>Paramètres / Apparence</2> ou <6>l'appliquer uniquement à cet événement</6>.",
"unexpected_error_try_again": "Une erreur inattendue s'est produite. Veuillez réessayer.",
"sunday_time_error": "Heure non valide le dimanche",
"monday_time_error": "Créneau invalide le lundi",
@@ -360,6 +377,7 @@
"user_dynamic_booking_disabled": "Certains utilisateurs du groupe ont actuellement désactivé les réservations de groupe dynamiques",
"allow_dynamic_booking_tooltip": "Les liens de réservation de groupe peuvent être créés dynamiquement en ajoutant plusieurs noms d'utilisateur séparés par un « + ». Exemple : « {{appName}}/bailey+peer ».",
"allow_dynamic_booking": "Autoriser les participants à prendre rendez-vous avec vous via des réservations de groupe dynamiques",
"dynamic_booking": "Liens de groupe dynamiques",
"email": "E-mail",
"email_placeholder": "jdoe@exemple.com",
"full_name": "Nom complet",
@@ -370,6 +388,8 @@
"booking_rescheduled": "Réservation replanifiée",
"recording_ready": "Lien de téléchargement d'enregistrement prêt",
"booking_created": "Réservation créée",
"booking_rejected": "Réservation rejetée",
"booking_requested": "Réservation demandée",
"meeting_ended": "Rendez-vous terminé",
"form_submitted": "Formulaire envoyé",
"event_triggers": "Déclencheurs d'événement",
@@ -503,7 +523,7 @@
"or": "OU",
"go_back": "Retour",
"email_or_username": "Adresse e-mail ou identifiant",
"send_invite_email": "Envoyer un e-mail d'invitation",
"send_invite_email": "Envoyer une invitation par e-mail",
"role": "Rôle",
"edit_role": "Modifier le rôle",
"edit_team": "Modifier l'équipe",
@@ -627,8 +647,6 @@
"event_type_created_successfully": "Type d'événement {{eventTypeTitle}} créé avec succès",
"event_type_updated_successfully": "Type d'événement {{eventTypeTitle}} mis à jour avec succès",
"event_type_deleted_successfully": "Type d'événement supprimé avec succès",
"web3_metamask_added": "MetaMask ajouté avec succès",
"web3_metamask_disconnected": "MetaMask déconnecté avec succès",
"hours": "heures",
"your_email": "Votre adresse e-mail",
"change_avatar": "Changer d'avatar",
@@ -755,6 +773,10 @@
"new_event_type_to_book_description": "Créez un nouveau type d’événement pour que les personnes puissent effectuer des réservations.",
"length": "Durée",
"minimum_booking_notice": "Préavis minimum",
"offset_toggle": "Décalage de l'heure de début",
"offset_toggle_description": "Appliquez un décalage de durée spécifique aux créneaux horaires affichés aux utilisateurs.",
"offset_start": "Décalage de",
"offset_start_description": "p. ex. cela affichera les créneaux à vos utilisateurs à {{ adjustedTime }} au lieu de {{ originalTime }}",
"slot_interval": "Fréquence de créneaux horaires",
"slot_interval_default": "Utiliser la durée de l'événement (par défaut)",
"delete_event_type": "Supprimer le type d'événement ?",
@@ -789,7 +811,7 @@
"connect_your_favourite_apps": "Connectez vos applications favorites.",
"automation": "Automatisation",
"configure_how_your_event_types_interact": "Configurez la manière dont vos types d'événements doivent interagir avec vos calendriers.",
"toggle_calendars_conflict": "Activez/désactivez les calendriers pour lesquels vous souhaitez vérifier les conflits afin d'éviter les réservations en double.",
"toggle_calendars_conflict": "Activez/désactivez les calendriers pour lesquels vous souhaitez vérifier les conflits afin d'éviter les doubles réservations.",
"select_destination_calendar": "Créer des événements dans :",
"connect_additional_calendar": "Connecter un calendrier supplémentaire",
"calendar_updated_successfully": "Calendrier mis à jour avec succès",
@@ -828,14 +850,14 @@
"installed_apps": "Apps installées",
"free_to_use_apps": "Gratuit",
"no_category_apps": "Aucune application {{category}}",
"no_category_apps_description_calendar": "Ajoutez une application de calendrier pour vérifier les conflits et éviter les réservations en double.",
"no_category_apps_description_calendar": "Ajoutez une application de calendrier pour vérifier les conflits et éviter les doubles réservations.",
"no_category_apps_description_conferencing": "Essayez d'ajouter une application de visioconférence pour intégrer les appels vidéo avec vos clients.",
"no_category_apps_description_payment": "Ajoutez une application de paiement pour faciliter les transactions entre vous et vos clients.",
"no_category_apps_description_analytics": "Ajoutez une application d'analyse pour vos pages de réservation.",
"no_category_apps_description_automation": "Ajoutez une application d'automatisation.",
"no_category_apps_description_other": "Ajoutez n'importe quel autre type d'application pour faire toutes sortes de choses.",
"no_category_apps_description_web3": "Ajoutez une application Web3 pour vos pages de réservation.",
"installed_app_calendar_description": "Définissez les calendriers pour vérifier les conflits afin d'éviter les réservations en double.",
"installed_app_calendar_description": "Définissez les calendriers pour vérifier les conflits afin d'éviter les doubles réservations.",
"installed_app_conferencing_description": "Ajoutez vos applications de visioconférence préférées pour vos rendez-vous.",
"installed_app_payment_description": "Configurez les services de traitement de paiement à utiliser lors de la facturation de vos clients.",
"installed_app_analytics_description": "Configurez les applications d'analyse à utiliser pour vos pages de réservation.",
@@ -865,7 +887,6 @@
"installed_one": "Installée",
"installed_other": "{{count}} installation(s)",
"verify_wallet": "Vérifier le portefeuille",
"connect_metamask": "Connecter MetaMask",
"create_events_on": "Créer des événements dans :",
"enterprise_license": "Il s'agit d'une fonctionnalité d'entreprise",
"enterprise_license_description": "Pour activer cette fonctionnalité, demandez à un administrateur d'accéder à {{setupUrl}} pour saisir une clé de licence. Si une clé de licence est déjà en place, veuillez contacter {{supportMail}} pour obtenir de l'aide.",
@@ -891,6 +912,7 @@
"availability_updated_successfully": "Planning {{scheduleName}} mis à jour avec succès",
"schedule_deleted_successfully": "Planning supprimé avec succès",
"default_schedule_name": "Heures de travail",
"member_default_schedule": "Planning par défaut du membre",
"new_schedule_heading": "Créer un planning de disponibilité",
"new_schedule_description": "La création de plannings de disponibilité vous permet de gérer la disponibilité pour tous les types d'événements. Ils peuvent être appliqués à un ou plusieurs types d'événements.",
"requires_ownership_of_a_token": "Nécessite la propriété d'un token appartenant à l'adresse suivante :",
@@ -907,6 +929,7 @@
"duplicate": "Dupliquer",
"offer_seats": "Proposer des places",
"offer_seats_description": "Proposez des places de réservation. Cela désactive automatiquement les réservations d'invités et d'opt-in.",
"seats_available_one": "Place disponible",
"seats_available_other": "places disponibles",
"number_of_seats": "Nombre de places par réservation",
"enter_number_of_seats": "Saisir le nombre de sièges",
@@ -1042,7 +1065,7 @@
"new_event_trigger": "lorsqu'un nouvel événement est réservé",
"email_host_action": "envoyer un e-mail à l'hôte",
"email_attendee_action": "envoyer un e-mail aux participants",
"sms_attendee_action": "envoyer un SMS au participant",
"sms_attendee_action": "Envoyer un SMS au participant",
"sms_number_action": "envoyer un SMS à un numéro spécifique",
"workflows": "Workflows",
"new_workflow_btn": "Nouveau workflow",
@@ -1206,7 +1229,7 @@
"recordings_title": "Enregistrements",
"recording": "Enregistrement",
"happy_scheduling": "Bonne planification",
"select_calendars": "Sélectionnez les calendriers dont vous souhaitez vérifier les conflits afin d'éviter les réservations en double.",
"select_calendars": "Sélectionnez les calendriers dont vous souhaitez vérifier les conflits afin d'éviter les doubles réservations.",
"check_for_conflicts": "Vérifier les conflits",
"view_recordings": "Voir les enregistrements",
"adding_events_to": "Ajout d'événements",
@@ -1219,11 +1242,6 @@
"upload": "Télécharger",
"add_profile_photo": "Ajouter une photo de profil",
"web3": "Web3",
"rainbow_token_gated": "Ce type d'événement est protégé par un token.",
"rainbow_connect_wallet_gate": "Connectez votre portefeuille si vous possédez <1>{{name}}</1> (<3>{{symbol}}</3>).",
"rainbow_insufficient_balance": "Votre portefeuille connecté ne contient pas assez de <1>{{symbol}}</1>.",
"rainbow_sign_message_request": "Signez la demande de message sur votre portefeuille.",
"rainbow_signature_error": "Erreur lors de la demande de signature de votre portefeuille.",
"token_address": "Adresse du token",
"blockchain": "Blockchain",
"old_password": "Ancien mot de passe",
@@ -1266,7 +1284,7 @@
"connect_automation_apps": "Connecter des applications d'automatisation",
"connect_analytics_apps": "Connecter des applications analytiques",
"connect_other_apps": "Connecter d'autres applications",
"connect_web3_apps": "Connecter des apps Web3",
"connect_web3_apps": "Connecter des applications Web3",
"current_step_of_total": "Étape {{currentStep}} sur {{maxSteps}}",
"add_variable": "Ajouter une variable",
"custom_phone_number": "Numéro de téléphone personnalisé",
@@ -1286,7 +1304,7 @@
"download_responses_description": "Téléchargez toutes les réponses à votre formulaire au format CSV.",
"download": "Télécharger",
"download_recording": "Télécharger l'enregistrement",
"recording_from_your_recent_call": "Un enregistrement de votre appel récent sur Cal.com est prêt à être téléchargé",
"recording_from_your_recent_call": "Un enregistrement de votre appel récent sur {{appName}} est prêt à être téléchargé",
"create_your_first_form": "Créez votre premier formulaire",
"create_your_first_form_description": "Avec les formulaires de routage, vous pouvez poser des questions de qualification et rediriger vers la bonne personne ou le bon type d'événement.",
"create_your_first_webhook": "Créez votre premier webhook",
@@ -1369,7 +1387,6 @@
"password_updated": "Mot de passe mis à jour !",
"pending_payment": "Paiement en attente",
"pending_invites": "Invitations en attente",
"confirmation_page_rainbow": "Le token protège votre événement avec des tokens ou des NFT sur Ethereum, Polygon et plus encore.",
"not_on_cal": "Pas sur {{appName}}",
"no_calendar_installed": "Aucun calendrier installé",
"no_calendar_installed_description": "Vous n'avez pas encore connecté vos calendriers.",
@@ -1483,8 +1500,8 @@
"find_the_best_person": "Trouvez la meilleure personne disponible et alternez à travers votre équipe.",
"fixed_round_robin": "Round-Robin fixe",
"add_one_fixed_attendee": "Ajoutez un participant fixe et le Round-Robin via un certain nombre de participants.",
"calcom_is_better_with_team": "Cal.com est meilleur en équipe",
"the_calcom_team": "L'équipe Cal.com",
"calcom_is_better_with_team": "{{appName}} est meilleur en équipe",
"the_calcom_team": "L'équipe {{companyName}}",
"add_your_team_members": "Ajoutez les membres de votre équipe à vos types d'événements. Utilisez la planification collective pour inclure tout le monde ou trouvez la personne la plus appropriée avec la planification Round-Robin.",
"booking_limit_reached": "La limite de réservation pour ce type d'événement a été atteinte",
"duration_limit_reached": "La limite de durée pour ce type d'événement a été atteinte",
@@ -1503,7 +1520,7 @@
"navigate_installed_apps": "Accéder aux applications installées",
"disabled_calendar": "Si un autre calendrier est installé, les nouvelles réservations y seront ajoutées. Si ce n'est pas le cas, connectez un nouveau calendrier pour ne pas manquer de nouvelles réservations.",
"enable_apps": "Activer les applications",
"enable_apps_description": "Activer les applications que les utilisateurs peuvent intégrer à Cal.com",
"enable_apps_description": "Activer les applications que les utilisateurs peuvent intégrer à {{appName}}",
"purchase_license": "Acheter une licence",
"already_have_key": "J'ai déjà une clé :",
"already_have_key_suggestion": "Veuillez copier votre variable d'environnement CALCOM_LICENSE_KEY existante ici.",
@@ -1660,6 +1677,7 @@
"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",
"identifier": "Identifiant",
"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.",
@@ -1701,6 +1719,7 @@
"spot_popular_event_types": "Identifiez les types d'événements populaires",
"spot_popular_event_types_description": "Découvrez lesquels de vos types d'événements reçoivent le plus de clics et de réservations.",
"no_responses_yet": "Aucune réponse pour l'instant",
"no_routes_defined": "Aucune route définie",
"this_will_be_the_placeholder": "Ce sera le texte de substitution",
"error_booking_event": "Une erreur s'est produite lors de la réservation de l'événement, veuillez actualiser la page et réessayer",
"timeslot_missing_title": "Aucun créneau sélectionné",
@@ -1799,20 +1818,42 @@
"complete_your_booking": "Terminer votre réservation",
"complete_your_booking_subject": "Terminer votre réservation : {{title}} le {{date}}",
"confirm_your_details": "Confirmez vos coordonnées",
"copy_invite_link": "Copier le lien d'invitation",
"edit_invite_link": "Modifier les paramètres du lien",
"invite_link_copied": "Lien d'invitation copié",
"invite_link_deleted": "Lien d'invitation supprimé",
"invite_link_updated": "Paramètres de lien d'invitation enregistrés",
"link_expires_after": "Les liens ont été définis pour expirer après...",
"one_day": "1 jour",
"seven_days": "7 jours",
"thirty_days": "30 jours",
"never_expire": "N'expire jamais",
"team_invite_received": "Vous avez été invité(e) à rejoindre {{teamName}}",
"currency_string": "{{amount, currency}}",
"charge_card_dialog_body": "Vous êtes sur le point de facturer {{amount, currency}} au participant. Voulez-vous vraiment continuer ?",
"charge_attendee": "Facturer {{amount, currency}} au participant",
"payment_app_commission": "Exiger un paiement ({{paymentFeePercentage}} % + {{fee, currency}} de commission par transaction)",
"email_invite_team": "{{email}} a été invité",
"email_invite_team_bulk": "{{userCount}} utilisateurs ont été invités",
"error_collecting_card": "Erreur lors de la collecte de la carte",
"image_size_limit_exceed": "L'image téléchargée ne doit pas dépasser 5 Mo",
"unauthorized_workflow_error_message": "{{errorCode}} : Vous n'êtes pas autorisé à activer ou désactiver ce workflow",
"inline_embed": "Intégration en ligne",
"load_inline_content": "Charge votre type d'événement directement en ligne avec le contenu de votre site web.",
"floating_pop_up_button": "Bouton pop-up flottant",
"need_help_embedding": "Besoin d'aide ? Consultez nos guides pour intégrer Cal sur Wix, Squarespace ou WordPress, consultez nos questions fréquentes ou explorez les options d'intégration avancées.",
"invite_as": "Inviter en tant que",
"form_updated_successfully": "Formulaire mis à jour avec succès.",
"email_not_cal_member_cta": "Rejoignez votre équipe",
"disable_attendees_confirmation_emails": "Désactiver les e-mails de confirmation par défaut pour les participants",
"disable_attendees_confirmation_emails_description": "Au moins un workflow est actif sur ce type d'événement qui envoie un e-mail aux participants lorsque l'événement est réservé.",
"disable_host_confirmation_emails": "Désactiver les e-mails de confirmation par défaut pour l'hôte",
"disable_host_confirmation_emails_description": "Au moins un workflow est actif sur ce type d'événement qui envoie un e-mail à l'hôte lorsque l'événement est réservé."
"disable_host_confirmation_emails_description": "Au moins un workflow est actif sur ce type d'événement qui envoie un e-mail à l'hôte lorsque l'événement est réservé.",
"add_an_override": "Ajouter une superposition",
"import_from_google_workspace": "Importer des utilisateurs depuis Google Workspace",
"connect_google_workspace": "Connecter Google Workspace",
"first_event_type_webhook_description": "Créez votre premier webhook pour ce type d'événement",
"create_for": "Créer pour",
"additional_url_parameters": "Paramètres d'URL supplémentaires",
"ADD_NEW_STRINGS_ABOVE_THIS_LINE_TO_PREVENT_MERGE_CONFLICTS": "↑↑↑↑↑↑↑↑↑↑↑↑↑ Ajoutez vos nouvelles chaînes ci-dessus ↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑"
}
+179 -13
View File
@@ -1,4 +1,5 @@
{
"identity_provider": "ספק זהויות",
"trial_days_left": "נותרו לך $t(day, {\"count\": {{days}} }) לשימוש בגרסת הניסיון של רישוי PRO",
"day_one": "יום {{count}}",
"day_other": "{{count}} ימים",
@@ -10,6 +11,16 @@
"calcom_explained_new_user": "סיים להגדיר את החשבון של {{appName}}! אתה רק מספר צעדים מפתרון כל בעיות התזמון שלך.",
"have_any_questions": "יש לך שאלות? אנחנו כאן כדי לעזור.",
"reset_password_subject": "{{appName}}: הנחיות לאיפוס סיסמה",
"verify_email_subject": "{{appName}}: אמת את החשבון",
"check_your_email": "בדוק את הדוא״ל שלך",
"verify_email_page_body": "שלחנו מייל ל- {{email}}. חשוב שתאמת את כתובת הדוא״ל שלך כדי להבטיח את תעבורת הדוא״ל והיומן מ- {{appName}}.",
"verify_email_banner_body": "אנא אמת את חשבון הדוא״ל שלך כדי להבטיח את תעבורת מ- {{appName}}.",
"verify_email_banner_button": "שליחת דוא\"ל",
"verify_email_email_header": "אמת את חשבון הדוא״ל שלך",
"verify_email_email_button": "אמת דוא״ל",
"verify_email_email_body": "אנא אמת את חשבון הדוא״ל שלך על ידי לחיצה על הכפתור מטה.",
"verify_email_email_link_text": "הנה הקישור, אם אתה לא אוהב ללחוץ על כפתורים:",
"email_sent": "מייל נשלח בהצלחה",
"event_declined_subject": "נדחה: {{title}} ב- {{date}}",
"event_cancelled_subject": "בוטל: {{title}} ב- {{date}}",
"event_request_declined": "בקשת האירוע שלך נדחתה",
@@ -25,6 +36,8 @@
"rejection_confirmation": "לדחות את ההזמנה",
"manage_this_event": "נהל את האירוע הזה",
"invite_team_member": "הזמן חבר צוות",
"invite_team_individual_segment": "הזמנת אדם אחד",
"invite_team_bulk_segment": "ייבוא בכמות גדולה",
"invite_team_notifcation_badge": "הזמנה",
"your_event_has_been_scheduled": "נקבע מועד לאירוע שלך",
"your_event_has_been_scheduled_recurring": "נקבע מועד לאירוע החוזר שלך",
@@ -69,6 +82,8 @@
"event_awaiting_approval_subject": "ממתין לאישור: {{title}} ב- {{date}}",
"event_still_awaiting_approval": "אירוע עדיין ממתין לאישורך",
"booking_submitted_subject": "ההזמנה נשלחה: {{title}} ב- {{date}}",
"download_recording_subject": "הורדת ההקלטה: {{title}} בתאריך {{date}}",
"download_your_recording": "הורד/י את ההקלטה שלך",
"your_meeting_has_been_booked": "הפגישה שלך הוזמנה",
"event_type_has_been_rescheduled_on_time_date": "{{title}} תוזמן מחדש לתאריך {{date}}.",
"event_has_been_rescheduled": "עודכן – מועד האירוע שלך השתנה",
@@ -190,6 +205,7 @@
"page_doesnt_exist": "דף זה אינו קיים.",
"check_spelling_mistakes_or_go_back": "ודא כי שאין שגיאות איות או חזור/י לדף הקודם.",
"404_page_not_found": "404: לא ניתן למצוא את הדף הזה.",
"booker_event_not_found": "לא מצאנו את הארוע שניסית להזמין.",
"getting_started": "תחילת העבודה",
"15min_meeting": "פגישה של 15 דקות",
"30min_meeting": "פגישה של 30 דקות",
@@ -219,11 +235,13 @@
"go_back_login": "חזרה לדף הכניסה",
"error_during_login": "אירעה שגיאה בעת הכניסה. נא לחזור אל מסך הכניסה ולנסות שוב.",
"request_password_reset": "לשלוח בקשת איפוס",
"send_invite": "שליחת הזמנה",
"forgot_password": "שכחת את הסיסמה?",
"forgot": "שכחת?",
"done": "בוצע",
"all_done": "זהו, סיימת!",
"all_apps": "כל האפליקציות",
"available_apps": "אפליקציות זמינות",
"check_email_reset_password": "בדוק/י בתיבת הדוא\"ל – שלחנו לך קישור לאיפוס הסיסמה.",
"finish": "סיום",
"few_sentences_about_yourself": "מספר משפטים אודותיך. המידע הזה יופיע בדף ה-URL האישי שלך.",
@@ -233,6 +251,8 @@
"set_availability": "ציין את הזמינות שלך",
"continue_without_calendar": "להמשיך בלי לוח שנה",
"connect_your_calendar": "קשר את לוח השנה שלך",
"connect_your_video_app": "חיבור אפליקציות הווידאו שלך",
"connect_your_video_app_instructions": "חבר/י את אפליקציות הווידאו שלך כדי להשתמש בהן עבור סוגי האירועים שלך.",
"connect_your_calendar_instructions": "קשר את לוח השנה שלך לצפייה בזמנים עמוסים ובאירועים חדשים באופן אוטומטי ברגע שנקבע מועד עבורם.",
"set_up_later": "להגדיר מאוחר יותר",
"current_time": "השעה הנוכחית",
@@ -284,6 +304,10 @@
"success": "הפעולה בוצעה בהצלחה",
"failed": "הפעולה נכשלה",
"password_has_been_reset_login": "הסיסמה שלך אופסה. עכשיו ניתן להיכנס עם הסיסמה החדשה.",
"bookerlayout_title": "פריסה",
"bookerlayout_default_title": "תצוגת ברירת מחדל",
"bookerlayout_description": "אתה יכול לבחור כמה והמתזמנים שלך יכולים לשנות תצוגות.",
"bookerlayout_user_settings_title": "פריסת תזמון",
"unexpected_error_try_again": "אירעה שגיאה בלתי צפויה. נא לנסות שוב.",
"sunday_time_error": "שעה לא תקפה ביום ראשון",
"monday_time_error": "שעה לא תקפה ביום שני",
@@ -362,6 +386,7 @@
"create_webhook": "יצירת Webhook",
"booking_cancelled": "ההזמנה בוטלה",
"booking_rescheduled": "מועד ההזמנה השתנה",
"recording_ready": "הקישור להורדת ההקלטה מוכן",
"booking_created": "ההזמנה נוצרה",
"meeting_ended": "הפגישה הסתיימה",
"form_submitted": "הטופס נשלח",
@@ -403,6 +428,7 @@
"add_time_availability": "הוספת חלון זמן חדש",
"add_an_extra_layer_of_security": "כדאי להוסיף רמת אבטחה נוספת לחשבון, למקרה שהסיסמה שלך תיגנב.",
"2fa": "אימות דו-גורמי",
"2fa_disabled": "ניתן להפעיל אימות דו-גורמי רק לאימות בדוא\"ל ובאמצעות סיסמה",
"enable_2fa": "הפעלת אימות דו-גורמי",
"disable_2fa": "השבתת אימות דו-גורמי",
"disable_2fa_recommendation": "אם עליך להשבית את האימות הדו-גורמי, מומלץ להפעיל אותו שוב בהקדם האפשרי.",
@@ -459,6 +485,7 @@
"friday": "יום שישי",
"saturday": "יום שבת",
"sunday": "יום ראשון",
"all_booked_today": "כל מה שהוזמן.",
"slots_load_fail": "לא ניתן לטעון את חלונות הזמן הזמינים.",
"additional_guests": "הוספת אורחים",
"your_name": "שמך",
@@ -583,6 +610,20 @@
"minutes": "דקות",
"round_robin": "לפי תורות",
"round_robin_description": "פגישות מחזוריות בין חברי צוות מרובים.",
"managed_event": "אירוע מנוהל",
"username_placeholder": "שם משתמש",
"managed_event_description": "יצירה והפצה של סוגי אירועים בכמות גדולה לחברי צוות",
"managed": "מנוהל",
"managed_event_url_clarification": "יש למלא את שדה \"username\" בשמות המשתמשים של החברים שהוקצו",
"assign_to": "הקצאה ל",
"add_members": "הוספת חברים...",
"count_members_one": "חבר {{count}}",
"count_members_other": "{{count}} חברים",
"no_assigned_members": "לא הוקצה אף חבר",
"assigned_to": "הוקצה ל",
"start_assigning_members_above": "התחל/י להקצות חברים למעלה",
"locked_fields_admin_description": "חברים לא יוכלו לערוך את זה",
"locked_fields_member_description": "האפשרות הזו ננעלה על ידי מנהל הצוות",
"url": "כתובת URL",
"hidden": "מוסתר",
"readonly": "לקריאה בלבד",
@@ -604,8 +645,6 @@
"event_type_created_successfully": "יצירת האירוע מסוג {{eventTypeTitle}} בוצעה בהצלחה",
"event_type_updated_successfully": "עדכון האירוע מסוג {{eventTypeTitle}} בוצע בהצלחה",
"event_type_deleted_successfully": "מחיקת סוג האירוע בוצעה בהצלחה",
"web3_metamask_added": "הוספת ה-Metamask בוצעה בהצלחה",
"web3_metamask_disconnected": "ניתוק ה-Metamask בוצע בהצלחה",
"hours": "שעות",
"your_email": "הדוא\"ל שלך",
"change_avatar": "שינוי אווטאר",
@@ -732,8 +771,17 @@
"new_event_type_to_book_description": "צור סוג אירוע חדש שאנשים יוכלו לקבוע מועדים באמצעותו.",
"length": "משך זמן",
"minimum_booking_notice": "משך הזמן המינימלי לפני ביצוע הזמנה",
"offset_toggle": "הזזת זמני ההתחלה",
"offset_toggle_description": "הזזת חלונות הזמן שמוצגים למזמינים במספר מוגדר של דקות",
"offset_start": "הזזה של",
"offset_start_description": "לדוגמה, הבחירה באפשרות זו תציג למזמינים את חלונות הזמן כ-{{ adjustedTime }} במקום כ-{{ originalTime }}",
"slot_interval": "מרווחי חלונות זמן",
"slot_interval_default": "השתמש במשך האירוע (ברירת מחדל)",
"delete_event_type": "למחוק את סוג האירוע?",
"delete_managed_event_type": "למחוק את סוג האירוע המנוהל?",
"delete_event_type_description": "כל מי ששיתפת איתו את הקישור הזה כבר לא יוכל להזמין באמצעותו.",
"delete_managed_event_type_description": "<ul><li>סוגי האירועים האלה יימחקו גם אצל חברים שהוקצו לסוגי אירועים אלה.</li><li>כל מי שהם שיתפו איתו את הקישור שלהם כבר לא יוכל להזמין באמצעותו.</li></ul>",
"confirm_delete_event_type": "כן, למחוק",
"delete_account": "מחיקת חשבון",
"confirm_delete_account": "כן, למחוק את החשבון",
"delete_account_confirmation_message": "בטוח שברצונך למחוק את חשבון {{appName}} שלך? כל מי ששיתפת איתו את הקישור לחשבון לא יוכל יותר להזמין באמצעותו, וכל ההעדפות ששמרת יאבדו.",
@@ -837,7 +885,6 @@
"installed_one": "מותקן",
"installed_other": "{{count}} התקנות",
"verify_wallet": "אימות הארנק",
"connect_metamask": "קישור Metamask",
"create_events_on": "ליצור אירועים ב-",
"enterprise_license": "תכונה זו זמינה רק במינוי Enterprise",
"enterprise_license_description": "כדי להפעיל את יכולת זו, בקש ממנהל לגשת אל הקישור {{setupUrl}} והקלדת הרישיון. אם כבר יש רישיון מוגדר, צור קשר עם {{supportMail}} לעזרה.",
@@ -863,6 +910,7 @@
"availability_updated_successfully": "עדכון התזמון {{scheduleName}} בוצע בהצלחה",
"schedule_deleted_successfully": "מחיקת התזמון בוצעה בהצלחה",
"default_schedule_name": "שעות עבודה",
"member_default_schedule": "לוח הזמנים שמוגדר כברירת מחדל עבור החבר/ה",
"new_schedule_heading": "יצירת לוח זמנים של מועדים פנויים",
"new_schedule_description": "יצירת לוחות זמנים להצגת זמינות מאפשרת לנהל את הזמינות של סוגי אירועים שונים. ניתן להחיל אותם על סוג אירוע אחד או יותר.",
"requires_ownership_of_a_token": "מחייב בעלות על טוקן ששייך לכתובת הבאה:",
@@ -879,6 +927,7 @@
"duplicate": "כפילות",
"offer_seats": "הצעת מקומות",
"offer_seats_description": "הצעת מקומות להזמנות (אפשרות זו משביתה באופן אוטומטי אישורי הזמנות ואורחים).",
"seats_available_one": "מקום זמין",
"seats_available_other": "מקומות זמינים",
"number_of_seats": "מספר המקומות לכל הזמנה",
"enter_number_of_seats": "יש להזין את מספר המקומות",
@@ -1013,7 +1062,7 @@
"event_cancelled_trigger": "כאשר אירוע מבוטל",
"new_event_trigger": "כאשר אירוע חדש מוזמן",
"email_host_action": "שלח מייל למארח",
"sms_attendee_action": "שלח SMS למשתתף",
"email_attendee_action": "שליחת דוא\"ל למשתתפים",
"sms_number_action": "שלח SMS למספר מסוים",
"workflows": "תהליכים",
"new_workflow_btn": "תהליך עבודה חדש",
@@ -1123,11 +1172,13 @@
"current_username": "שם משתמש נוכחי",
"example_1": "דוגמה 1",
"example_2": "דוגמה 2",
"booking_question_identifier": "מזהה שאלת הזמנה",
"company_size": "גודל החברה",
"what_help_needed": "במה דרושה לך עזרה?",
"variable_format": "הפורמט של המשתנה",
"webhook_subscriber_url_reserved": "כתובת ה-URL של מנוי Webhook כבר מוגדרת",
"custom_input_as_variable_info": "התעלמות מכל התווים המיוחדים של תווית הקלט הנוספת (שימוש באותיות ובספרות בלבד), שימוש באותיות רישיות עבור כל האותיות והחלפת רווחים במקפים תחתונים.",
"using_booking_questions_as_variables": "איך משתמשים בשאלות הזמנה בתור משתנים?",
"download_desktop_app": "הורדת האפליקציה למחשבים שולחניים",
"set_ping_link": "הגדרת קישור Ping",
"rate_limit_exceeded": "חריגה מהגבלת קצב",
@@ -1163,6 +1214,7 @@
"create_workflow": "יצירת תהליך עבודה",
"do_this": "עשה את זה",
"turn_off": "כבה",
"turn_on": "הפעלה",
"settings_updated_successfully": "עדכון ההגדרות בוצע בהצלחה",
"error_updating_settings": "שגיאה בעדכון ההגדרות",
"personal_cal_url": "כתובת ה-URL האישית שלי של {{appName}}",
@@ -1173,6 +1225,7 @@
"start_of_week": "תחילת השבוע",
"recordings_title": "הקלטות",
"recording": "הקלטה",
"happy_scheduling": "תזמון נעים!",
"select_calendars": "בחר את לוחות השנה שבהם ברצונך לבדוק אם יש התנגשויות, כדי למנוע כפל הזמנות.",
"check_for_conflicts": "בדיקת התנגשויות",
"view_recordings": "צפייה בהקלטות",
@@ -1186,11 +1239,6 @@
"upload": "העלאה",
"add_profile_photo": "הוספת תמונת פרופיל",
"web3": "Web3",
"rainbow_token_gated": "סוג אירוע זה מוגן באמצעות טוקן.",
"rainbow_connect_wallet_gate": "קשר/י את הארנק שלך אם בבעלותך <1>{{name}}</1> ‏(<3>{{symbol}}</3>).",
"rainbow_insufficient_balance": "אין בארנק שלך מספיק <1>{{symbol}}</1>.",
"rainbow_sign_message_request": "חתום/י על בקשת ההודעה בארנק.",
"rainbow_signature_error": "שגיאה בעת בקשת חתימה מהארנק.",
"token_address": "כתובת הטוקן",
"blockchain": "בלוקצ'יין",
"old_password": "סיסמה ישנה",
@@ -1210,6 +1258,7 @@
"impersonation": "התחזות",
"impersonation_description": "הגדרות לניהול התחזות למשתמשים",
"users": "משתמשים",
"user": "משתמש",
"profile_description": "ניהול הגדרות עבור פרופיל {{appName}} שלך",
"users_description": "כאן אפשר למצוא רשימה של כל המשתמשים",
"users_listing": "רשימת משתמשים",
@@ -1217,6 +1266,7 @@
"calendars_description": "הגדרת האינטראקציה בין סוגי האירועים שלך לבין לוחות השנה שלך",
"appearance_description": "ניהול ההגדרות של מראה ההזמנות שלך",
"conferencing_description": "הוסף/הוסיפי את האפליקציות האהובות עליך/ייך לשיחות ועידה לשימוש בפגישות",
"add_conferencing_app": "הוספת אפליקציה לשיחות ועידה",
"password_description": "נהל/י את ההגדרות של סיסמאות החשבון שלך",
"2fa_description": "נהל/י את ההגדרות של סיסמאות החשבון שלך",
"we_just_need_basic_info": "אנחנו זקוקים רק לפרטים בסיסיים כדי להגדיר את הפרופיל שלך.",
@@ -1250,6 +1300,7 @@
"download_responses": "הורד תגובות",
"download_responses_description": "הורד את כל התגובות לטופס שלך בפורמט CSV.",
"download": "הורדה",
"download_recording": "הורדת ההקלטה",
"create_your_first_form": "צור/צרי את הטופס הראשון שלך",
"create_your_first_form_description": "באמצעות טפסי ניתוב ניתן לשאול שאלות סיווג ולנתב אל האדם או אל סוג האירוע המתאימים.",
"create_your_first_webhook": "יצירת ה-Webhook הראשון שלך",
@@ -1286,6 +1337,15 @@
"exchange_authentication_standard": "אימות בסיסי",
"exchange_authentication_ntlm": "אימות NTLM",
"exchange_compression": "דחיסת GZip",
"exchange_version": "גרסת Exchange",
"exchange_version_2007_SP1": "‎2007 SP1",
"exchange_version_2010": "2010",
"exchange_version_2010_SP1": "‎2010 SP1",
"exchange_version_2010_SP2": "‎2010 SP2‎",
"exchange_version_2013": "2013",
"exchange_version_2013_SP1": "‎2013 SP1",
"exchange_version_2015": "2015",
"exchange_version_2016": "2016",
"routing_forms_description": "צור טפסים להפניית משתתפים ליעדים הנכונים",
"routing_forms_send_email_owner": "שליחת דוא\"ל לבעלים",
"routing_forms_send_email_owner_description": "דוא\"ל נשלח לבעלים לאחר שליחת הטופס",
@@ -1323,7 +1383,6 @@
"password_updated": "הסיסמה עודכנה!",
"pending_payment": "המתנה לתשלום",
"pending_invites": "הזמנות ממתינות",
"confirmation_page_rainbow": "הגן/י על האירוע שלך באמצעות טוקנים או אסימוני NFT במטבע Ethereum, Polygon ועוד.",
"not_on_cal": "לא ב-{{appName}}",
"no_calendar_installed": "לא מותקן לוח שנה",
"no_calendar_installed_description": "לא קישרת אף אחד מלוחות השנה שלך",
@@ -1340,6 +1399,7 @@
"add_limit": "הוספת הגבלה",
"team_name_required": "נדרש שם צוות",
"show_attendees": "שיתוף האורחים בפרטי המשתתפים",
"how_booking_questions_as_variables": "איך משתמשים בשאלות הזמנה בתור משתנים?",
"format": "פורמט",
"uppercase_for_letters": "שימוש באותיות רישיות עבור כל האותיות",
"replace_whitespaces_underscores": "החלפת רווחים במקפים תחתונים",
@@ -1354,6 +1414,7 @@
"billing_help_title": "צריך/ה משהו נוסף?",
"billing_help_description": "אם דרוש לך סיוע נוסף בענייני חיוב, צוות התמיכה שלנו כאן כדי לעזור.",
"billing_help_cta": "פנייה לתמיכה",
"ignore_special_characters_booking_questions": "להתעלם מתווים מיוחדים במזהה שאלת ההזמנה, להשתמש באותיות ובספרות בלבד",
"retry": "ניסיון נוסף",
"fetching_calendars_error": "אירעה בעיה בטעינת לוחות השנה שלך. <1>נסה/י שוב</1> או פנה/י למחלקת תמיכת הלקוחות.",
"calendar_connection_fail": "החיבור ללוח השנה נכשל",
@@ -1435,12 +1496,16 @@
"find_the_best_person": "למצוא את האדם הכי מתאים שגם זמין לפגישה, ולעבור בסבב דרך כל חברי הצוות.",
"fixed_round_robin": "סבב קבוע",
"add_one_fixed_attendee": "הוסף/י משתתף/ת קבוע/ה אחד/ת ועבור/י בסבב בין מספר משתתפים.",
"calcom_is_better_with_team": "Cal.com טוב יותר לשימוש עם צוותים",
"add_your_team_members": "הוסף/י את חברי הצוות לסוגי האירועים שלך. השתמש/י בתזמון שיתופי כדי לכלול את כולם או מצא/י את האדם הכי מתאים בעזרת תזמון בסבב.",
"booking_limit_reached": "הגעת להגבלת ההזמנות עבור סוג אירוע זה",
"duration_limit_reached": "מגבלת הזמן לארוע זה עבר",
"admin_has_disabled": "מנהל/ת מערכת השבית/ה את {{appName}}",
"disabled_app_affects_event_type": "מנהל/ת מערכת השבית/ה את {{appName}}, ויש לכך השפעה על האירוע שלך מסוג {{eventType}}",
"event_replaced_notice": "מנהל/ת מערכת החליף/ה אחד מסוגי האירועים שלך",
"email_subject_slug_replacement": "מנהל/ת צוות החליף/ה את האירוע שלך /{{slug}}",
"email_body_slug_replacement_notice": "מנהל/ת בצוות <strong>{{teamName}}</strong> החליף/ה את סוג האירוע שלך, <strong>/{{slug}}</strong>, בסוג של אירוע מנוהל שתהיה לו/ה אפשרות לשלוט בו.",
"email_body_slug_replacement_info": "הקישור שלך ימשיך לעבוד, אבל ייתכן שחלק מההגדרות עבורו השתנו. ניתן לבדוק אותו בסוגי האירועים.",
"email_body_slug_replacement_suggestion": "אם יש לך שאלות לגבי סוג האירוע, פנה/י אל מנהל/ת המערכת.<br /><br />שיהיה תזמון נעים, <br />הצוות של Cal.com",
"disable_payment_app": "מנהל/ת המערכת השבית/ה את {{appName}}, ויש לכך השפעה על סוג האירוע שלך בשם {{title}}. המשתתפים עדיין יוכלו להזמין אירוע מסוג זה, אבל לא תוצג להם בקשה לביצוע תשלום. ניתן להסתיר את סוג האירוע הזה על מנת למנוע מצב זה עד שמנהל/ת המערכת יפעיל/תפעיל שוב את שיטת התשלום.",
"payment_disabled_still_able_to_book": "המשתתפים עדיין יוכלו להזמין אירוע מסוג זה, אבל לא תוצג להם בקשה לביצוע תשלום. ניתן להסתיר את סוג האירוע הזה על מנת למנוע מצב זה עד שמנהל/ת המערכת יפעיל/תפעיל שוב את שיטת התשלום.",
"app_disabled_with_event_type": "מנהל/ת המערכת השבית/ה את {{appName}}, ויש לכך השפעה על האירוע שלך מסוג {{title}}.",
@@ -1449,7 +1514,6 @@
"navigate_installed_apps": "מעבר לאפליקציות המותקנות",
"disabled_calendar": "אם התקנת לוח שנה אחר, ההזמנות החדשות יתווספו אליו. אם לא, קשר/י לוח שנה חדש כדי לא להחמיץ הזמנות חדשות.",
"enable_apps": "הפעלת אפליקציות",
"enable_apps_description": "להפעיל אפליקציות שמשתמשים יכולים לשלב עם Cal.com",
"purchase_license": "רכוש רישיון",
"already_have_key": "כבר יש לי מפתח:",
"already_have_key_suggestion": "אנא העתק את משתנה הסביבה CALCOM_LICENSE_KEY הקיים שלך לכאן.",
@@ -1489,6 +1553,7 @@
"date_overrides_update_btn": "עדכון מעקף",
"event_type_duplicate_copy_text": "{{slug}}-עותק",
"set_as_default": "להגדיר כברירת מחדל",
"hide_eventtype_details": "הסתרת פרטי סוג האירוע",
"show_navigation": "הצגת הניווט",
"hide_navigation": "הסתרת הניווט",
"verification_code_sent": "הקוד לאימות נשלח",
@@ -1502,6 +1567,7 @@
"create_your_first_team_webhook_description": "צור/צרי את ה-Webhook הראשון שלך עבור סוג זה של אירוע צוות",
"create_webhook_team_event_type": "צור/צרי Webhook עבור סוג זה של אירוע צוות",
"disable_success_page": "השבתת דף 'הפעולה הצליחה' (עובד רק אם יש לך כתובת URL להפניה אוטומטית)",
"invalid_admin_password": "את/ה מנהל/ת מערכת, אבל הסיסמה שלך לא כוללת את האורך המינימלי של 15 תווים או שלא הגדרת עדיין אימות דו-גורמי",
"change_password_admin": "שנה/י את הסיסמה כדי לקבל גישה של מנהל/ת מערכת",
"username_already_taken": "שם המשתמש הזה כבר תפוס",
"assignment": "הקצאה",
@@ -1534,6 +1600,7 @@
"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/לחודש",
@@ -1569,6 +1636,7 @@
"email_user_cta": "צפה בהזמנה",
"email_no_user_invite_heading": "הוזמנת להצטרף לצוות ב- {{appName}}",
"email_no_user_invite_subheading": "{{invitedBy}} הזמין אותך להצטרף לצוות שלו ב- {{appName}}. {{appName}} הינה מתזמן זימונים שמאפשר לך ולצוות שלך לזמן פגישות בלי כל הפינג פונג במיילים.",
"email_user_invite_subheading": "{{invitedBy}} הזמין/ה אותך להצטרף לצוות שלו/ה בשם '{{teamName}}' באפליקציה {{appName}}. אפליקציית {{appName}} היא כלי לקביעת מועדים לאירועים שמאפשר לך ולצוות שלך לתזמן פגישות בלי כל הפינג פונג במיילים.",
"email_no_user_invite_steps_intro": "אנחנו נדריך אותך במספר צעדים קצרים ואתה תהנה תזמון נטול מתח עם הצוות שלך כהרף עין.",
"email_no_user_step_one": "בחר שם משתמש",
"email_no_user_step_two": "קשר את לוח השנה שלך",
@@ -1595,6 +1663,7 @@
"default_app_link_title": "צור קישור אפליקציה ברירת מחדל",
"default_app_link_description": "הגדרת קישור אפליקציה ברירת מחדל מאפשר לכל הארועים החדשים להשתמש בקישור שהגדרת.",
"change_default_conferencing_app": "להגדיר כברירת מחדל",
"organizer_default_conferencing_app": "אפליקציית ברירת המחדל של המארגן/ת",
"under_maintenance": "אינו זמין עקב תחזוקה",
"under_maintenance_description": "צוות {{appName}} מבצע עבודות תחזוקה שתוכננו מראש. אם יש לך שאלות, נא צור קשר עם התמיכה.",
"event_type_seats": "{{numberOfSeats}} מושבים",
@@ -1609,6 +1678,7 @@
"not_enough_seats": "אין מספיק מושבים",
"form_builder_field_already_exists": "שדה עם שם זה כבר קיים",
"form_builder_field_add_subtitle": "התאמת השאלות שנשאלות בדף התזמון",
"show_on_booking_page": "להציג בדף ההזמנות",
"get_started_zapier_templates": "התחל עם תבניות Zapier",
"team_is_unpublished": "צוות {{team}} אינו מפורסם",
"team_is_unpublished_description": "קישור הצוות הזה אינו זמין כעת. אנא צור קשר עם הבעלים של הצוות או בקש מהם לפרסם אותו.",
@@ -1642,6 +1712,15 @@
"spot_popular_event_types_description": "צפה איזה ארועים מקבלים הכי הרבה גישות ותזמונים",
"no_responses_yet": "אין עדיין תגובות",
"this_will_be_the_placeholder": "זה יהיה הממלא מקום",
"error_booking_event": "אירעה שגיאה בעת הזמנת האירוע, רענן/י את הדף ונסה/י שוב",
"timeslot_missing_title": "לא נבחר חלון זמן",
"timeslot_missing_description": "כדי להזמין את האירוע, יש לבחור חלון זמן.",
"timeslot_missing_cta": "חלון הזמן שנבחר",
"switch_monthly": "מעבר לתצוגת חודש",
"switch_weekly": "מעבר לתצוגת שבוע",
"switch_multiday": "מעבר לתצוגת יום",
"num_locations": "{{num}} אפשרויות מיקום",
"select_on_next_step": "בחר/י בשלב הבא",
"this_meeting_has_not_started_yet": "פגישה זו עוד לא התחילה",
"this_app_requires_connected_account": "{{appName}} דורש חשבון {{dependencyName}} מחובר",
"connect_app": "חבר את {{dependencyName}}",
@@ -1651,12 +1730,39 @@
"can_you_try_again": "אתה יכול לנסות שוב עם שעה אחרת?",
"verify": "אמת",
"timezone_variable": "אזור זמן",
"timezone_info": "אזור הזמן של האדם שיקבל את ההזמנה",
"event_end_time_variable": "שעת סיום האירוע",
"event_end_time_info": "שעת סיום האירוע",
"cancel_url_variable": "ה-URL לביטול",
"cancel_url_info": "כתובת ה-URL לביטול ההזמנה",
"reschedule_url_variable": "ה-URL לתזמון מחדש",
"reschedule_url_info": "כתובת ה-URL לקביעת מועד חדש להזמנה",
"invalid_event_name_variables": "יש משתנה שגוי בשם הארוע שלך",
"select_all": "בחר הכל",
"default_conferencing_bulk_title": "בצע עדכון אצווה של סוגי הארועים הקיימים",
"members_default_schedule": "לוח הזמנים שמוגדר כברירת מחדל עבור החבר/ה",
"set_by_admin": "הגדרה לפי מנהל/ת הצוות",
"members_default_location": "מיקום ברירת המחדל של החבר/ה",
"members_default_schedule_description": "אנחנו נשתמש בלוח הזמנים לזמינות שמוגדר כברירת מחדל עבור כל חבר/ה. החברים יוכלו לערוך את הנתונים.",
"requires_at_least_one_schedule": "אתה חייב שיהיה לך לפחות לוח זמנים אחד",
"default_conferencing_bulk_description": "עדכן את המיקומים עבור סוגי הארועים שנבחרו",
"locked_for_members": "נעול לחברים",
"locked_apps_description": "החברים יוכלו לראות את האפליקציות הפעילות, אבל לא יוכלו לערוך הגדרות של האפליקציה",
"locked_webhooks_description": "החברים יוכלו לראות את רכיבי ה-Webhook הפעילים, אבל לא יוכלו לערוך הגדרות של רכיבי Webhook",
"locked_workflows_description": "החברים יוכלו לראות את תהליכי העבודה הפעילים, אבל לא יוכלו לערוך הגדרות של תהליכי עבודה",
"locked_by_admin": "נעול על ידי מנהל/ת הצוות",
"app_not_connected": "לא קישרת חשבון {{appName}}.",
"connect_now": "להתחבר עכשיו",
"managed_event_dialog_confirm_button_one": "החלפה ועדכון של חבר/ה {{count}}",
"managed_event_dialog_confirm_button_other": "החלפה ועדכון של {{count}} חברים",
"managed_event_dialog_title_one": "כתובת ה-URL /‏{{slug}} כבר קיימת עבור חבר/ה {{count}}. האם ברצונך להחליף אותה?",
"managed_event_dialog_title_other": "כתובת ה-URL /‏{{slug}} כבר קיימת עבור {{count}} חברים. האם ברצונך להחליף אותה?",
"managed_event_dialog_information_one": "<strong>{{names}}</strong> כבר משתמש/ת בכתובת ה-URL ‏<strong>/{{slug}}</strong>.",
"managed_event_dialog_information_other": "<strong>{{names}}</strong> כבר משתמשים בכתובת ה-URL ‏<string>/{{slug}}</strong>.",
"managed_event_dialog_clarification": "אם תבחר/י להחליף את כתובת ה-URL, נודיע לחברים. אם אינך רוצה להחליף אותה, חזור/י אחורה והסר/י את החברים.",
"review_event_type": "בדיקת סוג האירוע",
"looking_for_more_analytics": "מחפש עוד מידע אנליטי?",
"looking_for_more_insights": "רצית עוד Insights?",
"add_filter": "הוסף סנן",
"select_user": "בחר משתמש",
"select_event_type": "בחר סוג ארוע",
@@ -1672,5 +1778,65 @@
"events_rescheduled": "ארועים שתוזמנו מחדש",
"from_last_period": "מפרק הזמן האחרון",
"from_to_date_period": "מ: {{startDate}} עד: {{endDate}}",
"event_trends": "מגמות ארוע"
"analytics_for_organisation": "Insights",
"subtitle_analytics": "קבל/י מידע נוסף על הפעילות של הצוות שלך",
"redirect_url_warning": "הוספת כתובת URL להפניה אוטומטית תגרום להשבתת דף 'הפעולה הצליחה'. חשוב להוסיף את ההודעה 'ההזמנה אושרה בהצלחה' בדף המותאם אישית לציון שהפעולה הצליחה.",
"event_trends": "מגמות ארוע",
"clear_filters": "ניקוי המסננים",
"hold": "החזקה",
"on_booking_option": "גביית תשלום בעת ההזמנה",
"hold_option": "חיוב דמי אי-הגעה",
"card_held": "החזקת הסכום בכרטיס",
"charge_card": "חיוב הכרטיס",
"card_charged": "הכרטיס חויב",
"no_show_fee_amount": "דמי אי-הגעה בסך {{amount, currency}}",
"no_show_fee": "דמי אי-הגעה",
"submit_card": "מסירת כרטיס",
"submit_payment_information": "מסירת פרטי כרטיס",
"meeting_awaiting_payment_method": "עוד לא צוין אמצעי תשלום עבור הפגישה",
"no_show_fee_charged_email_subject": "דמי אי-הגעה בסך {{amount, currency}} חויבו עבור {{title}} ב-{{date}}",
"no_show_fee_charged_text_body": "דמי אי-הגעה חויבו",
"no_show_fee_charged_subtitle": "דמי אי-הגעה בסך {{amount, currency}} חויבו עבור האירוע הבא",
"error_charging_card": "משהו השתבש בעת גביית התשלום על אי-הגעה. אפשר לנסות שוב מאוחר יותר.",
"collect_no_show_fee": "גביית דמי אי-הגעה",
"no_show_fee_charged": "דמי אי-הגעה חויבו",
"insights": "Insights",
"testing_workflow_info_message": "במהלך בדיקת תהליך העבודה הזה, קח/י בחשבון שהודעות דוא\"ל ו-SMS ניתנות לתזמון לפחות שעה מראש",
"insights_no_data_found_for_filter": "לא נמצאו נתונים עבור המסנן שנבחר או התאריכים שנבחרו.",
"acknowledge_booking_no_show_fee": "מובן לי שאם לא אשתתף באירוע הזה, דמי אי-הגעה בסך {{amount, currency}} ינוכו מהכרטיס שלי.",
"card_details": "פרטי כרטיס",
"seats_and_no_show_fee_error": "נכון לעכשיו, אי אפשר להפעיל מקומות ולחייב דמי אי-הגעה",
"complete_your_booking": "יש להשלים את ההזמנה",
"complete_your_booking_subject": "יש להשלים את ההזמנה: {{title}} ב-{{date}}",
"confirm_your_details": "אישור הפרטים שלך",
"never_expire": "התוקף לעולם לא יפוג",
"currency_string": "{{amount, currency}}",
"charge_card_dialog_body": "את/ה עומד/ת לחייב את המשתתף/ת בסכום של {{amount, currency}}. בטוח שברצונך להמשיך?",
"charge_attendee": "לחייב את המשתתף/ת ב-{{amount, currency}}",
"payment_app_commission": "דרישת תשלום (‎{{paymentFeePercentage}}%‎ + ‏{{fee, currency}} עמלה על העסקה)",
"email_invite_team": "נשלחה הזמנה ל-{{email}}",
"email_invite_team_bulk": "{{userCount}} משתמשים הוזמנו",
"error_collecting_card": "שגיאה בחיוב הכרטיס",
"image_size_limit_exceed": "התמונה שתעלה/י יכולה להיות בנפח של מקסימום 5MB",
"inline_embed": "הטמעה מוטבעת",
"load_inline_content": "סוג האירוע נטען ישירות בתוך שאר תוכן האתר שלך.",
"floating_pop_up_button": "לחצן קופץ צף",
"floating_button_trigger_modal": "אפשרות זו מציבה באתר שלך לחצן צף שמפעיל חלון מודאלי עם סוג האירוע שלך.",
"pop_up_element_click": "קופץ בעקבות לחיצה על הרכיב",
"open_dialog_with_element_click": "פתיחת תיבת הדו-שיח ב-Cal כשמישהו לוחץ על רכיב.",
"need_help_embedding": "זקוק/ה לעזרה? ניתן לעיין במדריכים שלנו בנושא הטמעת Cal ב-Wix, ב-Squarespace או ב-WordPress, לקרוא את דף השאלות הנפוצות או לסקור אפשרויות הטמעה מתקדמות.",
"book_my_cal": "הזמנה ביומן שלי",
"invite_as": "הזמנה בְתור",
"form_updated_successfully": "עדכון הטופס בוצע בהצלחה.",
"email_not_cal_member_cta": "הצטרף/י לצוות שלך",
"disable_attendees_confirmation_emails": "השבתת הודעות דוא\"ל לאישור שנשלחות כברירת מחדל עבור המשתתפים",
"disable_attendees_confirmation_emails_description": "בסוג האירוע הזה פעיל לפחות תהליך עבודה אחד ששולח דוא\"ל למשתתפים כשהאירוע מוזמן.",
"disable_host_confirmation_emails": "השבתת הודעות דוא\"ל לאישור שנשלחות כברירת מחדל עבור המארח/ת",
"disable_host_confirmation_emails_description": "בסוג האירוע הזה פעיל לפחות תהליך עבודה אחד ששולח דוא\"ל למארח/ת כשהאירוע מוזמן.",
"add_an_override": "הוספת מעקף",
"import_from_google_workspace": "ייבוא משתמשים מ-Google Workspace",
"connect_google_workspace": "חיבור Google Workspace",
"google_workspace_admin_tooltip": "עליך להיות אדמין/ית ב-Workspace כדי להשתמש בתכונה הזו",
"first_event_type_webhook_description": "צור/צרי את ה-Webhook הראשון שלך עבור סוג זה של אירוע",
"create_for": "צור/צרי עבור"
}
@@ -189,7 +189,6 @@
"remove": "Ektávolítás",
"add": "Hozzáadás",
"installed_one": "Telepített",
"connect_metamask": "Metamask csatlakoztatása",
"error_404": "404-es hiba",
"default": "Alapértelmezett",
"24_hour_short": "0-24",
+6 -17
View File
@@ -11,6 +11,7 @@
"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",
"verify_email_banner_button": "Invia e-mail",
"event_declined_subject": "Rifiutato: {{title}} il {{date}}",
"event_cancelled_subject": "Cancellato: {{title}} il {{date}}",
"event_request_declined": "La tua richiesta per l'evento è stata rifiutata",
@@ -630,8 +631,6 @@
"event_type_created_successfully": "{{eventTypeTitle}} tipo di evento creato con successo",
"event_type_updated_successfully": "{{eventTypeTitle}} tipo di evento aggiornato con successo",
"event_type_deleted_successfully": "Tipo di evento eliminato con successo",
"web3_metamask_added": "Metamask aggiunto",
"web3_metamask_disconnected": "Metamask disconnesso",
"hours": "Ore",
"your_email": "La Tua Email",
"change_avatar": "Cambia Avatar",
@@ -872,7 +871,6 @@
"installed_one": "Installata",
"installed_other": "{{count}} installate",
"verify_wallet": "Verifica Wallet",
"connect_metamask": "Connetti Metamask",
"create_events_on": "Crea eventi su:",
"enterprise_license": "Questa è una funzione Enterprise",
"enterprise_license_description": "Per abilitare questa funzione, ottenere una chiave di distribuzione presso la console {{consoleUrl}} e aggiungerla al proprio .env come CALCOM_LICENSE_KEY. Nel caso il team possieda già una licenza, contattare {{supportMail}} per assistenza.",
@@ -898,6 +896,7 @@
"availability_updated_successfully": "Disponibilità aggiornata con successo",
"schedule_deleted_successfully": "Programma eliminato",
"default_schedule_name": "Orario lavorativo",
"member_default_schedule": "Pianificazione predefinita membro",
"new_schedule_heading": "Crea un programma di disponibilità",
"new_schedule_description": "La creazione di programmi di disponibilità consente di gestire la disponibilità per i diversi tipi di eventi. I programmi possono essere applicati a uno o più tipi di evento.",
"requires_ownership_of_a_token": "Richiede il possesso di un token appartenente al seguente indirizzo:",
@@ -1050,7 +1049,6 @@
"new_event_trigger": "quando viene prenotato un nuovo evento",
"email_host_action": "invia e-mail all'organizzatore",
"email_attendee_action": "invia e-mail ai partecipanti",
"sms_attendee_action": "invia SMS al partecipante",
"sms_number_action": "invia SMS a un numero specifico",
"workflows": "Flussi di lavoro",
"new_workflow_btn": "Nuovo flusso di lavoro",
@@ -1227,11 +1225,6 @@
"upload": "Carica",
"add_profile_photo": "Aggiungi foto del profilo",
"web3": "Web3",
"rainbow_token_gated": "Questo tipo di evento è protetto da token.",
"rainbow_connect_wallet_gate": "Collega il tuo portafoglio se possiedi <1>{{name}}</1> (<3>{{symbol}}</3>).",
"rainbow_insufficient_balance": "Il portafoglio collegato non contiene abbastanza <1>{{symbol}}</1>.",
"rainbow_sign_message_request": "Firma la richiesta di messaggio sul tuo portafoglio.",
"rainbow_signature_error": "Errore durante la richiesta di firma al tuo portafoglio.",
"token_address": "Indirizzo token",
"blockchain": "Blockchain",
"old_password": "Vecchia password",
@@ -1294,7 +1287,6 @@
"download_responses_description": "Scarica tutte le risposte al tuo modulo in formato CSV.",
"download": "Scarica",
"download_recording": "Scarica registrazione",
"recording_from_your_recent_call": "Una registrazione della tua recente chiamata su Cal.com è pronta per il download",
"create_your_first_form": "Crea il tuo primo modulo",
"create_your_first_form_description": "I Moduli di instradamento consentono di porre domande qualificanti agli utenti per indirizzarli a persone o eventi pertinenti.",
"create_your_first_webhook": "Crea il tuo primo Webhook",
@@ -1377,7 +1369,6 @@
"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",
"no_calendar_installed_description": "Non hai ancora collegato alcun calendario",
@@ -1491,8 +1482,6 @@
"find_the_best_person": "Trova la persona più adatta disponibile e fai ruotare i membri del team.",
"fixed_round_robin": "Round robin fisso",
"add_one_fixed_attendee": "Aggiungi un partecipante fisso e fai intervenire a turno altri partecipanti.",
"calcom_is_better_with_team": "Cal.com funziona meglio in team",
"the_calcom_team": "Il team Cal.com",
"add_your_team_members": "Aggiungi i membri del tuo team ai tuoi tipi di eventi. Usa la pianificazione collettiva per includere tutti o trova la persona più adatta con la pianificazione round robin.",
"booking_limit_reached": "È stato raggiunto il limite di prenotazione per questo tipo di evento",
"duration_limit_reached": "È stato raggiunto il limite di durata per questo tipo di evento",
@@ -1511,7 +1500,6 @@
"navigate_installed_apps": "Vai alle app installate",
"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.",
@@ -1634,7 +1622,7 @@
"email_user_cta": "Visualizza invito",
"email_no_user_invite_heading": "Sei stato invitato a unirti a un 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_user_invite_subheading": "{{invitedBy}} ti ha invitato a unirti al suo team `{{teamName}}` 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_user_invite_subheading": "{{invitedBy}} ti ha invitato a unirti al suo team `{{teamName}}` su {{appName}}. {{appName}} è uno strumento di pianificazione di eventi che permette a te e 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",
@@ -1760,7 +1748,7 @@
"managed_event_dialog_clarification": "Se decidi di sostituirlo, i membri ne saranno avvisati. Torna indietro e rimuovili se non desideri sovrascriverlo.",
"review_event_type": "Rivedi tipo di evento",
"looking_for_more_analytics": "Hai bisogno di più dati analitici?",
"looking_for_more_insights": "Hai bisogno di maggiori approfondimenti?",
"looking_for_more_insights": "Ti servono più Insights?",
"add_filter": "Aggiungi filtro",
"select_user": "Seleziona utente",
"select_event_type": "Seleziona tipo di evento",
@@ -1807,6 +1795,7 @@
"complete_your_booking": "Completa la prenotazione",
"complete_your_booking_subject": "Completa la prenotazione: {{title}} del {{date}}",
"confirm_your_details": "Conferma i tuoi dati",
"never_expire": "Nessuna scadenza",
"currency_string": "{{amount, currency}}",
"charge_card_dialog_body": "Stai per addebitare {{amount, currency}} al partecipante. Continuare?",
"charge_attendee": "Addebita {{amount, currency}} al partecipante",
@@ -1821,7 +1810,7 @@
"floating_button_trigger_modal": "Inserisce nel sito un pulsante mobile che attiva una finestra modale con il tuo tipo di evento.",
"pop_up_element_click": "Finestra popup tramite clic su un elemento",
"open_dialog_with_element_click": "Apre la finestra di dialogo di Cal quando un utente clicca su un elemento.",
"need_help_embedding": "Hai bisogno di aiuto? Consulta le nostre guide per integrare Cal su Wix, Squarespace o WordPress, legge le risposte alle domande più frequenti o esplora le opzioni di icorporamento avanzate.",
"need_help_embedding": "Hai bisogno di aiuto? Consulta le nostre guide per integrare Cal su Wix, Squarespace o WordPress, leggi le risposte alle domande più frequenti o esplora le opzioni di incorporamento avanzate.",
"book_my_cal": "Prenota il mio Cal",
"invite_as": "Invita come",
"form_updated_successfully": "Modulo aggiornato correttamente.",

Some files were not shown because too many files have changed in this diff Show More