Compare commits

...
57 Commits
Author SHA1 Message Date
zomars da8d2da368 v2.0.3 2022-10-04 14:46:51 -05:00
alannncandOmar López f01058e073 fix/error-while-confirm-booking (#4834)
* Add try/catch on workflows while confirming a booking

* Revert "added ?tabName=setup to event-type detail link to give it active status (#4830)"

This reverts commit 11c44db609.

Co-authored-by: Omar López <zomars@me.com>
2022-10-04 14:46:17 -05:00
zomars 8e369d3fb5 Submodule sync 2022-10-04 13:10:16 -05:00
Peer Richelsenandkodiakhq[bot] 11c44db609 added ?tabName=setup to event-type detail link to give it active status (#4830)
Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com>
2022-10-04 17:03:31 +01:00
Peer RichelsenandAlex van Andel 9d911cbb59 fixed dropdown in safari (#4828)
* fixed dropdown in safari

* nit

Co-authored-by: Alex van Andel <me@alexvanandel.com>
2022-10-04 15:50:15 +00:00
Alex van Andel 30a887df6f Some tweaks to the ui - use button - use flex justify-between (#4826) 2022-10-04 15:37:20 +00:00
62fea25eb9 fix/connected calendar list different states (#4821)
* Display error if trpc query failed, catch error on getting calendar and cleanup to don't leak credentials to client

* Add calendar connection broke error

* Edit style on alert and disconnecting button

* Ts errors and added translation

* Type fix

* Key and text change for broken calendar connection

Co-authored-by: Joe Au-Yeung <65426560+joeauyeung@users.noreply.github.com>
Co-authored-by: Alex van Andel <me@alexvanandel.com>
2022-10-04 14:56:38 +00:00
Alex van Andel d43d8700d0 Fixes global console error (#4825) 2022-10-04 14:01:32 +00:00
Peer Richelsen e7ed20ea27 fixed border on dark mode success (#4823) 2022-10-04 13:43:49 +01:00
Peer RichelsenandBailey Pumfleet 5e12b5defe new button in logout (#4816)
Co-authored-by: Bailey Pumfleet <pumfleet@hey.com>
2022-10-04 09:31:13 +00:00
Joe Au-YeungandBailey Pumfleet d241a522fb Add placeholder (#4803)
Co-authored-by: Bailey Pumfleet <pumfleet@hey.com>
2022-10-04 10:20:21 +01:00
+2 ae929f27b0 /workflows /detail-view - unusual scroll behaviour (#4806)
Co-authored-by: gitstart <gitstart@users.noreply.github.com>
Co-authored-by: Júlio Piubello da Silva Cabral <julio.piubello@gitstart.dev>
Co-authored-by: Nitesh Singh <nitesh.singh@gitstart.dev>
Co-authored-by: C000Ldude <coolmagnas@gmail.com>
Co-authored-by: Matheus Muniz <87545749+matheusmuniz03@users.noreply.github.com>
Co-authored-by: Klinger Matheus <50892465+KlingerMatheus@users.noreply.github.com>
Co-authored-by: Grace Nshokano <grace.devolop@gmail.com>
Co-authored-by: Olusanya Timothy <48022904+seunexplicit@users.noreply.github.com>
Co-authored-by: Thiago Nascimbeni <tnascimbeni@gmail.com>
Co-authored-by: Peer Richelsen <peeroke@gmail.com>
Co-authored-by: Bailey Pumfleet <pumfleet@hey.com>
2022-10-04 09:17:30 +00:00
Syed Ali Shahbaz 369d7c4e28 adds custom filter allowing eml format (#4815) 2022-10-04 10:02:28 +01:00
Jeroen Reumkens 4438ca2a63 Improve password peek positioning accross app and website. (#4810) 2022-10-03 19:52:57 +00:00
Hariom Balhara 75589db569 Hotfix: Fix Broken webhooks (#4807) 2022-10-04 00:33:47 +05:30
Alex van Andel 3752ac767a Remove eye for todays release (#4802) 2022-10-03 17:08:17 +01:00
+3 f3e2cf5075 Onboarding, input validation error isn't positioned correctly (#4758)
Co-authored-by: gitstart <gitstart@users.noreply.github.com>
Co-authored-by: gitstart <gitstart@gitstart.com>
Co-authored-by: Nitesh Singh <nitesh.singh@gitstart.dev>
Co-authored-by: Matheus Muniz <87545749+matheusmuniz03@users.noreply.github.com>
Co-authored-by: Klinger Matheus <50892465+KlingerMatheus@users.noreply.github.com>
Co-authored-by: Eman <emmanuelgatwech@gmail.com>
Co-authored-by: Grace Nshokano <grace.devolop@gmail.com>
Co-authored-by: Olusanya Timothy <48022904+seunexplicit@users.noreply.github.com>
Co-authored-by: Thiago Nascimbeni <tnascimbeni@gmail.com>
Co-authored-by: Peer Richelsen <peeroke@gmail.com>
Co-authored-by: Joe Au-Yeung <65426560+joeauyeung@users.noreply.github.com>
Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com>
2022-10-01 21:01:41 +00:00
Peer Richelsen 92a29593aa Update README.md 2022-10-01 21:47:34 +01:00
Peer Richelsen 367c5d89cc removed capitalize from headlines (#4790) 2022-10-01 11:50:27 +01:00
f21f36547c /event-types /team-detail /scheduling type - double divider under team members (#4485)
Co-authored-by: Nitesh Singh <nitesh.singh@gitstart.dev>
Co-authored-by: gitstart <gitstart@users.noreply.github.com>
Co-authored-by: Matheus Muniz <87545749+matheusmuniz03@users.noreply.github.com>
Co-authored-by: Klinger Matheus <50892465+KlingerMatheus@users.noreply.github.com>
Co-authored-by: hustle-ps <grace.devolop@gmail.com>
Co-authored-by: gitstart <gitstart@gitstart.com>
Co-authored-by: Olusanya Timothy <48022904+seunexplicit@users.noreply.github.com>
Co-authored-by: Thiago Nascimbeni <tnascimbeni@gmail.com>

Co-authored-by: gitstart <gitstart@users.noreply.github.com>
Co-authored-by: Nitesh Singh <nitesh.singh@gitstart.dev>
Co-authored-by: Matheus Muniz <87545749+matheusmuniz03@users.noreply.github.com>
Co-authored-by: Klinger Matheus <50892465+KlingerMatheus@users.noreply.github.com>
Co-authored-by: hustle-ps <grace.devolop@gmail.com>
Co-authored-by: gitstart <gitstart@gitstart.com>
Co-authored-by: Olusanya Timothy <48022904+seunexplicit@users.noreply.github.com>
Co-authored-by: Thiago Nascimbeni <tnascimbeni@gmail.com>
Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com>
2022-10-01 02:59:20 +00:00
Joe Au-Yeung d3f8d954e7 Update Close.com info (#4777) 2022-09-30 20:22:47 +01:00
27372d624d add skeleton loader for workflows in event type settings (#4774)
Co-authored-by: CarinaWolli <wollencarina@gmail.com>
Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com>
2022-09-30 19:39:23 +01:00
a5d2f2444a Fixes 'How to use Additional Inputs as Variables' dialog in workflows (#4773)
* add i18n translations and fix dialog width and height

* fix typo

Co-authored-by: CarinaWolli <wollencarina@gmail.com>
Co-authored-by: Bailey Pumfleet <pumfleet@hey.com>
2022-09-30 14:41:12 +00:00
6d45e1c7c7 #4533: Show correct time format on booking page (#4771)
* #4533: Store timeformat preferences in localstorage when changing profile. This way you see the correct format on the booking page. Also abstracted the reuse of the localstorage key for timeformat into a small util function, to prevent typos in the future.

* Update apps/web/components/booking/pages/AvailabilityPage.tsx

* 4533: Changed 24hfromlocalstorage values from strings to real booleans for better DX.

* Update apps/web/lib/clock.ts

Co-authored-by: alannnc <alannnc@gmail.com>

* Make code shorter by only handling remaining cases

Co-authored-by: alannnc <alannnc@gmail.com>

* Remove unnecessary boolean check

Co-authored-by: alannnc <alannnc@gmail.com>

Co-authored-by: Omar López <zomars@me.com>
Co-authored-by: alannnc <alannnc@gmail.com>
2022-09-30 14:45:28 +02:00
48419469a6 #4445: Fix to prevent bookings with long titles or a lot of content from overflowing on the page. (#4769)
Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com>
Co-authored-by: Omar López <zomars@me.com>
2022-09-30 11:47:20 +01:00
Joe Au-Yeung 045ebb6e01 Fix RadixUI dropdown 1.0.0 (#4767)
* Add portal part

* Add portal part to pages

* Add portal part to pages
2022-09-30 12:29:22 +02:00
Jeroen Reumkens c78ea5de0b Added 100vh fix for ios to make sure it always fills the screen height. By default 100vh on ios sometimes will and sometimes won't take into account the address bar height, causing on eg the event types or bookings pages the content to be behind our bottom nav. (#4770) 2022-09-30 10:12:22 +01:00
github-actions[bot]andCrowdin Bot d1a787315c New Crowdin translations by Github Action (#4762)
Co-authored-by: Crowdin Bot <support+bot@crowdin.com>
2022-09-29 19:23:43 +01:00
ce1f1f3c47 Upgrade to Radix 1.0 (#4746)
* Change package.json version and yarn lock

* Add popover

Co-authored-by: Alex van Andel <me@alexvanandel.com>
Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com>
2022-09-29 18:22:07 +01:00
2f8bd3c07a add trpc v10 (#4683)
* revert me later

* let's see if this builds

* fix dupe proc

* fix: v10 works

* fix type error

* fix type error

* fix type errors

* fix more

* add example procedure

* spreading not needed

* Update yarn.lock

* Revert "revert me later"

This reverts commit 0c8c15d0577e0c287223039c7b6958b2b0c12c69.

Co-authored-by: Chris Bautista <chrisbautista@netflix.com>
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>
2022-09-29 16:58:29 +00:00
Omar LópezandAlex van Andel d2f27a0463 Fixes for advanced tabs form logic (#4731)
* Fixes for advanced tabs form logic

* Typefix

Co-authored-by: Alex van Andel <me@alexvanandel.com>
2022-09-29 16:46:47 +00:00
Jeroen Reumkensandkodiakhq[bot] 9134ad8c5e Improved team layout when blocks have unequal content length. (#4763)
* Improved team layout when blocks have unequal content length.

* Removed unused translation in members component.

Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com>
2022-09-29 16:34:01 +00:00
Alex van Andel 506036e751 Fixes few i18n related bugs on change password (#4755)
* Fixes few i18n related bugs

* Use PasswordField
2022-09-29 16:19:03 +00:00
5e80f5056d Ensure currentUsername is set before comparing it with username (#4750)
Co-authored-by: Omar López <zomars@me.com>
Co-authored-by: Alan <alannnc@gmail.com>
Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com>
2022-09-29 17:05:01 +01:00
9304ca1415 Fix long url and show password (#4738)
Co-authored-by: Omar López <zomars@me.com>
Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com>
2022-09-29 11:40:37 -03:00
github-actions[bot]andCrowdin Bot fb246fdee6 New Crowdin translations by Github Action (#4754)
Co-authored-by: Crowdin Bot <support+bot@crowdin.com>
2022-09-29 14:31:30 +01:00
7b9e77f43a Fixing border in installed apps (#4745)
Co-authored-by: Omar López <zomars@me.com>
Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com>
2022-09-29 13:26:36 +00:00
47df21322d Fixes translation issue of dynamic variables in workflows (#4734)
* replace all underscores for variable translations

* use g instead of replaceAll

Co-authored-by: CarinaWolli <wollencarina@gmail.com>
Co-authored-by: Omar López <zomars@me.com>
2022-09-29 15:07:22 +02:00
6017806763 Fix connected calendar list (#4743)
* Fix connected calendar list

* Fixed invalid params in setDestinationCalendar

* Attempt to fix tests by changing viewport size, bug on /booking pages

* Fixes BookingListItem + another user.id param removed

Co-authored-by: Peer Richelsen <peeroke@gmail.com>
Co-authored-by: Alex van Andel <me@alexvanandel.com>
2022-09-29 12:58:53 +00:00
Alex van Andel b347f29d6c Feature/deprecate title translations (#4682)
* wip

* Aims to deprecate _title keys

* Removed _title translation

* Revert "wip"

This reverts commit 3e33fc6b1ebc064ddfacd8ebc2b63b2ba009d416.
2022-09-29 12:41:40 +00:00
zomars c26cf74aec Revert "Increase timeouts (#4716)"
This reverts commit 145fb09b73.
2022-09-29 14:23:52 +02:00
zomars 760ed74a11 Fixes broken E2E tests
Introduced in #4657
2022-09-29 14:19:04 +02:00
Hariom BalharaandAlex van Andel 145fb09b73 Increase timeouts (#4716)
Co-authored-by: Alex van Andel <me@alexvanandel.com>
2022-09-29 10:06:57 +00:00
Peer Richelsen dd14e827e1 added cancel button to team creation (#4756)
* added cancel button

* nit

* nit
2022-09-29 10:47:51 +01:00
246c90c10f public page: border and padding (#4730)
Co-authored-by: gitstart <gitstart@users.noreply.github.com>
Co-authored-by: Nitesh Singh <nitesh.singh@gitstart.dev>
Co-authored-by: Klinger Matheus <50892465+KlingerMatheus@users.noreply.github.com>
Co-authored-by: Klinger Matheus <klinger.matheus@gitstart.dev>
Co-authored-by: Grace Nshokano <grace.devolop@gmail.com>
Co-authored-by: Matheus Muniz <87545749+matheusmuniz03@users.noreply.github.com>
Co-authored-by: Olusanya Timothy <48022904+seunexplicit@users.noreply.github.com>
Co-authored-by: Thiago Nascimbeni <tnascimbeni@gmail.com>
Co-authored-by: Peer Richelsen <peeroke@gmail.com>
2022-09-29 10:24:28 +01:00
Alexey Pavlov a42f703c1d fix: calendar spacings for mobile on availability page (#4728) 2022-09-29 10:21:52 +01:00
Leo Giovanetti 7256dbf84f Fix updating slug (#4747) 2022-09-28 23:07:55 +01:00
github-actions[bot]andCrowdin Bot f5faebad67 New Crowdin translations by Github Action (#4744)
Co-authored-by: Crowdin Bot <support+bot@crowdin.com>
2022-09-28 22:19:00 +01:00
+3 be15affa5d fix padding (#4673)
Co-authored-by: gitstart <gitstart@users.noreply.github.com>
Co-authored-by: gitstart <gitstart@gitstart.com>
Co-authored-by: Nitesh Singh <nitesh.singh@gitstart.dev>
Co-authored-by: Rafael Toledo <87545086+Toledodev@users.noreply.github.com>
Co-authored-by: Matheus Muniz <matheusmuniz100@hotmail.com>
Co-authored-by: Grace Nshokano <grace.devolop@gmail.com>
Co-authored-by: Matheus Muniz <87545749+matheusmuniz03@users.noreply.github.com>
Co-authored-by: Olusanya Timothy <48022904+seunexplicit@users.noreply.github.com>
Co-authored-by: Thiago Nascimbeni <tnascimbeni@gmail.com>
Co-authored-by: CarinaWolli <wollencarina@gmail.com>
Co-authored-by: Carina Wollendorfer <30310907+CarinaWolli@users.noreply.github.com>
Co-authored-by: Peer Richelsen <peeroke@gmail.com>
2022-09-28 22:02:07 +01:00
58dd5308ac Improved load state (#4696)
* Improved load state

* Don't use editable heading if it is readonly

* Fix ts errors

Co-authored-by: Peer Richelsen <peeroke@gmail.com>
Co-authored-by: Omar López <zomars@me.com>
Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com>
2022-09-28 19:05:28 +01:00
14a6c5a03f feat: add transition in toasts (#4658)
* feat: add transition in toasts

* feat: toast animation improved

* fix: type check in toast

Co-authored-by: Alex van Andel <me@alexvanandel.com>
Co-authored-by: Peer Richelsen <peeroke@gmail.com>
2022-09-28 19:01:19 +01:00
5af20f5a7b New Crowdin translations by Github Action (#4742)
Co-authored-by: Crowdin Bot <support+bot@crowdin.com>
Co-authored-by: Peer Richelsen <peeroke@gmail.com>
2022-09-28 18:57:58 +01:00
Peer Richelsen 8478363a23 minor layout fixes (#4741)
* fixed back button, fixed app store detail on mobile

* fixed settings padding and go back button

* Update packages/ui/v2/core/Shell.tsx

* Update packages/ui/v2/core/navigation/tabs/VerticalTabItem.tsx
2022-09-28 18:56:59 +01:00
19b3157c94 New Crowdin translations by Github Action (#4729)
Co-authored-by: Crowdin Bot <support+bot@crowdin.com>
Co-authored-by: Peer Richelsen <peeroke@gmail.com>
2022-09-28 18:51:19 +01:00
Peer Richelsen d4dd451c26 Update packages/ui/v2/core/Shell.tsx 2022-09-28 18:49:23 +01:00
Peer Richelsen 6c046f6507 fixed back button, fixed app store detail on mobile (#4737) 2022-09-28 18:46:14 +01:00
Peer Richelsen a792d31939 Update package.json 2022-09-28 17:13:04 +01:00
121 changed files with 1680 additions and 1122 deletions
+1 -1
View File
@@ -31,7 +31,7 @@
<a href="https://news.ycombinator.com/item?id=26817795"><img src="https://img.shields.io/badge/Hacker%20News-311-%23FF6600" alt="Hacker News"></a>
<a href="https://github.com/calcom/cal.com/blob/main/LICENSE"><img src="https://img.shields.io/badge/license-AGPLv3-purple" alt="License"></a>
<a href="https://github.com/calcom/cal.com/pulse"><img src="https://img.shields.io/github/commit-activity/m/calcom/cal.com" alt="Commits-per-month"></a>
<a href="https://cal.com/pricing"><img src="https://img.shields.io/badge/Pricing-%2412%2Fmonth-brightgreen" alt="Pricing"></a>
<a href="https://cal.com/pricing"><img src="https://img.shields.io/badge/Pricing-Free-brightgreen" alt="Pricing"></a>
<a href="https://jitsu.com?utm_source=github/calcom/cal.com"><img src="https://img.shields.io/badge/Metrics_tracked_by-JITSU-AA00FF?logo=data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAA4AAAAOCAYAAAAfSC3RAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAACKSURBVHgBrZDRCYAwDEQv6gCOoKO4hOCXI9QVnEZwiY5iF5GaVClaBNtioCSUvCR3tMJaxIfZgW4AGUoEPVwgPZoS0Dmgg3NBVDFNbMIsmYCak3J1jDk9iCQvsKJvkzr71N81Gj6vDT/LU2P6RhY63jcafk3YJEbgeZpiFyc/5HJKv8Ef273NSfABGbQfUZhnOSAAAAAASUVORK5CYII=" alt="Jitsu Tracked"></a>
<img src="https://api.checklyhq.com/v1/badges/checks/5e048048-1b51-47ba-9209-60607507622e?responseTime=true" alt="Checkly Availability" />
<a href="https://hub.docker.com/r/calendso/calendso"><img src="https://img.shields.io/docker/pulls/calendso/calendso"></a>
+9 -8
View File
@@ -15,14 +15,15 @@
"dependencies": {
"@calcom/dayjs": "*",
"@calcom/ui": "*",
"@radix-ui/react-avatar": "^0.1.4",
"@radix-ui/react-collapsible": "^0.1.0",
"@radix-ui/react-dialog": "^0.1.0",
"@radix-ui/react-dropdown-menu": "^0.1.1",
"@radix-ui/react-id": "^0.1.0",
"@radix-ui/react-radio-group": "^0.1.1",
"@radix-ui/react-slider": "^0.1.1",
"@radix-ui/react-switch": "^0.1.1",
"@radix-ui/react-avatar": "^1.0.0",
"@radix-ui/react-collapsible": "^1.0.0",
"@radix-ui/react-dialog": "^1.0.0",
"@radix-ui/react-dropdown-menu": "^1.0.0",
"@radix-ui/react-id": "^1.0.0",
"@radix-ui/react-popover": "^1.0.0",
"@radix-ui/react-radio-group": "^1.0.0",
"@radix-ui/react-slider": "^1.0.0",
"@radix-ui/react-switch": "^1.0.0",
"@radix-ui/react-tooltip": "^1.0.0",
"next": "^12.2.5",
"next-transpile-modules": "^9.0.0",
+3 -1
View File
@@ -10,7 +10,9 @@ export function useViewerI18n() {
* i18n should never be clubbed with other queries, so that it's caching can be managed independently.
* We intend to not cache i18n query
**/
context: { skipBatch: true },
trpc: {
context: { skipBatch: true },
},
});
}
@@ -44,6 +44,11 @@ function BookingListItem(booking: BookingItemProps) {
const mutation = trpc.useMutation(["viewer.bookings.confirm"], {
onSuccess: () => {
setRejectionDialogIsOpen(false);
showToast(t("booking_confirmation_success"), "success");
utils.invalidateQueries("viewer.bookings");
},
onError: () => {
showToast(t("booking_confirmation_failed"), "error");
utils.invalidateQueries("viewer.bookings");
},
});
@@ -262,7 +267,7 @@ function BookingListItem(booking: BookingItemProps) {
</Dialog>
<tr className="flex flex-col hover:bg-neutral-50 sm:flex-row">
<td className="hidden align-top ltr:pl-6 rtl:pr-6 sm:table-cell sm:w-48" onClick={onClick}>
<td className="hidden align-top ltr:pl-6 rtl:pr-6 sm:table-cell sm:min-w-[10rem]" onClick={onClick}>
<div className="cursor-pointer py-4">
<div className="text-sm leading-6 text-gray-900">{startTime}</div>
<div className="text-sm text-gray-500">
@@ -296,7 +301,7 @@ function BookingListItem(booking: BookingItemProps) {
</div>
</div>
</td>
<td className={"flex-1 px-4" + (isRejected ? " line-through" : "")} onClick={onClick}>
<td className={"w-full px-4" + (isRejected ? " line-through" : "")} onClick={onClick}>
{/* Time and Badges for mobile */}
<div className="w-full pt-4 pb-2 sm:hidden">
<div className="flex w-full items-center justify-between sm:hidden">
@@ -335,7 +340,7 @@ function BookingListItem(booking: BookingItemProps) {
<div
title={booking.title}
className={classNames(
"max-w-10/12 sm:max-w-56 truncate text-sm font-medium leading-6 text-neutral-900 md:max-w-max",
"max-w-10/12 sm:max-w-56 text-sm font-medium leading-6 text-neutral-900 md:max-w-full",
isCancelled ? "line-through" : ""
)}>
{booking.title}
@@ -365,20 +370,8 @@ function BookingListItem(booking: BookingItemProps) {
</div>
)}
</div>
<div className="flex justify-end sm:hidden">
<div className="whitespace-nowrap pt-2 pb-4 text-right text-sm font-medium ltr:pr-4 rtl:pl-4">
{isUpcoming && !isCancelled ? (
<>
{isPending && user?.id === booking.user?.id && <TableActions actions={pendingActions} />}
{isConfirmed && <TableActions actions={bookedActions} />}
{isRejected && <div className="text-sm text-gray-500">{t("rejected")}</div>}
</>
) : null}
{isPast && isPending && !isConfirmed ? <TableActions actions={bookedActions} /> : null}
</div>
</div>
</td>
<td className="hidden whitespace-nowrap py-4 text-right text-sm font-medium ltr:pr-4 rtl:pl-4 sm:block">
<td className="py-4 pl-4 text-right text-sm font-medium ltr:pr-4 rtl:pl-4 sm:pl-0">
{isUpcoming && !isCancelled ? (
<>
{isPending && user?.id === booking.user?.id && <TableActions actions={pendingActions} />}
@@ -24,8 +24,7 @@ import useTheme from "@calcom/lib/hooks/useTheme";
import notEmpty from "@calcom/lib/notEmpty";
import { getRecurringFreq } from "@calcom/lib/recurringStrings";
import { collectPageParameters, telemetryEventTypes, useTelemetry } from "@calcom/lib/telemetry";
import { detectBrowserTimeFormat } from "@calcom/lib/timeFormat";
import { localStorage } from "@calcom/lib/webstorage";
import { detectBrowserTimeFormat, getIs24hClockFromLocalStorage } from "@calcom/lib/timeFormat";
import { trpc } from "@calcom/trpc/react";
import { Icon } from "@calcom/ui/Icon";
import DatePicker from "@calcom/ui/v2/modules/booker/DatePicker";
@@ -79,7 +78,7 @@ const useSlots = ({
usernameList: string[];
timeZone?: string;
}) => {
const { data, isLoading, isIdle } = trpc.useQuery(
const { data, isLoading, isPaused } = trpc.useQuery(
[
"viewer.public.slots.getSchedule",
{
@@ -101,8 +100,8 @@ const useSlots = ({
}
}, [data]);
// The very first time isIdle is set if auto-fetch is disabled, so isIdle should also be considered a loading state.
return { slots: cachedSlots, isLoading: isLoading || isIdle };
// The very first time isPaused is set if auto-fetch is disabled, so isPaused should also be considered a loading state.
return { slots: cachedSlots, isLoading: isLoading || isPaused };
};
const SlotPicker = ({
@@ -176,7 +175,7 @@ const SlotPicker = ({
<DatePicker
isLoading={isLoading}
className={classNames(
"mt-8 w-full px-4 sm:mt-0 sm:min-w-[455px] md:px-5",
"mt-8 w-full px-4 pb-4 sm:mt-0 sm:min-w-[455px] md:px-5",
selectedDate
? "sm:dark:border-darkgray-200 border-gray-200 sm:w-1/2 sm:border-r sm:p-4 sm:pr-6 md:w-1/3"
: "sm:p-4"
@@ -225,7 +224,7 @@ function TimezoneDropdown({
const [isTimeOptionsOpen, setIsTimeOptionsOpen] = useState(false);
useEffect(() => {
handleToggle24hClock(localStorage.getItem("timeOption.is24hClock") === "true");
handleToggle24hClock(!!getIs24hClockFromLocalStorage());
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);
@@ -393,7 +392,9 @@ const AvailabilityPage = ({ profile, eventType }: Props) => {
<div
style={availabilityDatePickerEmbedStyles}
className={classNames(
isBackgroundTransparent ? "" : "dark:bg-darkgray-100 sm:dark:border-darkgray-300 bg-white",
isBackgroundTransparent
? ""
: "dark:bg-darkgray-100 sm:dark:border-darkgray-300 bg-white pb-4 md:pb-0",
"border-bookinglightest overflow-hidden rounded-md md:border",
isEmbed ? "mx-auto" : maxWidth
)}>
@@ -1,6 +1,7 @@
import { zodResolver } from "@hookform/resolvers/zod";
import { EventTypeCustomInputType, WorkflowActions } from "@prisma/client";
import { SchedulingType } from "@prisma/client";
import { useMutation } from "@tanstack/react-query";
import { isValidPhoneNumber } from "libphonenumber-js";
import { useSession } from "next-auth/react";
import Head from "next/head";
@@ -9,7 +10,6 @@ import { useEffect, useMemo, useState, useReducer } from "react";
import { Controller, useForm, useWatch } from "react-hook-form";
import { FormattedNumber, IntlProvider } from "react-intl";
import { ReactMultiEmail } from "react-multi-email";
import { useMutation } from "react-query";
import { v4 as uuidv4 } from "uuid";
import { z } from "zod";
@@ -445,7 +445,6 @@ const BookingPage = ({
<div
className={classNames(
"main overflow-hidden",
isEmbed ? "" : "border border-gray-200",
isBackgroundTransparent ? "" : "dark:border-1 dark:bg-darkgray-100 bg-white",
"dark:border-darkgray-300 rounded-md sm:border"
)}>
@@ -1,6 +1,6 @@
import { useMutation } from "@tanstack/react-query";
import { RescheduleResponse } from "pages/api/book/request-reschedule";
import React, { useState, Dispatch, SetStateAction } from "react";
import { useMutation } from "react-query";
import { useLocale } from "@calcom/lib/hooks/useLocale";
import showToast from "@calcom/lib/notification";
@@ -14,10 +14,11 @@ const CalendarItem = (props: ICalendarItem) => {
const { title, imageSrc, type } = props;
const { t } = useLocale();
return (
<div className="flex flex-row items-center p-5">
<img src={imageSrc} alt={title} className="h-8 w-8" />
<p className="mx-3 text-sm font-bold">{title}</p>
<div className="flex flex-row items-center justify-between p-5">
<div className="flex items-center space-x-3">
<img src={imageSrc} alt={title} className="h-8 w-8" />
<p className="text-sm font-bold">{title}</p>
</div>
<InstallAppButtonWithoutPlanCheck
type={type}
render={(buttonProps) => (
@@ -29,8 +30,7 @@ const CalendarItem = (props: ICalendarItem) => {
// Save cookie key to return url step
document.cookie = `return-to=${window.location.href};path=/;max-age=3600;SameSite=Lax`;
buttonProps && buttonProps.onClick && buttonProps?.onClick(event);
}}
className="ml-auto rounded-md border border-gray-200 py-[10px] px-4 text-sm font-bold">
}}>
{t("connect")}
</Button>
)}
@@ -1,4 +1,4 @@
import { useMutation } from "react-query";
import { useMutation } from "@tanstack/react-query";
import showToast from "@calcom/lib/notification";
import { trpc } from "@calcom/trpc/react";
@@ -76,7 +76,7 @@ const ConnectedCalendars = (props: IConnectCalendarsProps) => {
</List>
)}
{queryConnectedCalendars.isLoading && (
{queryIntegrations.isLoading && (
<ul className="divide-y divide-gray-200 rounded-md border border-gray-200 bg-white p-0 dark:bg-black">
{[0, 0, 0, 0].map((_item, index) => {
return (
@@ -149,7 +149,7 @@ const UserProfile = (props: IUserProfile) => {
}}
/>
{errors.bio && (
<p data-testid="required" className="text-xs italic text-red-500">
<p data-testid="required" className="py-2 text-xs text-red-500">
{t("required")}
</p>
)}
@@ -85,7 +85,7 @@ const UserSettings = (props: IUserSettingsProps) => {
className="w-full rounded-md border border-gray-300 text-sm"
/>
{errors.name && (
<p data-testid="required" className="text-xs italic text-red-500">
<p data-testid="required" className="py-2 text-xs text-red-500">
{t("required")}
</p>
)}
@@ -1,5 +1,5 @@
import { useMutation } from "@tanstack/react-query";
import { Fragment } from "react";
import { useMutation } from "react-query";
import { InstallAppButton } from "@calcom/app-store/components";
import { useLocale } from "@calcom/lib/hooks/useLocale";
@@ -1,5 +1,5 @@
import { useMutation } from "@tanstack/react-query";
import { useState } from "react";
import { useMutation } from "react-query";
import showToast from "@calcom/lib/notification";
import { ButtonBaseProps } from "@calcom/ui/Button";
+34 -37
View File
@@ -1,10 +1,7 @@
import Link from "next/link";
import { TeamPageProps } from "pages/team/[slug]";
import React from "react";
import { WEBAPP_URL } from "@calcom/lib/constants";
import Button from "@calcom/ui/Button";
import { Icon } from "@calcom/ui/Icon";
import { Avatar } from "@calcom/ui/v2";
import { useLocale } from "@lib/hooks/useLocale";
@@ -13,46 +10,46 @@ type TeamType = TeamPageProps["team"];
type MembersType = TeamType["members"];
type MemberType = MembersType[number];
const Team = ({ team }: TeamPageProps) => {
const Member = ({ member, teamName }: { member: MemberType; teamName: string | null }) => {
const { t } = useLocale();
const Member = ({ member }: { member: MemberType }) => {
return (
<Link key={member.id} href={`/${member.username}`}>
<div className="sm:min-w-80 sm:max-w-80 dark:bg-darkgray-200 dark:hover:bg-darkgray-300 group flex h-full flex-col space-y-2 rounded-md bg-white p-4 hover:cursor-pointer hover:bg-gray-50 ">
<Avatar
size="md"
alt={member.name || ""}
imageSrc={WEBAPP_URL + "/" + member.username + "/avatar.png"}
/>
<section className="line-clamp-4 mt-2 w-full space-y-1">
<p className="font-medium text-neutral-900 dark:text-white">{member.name}</p>
<p className="line-clamp-3 overflow-ellipsis text-sm font-normal text-neutral-500 dark:text-white">
{member.bio || t("user_from_team", { user: member.name, team: team.name })}
</p>
</section>
</div>
</Link>
);
};
return (
<Link key={member.id} href={`/${member.username}`}>
<div className="sm:min-w-80 sm:max-w-80 dark:bg-darkgray-200 dark:hover:bg-darkgray-300 group flex min-h-full w-[90%] flex-col space-y-2 rounded-md bg-white p-4 hover:cursor-pointer hover:bg-gray-50 ">
<Avatar
size="md"
alt={member.name || ""}
imageSrc={WEBAPP_URL + "/" + member.username + "/avatar.png"}
/>
<section className="line-clamp-4 mt-2 w-full space-y-1">
<p className="font-medium text-neutral-900 dark:text-white">{member.name}</p>
<p className="line-clamp-3 overflow-ellipsis text-sm font-normal text-neutral-500 dark:text-white">
{member.bio || t("user_from_team", { user: member.name, team: teamName })}
</p>
</section>
</div>
</Link>
);
};
const Members = ({ members }: { members: MembersType }) => {
if (!members || members.length === 0) {
return null;
}
return (
<section className="lg:min-w-lg mx-auto flex min-w-full max-w-5xl flex-wrap justify-center gap-x-6 gap-y-6">
{members.map((member) => {
return member.username !== null && <Member key={member.id} member={member} />;
})}
</section>
);
};
const Members = ({ members, teamName }: { members: MembersType; teamName: string | null }) => {
if (!members || members.length === 0) {
return null;
}
return (
<section className="lg:min-w-lg mx-auto flex min-w-full max-w-5xl flex-wrap justify-center gap-x-6 gap-y-6">
{members.map((member) => {
return member.username !== null && <Member key={member.id} member={member} teamName={teamName} />;
})}
</section>
);
};
const Team = ({ team }: TeamPageProps) => {
return (
<div>
<Members members={team.members} />
<Members members={team.members} teamName={team.name} />
</div>
);
};
+30 -32
View File
@@ -1,50 +1,48 @@
import { useState } from "react";
import classNames from "classnames";
import React, { useState } from "react";
import { ControllerRenderProps } from "react-hook-form";
import { Icon } from "@calcom/ui/Icon";
const EditableHeading = ({
title,
const EditableHeading = function EditableHeading({
value,
onChange,
placeholder = "",
readOnly = false,
isReady,
...passThroughProps
}: {
title: string;
onChange?: (value: string) => void;
placeholder?: string;
readOnly?: boolean;
}) => {
isReady?: boolean;
} & Omit<JSX.IntrinsicElements["input"], "name" | "onChange"> &
ControllerRenderProps) {
const [isEditing, setIsEditing] = useState(false);
const enableEditing = () => !readOnly && setIsEditing(true);
const enableEditing = () => setIsEditing(true);
return (
<div className="group relative cursor-pointer" onClick={enableEditing}>
{!isEditing ? (
<>
<h1
style={{ fontSize: 22, letterSpacing: "-0.0009em" }}
className="inline pl-0 normal-case text-gray-900 focus:text-black group-hover:text-gray-500">
{title}
</h1>
{!readOnly ? (
<Icon.FiEdit2 className="ml-1 -mt-1 inline h-4 w-4 text-gray-700 group-hover:text-gray-500" />
) : null}
</>
) : (
<div style={{ marginBottom: -11 }}>
<div className="flex items-center">
<label className="min-w-8 relative inline-block">
<span className="whitespace-pre text-xl tracking-normal text-transparent">{value}&nbsp;</span>
{!isEditing && isReady && (
<Icon.FiEdit2 className="ml-1 inline h-4 w-4 align-top text-gray-700 group-hover:text-gray-500" />
)}
<input
{...passThroughProps}
type="text"
autoFocus
style={{ top: -6, fontSize: 22 }}
value={value}
required
className="relative h-10 w-full cursor-pointer border-none bg-transparent pl-0 text-gray-900 hover:text-gray-700 focus:text-black focus:outline-none focus:ring-0"
placeholder={placeholder}
defaultValue={title}
className={classNames(
"absolute top-0 left-0 w-full cursor-pointer border-none bg-transparent p-0 align-top text-xl text-gray-900 hover:text-gray-700 focus:text-black focus:outline-none focus:ring-0"
)}
onFocus={(e) => {
setIsEditing(true);
passThroughProps.onFocus && passThroughProps.onFocus(e);
}}
onBlur={(e) => {
setIsEditing(false);
onChange && onChange(e.target.value);
passThroughProps.onBlur && passThroughProps.onBlur(e);
}}
onChange={(e) => onChange && onChange(e.target.value)}
/>
</div>
)}
</label>
</div>
</div>
);
};
+24 -17
View File
@@ -1,6 +1,11 @@
import React, { FC } from "react";
import Dropdown, { DropdownMenuContent, DropdownMenuItem, DropdownMenuTrigger } from "@calcom/ui/Dropdown";
import Dropdown, {
DropdownMenuContent,
DropdownMenuItem,
DropdownMenuTrigger,
DropdownMenuPortal,
} from "@calcom/ui/Dropdown";
import { Icon } from "@calcom/ui/Icon";
import Button from "@calcom/ui/v2/core/Button";
@@ -43,22 +48,24 @@ const DropdownActions = ({
) : (
<DropdownMenuTrigger asChild>{actionTrigger}</DropdownMenuTrigger>
)}
<DropdownMenuContent portalled>
{actions.map((action) => (
<DropdownMenuItem key={action.id} className="focus-visible:outline-none">
<Button
type="button"
color="minimal"
className="w-full rounded-none font-normal"
href={action.href}
StartIcon={action.icon}
onClick={action.onClick || defaultAction}
data-testid={action.id}>
{action.label}
</Button>
</DropdownMenuItem>
))}
</DropdownMenuContent>
<DropdownMenuPortal>
<DropdownMenuContent>
{actions.map((action) => (
<DropdownMenuItem key={action.id} className="focus-visible:outline-none">
<Button
type="button"
color="minimal"
className="w-full rounded-none font-normal"
href={action.href}
StartIcon={action.icon}
onClick={action.onClick || defaultAction}
data-testid={action.id}>
{action.label}
</Button>
</DropdownMenuItem>
))}
</DropdownMenuContent>
</DropdownMenuPortal>
</Dropdown>
);
};
@@ -91,11 +91,10 @@ const PremiumTextfield = (props: ICustomUsernameProps) => {
const isCurrentUsernamePremium =
user && user.metadata && hasKeyInMetadata(user, "isPremium") ? !!user.metadata.isPremium : false;
const [isInputUsernamePremium, setIsInputUsernamePremium] = useState(false);
const debouncedApiCall = useCallback(
debounce(async (username) => {
debounce(async (username: string) => {
const { data } = await fetchUsername(username);
setMarkAsError(!data.available && username && username !== currentUsername);
setMarkAsError(!data.available && !!currentUsername && username !== currentUsername);
setIsInputUsernamePremium(data.premium);
setUsernameIsAvailable(data.available);
}, 150),
+1 -1
View File
@@ -66,7 +66,7 @@ const Component = ({
return (
<div className="relative flex-1 flex-col items-start justify-start px-4 md:flex md:px-8 lg:flex-row lg:px-0">
{hasImages && (
<div className="flex-2 mb-4 -ml-4 -mr-4 flex min-h-[450px] w-auto min-w-[672px] snap-x snap-mandatory flex-row overflow-auto whitespace-nowrap bg-gray-100 p-4 md:mb-8 md:-ml-8 md:-mr-8 md:p-8 lg:mx-0 lg:mb-0 lg:max-w-2xl lg:flex-col lg:rounded-md">
<div className="flex-2 mb-4 -ml-4 -mr-4 flex min-h-[450px] w-auto snap-x snap-mandatory flex-row overflow-auto whitespace-nowrap bg-gray-100 p-4 md:mb-8 md:-ml-8 md:-mr-8 md:p-8 lg:mx-0 lg:mb-0 lg:max-w-2xl lg:flex-col lg:rounded-md">
{images ? (
images.map((img) => (
<img
@@ -1,6 +1,6 @@
import { useMutation } from "@tanstack/react-query";
import Link from "next/link";
import { Fragment } from "react";
import { useMutation } from "react-query";
import { InstallAppButton } from "@calcom/app-store/components";
import { useLocale } from "@calcom/lib/hooks/useLocale";
@@ -32,7 +32,7 @@ function IntegrationListItem(props: {
<ListItem
expanded={!!props.children}
className={classNames(
"my-0 flex-col rounded-md border transition-colors duration-500",
"my-0 flex-col border transition-colors duration-500 first:rounded-t-md last:rounded-b-md",
highlight ? "bg-yellow-100" : ""
)}>
<div className={classNames("flex w-full flex-1 items-center space-x-2 p-4 rtl:space-x-reverse")}>
@@ -1,3 +1,4 @@
import classNames from "classnames";
import React from "react";
import { SkeletonText } from "@calcom/ui/v2";
@@ -32,9 +33,13 @@ function SkeletonItem() {
);
}
export const AvailabilitySelectSkeletonLoader = () => {
export const SelectSkeletonLoader = ({ className }: { className?: string }) => {
return (
<li className="group flex w-full items-center justify-between rounded-sm border border-gray-200 px-[10px] py-3">
<li
className={classNames(
"group flex w-full items-center justify-between rounded-sm border border-gray-200 px-[10px] py-3",
className
)}>
<div className="flex-grow truncate text-sm">
<div className="flex justify-between">
<SkeletonText className="h-4 w-32" />
@@ -11,7 +11,7 @@ import Button from "@calcom/ui/v2/core/Button";
import Select from "@calcom/ui/v2/core/form/Select";
import { SkeletonText } from "@calcom/ui/v2/core/skeleton";
import { AvailabilitySelectSkeletonLoader } from "@components/v2/availability/SkeletonLoader";
import { SelectSkeletonLoader } from "@components/v2/availability/SkeletonLoader";
type AvailabilityOption = {
label: string;
@@ -30,7 +30,7 @@ const AvailabilitySelect = ({
}) => {
const { data, isLoading } = trpc.useQuery(["viewer.availability.list"]);
if (isLoading) {
return <AvailabilitySelectSkeletonLoader />;
return <SelectSkeletonLoader />;
}
const schedules = data?.schedules || [];
@@ -42,7 +42,6 @@ export const EventAdvancedTab = ({ eventType, team }: Pick<EventTypeSetupInfered
const [hashedLinkVisible, setHashedLinkVisible] = useState(!!eventType.hashedLink);
const [hashedUrl, setHashedUrl] = useState(eventType.hashedLink?.link);
const [seatsInputVisible, setSeatsInputVisible] = useState(!!eventType.seatsPerTimeSlot);
const [seatsPerTimeSlot, setSeatsPerTimeSlot] = useState(eventType.seatsPerTimeSlot || 2);
const [customInputs, setCustomInputs] = useState<EventTypeCustomInput[]>(
eventType.customInputs.sort((a, b) => a.id - b.id) || []
);
@@ -51,7 +50,7 @@ export const EventAdvancedTab = ({ eventType, team }: Pick<EventTypeSetupInfered
const placeholderHashedLink = `${CAL_URL}/d/${hashedUrl}/${eventType.slug}`;
const animationRef = useRef(null);
const seatsEnabled = !!eventType.seatsPerTimeSlot;
const seatsEnabled = formMethods.getValues("seatsPerTimeSlotEnabled");
useEffect(() => {
animationRef.current && autoAnimate(animationRef.current);
@@ -313,45 +312,57 @@ export const EventAdvancedTab = ({ eventType, team }: Pick<EventTypeSetupInfered
/>
<hr />
<Controller
name="seatsPerTimeSlot"
name="seatsPerTimeSlotEnabled"
control={formMethods.control}
defaultValue={seatsPerTimeSlot}
defaultValue={!!eventType.seatsPerTimeSlot}
render={({ field: { value, onChange } }) => (
<>
<div className="flex space-x-3">
<Switch
name="seatsPerTimeSlot"
checked={seatsInputVisible}
onCheckedChange={(e) => {
setSeatsInputVisible(e);
formMethods.setValue("seatsPerTimeSlot", seatsPerTimeSlot);
onChange(e ? seatsPerTimeSlot : null);
}}
fitToHeight={true}
/>
<div className="flex flex-col">
<Label className="text-sm font-semibold leading-none text-black">{t("offer_seats")}</Label>
<p className="-mt-2 text-sm leading-normal text-gray-600">{t("offer_seats_description")}</p>
</div>
<div className="flex space-x-3">
<Switch
name="seatsPerTimeSlotEnabled"
checked={value}
onCheckedChange={(e) => {
setSeatsInputVisible(e);
// Enabling seats will disable guests and requiring confimation until fully supported
if (e) {
formMethods.setValue("disableGuests", true);
formMethods.setValue("requiresConfirmation", false);
formMethods.setValue("seatsPerTimeSlot", 2);
} else {
formMethods.setValue("seatsPerTimeSlot", null);
}
onChange(e);
}}
fitToHeight={true}
/>
<div className="flex flex-col">
<Label className="text-sm font-semibold leading-none text-black">{t("offer_seats")}</Label>
<p className="-mt-2 text-sm leading-normal text-gray-600">{t("offer_seats_description")}</p>
</div>
{seatsInputVisible && (
<div className="">
<TextField
required
name="seatsPerTimeSlot"
label={t("number_of_seats")}
type="number"
defaultValue={seatsPerTimeSlot || 2}
addOnSuffix={<>{t("seats")}</>}
onChange={(e) => {
formMethods.setValue("seatsPerTimeSlot", Number(e.target.value));
}}
/>
</div>
)}
</>
</div>
)}
/>
{seatsInputVisible && (
<Controller
name="seatsPerTimeSlot"
control={formMethods.control}
defaultValue={eventType.seatsPerTimeSlot}
render={({ field: { value, onChange } }) => (
<div className="">
<TextField
required
name="seatsPerTimeSlot"
label={t("number_of_seats")}
type="number"
defaultValue={value || 2}
addOnSuffix={<>{t("seats")}</>}
onChange={(e) => {
onChange(Number(e.target.value));
}}
/>
</div>
)}
/>
)}
{showEventNameTip && (
<Dialog open={showEventNameTip} onOpenChange={setShowEventNameTip}>
<DialogContent
@@ -157,7 +157,7 @@ function EventTypeSingleLayout({
return (
<Shell
backPath="/event-types"
title={t("event_type_title", { eventTypeTitle: eventType.title })}
title={eventType.title + " | " + t("event_type")}
heading={eventType.title}
subtitle={eventType.description || ""}
CTA={
@@ -1,4 +1,4 @@
import { useMutation } from "react-query";
import { useMutation } from "@tanstack/react-query";
import { useLocale } from "@calcom/lib/hooks/useLocale";
import { trpc } from "@calcom/trpc/react";
+5 -9
View File
@@ -1,16 +1,14 @@
import { ReactNode } from "react";
import {
QueryObserverIdleResult,
QueryObserverLoadingErrorResult,
QueryObserverLoadingResult,
QueryObserverRefetchErrorResult,
QueryObserverSuccessResult,
UseQueryResult,
} from "react-query";
} from "@tanstack/react-query";
import { ReactNode } from "react";
import { useLocale } from "@calcom/lib/hooks/useLocale";
import type { TRPCClientErrorLike } from "@calcom/trpc/client";
import type { UseTRPCQueryOptions } from "@calcom/trpc/react";
import { trpc } from "@calcom/trpc/react";
import type {
inferHandlerInput,
@@ -22,6 +20,8 @@ import type { AppRouter } from "@calcom/trpc/server/routers/_app";
import { Alert } from "@calcom/ui/Alert";
import Loader from "@calcom/ui/Loader";
import type { UseTRPCQueryOptions } from "@trpc/react/shared";
type ErrorLike = {
message: string;
};
@@ -34,7 +34,6 @@ interface QueryCellOptionsBase<TData, TError extends ErrorLike> {
query: QueryObserverLoadingErrorResult<TData, TError> | QueryObserverRefetchErrorResult<TData, TError>
) => JSXElementOrNull;
loading?: (query: QueryObserverLoadingResult<TData, TError> | null) => JSXElementOrNull;
idle?: (query: QueryObserverIdleResult<TData, TError>) => JSXElementOrNull;
}
interface QueryCellOptionsNoEmpty<TData, TError extends ErrorLike>
@@ -84,14 +83,11 @@ export function QueryCell<TData, TError extends ErrorLike>(
);
}
if (query.status === "idle") {
return opts.idle?.(query) ?? StatusLoader;
}
// impossible state
return null;
}
type inferProcedures<TObj extends ProcedureRecord<any, any, any, any, any, any>> = {
type inferProcedures<TObj extends ProcedureRecord> = {
[TPath in keyof TObj]: {
input: inferProcedureInput<TObj[TPath]>;
output: inferProcedureOutput<TObj[TPath]>;
+4 -3
View File
@@ -9,7 +9,7 @@ import { ComponentProps, ReactNode } from "react";
import DynamicHelpscoutProvider from "@calcom/features/ee/support/lib/helpscout/providerDynamic";
import DynamicIntercomProvider from "@calcom/features/ee/support/lib/intercom/providerDynamic";
import { trpc } from "@calcom/trpc/react";
import { trpc, proxy } from "@calcom/trpc/react";
import { MetaProvider } from "@calcom/ui/v2/core/Meta";
import usePublicPage from "@lib/hooks/usePublicPage";
@@ -38,7 +38,8 @@ const CustomI18nextProvider = (props: AppPropsWithChildren) => {
* i18n should never be clubbed with other queries, so that it's caching can be managed independently.
* We intend to not cache i18n query
**/
const { i18n, locale } = trpc.useQuery(["viewer.public.i18n"], { context: { skipBatch: true } }).data ?? {
const { i18n, locale } = trpc.useQuery(["viewer.public.i18n"], { trpc: { context: { skipBatch: true } } })
.data ?? {
locale: "en",
};
@@ -54,7 +55,7 @@ const CustomI18nextProvider = (props: AppPropsWithChildren) => {
};
const AppProviders = (props: AppPropsWithChildren) => {
const session = trpc.useQuery(["viewer.public.session"]).data;
const session = proxy.public.session.useQuery().data;
// No need to have intercom on public pages - Good for Page Performance
const isPublicPage = usePublicPage();
const isThemeSupported =
+8 -4
View File
@@ -1,6 +1,10 @@
// handles logic related to user clock display using 24h display / timeZone options.
import dayjs from "@calcom/dayjs";
import { isBrowserLocale24h } from "@calcom/lib/timeFormat";
import {
getIs24hClockFromLocalStorage,
isBrowserLocale24h,
setIs24hClockInLocalStorage,
} from "@calcom/lib/timeFormat";
import { localStorage } from "@calcom/lib/webstorage";
interface TimeOptions {
@@ -20,8 +24,8 @@ const initClock = () => {
return;
}
// This only sets browser locale if there's no preference on localStorage.
if (!localStorage.getItem("timeOption.is24hClock")) set24hClock(isBrowserLocale24h());
timeOptions.is24hClock = localStorage.getItem("timeOption.is24hClock") === "true";
if (getIs24hClockFromLocalStorage() === null) set24hClock(isBrowserLocale24h());
timeOptions.is24hClock = !!getIs24hClockFromLocalStorage();
timeOptions.inviteeTimeZone = localStorage.getItem("timeOption.preferredTimeZone") || dayjs.tz.guess();
};
@@ -32,7 +36,7 @@ const is24h = (is24hClock?: boolean) => {
};
const set24hClock = (is24hClock: boolean) => {
localStorage.setItem("timeOption.is24hClock", is24hClock.toString());
setIs24hClockInLocalStorage(is24hClock);
timeOptions.is24hClock = is24hClock;
};
+12 -11
View File
@@ -1,6 +1,6 @@
{
"name": "@calcom/web",
"version": "2.0.2",
"version": "2.0.3",
"private": true,
"scripts": {
"analyze": "ANALYZE=true next build",
@@ -45,18 +45,20 @@
"@hookform/resolvers": "^2.9.7",
"@next-auth/prisma-adapter": "^1.0.4",
"@next/bundle-analyzer": "12.1.6",
"@radix-ui/react-avatar": "^0.1.4",
"@radix-ui/react-collapsible": "^0.1.0",
"@radix-ui/react-dialog": "^0.1.0",
"@radix-ui/react-dropdown-menu": "^0.1.1",
"@radix-ui/react-id": "^0.1.0",
"@radix-ui/react-radio-group": "^0.1.1",
"@radix-ui/react-slider": "^0.1.1",
"@radix-ui/react-switch": "^0.1.1",
"@radix-ui/react-toggle-group": "^0.1.5",
"@radix-ui/react-avatar": "^1.0.0",
"@radix-ui/react-collapsible": "^1.0.0",
"@radix-ui/react-dialog": "^1.0.0",
"@radix-ui/react-dropdown-menu": "^1.0.0",
"@radix-ui/react-id": "^1.0.0",
"@radix-ui/react-popover": "^1.0.0",
"@radix-ui/react-radio-group": "^1.0.0",
"@radix-ui/react-slider": "^1.0.0",
"@radix-ui/react-switch": "^1.0.0",
"@radix-ui/react-toggle-group": "^1.0.0",
"@radix-ui/react-tooltip": "^1.0.0",
"@stripe/react-stripe-js": "^1.10.0",
"@stripe/stripe-js": "^1.35.0",
"@tanstack/react-query": "^4.3.9",
"@vercel/edge-functions-ui": "^0.2.1",
"@wojtekmaj/react-daterange-picker": "^3.3.1",
"accept-language-parser": "^1.5.0",
@@ -105,7 +107,6 @@
"react-live-chat-loader": "^2.7.3",
"react-multi-email": "^0.5.3",
"react-phone-number-input": "^3.2.7",
"react-query": "^3.39.2",
"react-select": "^5.4.0",
"react-timezone-select": "^1.3.2",
"react-use-intercom": "1.5.1",
+1 -1
View File
@@ -76,7 +76,7 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse)
});
// get user's credentials + their connected integrations
const calendarCredentials = getCalendarCredentials(user.credentials, user.id);
const calendarCredentials = getCalendarCredentials(user.credentials);
// get all the connected integrations' calendars (from third party)
const connectedCalendars = await getConnectedCalendars(calendarCredentials, user.selectedCalendars);
const calendars = connectedCalendars.flatMap((c) => c.calendars).filter(notEmpty);
+6 -7
View File
@@ -1,17 +1,16 @@
import { GetServerSidePropsContext } from "next";
import { signOut, useSession } from "next-auth/react";
import Link from "next/link";
import { useRouter } from "next/router";
import { useEffect } from "react";
import { WEBSITE_URL } from "@calcom/lib/constants";
import { useLocale } from "@calcom/lib/hooks/useLocale";
import Button from "@calcom/ui/Button";
import { Icon } from "@calcom/ui/Icon";
import Button from "@calcom/ui/v2/core/Button";
import { inferSSRProps } from "@lib/types/inferSSRProps";
import AuthContainer from "@components/ui/AuthContainer";
import AuthContainer from "@components/v2/ui/AuthContainer";
import { ssrInit } from "@server/lib/ssr";
@@ -30,7 +29,7 @@ export default function Logout(props: Props) {
const { t } = useLocale();
return (
<AuthContainer title={t("logged_out")} description={t("youve_been_logged_out")}>
<AuthContainer title={t("logged_out")} description={t("youve_been_logged_out")} showLogo>
<div className="mb-4">
<div className="mx-auto flex h-12 w-12 items-center justify-center rounded-full bg-green-100">
<Icon.FiCheck className="h-6 w-6 text-green-600" />
@@ -44,9 +43,9 @@ export default function Logout(props: Props) {
</div>
</div>
</div>
<Link href="/auth/login" passHref>
<Button className="flex w-full justify-center"> {t("go_back_login")}</Button>
</Link>
<Button href="/auth/login" passHref className="flex w-full justify-center">
{t("go_back_login")}
</Button>
</AuthContainer>
);
}
+34 -17
View File
@@ -1,5 +1,6 @@
import { CheckIcon } from "@heroicons/react/solid";
import { zodResolver } from "@hookform/resolvers/zod";
import classNames from "classnames";
import { useRouter } from "next/router";
import { useState } from "react";
import { Controller, FormProvider, useForm } from "react-hook-form";
@@ -9,7 +10,7 @@ import { isPasswordValid } from "@calcom/lib/auth";
import { useLocale } from "@calcom/lib/hooks/useLocale";
import prisma from "@calcom/prisma";
import { inferSSRProps } from "@calcom/types/inferSSRProps";
import { TextField, EmailField, PasswordField } from "@calcom/ui/v2";
import { TextField, EmailField, PasswordField, Label } from "@calcom/ui/v2";
import WizardForm from "@calcom/ui/v2/core/WizardForm";
const StepDone = () => {
@@ -85,6 +86,8 @@ const SetupFormStep1 = (props: { setIsLoading: (val: boolean) => void }) => {
}
}, onError);
const longWebsiteUrl = process.env.NEXT_PUBLIC_WEBSITE_URL.length > 30;
return (
<FormProvider {...formMethods}>
<form id="setup-step-1" name="setup-step-1" className="space-y-4" onSubmit={onSubmit}>
@@ -93,22 +96,36 @@ const SetupFormStep1 = (props: { setIsLoading: (val: boolean) => void }) => {
name="username"
control={formMethods.control}
render={({ field: { onBlur, onChange, value } }) => (
<TextField
addOnLeading={
<span className="items-centerpx-3 inline-flex rounded-none text-sm text-gray-500">
{process.env.NEXT_PUBLIC_WEBSITE_URL}/
</span>
}
value={value || ""}
className="my-0"
onBlur={onBlur}
name="username"
onChange={async (e) => {
onChange(e.target.value);
formMethods.setValue("username", e.target.value);
await formMethods.trigger("username");
}}
/>
<>
<Label htmlFor="username" className={classNames(longWebsiteUrl && "mb-0")}>
<span className="block">{t("username")}</span>
{longWebsiteUrl && (
<small className="items-centerpx-3 mt-2 inline-flex rounded-t-md border border-b-0 border-gray-300 bg-gray-100 py-1 px-3 text-gray-500">
{process.env.NEXT_PUBLIC_WEBSITE_URL}
</small>
)}
</Label>
<TextField
addOnLeading={
!longWebsiteUrl && (
<span className="items-centerpx-3 inline-flex rounded-none text-sm text-gray-500">
{process.env.NEXT_PUBLIC_WEBSITE_URL}/
</span>
)
}
id="username"
labelSrOnly={true}
value={value || ""}
className={classNames("my-0", longWebsiteUrl && "rounded-t-none")}
onBlur={onBlur}
name="username"
onChange={async (e) => {
onChange(e.target.value);
formMethods.setValue("username", e.target.value);
await formMethods.trigger("username");
}}
/>
</>
)}
/>
</div>
@@ -2,6 +2,8 @@
* @deprecated modifications to this file should be v2 only
* Use `/apps/web/pages/v2/availability/[schedule].tsx` instead
*/
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-nocheck
import { GetStaticPaths, GetStaticProps } from "next";
import { useRouter } from "next/router";
import { useState } from "react";
+1 -1
View File
@@ -92,7 +92,7 @@ export default function Bookings() {
{query.status === "error" && (
<Alert severity="error" title={t("something_went_wrong")} message={query.error.message} />
)}
{(query.status === "loading" || query.status === "idle") && <SkeletonLoader />}
{(query.status === "loading" || query.isPaused) && <SkeletonLoader />}
{query.status === "success" && !isEmpty && (
<>
<div className="mt-6 overflow-hidden rounded-sm border border-b border-gray-200">
+8 -1
View File
@@ -1,3 +1,9 @@
/**
* @deprecated modifications to this file should be v2 only
* Use `apps/web/pages/v2/event-types/[type].tsx` instead
*/
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-nocheck
import { zodResolver } from "@hookform/resolvers/zod";
import { EventTypeCustomInput, MembershipRole, PeriodType, Prisma, SchedulingType } from "@prisma/client";
import { Collapsible, CollapsibleContent, CollapsibleTrigger } from "@radix-ui/react-collapsible";
@@ -25,6 +31,7 @@ import { CAL_URL, WEBAPP_URL } from "@calcom/lib/constants";
import { useLocale } from "@calcom/lib/hooks/useLocale";
import showToast from "@calcom/lib/notification";
import prisma from "@calcom/prisma";
import { TRPCClientError } from "@calcom/trpc/client";
import { trpc } from "@calcom/trpc/react";
import type { RecurringEvent } from "@calcom/types/Calendar";
import { Alert } from "@calcom/ui/Alert";
@@ -64,7 +71,6 @@ import * as RadioArea from "@components/ui/form/radio-area";
import WebhookListContainer from "@components/webhook/WebhookListContainer";
import { getTranslation } from "@server/lib/i18n";
import { TRPCClientError } from "@trpc/client";
const RainbowInstallForm = dynamic(() => import("@calcom/rainbow/components/RainbowInstallForm"), {
suspense: true,
@@ -108,6 +114,7 @@ export type FormValues = {
periodCountCalendarDays: "1" | "0";
periodDates: { startDate: Date; endDate: Date };
seatsPerTimeSlot: number | null;
seatsPerTimeSlotEnabled: boolean;
minimumBookingNotice: number;
beforeBufferTime: number;
afterBufferTime: number;
+81 -79
View File
@@ -13,6 +13,7 @@ import { CAL_URL, WEBAPP_URL } from "@calcom/lib/constants";
import { useLocale } from "@calcom/lib/hooks/useLocale";
import showToast from "@calcom/lib/notification";
import { inferQueryOutput, trpc } from "@calcom/trpc/react";
import { TRPCClientError } from "@calcom/trpc/react";
import { Button } from "@calcom/ui";
import { Alert } from "@calcom/ui/Alert";
import Badge from "@calcom/ui/Badge";
@@ -23,6 +24,7 @@ import Dropdown, {
DropdownMenuItem,
DropdownMenuSeparator,
DropdownMenuTrigger,
DropdownMenuPortal,
} from "@calcom/ui/Dropdown";
import EmptyScreen from "@calcom/ui/EmptyScreen";
import { Icon } from "@calcom/ui/Icon";
@@ -42,8 +44,6 @@ import { LinkText } from "@components/ui/LinkText";
import NoCalendarConnectedAlert from "@components/ui/NoCalendarConnectedAlert";
import SkeletonLoader from "@components/v2/eventtype/SkeletonLoader";
import { TRPCClientError } from "@trpc/react";
type EventTypeGroups = inferQueryOutput<"viewer.eventTypes">["eventTypeGroups"];
type EventTypeGroupProfile = EventTypeGroups[number]["profile"];
interface EventTypeListHeadingProps {
@@ -346,36 +346,70 @@ export const EventTypeList = ({ group, groupIndex, readOnly, types }: EventTypeL
<DropdownMenuTrigger asChild data-testid={"event-type-options-" + type.id}>
<Button type="button" size="icon" color="minimal" StartIcon={Icon.FiMoreHorizontal} />
</DropdownMenuTrigger>
<DropdownMenuContent portalled>
<DropdownMenuItem className="outline-none">
<Link href={calLink}>
<DropdownMenuPortal>
<DropdownMenuContent>
<DropdownMenuItem className="outline-none">
<Link href={calLink}>
<Button
rel="noreferrer"
target="_blank"
color="minimal"
size="sm"
StartIcon={Icon.FiExternalLink}
className="w-full rounded-none">
{t("preview") as string}
</Button>
</Link>
</DropdownMenuItem>
<DropdownMenuItem className="outline-none">
<Button
rel="noreferrer"
target="_blank"
type="button"
color="minimal"
size="sm"
StartIcon={Icon.FiExternalLink}
className="w-full rounded-none">
{t("preview") as string}
className="w-full rounded-none text-left"
data-testid={"event-type-duplicate-" + type.id}
StartIcon={Icon.FiClipboard}
onClick={() => {
navigator.clipboard.writeText(calLink);
showToast(t("link_copied"), "success");
}}>
{t("copy_link") as string}
</Button>
</Link>
</DropdownMenuItem>
<DropdownMenuItem className="outline-none">
<Button
type="button"
color="minimal"
size="sm"
className="w-full rounded-none text-left"
data-testid={"event-type-duplicate-" + type.id}
StartIcon={Icon.FiClipboard}
onClick={() => {
navigator.clipboard.writeText(calLink);
showToast(t("link_copied"), "success");
}}>
{t("copy_link") as string}
</Button>
</DropdownMenuItem>
{isNativeShare ? (
</DropdownMenuItem>
{isNativeShare ? (
<DropdownMenuItem className="outline-none">
<Button
type="button"
color="minimal"
size="sm"
className="w-full rounded-none"
data-testid={"event-type-duplicate-" + type.id}
StartIcon={Icon.FiUpload}
onClick={() => {
navigator
.share({
title: t("share"),
text: t("share_event"),
url: calLink,
})
.then(() => showToast(t("link_shared"), "success"))
.catch(() => showToast(t("failed"), "error"));
}}>
{t("share") as string}
</Button>
</DropdownMenuItem>
) : null}
<DropdownMenuItem className="outline-none">
<Button
type="button"
size="sm"
href={"/event-types/" + type.id}
color="minimal"
className="w-full rounded-none"
StartIcon={Icon.FiEdit2}>
{t("edit") as string}
</Button>
</DropdownMenuItem>
<DropdownMenuItem className="outline-none">
<Button
type="button"
@@ -383,59 +417,27 @@ export const EventTypeList = ({ group, groupIndex, readOnly, types }: EventTypeL
size="sm"
className="w-full rounded-none"
data-testid={"event-type-duplicate-" + type.id}
StartIcon={Icon.FiUpload}
onClick={() => {
navigator
.share({
title: t("share"),
text: t("share_event"),
url: calLink,
})
.then(() => showToast(t("link_shared"), "success"))
.catch(() => showToast(t("failed"), "error"));
}}>
{t("share") as string}
StartIcon={Icon.FiCopy}
onClick={() => openModal(group, type)}>
{t("duplicate") as string}
</Button>
</DropdownMenuItem>
) : null}
<DropdownMenuItem className="outline-none">
<Button
type="button"
size="sm"
href={"/event-types/" + type.id}
color="minimal"
className="w-full rounded-none"
StartIcon={Icon.FiEdit2}>
{t("edit") as string}
</Button>
</DropdownMenuItem>
<DropdownMenuItem className="outline-none">
<Button
type="button"
color="minimal"
size="sm"
className="w-full rounded-none"
data-testid={"event-type-duplicate-" + type.id}
StartIcon={Icon.FiCopy}
onClick={() => openModal(group, type)}>
{t("duplicate") as string}
</Button>
</DropdownMenuItem>
<DropdownMenuSeparator className="h-px bg-gray-200" />
<DropdownMenuItem className="outline-none">
<Button
onClick={() => {
setDeleteDialogOpen(true);
setDeleteDialogTypeId(type.id);
}}
color="warn"
size="sm"
StartIcon={Icon.FiTrash}
className="w-full rounded-none">
{t("delete") as string}
</Button>
</DropdownMenuItem>
</DropdownMenuContent>
<DropdownMenuSeparator className="h-px bg-gray-200" />
<DropdownMenuItem className="outline-none">
<Button
onClick={() => {
setDeleteDialogOpen(true);
setDeleteDialogTypeId(type.id);
}}
color="warn"
size="sm"
StartIcon={Icon.FiTrash}
className="w-full rounded-none">
{t("delete") as string}
</Button>
</DropdownMenuItem>
</DropdownMenuContent>
</DropdownMenuPortal>
</Dropdown>
</div>
</div>
+1 -2
View File
@@ -21,6 +21,7 @@ import { useLocale } from "@calcom/lib/hooks/useLocale";
import showToast from "@calcom/lib/notification";
import { collectPageParameters, telemetryEventTypes, useTelemetry } from "@calcom/lib/telemetry";
import prisma from "@calcom/prisma";
import { TRPCClientErrorLike } from "@calcom/trpc/client";
import { trpc } from "@calcom/trpc/react";
import type { AppRouter } from "@calcom/trpc/server/routers/_app";
import { Alert } from "@calcom/ui/Alert";
@@ -39,8 +40,6 @@ import Schedule from "@components/availability/Schedule";
import { CalendarListContainer } from "@components/integrations/CalendarListContainer";
import { UsernameAvailability } from "@components/ui/UsernameAvailability";
import { TRPCClientErrorLike } from "@trpc/client";
// Embed isn't applicable to onboarding, so ignore the rule
/* eslint-disable @calcom/eslint/avoid-web-storage */
+1 -1
View File
@@ -1,5 +1,5 @@
import { useQuery } from "@tanstack/react-query";
import React from "react";
import { useQuery } from "react-query";
import { HttpError } from "@lib/core/http/error";
+3 -2
View File
@@ -17,6 +17,7 @@ import TimezoneSelect, { ITimezone } from "react-timezone-select";
import { useLocale } from "@calcom/lib/hooks/useLocale";
import showToast from "@calcom/lib/notification";
import { setIs24hClockInLocalStorage } from "@calcom/lib/timeFormat";
import prisma from "@calcom/prisma";
import { TRPCClientErrorLike } from "@calcom/trpc/client";
import { trpc } from "@calcom/trpc/react";
@@ -229,7 +230,7 @@ function SettingsView(props: ComponentProps<typeof Settings> & { localeProp: str
// Write time format to localStorage if available
// Embed isn't applicable to profile pages. So ignore the rule
// eslint-disable-next-line @calcom/eslint/avoid-web-storage
window.localStorage.setItem("timeOption.is24hClock", selectedTimeFormat.value === 12 ? "false" : "true");
setIs24hClockInLocalStorage(selectedTimeFormat.value === 24);
// TODO: Add validation
@@ -575,7 +576,7 @@ function SettingsView(props: ComponentProps<typeof Settings> & { localeProp: str
* i18n should never be clubbed with other queries, so that it's caching can be managed independently.
* We intend to not cache i18n query
**/
const WithQuery = withQuery(["viewer.public.i18n"], { context: { skipBatch: true } });
const WithQuery = withQuery(["viewer.public.i18n"], { trpc: { context: { skipBatch: true } } });
export default function Settings(props: Props) {
const { t } = useLocale();
+2 -2
View File
@@ -26,7 +26,7 @@ import { useLocale } from "@calcom/lib/hooks/useLocale";
import useTheme from "@calcom/lib/hooks/useTheme";
import { getEveryFreqFor } from "@calcom/lib/recurringStrings";
import { collectPageParameters, telemetryEventTypes, useTelemetry } from "@calcom/lib/telemetry";
import { isBrowserLocale24h } from "@calcom/lib/timeFormat";
import { getIs24hClockFromLocalStorage, isBrowserLocale24h } from "@calcom/lib/timeFormat";
import { localStorage } from "@calcom/lib/webstorage";
import prisma from "@calcom/prisma";
import Button from "@calcom/ui/Button";
@@ -203,7 +203,7 @@ export default function Success(props: SuccessProps) {
// TODO: Add payment details
});
setDate(date.tz(localStorage.getItem("timeOption.preferredTimeZone") || dayjs.tz.guess()));
setIs24h(!!localStorage.getItem("timeOption.is24hClock"));
setIs24h(!!getIs24hClockFromLocalStorage());
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [eventType, needsConfirmation]);
@@ -91,7 +91,7 @@ interface IntegrationsContainerProps {
const IntegrationsList = ({ data }: { data: inferQueryOutput<"viewer.integrations"> }) => {
return (
<List>
<List noBorderTreatment>
{data.items.map((item) => (
<IntegrationListItem
name={item.name}
+28 -14
View File
@@ -19,11 +19,12 @@ import Switch from "@calcom/ui/v2/core/Switch";
import VerticalDivider from "@calcom/ui/v2/core/VerticalDivider";
import { Form, Label } from "@calcom/ui/v2/core/form/fields";
import showToast from "@calcom/ui/v2/core/notifications";
import { SkeletonText } from "@calcom/ui/v2/core/skeleton";
import { Skeleton, SkeletonText } from "@calcom/ui/v2/core/skeleton";
import { HttpError } from "@lib/core/http/error";
import EditableHeading from "@components/ui/EditableHeading";
import { SelectSkeletonLoader } from "@components/v2/availability/SkeletonLoader";
const querySchema = z.object({
schedule: stringOrNumber,
@@ -45,7 +46,7 @@ export default function Availability({ schedule }: { schedule: number }) {
const { data, isLoading } = trpc.useQuery(["viewer.availability.schedule", { scheduleId: schedule }]);
const form = useForm<AvailabilityFormValues>();
const { control, reset, setValue } = form;
const { control, reset } = form;
useEffect(() => {
if (!isLoading && data) {
@@ -81,22 +82,35 @@ export default function Availability({ schedule }: { schedule: number }) {
return (
<Shell
backPath="/availability"
title={t("availability_title", { availabilityTitle: data?.schedule.name })}
title={data?.schedule.name && data.schedule.name + " | " + t("availability")}
heading={
<EditableHeading title={data?.schedule.name || ""} onChange={(name) => setValue("name", name)} />
<Controller
control={form.control}
name="name"
render={({ field }) => <EditableHeading isReady={!isLoading} {...field} />}
/>
}
subtitle={
data ? (
data.schedule.availability.map((availability) => (
<span key={availability.id}>
{availabilityAsString(availability, { locale: i18n.language })}
<br />
</span>
))
) : (
<SkeletonText className="h-4 w-48" />
)
}
subtitle={data?.schedule.availability.map((availability) => (
<span key={availability.id}>
{availabilityAsString(availability, { locale: i18n.language })}
<br />
</span>
))}
CTA={
<div className="flex items-center justify-end">
<div className="flex items-center rounded-md px-2 sm:hover:bg-gray-100">
<Label htmlFor="hiddenSwitch" className="mt-2 hidden cursor-pointer self-center pr-2 sm:inline">
<Skeleton
as={Label}
htmlFor="hiddenSwitch"
className="mt-2 hidden cursor-pointer self-center pr-2 sm:inline">
{t("set_to_default")}
</Label>
</Skeleton>
<Switch
id="hiddenSwitch"
disabled={isLoading}
@@ -159,11 +173,11 @@ export default function Availability({ schedule }: { schedule: number }) {
value ? (
<TimezoneSelect
value={value}
className="focus:border-brand mt-1 block rounded-md border-gray-300 text-sm"
className="focus:border-brand mt-1 block w-72 rounded-md border-gray-300 text-sm"
onChange={(timezone) => onChange(timezone.value)}
/>
) : (
<SkeletonText className="h-6 w-full" />
<SelectSkeletonLoader className="w-72" />
)
}
/>
+3 -3
View File
@@ -90,11 +90,11 @@ export default function Bookings() {
return (
<BookingLayout heading={t("bookings")} subtitle={t("bookings_description")}>
<div className="flex w-full flex-1 flex-col" ref={animationParentRef}>
<div className="flex w-full flex-col" ref={animationParentRef}>
{query.status === "error" && (
<Alert severity="error" title={t("something_went_wrong")} message={query.error.message} />
)}
{(query.status === "loading" || query.status === "idle") && <SkeletonLoader />}
{(query.status === "loading" || query.isPaused) && <SkeletonLoader />}
{query.status === "success" && !isEmpty && (
<div className="pt-2 xl:pt-0">
<WipeMyCalActionButton bookingStatus={status} bookingsEmpty={isEmpty} />
@@ -103,7 +103,7 @@ export default function Bookings() {
*/}
<div className="overflow-hidden rounded-md border border-gray-200">
<table className="w-full">
<table className="w-full max-w-full table-fixed">
<tbody className="divide-y divide-gray-200 bg-white" data-testid="bookings">
{query.data.pages.map((page, index) => (
<Fragment key={index}>
@@ -70,6 +70,7 @@ export type FormValues = {
periodCountCalendarDays: "1" | "0";
periodDates: { startDate: Date; endDate: Date };
seatsPerTimeSlot: number | null;
seatsPerTimeSlotEnabled: boolean;
minimumBookingNotice: number;
beforeBufferTime: number;
afterBufferTime: number;
@@ -96,7 +97,8 @@ export type EventTypeSetupInfered = inferSSRProps<typeof getServerSideProps>;
const EventTypePage = (props: inferSSRProps<typeof getServerSideProps>) => {
const { t } = useLocale();
const { eventType, locationOptions, team, teamMembers } = props;
const { eventType: dbEventType, locationOptions, team, teamMembers } = props;
const [eventType, setEventType] = useState(dbEventType);
const animationParentRef = useRef(null);
const router = useRouter();
const { tabName } = querySchema.parse(router.query);
@@ -106,7 +108,8 @@ const EventTypePage = (props: inferSSRProps<typeof getServerSideProps>) => {
}, [animationParentRef]);
const updateMutation = trpc.useMutation("viewer.eventTypes.update", {
onSuccess: async ({ eventType }) => {
onSuccess: async ({ eventType: newEventType }) => {
setEventType({ ...eventType, slug: newEventType.slug });
showToast(
t("event_type_updated_successfully", {
eventTypeTitle: eventType.title,
@@ -221,6 +224,9 @@ const EventTypePage = (props: inferSSRProps<typeof getServerSideProps>) => {
locations,
blockchainId,
smartContractAddress,
// We don't need to send it to the backend
// eslint-disable-next-line @typescript-eslint/no-unused-vars
seatsPerTimeSlotEnabled,
...input
} = values;
+80 -78
View File
@@ -1,5 +1,4 @@
import { useAutoAnimate } from "@formkit/auto-animate/react";
import { UserPlan } from "@prisma/client";
import Head from "next/head";
import Link from "next/link";
import { useRouter } from "next/router";
@@ -8,6 +7,7 @@ import React, { Fragment, useEffect, useState } from "react";
import { CAL_URL, WEBAPP_URL } from "@calcom/lib/constants";
import { useLocale } from "@calcom/lib/hooks/useLocale";
import { inferQueryOutput, trpc } from "@calcom/trpc/react";
import { TRPCClientError } from "@calcom/trpc/react";
import { Icon } from "@calcom/ui";
import { Badge, Button, ButtonGroup, Dialog, EmptyScreen, showToast, Switch, Tooltip } from "@calcom/ui/v2";
import ConfirmationDialogContent from "@calcom/ui/v2/core/ConfirmationDialogContent";
@@ -17,6 +17,7 @@ import Dropdown, {
DropdownMenuItem,
DropdownMenuSeparator,
DropdownMenuTrigger,
DropdownMenuPortal,
} from "@calcom/ui/v2/core/Dropdown";
import Shell from "@calcom/ui/v2/core/Shell";
import CreateEventTypeButton from "@calcom/ui/v2/modules/event-types/CreateEventType";
@@ -30,8 +31,6 @@ import Avatar from "@components/ui/Avatar";
import AvatarGroup from "@components/ui/AvatarGroup";
import SkeletonLoader from "@components/v2/eventtype/SkeletonLoader";
import { TRPCClientError } from "@trpc/react";
type EventTypeGroups = inferQueryOutput<"viewer.eventTypes">["eventTypeGroups"];
type EventTypeGroupProfile = EventTypeGroups[number]["profile"];
@@ -293,8 +292,9 @@ export const EventTypeList = ({ group, groupIndex, readOnly, types }: EventTypeL
<DropdownMenuItem>
<DropdownItem
type="button"
href={"/event-types/" + type.id}
StartIcon={Icon.FiEdit2}>
data-testid={"event-type-edit-" + type.id}
StartIcon={Icon.FiEdit2}
onClick={() => router.push("/event-types/" + type.id)}>
{t("edit") as string}
</DropdownItem>
</DropdownMenuItem>
@@ -344,90 +344,92 @@ export const EventTypeList = ({ group, groupIndex, readOnly, types }: EventTypeL
<DropdownMenuTrigger asChild data-testid={"event-type-options-" + type.id}>
<Button type="button" size="icon" color="secondary" StartIcon={Icon.FiMoreHorizontal} />
</DropdownMenuTrigger>
<DropdownMenuContent portalled>
<DropdownMenuItem className="outline-none">
<Link href={calLink}>
<a target="_blank">
<DropdownMenuPortal>
<DropdownMenuContent>
<DropdownMenuItem className="outline-none">
<Link href={calLink}>
<a target="_blank">
<Button
color="minimal"
StartIcon={Icon.FiExternalLink}
className="w-full rounded-none">
{t("preview") as string}
</Button>
</a>
</Link>
</DropdownMenuItem>
<DropdownMenuItem className="outline-none">
<Button
type="button"
color="minimal"
className="w-full rounded-none text-left"
data-testid={"event-type-duplicate-" + type.id}
StartIcon={Icon.FiClipboard}
onClick={() => {
navigator.clipboard.writeText(calLink);
showToast(t("link_copied"), "success");
}}>
{t("copy_link") as string}
</Button>
</DropdownMenuItem>
{isNativeShare ? (
<DropdownMenuItem className="outline-none">
<Button
type="button"
color="minimal"
StartIcon={Icon.FiExternalLink}
className="w-full rounded-none">
{t("preview") as string}
className="w-full rounded-none"
data-testid={"event-type-duplicate-" + type.id}
StartIcon={Icon.FiUpload}
onClick={() => {
navigator
.share({
title: t("share"),
text: t("share_event"),
url: calLink,
})
.then(() => showToast(t("link_shared"), "success"))
.catch(() => showToast(t("failed"), "error"));
}}>
{t("share") as string}
</Button>
</a>
</Link>
</DropdownMenuItem>
<DropdownMenuItem className="outline-none">
<Button
type="button"
color="minimal"
className="w-full rounded-none text-left"
data-testid={"event-type-duplicate-" + type.id}
StartIcon={Icon.FiClipboard}
onClick={() => {
navigator.clipboard.writeText(calLink);
showToast(t("link_copied"), "success");
}}>
{t("copy_link") as string}
</Button>
</DropdownMenuItem>
{isNativeShare ? (
</DropdownMenuItem>
) : null}
<DropdownMenuItem className="outline-none">
<Button
type="button"
onClick={() => router.push("/event-types/" + type.id)}
color="minimal"
className="w-full rounded-none"
StartIcon={Icon.FiEdit}>
{t("edit") as string}
</Button>
</DropdownMenuItem>
<DropdownMenuItem className="outline-none">
<Button
type="button"
color="minimal"
className="w-full rounded-none"
data-testid={"event-type-duplicate-" + type.id}
StartIcon={Icon.FiUpload}
onClick={() => {
navigator
.share({
title: t("share"),
text: t("share_event"),
url: calLink,
})
.then(() => showToast(t("link_shared"), "success"))
.catch(() => showToast(t("failed"), "error"));
}}>
{t("share") as string}
StartIcon={Icon.FiCopy}
onClick={() => openModal(group, type)}>
{t("duplicate") as string}
</Button>
</DropdownMenuItem>
) : null}
<DropdownMenuItem className="outline-none">
<Button
type="button"
href={"/event-types/" + type.id}
color="minimal"
className="w-full"
StartIcon={Icon.FiEdit}>
{t("edit") as string}
</Button>
</DropdownMenuItem>
<DropdownMenuItem className="outline-none">
<Button
type="button"
color="minimal"
className="w-full rounded-none"
data-testid={"event-type-duplicate-" + type.id}
StartIcon={Icon.FiCopy}
onClick={() => openModal(group, type)}>
{t("duplicate") as string}
</Button>
</DropdownMenuItem>
<DropdownMenuSeparator className="h-px bg-gray-200" />
<DropdownMenuItem className="outline-none">
<Button
onClick={() => {
setDeleteDialogOpen(true);
setDeleteDialogTypeId(type.id);
}}
color="destructive"
StartIcon={Icon.FiTrash}
className="w-full rounded-none">
{t("delete") as string}
</Button>
</DropdownMenuItem>
</DropdownMenuContent>
<DropdownMenuSeparator className="h-px bg-gray-200" />
<DropdownMenuItem className="outline-none">
<Button
onClick={() => {
setDeleteDialogOpen(true);
setDeleteDialogTypeId(type.id);
}}
color="destructive"
StartIcon={Icon.FiTrash}
className="w-full rounded-none">
{t("delete") as string}
</Button>
</DropdownMenuItem>
</DropdownMenuContent>
</DropdownMenuPortal>
</Dropdown>
</div>
</div>
@@ -7,6 +7,7 @@ import { WEBAPP_URL } from "@calcom/lib/constants";
import { useLocale } from "@calcom/lib/hooks/useLocale";
import { trpc } from "@calcom/trpc/react";
import { Icon } from "@calcom/ui";
import { Alert } from "@calcom/ui/v2";
import Badge from "@calcom/ui/v2/core/Badge";
import EmptyScreen from "@calcom/ui/v2/core/EmptyScreen";
import Meta from "@calcom/ui/v2/core/Meta";
@@ -23,7 +24,7 @@ import { CalendarSwitch } from "@components/v2/settings/CalendarSwitch";
const SkeletonLoader = () => {
return (
<SkeletonContainer>
<div className="mt-6 mb-8 space-y-6 divide-y">
<div className="mt-6 mb-8 space-y-6">
<SkeletonText className="h-8 w-full" />
<SkeletonText className="h-8 w-full" />
<SkeletonText className="h-8 w-full" />
@@ -89,7 +90,30 @@ const CalendarsView = () => {
<List>
{data.connectedCalendars.map((item) => (
<Fragment key={item.credentialId}>
{item.calendars && (
{item.error && item.error.message && (
<Alert
severity="warning"
key={item.credentialId}
title={t("calendar_connection_fail")}
message={item.error.message}
className="mb-4 mt-4"
actions={
<>
{/* @TODO: add a reconnect button, that calls add api and delete old credential */}
<DisconnectIntegration
credentialId={item.credentialId}
trashIcon
onSuccess={() => query.refetch()}
buttonProps={{
className: "border border-gray-300 py-[2px]",
color: "secondary",
}}
/>
</>
}
/>
)}
{item?.error === undefined && item.calendars && (
<ListItem expanded className="flex-col">
<div className="flex w-full flex-1 items-center space-x-3 pb-5 pl-1 pt-1 rtl:space-x-reverse">
{
@@ -154,6 +178,22 @@ const CalendarsView = () => {
/>
);
}}
error={() => {
return (
<Alert
message={
<Trans i18nKey="fetching_calendars_error">
An error ocurred while fetching your Calendars.
<a className="cursor-pointer underline" onClick={() => query.refetch()}>
try again
</a>
.
</Trans>
}
severity="error"
/>
);
}}
/>
</>
);
@@ -3,6 +3,7 @@ import { useMemo } from "react";
import { useForm, Controller } from "react-hook-form";
import { useLocale } from "@calcom/lib/hooks/useLocale";
import { setIs24hClockInLocalStorage } from "@calcom/lib/timeFormat";
import { trpc } from "@calcom/trpc/react";
import { Button } from "@calcom/ui/v2/core/Button";
import Meta from "@calcom/ui/v2/core/Meta";
@@ -35,7 +36,7 @@ interface GeneralViewProps {
localeProp: string;
}
const WithQuery = withQuery(["viewer.public.i18n"], { context: { skipBatch: true } });
const WithQuery = withQuery(["viewer.public.i18n"], { trpc: { context: { skipBatch: true } } });
const GeneralQueryView = () => {
return (
@@ -110,6 +111,8 @@ const GeneralView = ({ localeProp }: GeneralViewProps) => {
<Form
form={formMethods}
handleSubmit={(values) => {
setIs24hClockInLocalStorage(values.timeFormat.value === 24);
mutation.mutate({
...values,
locale: values.locale.value,
@@ -7,7 +7,7 @@ import { useLocale } from "@calcom/lib/hooks/useLocale";
import { trpc } from "@calcom/trpc/react";
import Button from "@calcom/ui/v2/core/Button";
import Meta from "@calcom/ui/v2/core/Meta";
import { Form, TextField } from "@calcom/ui/v2/core/form/fields";
import { Form, PasswordField } from "@calcom/ui/v2/core/form/fields";
import { getLayout } from "@calcom/ui/v2/core/layouts/SettingsLayout";
import showToast from "@calcom/ui/v2/core/notifications";
@@ -48,7 +48,7 @@ const PasswordView = () => {
return (
<>
<Meta title="Password" description="Manage settings for your account passwords" />
<Meta title={t("password")} description={t("password_description")} />
{user && user.identityProvider !== IdentityProvider.CAL ? (
<div>
<div className="mt-6">
@@ -65,22 +65,17 @@ const PasswordView = () => {
</p>
</div>
) : (
<Form<ChangePasswordFormValues> form={formMethods} handleSubmit={handleSubmit}>
<Form form={formMethods} handleSubmit={handleSubmit}>
<div className="max-w-[38rem] sm:flex sm:space-x-4">
<div className="flex-grow">
<TextField {...register("oldPassword")} label={t("old_password")} type="password" />
<PasswordField {...register("oldPassword")} label={t("old_password")} />
</div>
<div className="flex-grow">
<TextField
{...register("newPassword")}
label={t("new_password")}
type="password"
placeholder={t("secure_password")}
/>
<PasswordField {...register("newPassword")} label={t("new_password")} />
</div>
</div>
<p className="text-sm text-gray-600">
<Trans i18nKey="valid_password">
<Trans i18nKey="invalid_password_hint">
Password must be at least at least 7 characters, mix of uppercase & lowercase letters, and
contain at least 1 number
</Trans>
@@ -89,8 +84,8 @@ const PasswordView = () => {
<Button
color="primary"
className="mt-8"
disabled={isSubmitting || mutation.isLoading}
onClick={() => handleSubmit(formMethods.getValues())}>
type="submit"
disabled={isSubmitting || mutation.isLoading}>
{t("update")}
</Button>
</Form>
@@ -69,10 +69,9 @@ const CreateNewTeamPage = () => {
data-testid="onboarding"
key={router.asPath}>
<Head>
<title>{t("create_new_team")}</title>
<title>Create a new Team</title>
<link rel="icon" href="/favicon.ico" />
</Head>
<div className="mx-auto px-4 py-24">
<div className="relative">
<div className="sm:mx-auto sm:w-full sm:max-w-[600px]">
+5 -5
View File
@@ -26,7 +26,7 @@ import { useLocale } from "@calcom/lib/hooks/useLocale";
import useTheme from "@calcom/lib/hooks/useTheme";
import { getEveryFreqFor } from "@calcom/lib/recurringStrings";
import { collectPageParameters, telemetryEventTypes, useTelemetry } from "@calcom/lib/telemetry";
import { isBrowserLocale24h } from "@calcom/lib/timeFormat";
import { getIs24hClockFromLocalStorage, isBrowserLocale24h } from "@calcom/lib/timeFormat";
import { localStorage } from "@calcom/lib/webstorage";
import prisma from "@calcom/prisma";
import Button from "@calcom/ui/Button";
@@ -201,7 +201,7 @@ export default function Success(props: SuccessProps) {
// TODO: Add payment details
});
setDate(date.tz(localStorage.getItem("timeOption.preferredTimeZone") || dayjs.tz.guess()));
setIs24h(!!localStorage.getItem("timeOption.is24hClock"));
setIs24h(!!getIs24hClockFromLocalStorage());
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [eventType, needsConfirmation]);
@@ -263,7 +263,7 @@ export default function Success(props: SuccessProps) {
{userIsOwner && !isEmbed && (
<div className="mt-2 ml-4 -mb-4">
<Link href={eventType.recurringEvent?.count ? "/bookings/recurring" : "/bookings/upcoming"}>
<a className="mt-2 inline-flex px-1 py-2 text-sm text-gray-500 hover:bg-gray-100 hover:text-gray-800">
<a className="mt-2 inline-flex px-1 py-2 text-sm text-gray-500 hover:bg-gray-100 hover:text-gray-800 dark:hover:bg-transparent dark:hover:text-white">
<Icon.FiChevronLeft className="h-5 w-5" /> {t("back_to_bookings")}
</a>
</Link>
@@ -411,7 +411,7 @@ export default function Success(props: SuccessProps) {
!isCancelled &&
(!isCancellationMode ? (
<>
<hr className="border-bookinglightest" />
<hr className="border-bookinglightest dark:border-darkgray-300" />
<div className="py-8 text-center last:pb-0">
<span className="text-gray-900 ltr:mr-2 rtl:ml-2 dark:text-gray-50">
{t("need_to_make_a_change")}
@@ -448,7 +448,7 @@ export default function Success(props: SuccessProps) {
))}
{userIsOwner && !needsConfirmation && !isCancellationMode && !isCancelled && (
<>
<hr className="border-bookinglightest" />
<hr className="border-bookinglightest dark:border-darkgray-300" />
<div className="text-bookingdark align-center flex flex-row justify-center pt-8">
<span className="flex self-center font-medium text-gray-700 ltr:mr-2 rtl:ml-2 dark:text-gray-50">
{t("add_to_calendar")}
@@ -112,7 +112,6 @@
"use_link_to_reset_password": "استخدم الرابط أدناه لإعادة تعيين كلمة المرور",
"hey_there": "مرحبًا،",
"forgot_your_password_calcom": "نسيت كلمة المرور الخاصة بك؟ - Cal.com",
"event_type_title": "{{eventTypeTitle}} | نوع الحدث",
"delete_webhook_confirmation_message": "هل أنت متأكد أنك تريد حذف الويب هوك هذا؟ لن تتلقى بعد الآن بيانات اجتماعات Cal.com على عنوان URL محدد، وفي الوقت الفعلي، عندما تتم جدولة حدث أو يتم إلغاؤه.",
"confirm_delete_webhook": "نعم، قم بحذف الويبهوك",
"edit_webhook": "تعديل الويبهوك",
@@ -633,7 +632,6 @@
"billing": "الفوترة",
"manage_your_billing_info": "قم بإدارة معلومات الفوترة لديك وإلغاء اشتراكك.",
"availability": "الأوقات المتاحة",
"availability_title": "{{availabilityTitle}} | توفر",
"edit_availability": "تعديل التوفر",
"configure_availability": "اضبط الأوقات التي تكون متاحًا فيها للحجز.",
"copy_times_to": "نسخ الأوقات إلى",
@@ -112,7 +112,6 @@
"use_link_to_reset_password": "Pro obnovení hesla použijte odkaz níž",
"hey_there": "Zdravíme,",
"forgot_your_password_calcom": "Zapomněli jste heslo? - Cal.com",
"event_type_title": "{{eventTypeTitle}} | Typ události",
"delete_webhook_confirmation_message": "Opravdu chcete smazat tento webhook? Přestanete v reálném čase dostávat Cal.com data o schůzce na dané URL, pokud bude událost naplánována nebo zrušena.",
"confirm_delete_webhook": "Ano, smazat webhook",
"edit_webhook": "Upravit webhook",
@@ -633,7 +632,6 @@
"billing": "Fakturace",
"manage_your_billing_info": "Spravujte své fakturační údaje a zrušte své předplatné.",
"availability": "Dostupnost",
"availability_title": "{{availabilityTitle}} | Dostupnost",
"edit_availability": "Upravit dostupnost",
"configure_availability": "Nastavit časy, kdy jste dostupní pro rezervace.",
"copy_times_to": "Kopírovat časy do",
@@ -112,7 +112,6 @@
"use_link_to_reset_password": "Benutzen Sie den Link, um Ihr Passwort zurückzusetzen",
"hey_there": "Hallo,",
"forgot_your_password_calcom": "Passwort vergessen? - Cal.com",
"event_type_title": "{{eventTypeTitle}} | Event-Typ",
"delete_webhook_confirmation_message": "Sind Sie sicher, dass Sie diesen Webhook löschen möchten? Sie werden keine Cal.com Termindaten mehr erhalten.",
"confirm_delete_webhook": "Ja, Webhook löschen",
"edit_webhook": "Webhook bearbeiten",
@@ -255,7 +254,7 @@
"user_needs_to_confirm_or_reject_booking_recurring": "{{user}} muss noch die Terminreihe des wiederkehrenden Termins bestätigen oder ablehnen.",
"meeting_is_scheduled": "Dieser Termin ist geplant",
"meeting_is_scheduled_recurring": "Ihr wiederkehrender Termin wurde geplant",
"submitted": "Ihr Termin wurde gebuhct",
"submitted": "Ihr Termin wurde gebucht",
"submitted_recurring": "Ihr wiederkehrender Termin wurde gebucht",
"booking_submitted": "Ihre Buchung wurde versandt",
"booking_submitted_recurring": "Ihre wiederkehrende Buchung wurde versandt",
@@ -633,7 +632,6 @@
"billing": "Abrechnung",
"manage_your_billing_info": "Verwalten Sie Ihre Rechnungsinformationen und kündigen Sie Ihr Abonnement.",
"availability": "Verfügbarkeit",
"availability_title": "{{availabilityTitle}} | Verfügbarkeit",
"edit_availability": "Verfügbarkeit editieren",
"configure_availability": "Konfigurieren Sie die Zeiten, in denen Sie für Buchungen zur Verfügung stehen.",
"copy_times_to": "Zeiten kopieren in",
+15 -6
View File
@@ -112,7 +112,6 @@
"use_link_to_reset_password": "Use the link below to reset your password",
"hey_there": "Hey there,",
"forgot_your_password_calcom": "Forgot your password? - Cal.com",
"event_type_title": "{{eventTypeTitle}} | Event Type",
"delete_webhook_confirmation_message": "Are you sure you want to delete this webhook? You will no longer receive Cal.com meeting data at a specified URL, in real-time, when an event is scheduled or canceled.",
"confirm_delete_webhook": "Yes, delete webhook",
"edit_webhook": "Edit Webhook",
@@ -633,7 +632,6 @@
"billing": "Billing",
"manage_your_billing_info": "Manage your billing information and cancel your subscription.",
"availability": "Availability",
"availability_title": "{{availabilityTitle}} | Availability",
"edit_availability": "Edit availability",
"configure_availability": "Configure times when you are available for bookings.",
"copy_times_to": "Copy times to",
@@ -1255,9 +1253,9 @@
"create_first_api_key_description": "API keys allow other apps to communicate with Cal.com",
"back_to_signin": "Back to sign in",
"reset_link_sent": "Reset link sent",
"password_reset_email":"An email is on it’s way to {{email}} with instructions to reset your password.",
"password_reset_leading":"If you don't receive an email soon, check that the email address you entered is correct, check your spam folder or reach out to support if the issue persists.",
"password_updated":"Password updated!",
"password_reset_email": "An email is on it’s way to {{email}} with instructions to reset your password.",
"password_reset_leading": "If you don't receive an email soon, check that the email address you entered is correct, check your spam folder or reach out to support if the issue persists.",
"password_updated": "Password updated!",
"pending_payment": "Pending payment",
"confirmation_page_rainbow": "Token gate your event with tokens or NFTs on Ethereum, Polygon, and more.",
"not_on_cal": "Not on Cal.com",
@@ -1268,5 +1266,16 @@
"confirm_password_change_email": "Please confirm your password before changing your email address",
"seats": "seats",
"every_app_published": "Every app published on the Cal.com App Store is open source and thoroughly tested via peer reviews. Nevertheless, Cal.com, Inc. does not endorse or certify these apps unless they are published by Cal.com. If you encounter inappropriate content or behaviour please report it.",
"report_app": "Report app"
"report_app": "Report app",
"team_name_required": "Team name required",
"how_additional_inputs_as_variables": "How to use Additional Inputs as Variables",
"format": "Format",
"uppercase_for_letters": "Use uppercase for all letters",
"replace_whitespaces_underscores": "Replace whitespaces with underscores",
"ignore_special_characters": "Ignore special characters in your Additional Input label. Use only letters and numbers",
"retry": "Retry",
"fetching_calendars_error": "There was a problem fetching your calendars. Please <1>try again</1> or reach out to customer support.",
"calendar_connection_fail": "Calendar connection failed",
"booking_confirmation_success": "Booking confirmation succeeded",
"booking_confirmation_fail": "Booking confirmation failed"
}
+50 -2
View File
@@ -112,7 +112,6 @@
"use_link_to_reset_password": "Utilice el enlace de abajo para restablecer su contraseña",
"hey_there": "Hola,",
"forgot_your_password_calcom": "¿Has olvidado tu contraseña? - Cal.com",
"event_type_title": "{{eventTypeTitle}} | Tipo de Evento",
"delete_webhook_confirmation_message": "¿Está seguro de que desea eliminar este webhook? Ya no recibirá datos de reuniones de Cal.com en una URL específica, en tiempo real, cuando se programe o cancele un evento.",
"confirm_delete_webhook": "Sí, elimina este webhook",
"edit_webhook": "Editar Webhook",
@@ -633,7 +632,6 @@
"billing": "Facturación",
"manage_your_billing_info": "Gestione su información de facturación y cancele su suscripción.",
"availability": "Disponibilidad",
"availability_title": "{{availabilityTitle}} | Disponibilidad",
"edit_availability": "Editar disponibilidad",
"configure_availability": "Configure los horarios en los que está disponible para realizar reservas.",
"copy_times_to": "Copiar tiempos en",
@@ -1184,8 +1182,58 @@
"organizer_name_info": "Tu Nombre",
"additional_notes_info": "Las notas adicionales de la reserva",
"attendee_name_info": "El nombre de la persona que reserva",
"to": "Para",
"attendee_required_enter_number": "Será necesario que el asistente introduzca un número de teléfono al reservar",
"workflow_turned_on_successfully": "El flujo de trabajo {{workflowName}} se ajustó como {{offOn}} correctamente",
"download_responses": "Descargar respuestas",
"create_your_first_form": "Cree su primer formulario",
"create_your_first_form_description": "Con los formularios de orientación puede hacer preguntas de cualificación y llegar a la persona o tipo de evento correctos.",
"create_your_first_webhook": "Cree su primer Webhook",
"create_your_first_webhook_description": "Con Webhooks puede recibir datos de reuniones en tiempo real cuando suceda algo en Cal.com.",
"for_a_maximum_of": "Para un máximo de",
"event_one": "evento",
"event_other": "eventos",
"profile_team_description": "Administre ajustes para el perfil de su equipo",
"members_team_description": "Usuarios que están en el grupo",
"team_url": "URL del equipo",
"delete_team": "Eliminar equipo",
"team_members": "Miembros del equipo",
"more": "Más",
"more_page_footer": "Vemos la aplicación móvil como una extensión de la aplicación web. Si está realizando acciones complicadas, consulte la aplicación web.",
"workflow_example_1": "Enviar recordatorio por SMS al asistente 24 horas antes de que el evento comience",
"workflow_example_2": "Enviar SMS personalizado al asistente cuando se cambie la planificación del evento",
"workflow_example_3": "Enviar correo electrónico personalizado al anfitrión cuando se reserve un evento nuevo",
"workflow_example_4": "Enviar recordatorio por correo electrónico al asistente 1 hora antes de que el evento comience",
"workflow_example_5": "Enviar correo electrónico personalizado al anfitrión cuando se cambie la planificación del evento",
"workflow_example_6": "Enviar SMS personalizado al anfitrión cuando se reserve un evento nuevo",
"welcome_to_cal_header": "¡Bienvenido a Cal.com!",
"edit_form_later_subtitle": "Podrá editarlo más tarde.",
"connect_calendar_later": "Conectaré mi calendario más tarde",
"set_my_availability_later": "Indicaré mi disponibilidad más tarde",
"problem_saving_user_profile": "Se produjo un problema al guardar sus datos. Inténtelo de nuevo o póngase en contacto con el servicio de atención al cliente.",
"purchase_missing_seats": "Comprar licencias que faltan",
"slot_length": "Duración de franja",
"booking_appearance": "Aspecto de la reserva",
"appearance_team_description": "Administre los ajustes para el aspecto de la reserva de su equipo",
"only_owner_change": "Solo el propietario de este equipo puede hacer cambios en la reserva del equipo ",
"team_disable_cal_branding_description": "Elimina cualquier marca relacionada con Cal, p. ej., \"Powered by Cal\"",
"invited_by_team": "{{teamName}} le invitó a unirse a su equipo como {{role}}",
"token_invalid_expired": "El token no es válido o ha caducado.",
"exchange_add": "Conectar a Microsoft Exchange",
"exchange_authentication": "Método de autenticación",
"exchange_authentication_standard": "Autenticación básica",
"exchange_authentication_ntlm": "Autenticación NTLM",
"exchange_compression": "Compresión GZip",
"routing_forms_description": "Puede ver todos los formularios y rutas que ha creado aquí.",
"add_new_form": "Añadir formulario nuevo",
"form_description": "Cree su formulario para dirigirlo a un agente de reservas",
"copy_link_to_form": "Copiar enlace al formulario",
"theme": "Tema",
"theme_applies_note": "Solo se aplica a sus páginas de reservas públicas",
"theme_light": "Claro",
"theme_dark": "Oscuro",
"theme_system": "Predeterminado del sistema",
"add_a_team": "Añadir un equipo",
"saml_config": "Configuración de SAML",
"add_webhook_description": "Reciba datos de reuniones en tiempo real cuando suceda algo en Cal.com",
"triggers_when": "Se activa cuando",
+215 -2
View File
@@ -112,7 +112,6 @@
"use_link_to_reset_password": "Utilisez le lien ci-dessous pour réinitialiser votre mot de passe",
"hey_there": "Salut,",
"forgot_your_password_calcom": "Mot de passe oublié ? - Cal.com",
"event_type_title": "{{eventTypeTitle}} | Type d'événement",
"delete_webhook_confirmation_message": "Êtes-vous sûr de vouloir supprimer ce webhook ? Vous ne recevrez plus les données de réunion de Cal.com à une URL spécifiée, en temps réel, lorsqu'un événement est programmé ou annulé.",
"confirm_delete_webhook": "Oui, supprimer le webhook",
"edit_webhook": "Modifier le webhook",
@@ -633,7 +632,9 @@
"billing": "Facturation",
"manage_your_billing_info": "Gérez vos informations de facturation et annulez votre abonnement.",
"availability": "Disponibilité",
"edit_availability": "Modifier la disponibilité",
"configure_availability": "Déclarez les moments où vous êtes disponible pour un rendez-vous.",
"copy_times_to": "Copier les heures vers",
"change_weekly_schedule": "Modifier votre planning hebdomadaire",
"logo": "Logo",
"error": "Erreur",
@@ -648,6 +649,7 @@
"event_name_tooltip": "Le nom qui apparaîtra dans les calendriers",
"meeting_with_user": "Rendez-vous avec {ATTENDEE}",
"additional_inputs": "Entrées additionnelles",
"additional_input_description": "Exiger que le planificateur saisisse des entrées supplémentaires avant que la réservation soit confirmée",
"label": "Libellé",
"placeholder": "Placeholder",
"type": "Type",
@@ -662,6 +664,8 @@
"disable_guests": "Désactiver les invité. es",
"disable_guests_description": "Désactiver l'ajout d'invité·es supplémentaires lors de la réservation.",
"private_link": "Générer une URL privée",
"private_link_label": "Lien privé",
"private_link_hint": "Votre lien privé sera régénéré après chaque utilisation",
"copy_private_link": "Copier le lien privé",
"private_link_description": "Générer une URL privée à partager sans exposer votre nom d'utilisateur Cal",
"invitees_can_schedule": "Les invité·es peuvent réserver",
@@ -703,16 +707,21 @@
"delete_account_confirmation_message": "Êtes-vous sûr de vouloir supprimer votre compte Cal.com ? Toute personne avec qui vous avez partagé le lien de votre compte ne pourra plus réserver en utilisant ce lien et toutes les préférences que vous avez enregistrées seront perdues.",
"integrations": "Intégrations",
"apps": "Applications",
"category_apps": "{{category}} applications",
"app_store": "App Store",
"app_store_description": "Connecter les personnes, la technologie et l'espace de travail.",
"settings": "Paramètres",
"event_type_moved_successfully": "Le type d'évènement a bien été déplacé",
"next_step_text": "Prochaine étape",
"next_step": "Passer l'étape",
"prev_step": "Étape précédente",
"install": "Installer",
"installed": "Installé",
"active_install_one": "{{count}} installation active",
"active_install_other": "{{count}} installations actives",
"globally_install": "Installation globale",
"app_successfully_installed": "Application installée avec succès",
"app_could_not_be_installed": "Impossible d'installer l'application",
"disconnect": "Déconnecter",
"embed_your_calendar": "Intégrez votre calendrier dans votre page web",
"connect_your_favourite_apps": "Connectez vos applications favorites.",
@@ -723,6 +732,7 @@
"connect_additional_calendar": "Connecter un calendrier supplémentaire",
"conferencing": "Conférence",
"calendar": "Calendrier",
"payments": "Paiements",
"not_installed": "Non installé",
"error_password_mismatch": "Les mots de passe ne correspondent pas.",
"error_required_field": "Ce champ est requis.",
@@ -756,9 +766,22 @@
"import_from": "Importer depuis",
"access_token": "Jeton d'accès",
"visit_roadmap": "Feuille de route",
"featured_categories": "Catégories en vedette",
"popular_categories": "Catégories populaires",
"number_apps_one": "{{count}} Application",
"number_apps_other": "{{count}} Applications",
"trending_apps": "Applications populaires",
"explore_apps": "{{category}} applications",
"installed_apps": "Applications installées",
"no_category_apps": "Aucune application {{category}}",
"no_category_apps_description_calendar": "Ajouter une application de calendrier pour vérifier les conflits et éviter les doubles réservations",
"no_category_apps_description_conferencing": "Essayez d'ajouter une application de conférence pour interconnecter les appels vidéo avec vos clients",
"no_category_apps_description_payment": "Ajouter une application de paiement pour faciliter les transactions entre vous et vos clients",
"no_category_apps_description_other": "Ajouter n'importe quel autre type d'application pour faire toutes sortes de choses",
"installed_app_calendar_description": "Définir le(s) calendrier(s) pour vérifier les conflits pour éviter les doubles réservations.",
"installed_app_conferencing_description": "Ajoutez vos applications de vidéoconférence préférées pour vos réunions",
"installed_app_payment_description": "Configurez les services de traitement de paiement à utiliser lors de la facturation de vos clients.",
"installed_app_other_description": "Toutes vos applications installées à partir d'autres catégories.",
"empty_installed_apps_headline": "Aucune application installée",
"empty_installed_apps_description": "Les applications vous permettent d'améliorer votre flux de travail et votre processus de planification de façon significative.",
"empty_installed_apps_button": "Explorer l'App Store",
@@ -779,6 +802,7 @@
"remove": "Supprimer",
"add": "Ajouter",
"installed_one": "Installé",
"installed_other": "{{count}} installé(e)(s)",
"verify_wallet": "Vérifier le portefeuille",
"connect_metamask": "Connecter Metamask",
"create_events_on": "Créer des événements le :",
@@ -796,6 +820,8 @@
"set_to_default": "Définir par défaut",
"new_schedule_btn": "Nouveau programme",
"add_new_schedule": "Ajouter un nouveau programme",
"add_new_calendar": "Ajouter un nouveau calendrier",
"set_calendar": "Définir où ajouter de nouveaux événements lors de la réservation.",
"delete_schedule": "Supprimer le programme",
"schedule_created_successfully": "{{scheduleName}} programme créé",
"availability_updated_successfully": "{{scheduleName}} programme mis à jour",
@@ -949,6 +975,7 @@
"workflows": "Workflows",
"new_workflow_btn": "Nouveau workflow",
"add_new_workflow": "Ajouter un nouveau workflow",
"reschedule_event_trigger": "lorsque l'événement est reprogrammé",
"trigger": "Déclencheur",
"triggers": "Déclencheurs",
"action": "Action",
@@ -976,10 +1003,13 @@
"change_username_standard_to_premium": "Puisque vous passez d'un nom d'utilisateur standard à un premium, vous allez être envoyé au paiement pour valider le changement.",
"change_username_premium_to_standard": "Puisque vous passez d'un nom d'utilisateur premium à un standard, vous allez être envoyé au paiement pour valider la rétrogradation.",
"go_to_stripe_billing": "Accéder à la facturation",
"stripe_description": "Nécessite un paiement pour les réservations (0,5% + 0,10 € de commission par transaction)",
"trial_expired": "Votre période d'essai a expiré",
"remove_app": "Supprimer l'application",
"yes_remove_app": "Oui, supprimer l'application",
"are_you_sure_you_want_to_remove_this_app": "Voulez-vous vraiment supprimer cette application ?",
"app_removed_successfully": "Application supprimée avec succès",
"error_removing_app": "Erreur lors de la suppression de l'application",
"web_conference": "Conférence en ligne",
"number_for_sms_reminders": "Numéro de téléphone (pour les rappels par SMS)",
"requires_confirmation": "Nécessite une confirmation",
@@ -1035,18 +1065,201 @@
"navigate": "Naviguer",
"open": "Ouvrir",
"close": "Fermer",
"team_feature_teams": "Ceci est une fonctionnalité d'équipe. Mettez à niveau vers l'équipe pour voir la disponibilité de votre équipe.",
"team_feature_workflows": "Ceci est une fonctionnalité d'équipe. Mettez à niveau vers l'équipe pour automatiser vos notifications et rappels d'événements avec les flux de travail.",
"show_eventtype_on_profile": "Afficher sur le profil",
"embed": "Intégré",
"new_username": "Nouveau nom d'utilisateur",
"current_username": "Nom d'utilisateur actuel",
"example_1": "Exemple 1",
"example_2": "Exemple 2",
"additional_input_label": "Libellé de saisie supplémentaire",
"company_size": "Taille de l'entreprise",
"what_help_needed": "Pour quoi avez-vous besoin d'aide ?",
"variable_format": "Format des variables",
"webhook_subscriber_url_reserved": "L'url d'abonné au Webhook est déjà définie",
"custom_input_as_variable_info": "Ignorer tous les caractères spéciaux du libellé de saisie supplémentaire (utiliser uniquement des lettres et des chiffres), utiliser des majuscules pour toutes les lettres et remplacer les espaces par des tirets bas.",
"using_additional_inputs_as_variables": "Comment utiliser des entrées supplémentaires en tant que variables ?",
"download_desktop_app": "Télécharger l'application de bureau",
"set_ping_link": "Définir le lien Ping",
"rate_limit_exceeded": "Limite dépassée",
"when_something_happens": "Quand quelque chose se passe",
"action_is_performed": "Une action est effectuée",
"test_action": "Tester l'action",
"notification_sent": "Notification envoyée",
"no_input": "Aucune entrée",
"test_workflow_action": "Tester l'effet du workflow",
"send_sms": "Envoyer un SMS",
"send_sms_to_number": "Êtes-vous sûr de vouloir envoyer un SMS au {{number}}?",
"missing_connected_calendar": "Aucun calendrier par défaut connecté",
"connect_your_calendar_and_link": "Vous pouvez connecter votre calendrier depuis <1>ici</1>.",
"default_calendar_selected": "Calendrier par défaut",
"hide_from_profile": "Masquer du profil",
"event_setup_tab_title": "Configuration de l'événement",
"event_limit_tab_title": "Limites",
"event_limit_tab_description": "Fréquence de réservation",
"event_advanced_tab_description": "Paramètres du calendrier & plus...",
"event_advanced_tab_title": "Avancé",
"select_which_cal": "Sélectionnez le calendrier auquel ajouter des réservations",
"custom_event_name": "Nom de l'événement personnalisé",
"custom_event_name_description": "Créer des noms d'événements personnalisés à afficher sur l'événement du calendrier",
"2fa_required": "Authentification en deux étapes requise",
"incorrect_2fa": "Code d'authentification à deux facteurs incorrect",
"which_event_type_apply": "À quel type d'événement s'appliquera-t-il ?",
"no_workflows_description": "Les workflows permettent une automatisation simple pour envoyer des notifications et des rappels vous permettant de construire des processus autour de vos événements.",
"create_workflow": "Créer un workflow",
"do_this": "Effectuer ceci",
"turn_off": "Désactiver",
"settings_updated_successfully": "Paramètres mis à jour avec succès",
"error_updating_settings": "Erreur lors de la mise à jour des paramètres",
"personal_cal_url": "Mon URL Cal personnelle",
"bio_hint": "Quelques phrases à propos de vous. Ces informations apparaîtront sur votre page d'url personnelle.",
"delete_account_modal_title": "Supprimer le compte",
"confirm_delete_account_modal": "Êtes-vous sûr de vouloir supprimer votre compte Cal.com ?",
"delete_my_account": "Supprimer mon compte",
"start_of_week": "Début de la semaine",
"select_calendars": "Sélectionnez quels calendriers vous voulez vérifier les conflits pour éviter les doubles réservations.",
"check_for_conflicts": "Vérifier les conflits",
"adding_events_to": "Ajout d'événements à",
"follow_system_preferences": "Suivre les préférences système",
"custom_brand_colors": "Couleurs de marque personnalisées",
"customize_your_brand_colors": "Personnalisez votre propre couleur de marque dans votre page de réservation.",
"pro": "Pro",
"removes_cal_branding": "Supprime les marques associées à Cal, c'est-à-dire \"Powered by Cal.\"",
"profile_picture": "Photo de profil",
"upload": "Télécharger",
"web3": "Web3",
"rainbow_token_gated": "Ce type d'événement nécessite un jeton d'authentification.",
"rainbow_connect_wallet_gate": "Connectez votre portefeuille si vous possédez <1>{{name}}</1> (<3>{{symbol}}</3>).",
"rainbow_insufficient_balance": "Votre portefeuille connecté ne contient pas assez de <1>{{symbol}}</1>.",
"rainbow_sign_message_request": "Signez la demande de message sur votre portefeuille.",
"rainbow_signature_error": "Erreur lors de la demande de signature de votre portefeuille.",
"token_address": "Adresse du jeton",
"blockchain": "Blockchain",
"old_password": "Ancien mot de passe",
"secure_password": "Votre nouveau mot de passe super sécurisé",
"error_updating_password": "Erreur lors de la mise à jour du mot de passe",
"two_factor_auth": "Authentification en deux étapes",
"recurring_event_tab_description": "Configurez un calendrier récurrent",
"today": "aujourd'hui",
"appearance": "Apparence",
"appearance_subtitle": "Gérer les paramètres pour votre apparence de réservation",
"my_account": "Mon compte",
"general": "Général",
"calendars": "Calendriers",
"2fa_auth": "Authentification à deux facteurs",
"invoices": "Factures",
"embeds": "Intègre",
"impersonation": "Identification",
"users": "Utilisateurs",
"profile_description": "Gérer les paramètres de votre profil cal",
"general_description": "Gérer les paramètres pour votre langue et votre fuseau horaire",
"calendars_description": "Configurez la manière dont vos types d'événements interagissent avec vos calendriers",
"appearance_description": "Gérer les paramètres pour votre apparence de réservation",
"conferencing_description": "Gérez vos applications de vidéoconférence pour vos réunions",
"password_description": "Gérer les paramètres pour les mots de passe de votre compte",
"2fa_description": "Gérer les paramètres pour les mots de passe de votre compte",
"we_just_need_basic_info": "Nous avons juste besoin de quelques informations de base pour configurer votre profil.",
"skip": "Ignorer",
"do_this_later": "Effectuer ceci plus tard",
"set_availability_getting_started_subtitle_1": "Définir les plages de temps lorsque vous êtes disponible",
"set_availability_getting_started_subtitle_2": "Vous pouvez personnaliser tout cela plus tard dans la page de disponibilité.",
"connect_calendars_from_app_store": "Vous pouvez ajouter plus de calendriers depuis l'App Store",
"connect_conference_apps": "Connecter les applications de conférence",
"connect_calendar_apps": "Connecter les applications de calendrier",
"connect_payment_apps": "Connecter les applications de paiement",
"connect_other_apps": "Connecter d'autres applications",
"current_step_of_total": "Étape {{currentStep}} sur {{maxSteps}}",
"add_variable": "Ajouter une variable",
"custom_phone_number": "Numéro de téléphone personnalisé",
"message_template": "Modèle de message",
"email_subject": "Objet",
"add_dynamic_variables": "Ajouter des variables de texte dynamiques",
"event_name_info": "Nom du type d'événement",
"event_date_info": "Date de l'évènement",
"event_time_info": "Heure de début de l'événement",
"location_info": "Lieu de l'événement",
"organizer_name_info": "Votre nom",
"additional_notes_info": "Notes supplémentaires de réservation",
"attendee_name_info": "Nom de la personne réservant",
"to": "À/vers",
"attendee_required_enter_number": "Le participant devra entrer un numéro de téléphone lors de la réservation",
"workflow_turned_on_successfully": "Le workflow {{workflowName}} a été {{offOn}} avec succès",
"download_responses": "Télécharger les réponses",
"create_your_first_form": "Créer votre premier formulaire",
"create_your_first_form_description": "Grâce aux formulaires d'acheminement, vous pouvez poser des questions de qualification et vous diriger vers la personne ou le type d'événement appropriés.",
"create_your_first_webhook": "Créez votre premier Webhook",
"create_your_first_webhook_description": "Avec les Webhooks, vous pouvez recevoir des données de réunion en temps réel lorsque quelque chose se passe sur Cal.com.",
"for_a_maximum_of": "Pour un maximum de",
"event_one": "événement",
"event_other": "événements",
"profile_team_description": "Gérer les paramètres de votre profil d'équipe",
"members_team_description": "Utilisateurs membres du groupe",
"team_url": "URL de l'équipe",
"delete_team": "Supprimer l'équipe",
"team_members": "Membres de l'équipe",
"more": "En savoir plus",
"more_page_footer": "Nous considérons l'application mobile comme une extension de l'application web. Si vous effectuez des actions complexes, veuillez vous référer à l'application Web.",
"workflow_example_1": "Envoyer un rappel SMS 24 heures avant le début de l'événement",
"workflow_example_2": "Envoyer un SMS personnalisé lorsque l'événement est reprogrammé au participant",
"workflow_example_3": "Envoyer un email personnalisé quand un nouvel événement est réservé à un hôte",
"workflow_example_4": "Envoyer un rappel par e-mail 1 heure avant le début des événements",
"workflow_example_5": "Envoyer un email personnalisé lorsque l'événement est reprogrammé à l'hôte",
"workflow_example_6": "Envoyer un SMS personnalisé quand un nouvel événement est réservé à un hôte",
"welcome_to_cal_header": "Bienvenue sur Cal.com !",
"edit_form_later_subtitle": "Vous pourrez modifier cela plus tard.",
"connect_calendar_later": "Je connecterai mon calendrier plus tard",
"set_my_availability_later": "Je vais définir ma disponibilité plus tard",
"problem_saving_user_profile": "Un problème est survenu lors de l'enregistrement de vos données. Veuillez réessayer ou contacter le service client.",
"purchase_missing_seats": "Acheter des places manquantes",
"slot_length": "Durée du créneau",
"booking_appearance": "Apparence de réservation",
"appearance_team_description": "Gérer les paramètres pour l'apparence de réservation de votre équipe",
"only_owner_change": "Seul le propriétaire de cette équipe peut apporter des modifications à la réservation de l'équipe ",
"team_disable_cal_branding_description": "Supprime les marques associées à Cal, c'est-à-dire \"Powered by Cal\"",
"invited_by_team": "{{teamName}} vous a invité à rejoindre son équipe en tant que {{role}}",
"token_invalid_expired": "Le jeton est invalide ou expiré.",
"exchange_add": "Se connecter à Microsoft Exchange",
"exchange_authentication": "Méthode d'authentification",
"exchange_authentication_standard": "Authentification de base",
"exchange_authentication_ntlm": "Authentification NTLM",
"exchange_compression": "Compression GZip",
"routing_forms_description": "Vous pouvez voir tous les formulaires et tous les parcours que vous avez créés ici.",
"add_new_form": "Ajouter un nouveau formulaire",
"form_description": "Créez votre formulaire pour acheminer un organisateur",
"copy_link_to_form": "Copier le lien vers le formulaire",
"theme": "Thème",
"theme_applies_note": "Ceci s'applique uniquement à vos pages publiques de réservation",
"theme_light": "Clair",
"theme_dark": "Sombre"
"theme_dark": "Sombre",
"theme_system": "Défaut du système",
"add_a_team": "Ajouter une équipe",
"saml_config": "Configuration SAML",
"add_webhook_description": "Recevoir les données de la réunion en temps réel lorsque quelque chose se passe sur Cal.com",
"triggers_when": "Se déclenche quand",
"enable_webhook": "Activer le Webhook",
"add_webhook": "Ajouter un Webhook",
"webhook_edited_successfully": "Webhook enregistré",
"webhooks_description": "Recevez les données de la réunion en temps réel lorsque quelque chose se passe sur Cal.com",
"api_keys_description": "Générer des clés API pour accéder à votre propre compte",
"new_api_key": "Nouvelle clé API",
"active": "Actif",
"api_key_updated": "Nom de clé API mis à jour",
"api_key_update_failed": "Erreur de mise à jour du nom de la clé API",
"embeds_title": "Intégration d'iframe HTML",
"embeds_description": "Intégrez tous vos types d'événements sur votre site web",
"create_first_api_key": "Créez votre première clé API",
"create_first_api_key_description": "Les clés API permettent à d'autres applications de communiquer avec Cal.com",
"back_to_signin": "Retour à la connexion",
"reset_link_sent": "Lien de réinitialisation envoyé",
"password_updated": "Mot de passe mis à jour !",
"pending_payment": "Paiement en attente",
"not_on_cal": "Pas sur Cal.com",
"no_calendar_installed": "Aucun calendrier installé",
"no_calendar_installed_description": "Vous n'avez pas encore connecté vos calendriers",
"add_a_calendar": "Ajouter au calendrier",
"change_email_hint": "Vous devrez peut-être vous déconnecter et vous reconnecter pour que le changement prenne effet",
"seats": "places",
"every_app_published": "Chaque application publiée sur l'App Store de Cal.com est open source et soigneusement testée via les évaluations par les pairs. Néanmoins, Cal.com, Inc. n'approuve pas ou ne certifie pas ces applications à moins qu'elles ne soient publiées par Cal.com. Si vous rencontrez un contenu ou un comportement inapproprié, veuillez le signaler.",
"report_app": "Signaler une application"
}
@@ -112,7 +112,6 @@
"use_link_to_reset_password": "נא להשתמש בקישור הבא כדי לאפס את הסיסמה",
"hey_there": "שלום,",
"forgot_your_password_calcom": "שכחתה את הסיסמה? - cal.com",
"event_type_title": "{{eventTypeTitle}} | סוג האירוע",
"delete_webhook_confirmation_message": "בטוח שברצונך למחוק את ה-Webhook הזה? אם אירוע יבוטל או שייקבע עבורו מועד, לא תקבל יותר נתוני פגישות מ-Cal.com בזמן אמת או בכתובת ה-URL שציינת.",
"confirm_delete_webhook": "כן, אני רוצה למחוק את ה-Webhook",
"edit_webhook": "עריכת Webhook",
@@ -112,7 +112,6 @@
"use_link_to_reset_password": "Usa il link qui sotto per reimpostare la tua password",
"hey_there": "Ciao,",
"forgot_your_password_calcom": "Hai dimenticato la password? - Cal.com",
"event_type_title": "{{eventTypeTitle}} | Tipo di evento",
"delete_webhook_confirmation_message": "Sei sicuro di voler eliminare questo webhook? Non riceverai più Cal.com dati di riunione in un URL specificato, in tempo reale, quando un evento è programmato o annullato.",
"confirm_delete_webhook": "Sì, elimina webhook",
"edit_webhook": "Modifica Webhook",
@@ -633,7 +632,6 @@
"billing": "Fatturazione",
"manage_your_billing_info": "Gestisci le tue informazioni di fatturazione e annulla il tuo abbonamento.",
"availability": "Disponibilità",
"availability_title": "{{availabilityTitle}} | Disponibilità",
"edit_availability": "Modifica disponibilità",
"configure_availability": "Cambia quando sei disponibile per le prenotazioni.",
"copy_times_to": "Copia orari in",
@@ -112,7 +112,6 @@
"use_link_to_reset_password": "以下のリンクを使用してパスワードをリセットしてください",
"hey_there": "こんにちは!",
"forgot_your_password_calcom": "パスワードをお忘れですか? - Cal.com",
"event_type_title": "{{eventTypeTitle}} | イベントタイプ",
"delete_webhook_confirmation_message": "このウェブフックを削除してもよろしいですか? イベントがスケジュールまたはキャンセルされたときに、指定された URL でのミーティングデータをリアルタイムには受け取れなくなります。",
"confirm_delete_webhook": "はい、ウェブフックを削除します",
"edit_webhook": "ウェブフックを編集",
@@ -633,7 +632,6 @@
"billing": "請求",
"manage_your_billing_info": "請求情報の管理とサブスクリプションのキャンセル。",
"availability": "利用可能期間",
"availability_title": "{{availabilityTitle}} | 空き状況",
"edit_availability": "空き状況を編集",
"configure_availability": "予約が可能な時間を設定する。",
"copy_times_to": "次に時間をコピー",
@@ -112,7 +112,6 @@
"use_link_to_reset_password": "비밀번호를 재설정하시려면 아래 링크를 사용하세요.",
"hey_there": "안녕하세요.",
"forgot_your_password_calcom": "비밀번호를 잊어버리셨나요? - Cal.com",
"event_type_title": "{{eventTypeTitle}} | 이벤트 타입",
"delete_webhook_confirmation_message": "웹훅을 정말로 삭제하시겠습니까? 이벤트 일정이 잡혔거나 취소되었을 때 Cal.com의 회의 정보를 더 이상 실시간으로 받아보실 수 없게 됩니다.",
"confirm_delete_webhook": "네, 웹훅을 삭제하겠습니다.",
"edit_webhook": "웹훅 수정하기",
@@ -633,7 +632,6 @@
"billing": "청구",
"manage_your_billing_info": "결제 정보를 관리하고 구독을 취소하세요.",
"availability": "유효성",
"availability_title": "{{availabilityTitle}} | 가용성",
"edit_availability": "가용성 편집",
"configure_availability": "예약 가능한 시간을 구성하십시오.",
"copy_times_to": "횟수 복사:",
@@ -112,7 +112,6 @@
"use_link_to_reset_password": "Gebruik de onderstaande link om uw wachtwoord te resetten",
"hey_there": "Hallo daar,",
"forgot_your_password_calcom": "Wachtwoord vergeten? - Cal.com",
"event_type_title": "{{eventTypeTitle}} | Evenement",
"delete_webhook_confirmation_message": "Weet u zeker dat u deze webhook wilt verwijderen? U ontvangt dan niet langer Cal.com vergadergegevens op een opgegeven URL, in real-time, wanneer een evenement is geboekt of geannuleerd.",
"confirm_delete_webhook": "Ja, webhook verwijderen",
"edit_webhook": "Webhook bewerken",
@@ -633,7 +632,6 @@
"billing": "Abonnement",
"manage_your_billing_info": "Beheer uw betalingsgegevens en annuleer uw abonnement.",
"availability": "Beschikbaarheid",
"availability_title": "{{availabilityTitle}} | Beschikbaarheid",
"edit_availability": "Beschikbaarheid bewerken",
"configure_availability": "Configureer tijden wanneer u beschikbaar bent voor afspraken.",
"copy_times_to": "Tijden kopiëren naar",
@@ -112,7 +112,6 @@
"use_link_to_reset_password": "Użyj poniższego linku, aby zresetować swoje hasło",
"hey_there": "Cześć,",
"forgot_your_password_calcom": "Nie pamiętasz swojego hasła? - Cal.com",
"event_type_title": "{{eventTypeTitle}} | Typ Wydarzenia",
"delete_webhook_confirmation_message": "Czy na pewno chcesz usunąć ten webhook? Nie będziesz już otrzymywać danych o spotkaniach w Cal.com w określonym URL, w czasie rzeczywistym, gdy zdarzenie jest zaplanowane lub anulowane.",
"confirm_delete_webhook": "Tak, usuń webhook",
"edit_webhook": "Edytuj Webhook",
@@ -633,7 +632,6 @@
"billing": "Rozliczenia",
"manage_your_billing_info": "Zarządzaj informacjami rozliczeniowymi i anuluj subskrypcję.",
"availability": "Dostępność",
"availability_title": "{{availabilityTitle}} | Dostępność",
"edit_availability": "Edytuj dostępność",
"configure_availability": "Skonfiguruj czasy, kiedy jesteś dostępny dla rezerwacji.",
"copy_times_to": "Kopiuj czasy do",
@@ -112,7 +112,6 @@
"use_link_to_reset_password": "Use o link abaixo para redefinir a sua senha",
"hey_there": "Olá,",
"forgot_your_password_calcom": "Esqueceu sua senha? - Cal.com",
"event_type_title": "{{eventTypeTitle}} | Tipo de evento",
"delete_webhook_confirmation_message": "Você tem certeza que quer remover este Webhook? Você não receberá mais dados de reuniões de Cal.com na URL especificada, em tempo real, quando um evento for agendado ou cancelado.",
"confirm_delete_webhook": "Sim, remover o Webhook",
"edit_webhook": "Editar Webhook",
@@ -633,7 +632,6 @@
"billing": "Faturamento",
"manage_your_billing_info": "Gerenciar as suas informações de faturamento e cancelar a sua assinatura.",
"availability": "Disponibilidade",
"availability_title": "{{availabilityTitle}} | Disponibilidade",
"edit_availability": "Editar disponibilidade",
"configure_availability": "Configure os horários em que estiver disponível para reservas.",
"copy_times_to": "Copiar horários para",
@@ -112,7 +112,6 @@
"use_link_to_reset_password": "Use a ligação abaixo para redefinir a sua senha",
"hey_there": "Olá,",
"forgot_your_password_calcom": "Esqueceu-se da sua senha? - Cal.com",
"event_type_title": "{{eventTypeTitle}} | Tipo de evento",
"delete_webhook_confirmation_message": "De certeza que quer eliminar este Webhook? Não receberá mais dados de reuniões de Cal.com do URL especificado, em tempo real, quando um evento for agendado ou cancelado.",
"confirm_delete_webhook": "Sim, eliminar o Webhook",
"edit_webhook": "Editar Webhook",
@@ -633,7 +632,6 @@
"billing": "Facturação",
"manage_your_billing_info": "Gerir as suas informações de faturação e cancele a sua assinatura.",
"availability": "Disponibilidade",
"availability_title": "{{availabilityTitle}} | Disponibilidade",
"edit_availability": "Editar disponibilidade",
"configure_availability": "Configure os horários em que estiver disponível para reservas.",
"copy_times_to": "Copiar horários para",
@@ -112,7 +112,6 @@
"use_link_to_reset_password": "Utilizați linkul de mai jos pentru a vă reseta parola",
"hey_there": "Bună,",
"forgot_your_password_calcom": "Ți-ai uitat parola? - Cal.com",
"event_type_title": "{{eventTypeTitle}} Tip de Eveniment",
"delete_webhook_confirmation_message": "Ești sigur că vrei să ștergi acest webhook? Nu vei mai primi Cal.com date de întâlnire la un URL specificat, în timp real, atunci când un eveniment este programat sau anulat.",
"confirm_delete_webhook": "Da, șterge webhook",
"edit_webhook": "Editează Webhook",
@@ -633,7 +632,6 @@
"billing": "Facturare",
"manage_your_billing_info": "Gestionați informațiile de facturare și anulați abonamentul.",
"availability": "Disponibilitate",
"availability_title": "{{availabilityTitle}} | Disponibilitate",
"edit_availability": "Editează disponibilitatea",
"configure_availability": "Configurați orele când sunteți disponibil pentru rezervări.",
"copy_times_to": "Copiază orele la",
@@ -112,7 +112,6 @@
"use_link_to_reset_password": "Используйте ссылку ниже, чтобы сбросить пароль",
"hey_there": "Привет,",
"forgot_your_password_calcom": "Забыли пароль? - Cal.com",
"event_type_title": "{{eventTypeTitle}} | Тип события",
"delete_webhook_confirmation_message": "Вы уверены, что хотите удалить этот вебхук? Вы больше не будете получать от Cal.com данные о новых или отменённых встречах по указанному URL в реальном времени.",
"confirm_delete_webhook": "Да, удалить веб-хук",
"edit_webhook": "Изменить веб-хук",
@@ -633,7 +632,6 @@
"billing": "Биллинг",
"manage_your_billing_info": "Управление платежной информацией и отменой подписки.",
"availability": "Доступность",
"availability_title": "{{availabilityTitle}} | Доступность",
"edit_availability": "Изменить доступность",
"configure_availability": "Измените временные интервалы, доступные для бронирования.",
"copy_times_to": "Скопировать время в",
@@ -112,7 +112,6 @@
"use_link_to_reset_password": "Resetujte lozinku koristeći link ispod",
"hey_there": "Zdravo,",
"forgot_your_password_calcom": "Zaboravili ste lozinku? - Cal.com",
"event_type_title": "{{eventTypeTitle}} | Tip Dogadjaja",
"delete_webhook_confirmation_message": "Da li ste sigurni da želite da obrišete ovaj webhook? Nećete više dobijati Cal.com podatke o sastancima preko naznačenog URL, istovremeno kad je dogadjaj zakazan ili otkazan.",
"confirm_delete_webhook": "Da, obriši webhook",
"edit_webhook": "Uredi Webhook",
@@ -633,7 +632,6 @@
"billing": "Naplate",
"manage_your_billing_info": "Upravljajte svojim informacijama za plaćanje i otkažite pretplatu.",
"availability": "Dostupnost",
"availability_title": "{{availabilityTitle}} | Dostupnost",
"edit_availability": "Uredi dostupnost",
"configure_availability": "Konfigurišite vreme kada ste dostupni za rezervacije.",
"copy_times_to": "Kopiraj vremena u",
@@ -112,7 +112,6 @@
"use_link_to_reset_password": "Använd länken nedan för att återställa ditt lösenord",
"hey_there": "Hallå där,",
"forgot_your_password_calcom": "Glömt ditt lösenord? - Cal.com",
"event_type_title": "{{eventTypeTitle}} | Händelsetyp",
"delete_webhook_confirmation_message": "Är du säker på att du vill ta bort denna webhook? Du kommer inte längre att få Calcom mötesdata skickad till angiven URL, i realtid, när en händelse är schemalagd eller avbruten.",
"confirm_delete_webhook": "Ja, ta bort webhook",
"edit_webhook": "Redigera Webhook",
@@ -633,7 +632,6 @@
"billing": "Fakturering",
"manage_your_billing_info": "Hantera din faktureringsinformation och avsluta din prenumeration.",
"availability": "Tillgänglighet",
"availability_title": "{{availabilityTitle}} | Tillgänglighet",
"edit_availability": "Redigera tillgänglighet",
"configure_availability": "Ställ in de tider du är tillgänglig för bokningar.",
"copy_times_to": "Kopiera tider till",
+13 -15
View File
@@ -112,7 +112,6 @@
"use_link_to_reset_password": "Şifrenizi sıfırlamak için aşağıdaki bağlantıyı kullanın",
"hey_there": "Selam,",
"forgot_your_password_calcom": "Şifrenizi mi unuttunuz? - Cal.com",
"event_type_title": "{{eventTypeTitle}} | Etkinlik Türü",
"delete_webhook_confirmation_message": "Bu web kancasını silmek istediğinizden emin misiniz? Bir etkinlik planlandığında veya iptal edildiğinde, Cal.com toplantı verilerini gerçek zamanlı olarak belirli bir URL'de almazsınız.",
"confirm_delete_webhook": "Evet, web kancasını sil",
"edit_webhook": "Web kancasını düzenle",
@@ -633,7 +632,6 @@
"billing": "Fatura",
"manage_your_billing_info": "Fatura bilgilerinizi yönetin ve aboneliğinizi iptal edin.",
"availability": "Müsaitlik",
"availability_title": "{{availabilityTitle}} | Müsaitlik Durumu",
"edit_availability": "Müsaitlik durumunu düzenle",
"configure_availability": "Rezervasyon için uygun olduğunuz zamanları yapılandırın.",
"copy_times_to": "Saatleri şuraya kopyala:",
@@ -1185,13 +1183,13 @@
"additional_notes_info": "Ek rezervasyon notları",
"attendee_name_info": "Rezervasyon yaptıran kişinin adı",
"to": "Kime",
"attendee_required_enter_number": "Bu, katılımcının rezervasyon yapmak için bir telefon numarası girmesini gerektirecektir",
"attendee_required_enter_number": "Bu, katılımcının rezervasyon yapmak için bir telefon numarası girmesini gerektirir",
"workflow_turned_on_successfully": "{{workflowName}} iş akışı başarıyla {{offOn}}",
"download_responses": "Yanıtları İndir",
"create_your_first_form": "İlk formunuzu oluşturun",
"create_your_first_form_description": "Yönlendirme Formları ile niteliksel sorular sorabilir ve bunları doğru kişiye veya etkinlik türüne yönlendirebilirsiniz.",
"create_your_first_webhook": "İlk Web kancanızı oluşturun",
"create_your_first_webhook_description": "Web kancaları ile Cal.com'da bir etkinlik gerçekleştiğinde toplantı verilerini gerçek zamanlı olarak alabilirsiniz.",
"create_your_first_webhook": "İlk Web Kancanızı oluşturun",
"create_your_first_webhook_description": "Web Kancaları ile Cal.com'da bir etkinlik gerçekleştiğinde toplantı verilerini gerçek zamanlı olarak alabilirsiniz.",
"for_a_maximum_of": "Maksimum",
"event_one": "etkinlik",
"event_other": "etkinlik",
@@ -1201,12 +1199,12 @@
"delete_team": "Ekibi Sil",
"team_members": "Ekip üyeleri",
"more": "Daha fazla",
"more_page_footer": "Mobil uygulamayı web uygulamasının bir uzantısı olarak görüyoruz. Karmaşık bir işlem yapıyorsanız, lütfen web uygulamasına geri dönün.",
"more_page_footer": "Mobil uygulamayı web uygulamasının bir uzantısı olarak görüyoruz. Karmaşık bir işlem yapıyorsanız lütfen web uygulamasına geri dönün.",
"workflow_example_1": "Etkinlik başlamadan 24 saat önce katılımcıya SMS hatırlatıcısı gönder",
"workflow_example_2": "Etkinlik yeniden planlandığında katılımcıya özel SMS gönder",
"workflow_example_3": "Yeni bir etkinlik rezervasyonu yapıldığında organizatöre özel bir e-posta gönderin",
"workflow_example_4": "Etkinlikler başlamadan 1 saat önce katılımcıya e-posta hatırlatıcısı gönderin",
"workflow_example_5": "Etkinlik yeniden planlandığında ana bilgisayara özel e-posta gönder",
"workflow_example_5": "Etkinlik yeniden planlandığında organizatöre özel e-posta gönderin",
"workflow_example_6": "Yeni bir etkinlik rezervasyonu yapıldığında organizatöre özel SMS gönderin",
"welcome_to_cal_header": "Cal.com'a hoş geldiniz!",
"edit_form_later_subtitle": "Bunu daha sonra düzenleyebilirsiniz.",
@@ -1226,24 +1224,24 @@
"exchange_authentication_standard": "Temel kimlik doğrulaması",
"exchange_authentication_ntlm": "NTLM kimlik doğrulaması",
"exchange_compression": "GZip sıkıştırma",
"routing_forms_description": "Oluşturduğunuz tüm formları ve rotaları burada görebilirsiniz.",
"routing_forms_description": "Oluşturduğunuz tüm formları ve yönlendirmeleri burada görebilirsiniz.",
"add_new_form": "Yeni form ekle",
"form_description": "Rezervasyon yapan kişiyi yönlendirmek için formunuzu oluşturun",
"copy_link_to_form": "Bağlantıyı forma kopyala",
"theme": "Tema",
"theme_applies_note": "Bu, sadecev genel rezervasyon sayfalarınız için geçerlidir",
"theme_applies_note": "Bu, sadece genel rezervasyon sayfalarınız için geçerlidir",
"theme_light": "Açık",
"theme_dark": "Koyu",
"theme_system": "Sistem varsayılanı",
"add_a_team": "Ekip ekle",
"saml_config": "SAML Yapılandırması",
"add_webhook_description": "Cal.com'da bir etkinlik gerçekleştiğinde gerçek zamanlı olarak toplantı bilgilerini alın",
"add_webhook_description": "Cal.com'da bir etkinlik gerçekleştiğinde toplantı bilgilerini gerçek zamanlı olarak alın",
"triggers_when": "Tetiklenme zamanı",
"test_webhook": "Lütfen oluşturmadan önce ping testi yapın.",
"enable_webhook": "Web kancasını etkinleştir",
"add_webhook": "Web kancası ekle",
"add_webhook": "Web Kancası ekle",
"webhook_edited_successfully": "Web Kancası kaydedildi",
"webhooks_description": "Cal.com'da bir etkinlik gerçekleştiğinde gerçek zamanlı olarak toplantı bilgilerini alın",
"webhooks_description": "Cal.com'da bir etkinlik gerçekleştiğinde toplantı bilgilerini gerçek zamanlı olarak alın",
"api_keys_description": "Kendi hesabınıza erişmek için API anahtarları oluşturun",
"new_api_key": "Yeni API anahtarı",
"active": "Etkin",
@@ -1258,14 +1256,14 @@
"password_reset_email": "{{email}} adresine şifrenizi sıfırlama talimatlarını içeren bir e-posta gönderildi.",
"password_updated": "Şifre güncellendi!",
"pending_payment": "Bekleyen ödeme",
"confirmation_page_rainbow": "Ethereum, Polygon ve diğer token'lar veya NFT ile etkinliğinizi kontrol edin.",
"not_on_cal": "Cal.com'da değil",
"confirmation_page_rainbow": "Ethereum, Polygon ve diğer token'lar veya NFT ile etkinliğinizi kontrol altında tutun.",
"not_on_cal": "Cal.com'da yok",
"no_calendar_installed": "Yüklü takvim yok",
"no_calendar_installed_description": "Henüz hiçbir takviminizi bağlamadınız",
"add_a_calendar": "Takvim ekle",
"change_email_hint": "Değişikliklerin geçerli olduğunu görmek için oturumu kapatıp tekrar açmanız gerekebilir",
"confirm_password_change_email": "Lütfen e-posta adresinizi değiştirmeden önce şifrenizi onaylayın",
"seats": "yer",
"every_app_published": "Cal.com Uygulama Mağazası'nda yayınlanan her uygulama açık kaynak kodludur ve uzman incelemeleriyle kapsamlı bir şekilde test edilmiştir. Cal.com, Cal.com tarafından yayınlanmadıkça bu uygulamaları desteklemez veya onaylamaz. Uygunsuz içerik veya davranışla karşılaşırsanız lütfen bize bildirin.",
"every_app_published": "Cal.com Uygulama Mağazası'nda yayınlanan her uygulama açık kaynak kodludur ve uzman incelemeleriyle kapsamlı bir şekilde test edilmiştir. Cal.com, Cal.com tarafından yayınlanmadıkça bu uygulamaları desteklemez veya onaylamaz. Herhangi bir uygunsuz içerik veya davranışla karşılaşırsanız lütfen bize bildirin.",
"report_app": "Uygulamayı bildir"
}
+24 -2
View File
@@ -112,7 +112,6 @@
"use_link_to_reset_password": "Скористайтеся посиланням нижче, щоб скинути пароль",
"hey_there": "Привіт!",
"forgot_your_password_calcom": "Забули пароль? – Cal.com",
"event_type_title": "{{eventTypeTitle}} | Тип заходу",
"delete_webhook_confirmation_message": "Справді видалити цей вебгук? Ви більше не отримуватимете дані про нараду Cal.com за вказаною URL-адресою: у реальному часі, а також під час планування та скасування.",
"confirm_delete_webhook": "Так, видалити вебгук",
"edit_webhook": "Редагувати вебгук",
@@ -498,6 +497,8 @@
"new_member": "Новий учасник",
"invite": "Запросити",
"add_team_members": "Додати учасників команди",
"add_team_members_description": "Запросіть інших у свою команду",
"add_team_member": "Додати учасника команди",
"invite_new_member": "Запросіть нового учасника",
"invite_new_team_member": "Запросіть когось у свою команду.",
"change_member_role": "Змініть роль учасника команди",
@@ -610,6 +611,7 @@
"create_first_team_and_invite_others": "Створіть свою першу команду та запросіть інших, щоб працювати разом.",
"create_team_to_get_started": "Створіть команду, щоб почати",
"teams": "Команди",
"team": "Команда",
"team_billing": "Виставлення рахунків для команд",
"upgrade_to_flexible_pro_title": "Ми змінили умови оплати для команд",
"upgrade_to_flexible_pro_message": "У вашій команді є учасники без придбаних місць. Перейдіть на план Pro, щоб отримати всі потрібні місця.",
@@ -630,7 +632,9 @@
"billing": "Виставлення рахунків",
"manage_your_billing_info": "Керуйте своїми даними для виставлення рахунків і підписками.",
"availability": "Доступність",
"edit_availability": "Редагувати відомості про доступність",
"configure_availability": "Налаштовуйте свої часові вікна, доступні для бронювання.",
"copy_times_to": "Копіювати час до",
"change_weekly_schedule": "Змініть свій розклад на тиждень",
"logo": "Логотип",
"error": "Помилка",
@@ -645,6 +649,7 @@
"event_name_tooltip": "Ім’я, яке показуватиметься в календарях",
"meeting_with_user": "Нарада з користувачем {ATTENDEE}",
"additional_inputs": "Додаткові поля введення",
"additional_input_description": "Вимагати від особи, що хоче створити бронювання, надавати додаткові відомості",
"label": "Мітка",
"placeholder": "Заповнювач",
"type": "Тип",
@@ -659,6 +664,8 @@
"disable_guests": "Вимкнути гостей",
"disable_guests_description": "Забороніть додати гостей під час бронювання.",
"private_link": "Створити приватне посилання",
"private_link_label": "Приватне посилання",
"private_link_hint": "Після кожного використання ваше приватне посилання створюватиметься повторно",
"copy_private_link": "Копіювати приватне посилання",
"private_link_description": "Створіть приватну URL-адресу, щоб поширювати її, не виказуючи свого імені користувача в Cal",
"invitees_can_schedule": "Запрошені можуть планувати",
@@ -700,16 +707,21 @@
"delete_account_confirmation_message": "Справді видалити обліковий запис Cal.com? Усі, кому ви надавали посилання на свій обліковий запис, більше не зможуть бронювати ваш час за його допомогою. Усі збережені налаштування буде втрачено.",
"integrations": "Інтеграції",
"apps": "Додатки",
"category_apps": "Додатки з категорії «{{category}}»",
"app_store": "App Store",
"app_store_description": "Спілкування та технології на робочому місці.",
"settings": "Параметри",
"event_type_moved_successfully": "Тип події переміщено",
"next_step_text": "Наступний крок",
"next_step": "Пропустити крок",
"prev_step": "Попередній крок",
"install": "Установити",
"installed": "Установлено",
"active_install_one": "{{count}} активна інсталяція",
"active_install_other": "Активних інсталяцій: {{count}}",
"globally_install": "Установлено глобально",
"app_successfully_installed": "Додаток установлено",
"app_could_not_be_installed": "Не вдалося встановити додаток",
"disconnect": "Від’єднати",
"embed_your_calendar": "Вбудуйте календар у свою вебсторінку",
"connect_your_favourite_apps": "Підключіть улюблені застосунки.",
@@ -720,6 +732,7 @@
"connect_additional_calendar": "Підключити додатковий календар",
"conferencing": "Відеоконференції",
"calendar": "Календар",
"payments": "Платежі",
"not_installed": "Не встановлено",
"error_password_mismatch": "Паролі не збігаються.",
"error_required_field": "Це поле обов’язкове.",
@@ -753,9 +766,16 @@
"import_from": "Імпортувати з",
"access_token": "Токен доступу",
"visit_roadmap": "Дорожня карта",
"featured_categories": "Рекомендовані категорії",
"popular_categories": "Популярні категорії",
"number_apps_one": "{{count}} додаток",
"number_apps_other": "Додатків: {{count}}",
"trending_apps": "Популярні додатки",
"explore_apps": "Додатки з категорії «{{category}}»",
"installed_apps": "Установлені додатки",
"no_category_apps": "Немає додатків із категорії «{{category}}»",
"no_category_apps_description_calendar": "Додайте додаток-календар, щоб перевіряти розклад на наявність конфліктів і уникати подвійних бронювань",
"no_category_apps_description_conferencing": "Спробуйте додати програму для конференцій, щоб інтегрувати можливість відеовикликів зі своїми клієнтами",
"empty_installed_apps_headline": "Не встановлено жодних додатків",
"empty_installed_apps_description": "Додатки дають змогу оптимізувати робочий процес і спростити роботу з графіком.",
"empty_installed_apps_button": "Переглянути магазин додатків",
@@ -793,6 +813,7 @@
"set_to_default": "Установити за замовчуванням",
"new_schedule_btn": "Створити розклад",
"add_new_schedule": "Додати новий розклад",
"add_new_calendar": "Додати новий календар",
"delete_schedule": "Видалити розклад",
"schedule_created_successfully": "Розклад «{{scheduleName}}» створено",
"availability_updated_successfully": "Розклад «{{scheduleName}}» оновлено",
@@ -1045,5 +1066,6 @@
"set_ping_link": "Установити Ping-посилання",
"organizer_name_info": "Ваше ім’я",
"theme_light": "Світла",
"theme_dark": "Темна"
"theme_dark": "Темна",
"report_app": "Поскаржитися на додаток"
}
@@ -112,7 +112,6 @@
"use_link_to_reset_password": "Sử dụng đường link dưới đây để thay đổi mật khẩu của bạn",
"hey_there": "Xin chào,",
"forgot_your_password_calcom": "Quên mật khẩu của bạn? - Cal.com",
"event_type_title": "{{eventTypeTitle}} | Loại Sự Kiện",
"delete_webhook_confirmation_message": "Bạn có chắc bạn muốn xoá webhook này? Bạn sẽ không còn nhận dữ liệu cuộc họp Cal.com tại đường URL này, trong thời gian thực, khi một sự kiện được lên lịch hoặc huỷ.",
"confirm_delete_webhook": "Vâng, hãy xoá webhook",
"edit_webhook": "Chỉnh Webhook",
@@ -633,7 +632,6 @@
"billing": "Thanh toán",
"manage_your_billing_info": "Quản lý thông tin thanh toán của bạn và hủy đăng ký của bạn.",
"availability": "Lịch khả dụng",
"availability_title": "{{availabilityTitle}} | Tình trạng trống lịch",
"edit_availability": "Sửa tình trạng trống lịch",
"configure_availability": "Định cấu hình thời gian mà mọi người có thể đặt lịch hẹn.",
"copy_times_to": "Sao chép thời gian đến",
@@ -112,7 +112,6 @@
"use_link_to_reset_password": "使用下面的链接重置您的密码",
"hey_there": "嘿,您好!",
"forgot_your_password_calcom": "忘记密码?- Cal.com",
"event_type_title": "{{eventTypeTitle}} | 活动类型",
"delete_webhook_confirmation_message": "您确定要删除此Webhook吗?当活动被安排或取消时,您将不再会在指定的链接收到 Cal.com 实时提供的会议数据。",
"confirm_delete_webhook": "是,删除 Webhook",
"edit_webhook": "编辑 Webhook",
@@ -633,7 +632,6 @@
"billing": "计费",
"manage_your_billing_info": "管理您的账单信息和取消您的订阅。",
"availability": "可预约时间",
"availability_title": "{{availabilityTitle}} | 可预约时间",
"edit_availability": "编辑可预约时间",
"configure_availability": "配置您可预约的时间。",
"copy_times_to": "复制时间到",
@@ -112,7 +112,6 @@
"use_link_to_reset_password": "使用以下連結重置密碼",
"hey_there": "哈囉,",
"forgot_your_password_calcom": "忘記密碼了? - Cal.com",
"event_type_title": "{{eventTypeTitle}} | 活動類型",
"delete_webhook_confirmation_message": "您確定要刪除這組 Webhook 嗎?之後活動預定或取消的時候,您就不會即時經特定連結收到 Cal.com 的會議資料。",
"confirm_delete_webhook": "是的,刪除 Webhook",
"edit_webhook": "編輯 Webhook",
@@ -633,7 +632,6 @@
"billing": "付費",
"manage_your_billing_info": "管理付費資訊,以及取消訂閱。",
"availability": "開放時間",
"availability_title": "{{availabilityTitle}} | 開放時間",
"edit_availability": "編輯開放時間",
"configure_availability": "設定開放接受預約的時段。",
"copy_times_to": "將時間複製到",
+17 -3
View File
@@ -99,7 +99,7 @@ html.todesktop nav a[aria-current="page"]{
html.todesktop nav a svg{
color: #0272F7 !important
}
}
*/
@@ -153,11 +153,11 @@ button[role="switch"][data-state="checked"] {
}
/* TODO: avoid global specific css */
/* button[role="switch"][data-state="checked"] span {
transform: translateX(16px);
transform: translateX(16px);
} */
/* DateRangePicker */
/*
/*
TODO:: Remove on V2 launch
*/
.react-daterange-picker > .react-daterange-picker__wrapper {
@@ -482,3 +482,17 @@ hr {
opacity: 1;
}
}
/**
* Makes sure h-screen works on mobile Safari. By default h-screen
* does not take into account the height of the address bar, causing
* weird behaviour when scrolling — sometimes the height will be correct
* and sometimes it won't, depending on whether the address bar is
* in 'collapsed' state or not.
* @see: https://benborgers.com/posts/tailwind-h-screen
*/
@supports (-webkit-touch-callout: none) {
.h-screen {
height: -webkit-fill-available;
}
}
@@ -1,4 +1,4 @@
import { useMutation } from "react-query";
import { useMutation } from "@tanstack/react-query";
import type { IntegrationOAuthCallbackState } from "@calcom/app-store/types";
import { WEBAPP_URL } from "@calcom/lib/constants";
@@ -9,4 +9,10 @@ items:
<Slider items={items} />
Close is the inside sales CRM of choice for startups and SMBs. Make more calls, send more emails and close more deals starting today.
- Close is a modern CRM with build-in sales communication tools for email, phone, SMS, and meetings.
- Automate the sales process by enrolling leads and contacts into sequences.
- Track the entire sales process and performance with powerful activity and funnel reporting
Close.com subscriptions range from $29 - $149 per month. <a href="https://www.close.com/pricing" target="_blank">See pricing page</a>
@@ -60,7 +60,7 @@ function NewFormDialog({ appUrl }: { appUrl: string }) {
const router = useRouter();
const utils = trpc.useContext();
const mutation = trpc.useMutation("viewer.app_routing_forms.form", {
const mutation = trpc.useMutation("viewer.app_routing_forms.formMutation", {
onSuccess: (_data, variables) => {
utils.invalidateQueries("viewer.app_routing_forms.forms");
router.push(`${appUrl}/form-edit/${variables.id}`);
@@ -223,7 +223,7 @@ export function FormActionsProvider({ appUrl, children }: { appUrl: string; chil
const [deleteDialogFormId, setDeleteDialogFormId] = useState<string | null>(null);
const router = useRouter();
const toggleMutation = trpc.useMutation("viewer.app_routing_forms.form", {
const toggleMutation = trpc.useMutation("viewer.app_routing_forms.formMutation", {
onError: () => {
showToast(`Something went wrong`, "error");
},
@@ -194,7 +194,7 @@ export default function SingleForm({
const utils = trpc.useContext();
const router = useRouter();
const mutation = trpc.useMutation("viewer.app_routing_forms.form", {
const mutation = trpc.useMutation("viewer.app_routing_forms.formMutation", {
onSuccess() {
router.replace(router.asPath);
showToast("Form updated successfully.", "success");
@@ -203,7 +203,7 @@ export default function SingleForm({
showToast(`Something went wrong`, "error");
},
onSettled() {
utils.invalidateQueries(["viewer.app_routing_forms.form"]);
utils.invalidateQueries(["viewer.app_routing_forms.formQuery"]);
},
});
return (
@@ -109,7 +109,7 @@ function RoutingForm({ form, profile }: inferSSRProps<typeof getServerSideProps>
<form onSubmit={handleOnSubmit}>
<div className="mb-8">
<h1 className="font-cal mb-1 text-xl font-bold capitalize tracking-wide text-gray-900 dark:text-white">
<h1 className="font-cal mb-1 text-xl font-bold tracking-wide text-gray-900 dark:text-white">
{form.name}
</h1>
{form.description ? (
@@ -154,7 +154,7 @@ const app_RoutingForms = createRouter()
});
},
})
.query("form", {
.query("formQuery", {
input: z.object({
id: z.string(),
}),
@@ -169,7 +169,7 @@ const app_RoutingForms = createRouter()
return form;
},
})
.mutation("form", {
.mutation("formMutation", {
input: z.object({
id: z.string(),
name: z.string(),
@@ -1,6 +1,6 @@
import { ClockIcon } from "@heroicons/react/outline";
import { useMutation } from "@tanstack/react-query";
import { Dispatch, SetStateAction, useState } from "react";
import { useMutation } from "react-query";
import dayjs from "@calcom/dayjs";
import { useLocale } from "@calcom/lib/hooks/useLocale";
+1 -1
View File
@@ -4,7 +4,7 @@
"name": "@calcom/zapier",
"version": "0.0.0",
"main": "./index.ts",
"description": "Workflow automation for everyone. Use the Cal.com Zapier app to trigger your workflows when a booking was created, rescheduled or cancled.",
"description": "Workflow automation for everyone. Use the Cal.com Zapier app to trigger your workflows when a booking was created, rescheduled or cancelled.",
"dependencies": {
"@calcom/lib": "*",
"node-schedule": "2.1.0"
+15
View File
@@ -154,6 +154,21 @@ module.exports = {
900: "#f3f4f6",
},
},
keyframes: {
"fade-in-up": {
"0%": {
opacity: 0.75,
transform: "translateY(20px)",
},
"100%": {
opacity: 1,
transform: "translateY(0)",
},
},
},
animation: {
"fade-in-up": "fade-in-up 0.35s cubic-bezier(.21,1.02,.73,1)",
},
boxShadow: {
dropdown: "0px 2px 6px -1px rgba(0, 0, 0, 0.08)",
},
+72 -29
View File
@@ -5,23 +5,22 @@ import cache from "memory-cache";
import { getCalendar } from "@calcom/app-store/_utils/getCalendar";
import getApps from "@calcom/app-store/utils";
import { sendBrokenIntegrationEmail } from "@calcom/emails";
import { getUid } from "@calcom/lib/CalEventParser";
import { getErrorFromUnknown } from "@calcom/lib/errors";
import logger from "@calcom/lib/logger";
import { performance } from "@calcom/lib/server/perfObserver";
import { App } from "@calcom/types/App";
import type { CalendarEvent, EventBusyDate, NewCalendarEventType } from "@calcom/types/Calendar";
import type { EventResult } from "@calcom/types/EventManager";
const log = logger.getChildLogger({ prefix: ["CalendarManager"] });
export const getCalendarCredentials = (credentials: Array<Credential>, userId: number) => {
export const getCalendarCredentials = (credentials: Array<Credential>) => {
const calendarCredentials = getApps(credentials)
.filter((app) => app.type.endsWith("_calendar"))
.flatMap((app) => {
const credentials = app.credentials.flatMap((credential) => {
const calendar = getCalendar(credential);
return [{ integration: app, credential, calendar }];
return app.variant === "calendar" ? [{ integration: app, credential, calendar }] : [];
});
return credentials.length ? credentials : [];
});
@@ -35,41 +34,85 @@ export const getConnectedCalendars = async (
) => {
const connectedCalendars = await Promise.all(
calendarCredentials.map(async (item) => {
const { calendar, integration, credential } = item;
const credentialId = credential.id;
if (!calendar) {
try {
const { calendar, integration, credential } = item;
// Don't leak credentials to the client
const credentialId = credential.id;
if (!calendar) {
return {
integration,
credentialId,
};
}
const cals = await calendar.listCalendars();
const calendars = _(cals)
.map((cal) => ({
...cal,
readOnly: cal.readOnly || false,
primary: cal.primary || null,
isSelected: selectedCalendars.some((selected) => selected.externalId === cal.externalId),
credentialId,
}))
.sortBy(["primary"])
.value();
const primary = calendars.find((item) => item.primary) ?? calendars.find((cal) => cal !== undefined);
if (!primary) {
return {
integration,
credentialId,
error: {
message: "No primary calendar found",
},
};
}
return {
integration,
integration: cleanIntegrationKeys(integration),
credentialId,
primary,
calendars,
};
} catch (error) {
let errorMessage = "Could not get connected calendars";
// Here you can expect for specific errors
if (error instanceof Error) {
if (error.message === "invalid_grant") {
errorMessage = "Access token expired or revoked";
}
}
return {
integration: cleanIntegrationKeys(item.integration),
credentialId: item.credential.id,
error: {
message: errorMessage,
},
};
}
const cals = await calendar.listCalendars();
const calendars = _(cals)
.map((cal) => ({
...cal,
readOnly: cal.readOnly || false,
primary: cal.primary || null,
isSelected: selectedCalendars.some((selected) => selected.externalId === cal.externalId),
credentialId,
}))
.sortBy(["primary"])
.value();
const primary = calendars.find((item) => item.primary) ?? calendars[0];
if (!primary) {
throw new Error("No primary calendar found");
}
return {
integration,
credentialId,
primary,
calendars,
};
})
);
return connectedCalendars;
};
/**
* Important function to prevent leaking credentials to the client
* @param appIntegration
* @returns App
*/
const cleanIntegrationKeys = (
appIntegration: ReturnType<typeof getCalendarCredentials>[number]["integration"] & {
credentials?: Array<Credential>;
credential: Credential;
}
) => {
// eslint-disable-next-line @typescript-eslint/no-unused-vars
const { credentials, credential, ...rest } = appIntegration;
return rest;
};
const CACHING_TIME = 30_000; // 30 seconds
const getCachedResults = async (
@@ -11,7 +11,7 @@ import { sdkActionManager, useIsEmbed } from "@calcom/embed-core/embed-iframe";
import { WEBSITE_URL } from "@calcom/lib/constants";
import { useLocale } from "@calcom/lib/hooks/useLocale";
import useTheme from "@calcom/lib/hooks/useTheme";
import { isBrowserLocale24h } from "@calcom/lib/timeFormat";
import { getIs24hClockFromLocalStorage, isBrowserLocale24h } from "@calcom/lib/timeFormat";
import { Icon } from "@calcom/ui/Icon";
import type { PaymentPageProps } from "../pages/payment";
@@ -26,7 +26,7 @@ const PaymentPage: FC<PaymentPageProps> = (props) => {
useEffect(() => {
let embedIframeWidth = 0;
setDate(date.tz(localStorage.getItem("timeOption.preferredTimeZone") || dayjs.tz.guess()));
setIs24h(!!localStorage.getItem("timeOption.is24hClock"));
setIs24h(!!getIs24hClockFromLocalStorage());
if (isEmbed) {
requestAnimationFrame(function fixStripeIframe() {
// HACK: Look for stripe iframe and center position it just above the embed content
@@ -91,9 +91,15 @@ const CreateANewTeamForm = (props: { nextStep: () => void; setTeamId: (teamId: n
)}
/>
</div>
<Button type="submit" EndIcon={Icon.FiArrowRight} className="w-full justify-center">
{t("continue")}
</Button>
<div className="flex space-x-2">
<Button color="secondary" href="/settings" className="w-full justify-center">
{t("cancel")}
</Button>
<Button color="primary" type="submit" EndIcon={Icon.FiArrowRight} className="w-full justify-center">
{t("continue")}
</Button>
</div>
{createTeamMutation.isError && <p className="mt-4 text-red-700">{createTeamMutation.error.message}</p>}
</Form>
);
@@ -28,11 +28,11 @@ export const AddVariablesDropdown = (props: IAddVariablesDropdown) => {
return (
<Dropdown>
<DropdownMenuTrigger className="px-0 py-0 focus:bg-transparent focus:ring-transparent focus:ring-offset-0 ">
<Label>
<div className="flex">
<DropdownMenuTrigger className="focus:bg-transparent focus:ring-transparent focus:ring-offset-0 ">
<Label className="mb-0">
<div className="flex items-center">
{t("add_variable")}
<Icon.FiChevronDown className="mt-[1.8px] ml-1 h-4 w-4" />
<Icon.FiChevronDown className="ml-1 h-4 w-4" />
</div>
</Label>
</DropdownMenuTrigger>
@@ -48,7 +48,7 @@ export const AddVariablesDropdown = (props: IAddVariablesDropdown) => {
onClick={() => props.addVariable(props.isEmailSubject, t(`${variable}_workflow`))}>
<div className="md:grid md:grid-cols-2">
<div className="mr-3 text-left md:col-span-1">
{`{${t(`${variable}_workflow`).toUpperCase().replace(" ", "_")}}`}
{`{${t(`${variable}_workflow`).toUpperCase().replace(/ /g, "_")}}`}
</div>
<div className="invisible text-left text-gray-600 md:visible md:col-span-1">
{t(`${variable}_info`)}
@@ -8,11 +8,12 @@ import { useLocale } from "@calcom/lib/hooks/useLocale";
import { HttpError } from "@calcom/lib/http-error";
import { trpc } from "@calcom/trpc/react";
import { Icon } from "@calcom/ui";
import { Button, Loader, showToast, Switch, Tooltip } from "@calcom/ui/v2";
import { Button, showToast, Switch, Tooltip } from "@calcom/ui/v2";
import LicenseRequired from "../../../common/components/v2/LicenseRequired";
import { getActionIcon } from "../../lib/getActionIcon";
import EmptyScreen from "./EmptyScreen";
import SkeletonLoader from "./SkeletonLoaderEventWorkflowsTab";
import { WorkflowType } from "./WorkflowListPage";
type ItemProps = {
@@ -213,7 +214,7 @@ function EventWorkflowsTab(props: Props) {
/>
)
) : (
<Loader />
<SkeletonLoader />
)}
</LicenseRequired>
);
@@ -0,0 +1,38 @@
import { Icon } from "@calcom/ui";
import { SkeletonAvatar, SkeletonText } from "@calcom/ui/v2";
function SkeletonLoader() {
return (
<ul className="mt-4 animate-pulse divide-neutral-200 bg-white sm:overflow-hidden">
<SkeletonItem />
<SkeletonItem />
</ul>
);
}
export default SkeletonLoader;
function SkeletonItem() {
return (
<li className="group mb-4 flex h-[90px] w-full items-center justify-between rounded-md border border-gray-200 px-4 py-4 sm:px-6">
<div className="flex-grow truncate text-sm">
<div className="flex">
<SkeletonAvatar className="h-10 w-10" />
<div className="mt-1 ml-4 flex flex-col space-y-1">
<SkeletonText className="h-5 w-20 sm:w-24" />
<div className="flex">
<SkeletonText className="mr-2 h-4 w-16 sm:w-28" />
</div>
</div>
</div>
</div>
<div className="mt-0 flex flex-shrink-0 sm:ml-5">
<div className="flex justify-between space-x-2 rtl:space-x-reverse">
<SkeletonText className="h-8 w-8 sm:w-16" />
<SkeletonText className="h-8 w-8 sm:w-16" />
</div>
</div>
</li>
);
}
@@ -80,7 +80,7 @@ export default function WorkflowDetailsPage(props: Props) {
return (
<>
<div className="my-8 sm:my-0 md:flex">
<div className="pl-2 pr-3 md:pl-0">
<div className="pl-2 pr-3 md:sticky md:top-6 md:h-0 md:pl-0">
<div className="mb-5">
<TextField label={`${t("workflow_name")}:`} type="text" {...form.register("name")} />
</div>
@@ -116,7 +116,7 @@ export default function WorkflowDetailsPage(props: Props) {
</div>
{/* Workflow Trigger Event & Steps */}
<div className="w-full rounded-md border border-gray-200 bg-gray-50 p-3 py-5 md:ml-3 md:max-h-[calc(100vh-116px)] md:overflow-scroll md:p-8">
<div className="w-full rounded-md border border-gray-200 bg-gray-50 p-3 py-5 md:ml-3 md:p-8">
{form.getValues("trigger") && (
<div>
<WorkflowStepContainer form={form} />
@@ -86,14 +86,14 @@ export default function WorkflowStepContainer(props: WorkflowStepProps) {
const cursorPosition = refEmailSubject?.current?.selectionStart || currentEmailSubject.length;
const subjectWithAddedVariable = `${currentEmailSubject.substring(0, cursorPosition)}{${variable
.toUpperCase()
.replace(" ", "_")}}${currentEmailSubject.substring(cursorPosition)}`;
.replace(/ /g, "_")}}${currentEmailSubject.substring(cursorPosition)}`;
form.setValue(`steps.${step.stepNumber - 1}.emailSubject`, subjectWithAddedVariable);
} else {
const currentMessageBody = refReminderBody?.current?.value || "";
const cursorPosition = refReminderBody?.current?.selectionStart || currentMessageBody.length;
const messageWithAddedVariable = `${currentMessageBody.substring(0, cursorPosition)}{${variable
.toUpperCase()
.replace(" ", "_")}}${currentMessageBody.substring(cursorPosition)}`;
.replace(/ /g, "_")}}${currentMessageBody.substring(cursorPosition)}`;
form.setValue(`steps.${step.stepNumber - 1}.reminderBody`, messageWithAddedVariable);
}
}
@@ -327,11 +327,11 @@ export default function WorkflowStepContainer(props: WorkflowStepProps) {
/>
</div>
{isCustomReminderBodyNeeded && (
<div className="mt-2 rounded-md bg-gray-50 p-2 md:p-4">
<div className="mt-2 rounded-md bg-gray-50 p-4 pt-2 md:p-6 md:pt-4">
{isEmailSubjectNeeded && (
<div className="mb-5">
<div className="flex">
<Label className="flex-none">{t("subject")}</Label>
<div className="mb-2 flex items-center">
<Label className="mb-0 flex-none">{t("subject")}</Label>
<div className="flex-grow text-right">
<AddVariablesDropdown addVariable={addVariable} isEmailSubject={true} />
</div>
@@ -353,8 +353,8 @@ export default function WorkflowStepContainer(props: WorkflowStepProps) {
)}
</div>
)}
<div className="flex">
<Label className="flex-none">
<div className="mb-2 flex items-center">
<Label className="mb-0 flex-none">
{isEmailSubjectNeeded ? t("email_body") : t("text_message")}
</Label>
<div className="flex-grow text-right">
@@ -481,15 +481,15 @@ export default function WorkflowStepContainer(props: WorkflowStepProps) {
</ConfirmationDialogContent>
</Dialog>
<Dialog open={isAdditionalInputsDialogOpen} onOpenChange={setIsAdditionalInputsDialogOpen}>
<DialogContent useOwnActionButtons type="creation" className="sm:max-w-[600px] md:h-[570px]">
<div className="-m-3 h-[440px] overflow-x-hidden overflow-y-scroll sm:m-0">
<DialogContent useOwnActionButtons type="creation" className="sm:max-w-[610px] md:h-[570px]">
<div className="-m-3 h-[430px] overflow-x-hidden overflow-y-scroll sm:m-0">
<h1 className="w-full text-xl font-semibold ">{t("how_additional_inputs_as_variables")}</h1>
<div className="mt-7 rounded-md bg-gray-50 p-3 sm:p-5">
<div className="mb-7 mt-7 rounded-md bg-gray-50 p-3 sm:p-4">
<p className="test-sm font-medium">{t("format")}</p>
<ul className="mt-2 ml-5 list-disc text-gray-900">
<li>{t("uppercase_for_letters")}</li>
<li>{t("replace_whitespaces_underscores")}</li>
<li>{t("ingore_special_characters")}</li>
<li>{t("ignore_special_characters")}</li>
</ul>
<div className="mt-6">
<p className="test-sm w-full font-medium">{t("example_1")}</p>
@@ -526,7 +526,7 @@ export default function WorkflowStepContainer(props: WorkflowStepProps) {
</div>
</div>
</div>
<div className="mt-3 -mb-7 flex flex-row-reverse gap-x-2">
<div className="flex flex-row-reverse">
<DialogClose asChild>
<Button color="primary" type="button">
{t("close")}
@@ -45,12 +45,12 @@ export function translateVariablesToEnglish(text: string, language: { locale: st
originalVariables.forEach((originalVariable) => {
const newVariableName = variable.replace("_NAME", "");
if (
language.t(originalVariable).replace(/ /, "_").toUpperCase() === variable ||
language.t(originalVariable).replace(/ /, "_").toUpperCase() === newVariableName
language.t(originalVariable).replace(/ /g, "_").toUpperCase() === variable ||
language.t(originalVariable).replace(/ /g, "_").toUpperCase() === newVariableName
) {
newText = newText.replace(
variable,
language.t(originalVariable, { lng: "en" }).replace(" ", "_").toUpperCase()
language.t(originalVariable, { lng: "en" }).replace(/ /g, "_").toUpperCase()
);
return;
}
@@ -53,7 +53,9 @@ const WebhookForm = (props: {
const triggerOptions = [...WEBHOOK_TRIGGER_EVENTS_GROUPED_BY_APP_V2["core"]];
if (apps) {
for (const app of apps) {
triggerOptions.push(...WEBHOOK_TRIGGER_EVENTS_GROUPED_BY_APP_V2[app]);
if (WEBHOOK_TRIGGER_EVENTS_GROUPED_BY_APP_V2[app]) {
triggerOptions.push(...WEBHOOK_TRIGGER_EVENTS_GROUPED_BY_APP_V2[app]);
}
}
}
const translatedTriggerOptions = triggerOptions.map((option) => ({ ...option, label: t(option.label) }));
+15
View File
@@ -221,6 +221,20 @@ export default abstract class BaseCalendarService implements Calendar {
}
}
isValidFormat = (url: string): boolean => {
const acceptedFormats = ["eml", "ics"];
const urlFormat = url.split(".").pop();
if (urlFormat === undefined) {
console.error("Invalid request, calendar object extension missing");
return false;
}
if (!acceptedFormats.includes(urlFormat)) {
console.error(`Unsupported calendar object format: ${urlFormat}`);
return false;
}
return true;
};
async getAvailability(
dateFrom: string,
dateTo: string,
@@ -232,6 +246,7 @@ export default abstract class BaseCalendarService implements Calendar {
.filter((sc) => ["caldav_calendar", "apple_calendar"].includes(sc.integration ?? ""))
.map((sc) =>
fetchCalendarObjects({
urlFilter: (url: string) => this.isValidFormat(url),
calendar: {
url: sc.externalId,
},
+17 -5
View File
@@ -6,12 +6,24 @@
*/
import { localStorage } from "@calcom/lib/webstorage";
const is24hLocalstorageKey = "timeOption.is24hClock";
export const setIs24hClockInLocalStorage = (is24h: boolean) =>
localStorage.setItem(is24hLocalstorageKey, is24h.toString());
export const getIs24hClockFromLocalStorage = () => {
const is24hFromLocalstorage = localStorage.getItem(is24hLocalstorageKey);
if (is24hFromLocalstorage === null) return null;
return is24hFromLocalstorage === "true";
};
export const isBrowserLocale24h = () => {
const localStorageTimeFormat = localStorage.getItem("timeOption.is24hClock");
const localStorageTimeFormat = getIs24hClockFromLocalStorage();
// If time format is already stored in the browser then retrieve and return early
if (localStorageTimeFormat === "true") {
if (localStorageTimeFormat === true) {
return true;
} else if (localStorageTimeFormat === "false") {
} else if (localStorageTimeFormat === false) {
return false;
}
@@ -19,10 +31,10 @@ export const isBrowserLocale24h = () => {
if (typeof window !== "undefined" && navigator) locale = window.navigator?.language;
if (!new Intl.DateTimeFormat(locale, { hour: "numeric" }).format(0).match(/M/)) {
localStorage.setItem("timeOption.is24hClock", "false");
setIs24hClockInLocalStorage(false);
return false;
} else {
localStorage.setItem("timeOption.is24hClock", "true");
setIs24hClockInLocalStorage(true);
return true;
}
};
+5 -4
View File
@@ -6,10 +6,11 @@
"version": "1.0.0",
"main": "index.ts",
"dependencies": {
"@trpc/client": "^9.27.0",
"@trpc/next": "^9.27.0",
"@trpc/react": "^9.27.0",
"@trpc/server": "^9.27.0",
"@tanstack/react-query": "^4.3.9",
"@trpc/client": "^10.0.0-proxy-beta.5",
"@trpc/next": "^10.0.0-proxy-beta.5",
"@trpc/react": "^10.0.0-proxy-beta.5",
"@trpc/server": "^10.0.0-proxy-beta.5",
"superjson": "1.9.1",
"zod": "^3.18.0"
}
+4 -1
View File
@@ -1,6 +1,7 @@
import superjson from "superjson";
import { createReactQueryHooks } from "../react";
import { createReactQueryHooks } from "@trpc/react";
// ℹ️ Type-only import:
// https://www.typescriptlang.org/docs/handbook/release-notes/typescript-3-8.html#type-only-imports-and-export
import type { inferProcedureInput, inferProcedureOutput } from "../server";
@@ -12,6 +13,8 @@ import type { AppRouter } from "../server/routers/_app";
*/
export const trpc = createReactQueryHooks<AppRouter>();
export const proxy = trpc.proxy;
export const transformer = superjson;
/**
* This is a helper method to infer the output of a query resolver

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