Compare commits

...
697 Commits
Author SHA1 Message Date
zomars 70a31874f0 v1.7.4 2022-06-28 17:12:56 -06:00
zomars fe8b0fc5f8 Possible timeout fix take 3 2022-06-28 16:53:14 -06:00
zomars 2983fb4c12 Fixes month name 2022-06-28 16:24:53 -06:00
zomars 03cc4855a8 Update package.json 2022-06-28 16:01:50 -06:00
zomars c82a9853d2 Submodule sync 2022-06-28 15:58:14 -06:00
zomars d732a984c2 Merge branch 'main' of https://github.com/calcom/cal.com 2022-06-28 15:46:17 -06:00
zomars 826583f404 Second potential fix for timeout 2022-06-28 15:46:07 -06:00
zomars b6dd0d5804 Remove SSG prefetch 2022-06-28 15:32:40 -06:00
Leo Giovanetti df2c3c42bf Recurring config missing from event (#3182) 2022-06-28 18:04:44 -03:00
zomars 7122a4a91d Consolidates dayjs in a single package 2022-06-28 14:48:24 -06:00
zomars 5be669a479 Update zod-utils.ts 2022-06-28 13:33:55 -06:00
zomars 8629d92a64 Merge branch 'main' of https://github.com/calcom/cal.com 2022-06-28 13:18:53 -06:00
zomars 840b6c498a Potential fix for availability timeout 2022-06-28 13:18:47 -06:00
zomars 7a8b9e5f32 Potential fix for availability timeout 2022-06-28 13:17:43 -06:00
zomars fe50f04075 Only stale SSR requests 2022-06-28 11:37:01 -06:00
Leo Giovanetti e1e369de9e Hotfix: Fixing app types variants (fixes Hubspot) (#3176)
* Fixing Hubspot

* Comment
2022-06-28 16:36:19 +00:00
9b2ad3f350 Negative days in trial license period (#3133)
* Negative days in trial license period

* Update apps/web/public/static/locales/en/common.json

Co-authored-by: gitstart <gitstart@users.noreply.github.com>
Co-authored-by: Peer Richelsen <peeroke@gmail.com>
Co-authored-by: Omar López <zomars@me.com>
2022-06-28 10:03:31 -06:00
GlitchWitch 83dfafb8a1 Create SECURITY.md (#3174)
* Create SECURITY.md

Creates a SECURITY.md file based on https://cal.com/security

* Update markdown formatting
2022-06-28 17:24:11 +02:00
2cd7ddcdbe New Crowdin translations by Github Action (#3173)
Co-authored-by: Crowdin Bot <support+bot@crowdin.com>
Co-authored-by: Peer Richelsen <peeroke@gmail.com>
2022-06-28 15:27:29 +02:00
Esteban Dalel R 2fa9ea4501 Fix broken link (#3172) 2022-06-28 11:48:16 +01:00
Peer Richelsen 6fff27b5ad Update README.md 2022-06-28 09:54:37 +02:00
zomars 0794224288 Prevents undefined classNames in Skeletons 2022-06-27 21:04:10 -06:00
alannnc e3e1de3c11 Fix saving price and currency (#3168) 2022-06-27 20:31:25 -06:00
zomars 52759333fd Skeleton fixes 2022-06-27 20:25:06 -06:00
zomars e27a2bafcd AvailabilityPage cleanup 2022-06-27 20:17:23 -06:00
zomars 87befdbdf4 Adds perf metrics for each tRPC endpoint 2022-06-27 19:19:33 -06:00
zomars 2ba8f99302 v1.7.3 2022-06-27 18:08:18 -06:00
github-actions[bot]andCrowdin Bot e7b634419b New Crowdin translations by Github Action (#3166)
Co-authored-by: Crowdin Bot <support+bot@crowdin.com>
2022-06-27 18:06:39 -06:00
zomars de0cb867d1 DatePicker Skeleton visibility improvements 2022-06-27 18:04:59 -06:00
zomars 02571aabe0 Fixes yarn dx not setting up docker DB 2022-06-27 17:58:59 -06:00
58b2a6425a AvailabilityPage improvements (#3118)
* Share WIP

* Embed tests fixes

* AvailabilityPage improvements

* Type fixes

* Fixes Datepicker day witdth

* Update troubleshoot.tsx

* Adds local cached slots and browsingDate

* Migrating DatePicker to use Dayjs for timeZone support

* Fixed Sunday not being available

* Added comment to clarify what is going on

* Minor bugfix in DatePicker, double empty slot markup

* Change selected date with URL through ?date..

* Initialize properly w/o query params, remove minDate for now

* Remove Loader as now using Skeleton

* Handle Etc/GMT edge case (not a timeZone)

* Added dark mode bg- color to SkeletonText + made text slightly more subtle on DatePicker

Co-authored-by: zomars <zomars@me.com>
Co-authored-by: Peer Richelsen <peeroke@gmail.com>
2022-06-27 21:01:46 +00:00
Peer Richelsen 2c2261f085 remove duplicate datepicker, slight changes to success page (#3163)
* removed duplicate timezone dropdown

* minor fixes to success page and booking layout

* nit
2022-06-27 17:23:20 +00:00
alannnc 9a3624bb9a fix/request-reschedule-google-calendar-sync (#3157)
* Pass calendarId as parameter to deleteEvent()

* Updated deleteEvent param and default when sending calendarId
2022-06-27 08:52:42 -06:00
3449ad1a9f Apps: Riverside/Whereby/Around (#3053)
* Add Whereby Boilerplate

* Whereby App

* around boilerplate

* AroundCo App

* Add Riverside App

* Add Riverside to details

* Fix URL validation

* Remove Icons

* Remove console.log

* revert merge

* Fix images

* Update Iconds to be SVG

* Add Disconnect button

* Fix type

* Fixing i18n merge

* Refactor app installations

* Update varient

* Update default responder + riverside logo

* Update apps/web/pages/event-types/[type].tsx

Co-authored-by: Peer Richelsen <peeroke@gmail.com>
Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com>
Co-authored-by: Omar López <zomars@me.com>
2022-06-27 12:17:38 +02:00
Carina WollendorferandCarinaWolli 44f0893674 set right variable for name in hi_user_name (#3162)
Co-authored-by: CarinaWolli <wollencarina@gmail.com>
2022-06-27 09:50:03 +00:00
github-actions[bot]andCrowdin Bot af6f33c709 New Crowdin translations by Github Action (#3156)
Co-authored-by: Crowdin Bot <support+bot@crowdin.com>
2022-06-25 22:49:35 +02:00
zomars 942b8da124 Update yarn.lock 2022-06-25 14:02:31 -06:00
zomars 87efab5b2b Submodule sync 2022-06-25 14:02:26 -06:00
Bailey Pumfleetandzomars f16f9466cb Update Prisma to v3.15.2 to support data proxy (#3124)
* Update Prisma to v3.15.2 to support data proxy

* Update package.json

* Update package.json

* Update package.json

* Update yarn.lock

* Update console

* Update turbo.json

Co-authored-by: zomars <zomars@me.com>
2022-06-25 20:01:02 +00:00
zomars ddd62d3729 Create manifest.json 2022-06-25 10:51:08 -06:00
zomars 862feb2bc4 Delete manifest.json 2022-06-25 10:38:19 -06:00
zomars 79556f1d13 Upgrades turbo and adds snaplet configs 2022-06-25 10:14:53 -06:00
5ec4b7ad37 feat: adds new version endpoint in internal api (#3155)
Co-authored-by: Agusti Fernandez Pardo <git@agusti.me>
Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com>
2022-06-25 05:37:29 +00:00
zomars 3605fca9a4 Submodule sync 2022-06-24 23:27:29 -06:00
Peer Richelsen 7874ff9c6d removed hardcoded url for non-cal.com (#3120) 2022-06-24 23:25:17 -06:00
02e5ec37e7 Broken Integration Alarm System (#3135)
* Create broken integration email

* Send video on broken video link

* Add translations

* Add Trans components

* Remove calendars file

* Type fixes

* Add translations

* Fix type errors

* Fix Spanish translation

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

* Remove iCal event

* Locale fixes

* Clean up trans tag

* Apply suggested translation

Co-authored-by: Bailey Pumfleet <pumfleet@hey.com>

* Change email to en

* Fix type error

* Type fix

* Fix e2e

* Fix e2e

* Fix e2e

* Fix e2e

* Fix e2e

* Update webhookResponse-chromium.txt

Co-authored-by: Omar López <zomars@me.com>
Co-authored-by: Bailey Pumfleet <pumfleet@hey.com>
2022-06-24 23:16:20 -06:00
fd863b2ae7 Removed the Spinner in favour of a DatePicker skeleton loader (#3146)
* Removed the Spinner in favour of a DatePicker skeleton loader

* removed number, lighter skeleton, dark mode fixes

* replaced button with div

* readded number

Co-authored-by: Peer Richelsen <peer@cal.com>
Co-authored-by: Peer Richelsen <peeroke@gmail.com>
2022-06-25 00:45:38 +02:00
sean-brydonandPeer Richelsen 13b5618a71 Teams skeleton loader (#3148)
* Teams skeleton loader

* [id] skeleton

* Fix mt

Co-authored-by: Peer Richelsen <peeroke@gmail.com>
2022-06-25 00:44:49 +02:00
github-actions[bot]andCrowdin Bot 643b46aa8f New Crowdin translations by Github Action (#3117)
Co-authored-by: Crowdin Bot <support+bot@crowdin.com>
2022-06-24 21:57:44 +02:00
Hariom Balhara 06b7744b30 Fixes over Turborepo improvements (#3144) 2022-06-24 09:38:17 -06:00
zomars 7f53c4288d Prevents 404 in networks tab for TRIAL users 2022-06-24 09:27:52 -06:00
zomars 7be60b47f1 Runs format script 2022-06-24 07:37:56 -06:00
zomars bc88fd0a04 Fixes local dev env checks 2022-06-24 07:35:39 -06:00
zomars 60c989432e Update .gitignore 2022-06-24 07:35:34 -06:00
d1b791518e save appId in zoom callback (#3145)
Co-authored-by: CarinaWolli <wollencarina@gmail.com>
Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com>
2022-06-23 16:00:39 -06:00
zomars 39f6ef8dcd Submodule sync 2022-06-23 14:07:05 -06:00
Peer Richelsen 777d260d78 scroll to times after clicking a day, two column layout mobile (#3147) 2022-06-23 12:36:23 -06:00
zomars 7f6a9cf555 Embed tests fixes 2022-06-22 15:12:57 -06:00
Omar López 21fb0fc3a3 Turborepo improvements (#3139)
* WIP

* WIP

* Embed fixes

* Update turbo.json

* Update e2e-embed.yml

* E2E fixes

* Update turbo.json

* App store CLI cleanup

* Update turbo.json

* Update turbo.json

* Update turbo.json

* Update turbo.json

* Update turbo.json

* Update turbo.json
2022-06-22 14:41:19 -06:00
zomars 1e7eac4133 Create .gitkeep 2022-06-22 12:55:46 -06:00
alannnc fef6f3baff Fix/zoom response zod object (#3141)
* Added deepPartial to zodResultSchema

* Adding passtrough to zoomResponseSchema
2022-06-22 12:41:40 -06:00
Alex van Andel 6f354e0c7f Migration query + Schedule->EventType to EventType->Schedule (#3140)
* Wrote migration query + change Schedule->EventType to EventType->Schedule

* Removed warning as it is not strictly true
2022-06-22 09:43:25 -06:00
Peer Richelsenandsean-brydon 40a18243e4 padding fixes to menu and other improvements (#3114)
* padding fixes to menu and other improvements

* nit

* nit

Co-authored-by: sean-brydon <55134778+sean-brydon@users.noreply.github.com>
2022-06-22 11:25:43 +01:00
alannnc 43f1e86322 Remove spacebooking from app-store (#3119)
* Remove spacebooking from app-store

* Remove missing spacebooking variable
2022-06-21 22:58:07 +02:00
Hariom Balhara 2f5928be84 Fix ordering of event-types (#3126) 2022-06-21 11:00:14 -06:00
Carina WollendorferandCarinaWolli d7cd6e011e fix redirect to upcoming booking (#3129)
Co-authored-by: CarinaWolli <wollencarina@gmail.com>
2022-06-21 14:57:04 +00:00
Hariom Balharaandkodiakhq[bot] 993bd18a73 HotFix - Background not being transparent for [user]/[type] in embed (#3121)
Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com>
2022-06-21 09:38:59 +00:00
Hariom Balhara dfc6373bb4 Fix undefined in Calendar and also add manage event again (#3122) 2022-06-21 10:14:10 +01:00
Alex van AndelandOmar López 1b81e6d8ec Hotfix/fix legacy user eventtypes (#3116)
* includedDates would always disable excludedDates due to empty array

* Added migration to add all userids into _user_eventtype

Co-authored-by: Omar López <zomars@me.com>
2022-06-20 20:21:17 +00:00
zomars 591309f335 v1.7.2 2022-06-20 13:33:00 -06:00
b339736a6f Save currency to db (#3086)
* Save currency to db

* Add missing translation

* Get currency from user credentials server side

* Adds stripe data schema

Co-authored-by: Peer Richelsen <peeroke@gmail.com>
Co-authored-by: zomars <zomars@me.com>
Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com>
2022-06-20 19:09:22 +00:00
Joe Au-YeungandOmar López 89ef6c3f13 When deleting video app, change locations to Cal Video (#3022)
* tRPC endpoint to delete credentials

* Replace deleted app with daily

* Updated Jitisi logo

* Update logo size

* Update logo size

* Fix type error

* Remove type as prop

* Add isPrismaArray to lib

* Address feedback

* Remove connect calednar

* Expire payment sessions and cancel payment intent

* Expire payment sessions and cancel payment intent

* Refactor input

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

* Remove console.log

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

* Address feedback

* Find connected account on Stripe

* Fix type error

* Add interactive transactions

* Remove console.logs

* Remove console.log

Co-authored-by: Omar López <zomars@me.com>
2022-06-20 17:52:50 +00:00
67ca98018e Cutting down calls for installed apps + other UI tweaks (#3052)
* Cutting down calls for installed apps

* Fixing onboarding

* Reverting and invalidating more specifically

Co-authored-by: Peer Richelsen <peeroke@gmail.com>
Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com>
2022-06-20 11:33:07 -06:00
github-actions[bot]andCrowdin Bot 7337c75b26 New Crowdin translations by Github Action (#3109)
Co-authored-by: Crowdin Bot <support+bot@crowdin.com>
2022-06-20 18:08:32 +02:00
Joe Au-Yeung 4dee7d8a80 Fix ux (#3113) 2022-06-20 17:29:48 +02:00
Alex van Andel b004701601 includedDates would always disable excludedDates due to empty array (#3112) 2022-06-20 14:11:18 +00:00
Alex van Andel 929c3a9a27 Cast to boolean fix, thought we had them all (#3111) 2022-06-20 14:44:34 +01:00
Alex van Andel 5ca914b32e Fix weekStart passThrough + allow all days (#3108) 2022-06-20 10:01:57 +01:00
github-actions[bot] d440458794 New Crowdin translations by Github Action (#3107) 2022-06-19 20:00:53 +02:00
sean-brydon b3f8f9f51f Update tailwind to 3.1.3 (#3106) 2022-06-19 15:13:12 +00:00
Omar López 2d28ca61a4 Feature/parallel booking availability (#3087) 2022-06-19 16:02:00 +01:00
Choongkyu Kim 7599f2384e Add NEXTAUTH_URL to app.json to address heroku deploy failure (#3091) 2022-06-18 18:47:38 +01:00
github-actions[bot]andCrowdin Bot 9e598c8855 New Crowdin translations by Github Action (#3104)
Co-authored-by: Crowdin Bot <support+bot@crowdin.com>
2022-06-18 18:24:26 +02:00
github-actions[bot]andCrowdin Bot 7e75e50650 New Crowdin translations by Github Action (#3097)
Co-authored-by: Crowdin Bot <support+bot@crowdin.com>
2022-06-18 18:14:03 +02:00
Peer Richelsen 3ad160d0d8 fixed month buttons on darkmode (#3103) 2022-06-18 17:03:24 +02:00
Leo Giovanetti 314fef82a5 Adding Close.com library for console (#3099) 2022-06-17 21:58:27 -03:00
159c026533 As Google Meet is always installed, this fixes the doubling (#3093)
* As Google Meet is always installed, this fixes the doubling

* Make entire Google link clickable, fix extraData

* Attempt at type fixing :)

* AdditionalInformation for the booking page?

* Update packages/emails/src/components/LocationInfo.tsx

Being explicit :)

* Exclude AdditionalInformation as it is irrelevant here

Co-authored-by: Peer Richelsen <peeroke@gmail.com>
Co-authored-by: Omar López <zomars@me.com>
2022-06-17 18:34:41 +00:00
alannnc b9b3fef202 Less restrictive zod object parsing (#3095)
* Less restrictive zod object parsing

* Remove logs
2022-06-17 18:19:09 +00:00
zomars ee1edc9c27 Comments 2022-06-17 10:29:02 -06:00
zomars b38991fd25 Fixes 404 for trial users 2022-06-17 10:06:49 -06:00
github-actions[bot]andCrowdin Bot 3234e0f0a9 New Crowdin translations by Github Action (#3094)
Co-authored-by: Crowdin Bot <support+bot@crowdin.com>
2022-06-17 17:01:41 +02:00
github-actions[bot]andCrowdin Bot a9987bb795 New Crowdin translations by Github Action (#3088)
Co-authored-by: Crowdin Bot <support+bot@crowdin.com>
2022-06-17 16:16:54 +02:00
d44c8f7912 Stops users who are not in getting the "Requires confirmation" email (#3084)
* Update Email

* Remove console.debug

* Remove redundant assignment

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

* Update apps/web/pages/api/book/confirm.ts

* Fix E2E test

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-06-17 09:02:29 +00:00
alannnc 2e79446667 Change throw 500 to 204 no content (#3089) 2022-06-16 15:55:47 -06:00
github-actions[bot]andCrowdin Bot 16692aee16 New Crowdin translations by Github Action (#3078)
Co-authored-by: Crowdin Bot <support+bot@crowdin.com>
2022-06-16 23:15:11 +02:00
zomars 67ea727686 Fixed schema 2022-06-16 13:34:12 -06:00
zomars f239922fb6 v1.7.1 2022-06-16 11:01:57 -06:00
zomars 60e06e65c2 Fixes spinner for light mode 2022-06-16 10:44:36 -06:00
Joe Au-Yeung c4c20cf77d Add clarification to feedback screen (#3083) 2022-06-16 16:40:14 +00:00
Syed Ali Shahbaz 6253216484 Webhook polishing (#2987) 2022-06-16 17:21:48 +01:00
Alex van Andel c5a40f6c37 Fix for slots being duplicated in teams (#3082) 2022-06-16 10:03:51 -06:00
Hariom Balhara abe090881a avoid ref overriding because now we are rendering all tab codes at once (#3079) 2022-06-16 11:55:49 +00:00
Alex van Andel e65116d9e3 Fixed issue affecting people with multiple workingHours in single schedule (#3077) 2022-06-16 11:40:36 +01:00
github-actions[bot]andCrowdin Bot f82404392f New Crowdin translations by Github Action (#3070)
Co-authored-by: Crowdin Bot <support+bot@crowdin.com>
2022-06-16 11:30:08 +02:00
ddc686075b feat: update api to latest commit (#3073)
Co-authored-by: Agusti Fernandez Pardo <git@agusti.me>
Co-authored-by: Peer Richelsen <peeroke@gmail.com>
2022-06-16 11:07:58 +02:00
zomars 56e61c8d7c Type fixes 2022-06-15 21:35:16 -06:00
zomars 34cae662f3 Revert "Update troubleshoot.tsx"
This reverts commit 5dcd439901.
2022-06-15 21:27:14 -06:00
zomars 5dcd439901 Update troubleshoot.tsx 2022-06-15 21:21:20 -06:00
zomars 4eec01e2ad Frontend fixes 2022-06-15 21:19:13 -06:00
zomars 3ae35a3b5d Let's just build at runtime 2022-06-15 21:19:13 -06:00
zomars 673633a773 v1.7.0 2022-06-15 14:57:18 -06:00
e9f3248fc0 Feature/booking page refactor (#3035)
* Extracted UI related logic on the DatePicker, stripped out all logic

* wip

* fixed small regression due to merge

* Fix alignment of the chevrons

* Added isToday dot, added onMonthChange so we can fetch this month slots

* Added includedDates to inverse excludedDates

* removed trpcState

* Improvements to the state

* All params are now dynamic

* This builds the flat map so not all paths block on every new build

* Added requiresConfirmation

* Correctly take into account getFilteredTimes to make the calendar function

* Rewritten team availability, seems to work

* Circumvent i18n flicker by showing the loader instead

* 'You can remove this code. Its not being used now' - Hariom

* Nailed a persistent little bug, new Date() caused the current day to flicker on and off

* TS fixes

* Fix some eventType details in AvailableTimes

* '5 / 6 Seats Available' instead of '6 / Seats Available'

* More type fixes

* Removed unrelated merge artifact

* Use WEBAPP_URL instead of hardcoded

* Next round of TS fixes

* I believe this was mistyped

* Temporarily disabled rescheduling 'this is when you originally scheduled', so removed dep

* Sorting some dead code

* This page has a lot of red, not all related to this PR

* A PR to your PR (#3067)

* Cleanup

* Cleanup

* Uses zod to parse params

* Type fixes

* Fixes ISR

* E2E fixes

* Disabled dynamic bookings until post v1.7

* More test fixes

* Fixed border position (transparent border) to prevent dot from jumping - and possibly fix spacing

* Disabled style nitpicks

* Delete useSlots.ts

Removed early design artifact

* Unlock DatePicker locale

* Adds mini spinner to DatePicker

Co-authored-by: Peer Richelsen <peeroke@gmail.com>
Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com>
Co-authored-by: zomars <zomars@me.com>
2022-06-15 14:54:31 -06:00
Peer Richelsen 6959eb2d27 fixed flickering of more event name variables (#3069) 2022-06-15 22:12:11 +02:00
Leo Giovanettiandkodiakhq[bot] 6f8d0521f4 Missing calendar toggles fix (#3066)
* onboarding flag fix

* Adjusting text + adding into locales file

Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com>
2022-06-15 10:35:49 -06:00
github-actions[bot]andCrowdin Bot de375f0e77 New Crowdin translations by Github Action (#3065)
Co-authored-by: Crowdin Bot <support+bot@crowdin.com>
2022-06-15 18:14:39 +02:00
zomars 833adaf7e9 Revert "The booker get’s the Ui option to reschedule but can’t reschedule (#3061)"
This reverts commit 8cfc91df95.
2022-06-15 09:24:12 -06:00
m4tze 3e777dfaeb Update CalendarService.ts (#3060) 2022-06-15 13:52:24 +01:00
GitStart 8cfc91df95 The booker get’s the Ui option to reschedule but can’t reschedule (#3061) 2022-06-15 13:51:53 +01:00
GitStart ecea455b7f Flicker on booking success page (#3063) 2022-06-15 13:50:22 +01:00
041ad9cd94 Fix credential creation flow for msteams app (#3029)
* Fix credential creation flow for msteams app

* Code review improve

* Fix preffer early returns

Co-authored-by: Joe Au-Yeung <65426560+joeauyeung@users.noreply.github.com>
Co-authored-by: Peer Richelsen <peeroke@gmail.com>
Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com>
2022-06-15 02:42:13 +00:00
zomars eb64904ba3 updates api submodule 2022-06-14 15:25:55 -06:00
zomars a3e05ff98c Allows both username and userid availability 2022-06-14 15:23:18 -06:00
zomars f335678a78 Adds unrecognized_keys error handling 2022-06-14 14:43:50 -06:00
zomars b5b48e7992 Updates user metadata schemas 2022-06-14 14:07:54 -06:00
zomars c5d2bac26f Better ZodError handling 2022-06-14 14:07:39 -06:00
22460a460b feat: Adds new customPrisma for hosted API (#3055)
* feat: customPrisma for hosted API access

* fix: 24h not 24 days for expiry cache in customPrisma calls

* fix: move PRISMA_CLIENT_CACHING_TIME to API

Co-authored-by: Agusti Fernandez Pardo <git@agusti.me>
Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com>
2022-06-14 17:11:39 +00:00
zomars 7bef84a8d0 Fixed logging 2022-06-14 09:39:50 -06:00
zomars 7e8dc0f848 Make perfObserver retro-compatible with node v14 2022-06-14 09:32:37 -06:00
zomars 74704bb699 Fixes undefined link in opt-in email 2022-06-14 08:55:21 -06:00
Carina WollendorferandCarinaWolli cb66f96b63 Plain svg for Zapier icon (#3059)
* use svg instead of functional component for icon

* use svg from static folder

Co-authored-by: CarinaWolli <wollencarina@gmail.com>
2022-06-14 12:55:59 +00:00
zomars 0ebda5d483 Submodule updates 2022-06-13 16:42:51 -06:00
zomars 5208400b24 Playwright isn't needed here 2022-06-13 16:15:28 -06:00
1960046994 App/exchange v2 (#2493)
* Create 2013 package

* Create 2016 package

* Add ews

* Update package.json

* Translate 2013 app to new structure

* Translate 2013 app to new structure

* Translate 2016 app to new structure

* Add appId

* Move setup to a seperate page

* RHF dependency version mismatch

* Move exchange 2016 setup to new page

* Add translations

* Relying on AppSetupMap not defined static pages

* Console build fixes

* Resolved node version to 16

* Prisma errors can't be handled on client

* Fixes node version mismatches

* Improvements

* Endpoint fixes

* Revert "Endpoint fixes"

This reverts commit c0320e3f3d320091ee9a049e3abaf285169ed555.

* Fixes

Co-authored-by: Joe Au-Yeung <j.auyeung419@gmail.com>
Co-authored-by: Joe Au-Yeung <65426560+joeauyeung@users.noreply.github.com>
Co-authored-by: Peer Richelsen <peeroke@gmail.com>
Co-authored-by: Leo Giovanetti <hello@leog.me>
2022-06-13 16:12:27 -06:00
zomars 3c9cf81fb3 E2E debugging 2022-06-13 15:16:58 -06:00
8d893d3ed1 Fix/app multiple installs (#3045)
* Add new flag for apps with multiple installs

* WIP saving work in progress

* Fix typo in metadata property

* Update apps/web/components/App.tsx

Co-authored-by: Leo Giovanetti <hello@leog.me>

* Using category in pref of new variable on metadata

* Update App.tsx

* Update yarn.lock

* Update yarn.lock

Co-authored-by: Leo Giovanetti <hello@leog.me>
Co-authored-by: zomars <zomars@me.com>
2022-06-13 15:06:12 -06:00
zomars d1cf91a1ea Yarn lock fixes 2022-06-13 14:15:10 -06:00
alannncandOmar López 2362133b25 Fix/stripe payment intent succeded (#3044)
* Remove conditional that turned off booking payment update

* Added stripe webhook key to env vars

* Update .env.example

Co-authored-by: Omar López <zomars@me.com>
2022-06-13 13:41:57 -06:00
Joe Au-Yeungandzomars f9d05f7a0e Add helpscout to billing page (#3054)
* Add helpscout to billing page

* Upgrades CI node to 16

Co-authored-by: zomars <zomars@me.com>
2022-06-13 13:05:05 -06:00
zomars dfe3e55e74 Upgrades CI node to 16 2022-06-13 12:32:26 -06:00
zomars 881de59bf5 Fixes node version mismatches 2022-06-13 10:59:02 -06:00
zomars e0a391d46e Prisma errors can't be handled on client 2022-06-13 10:37:42 -06:00
zomars b044c6fb70 Resolved node version to 16 2022-06-13 10:32:45 -06:00
zomars 06482388bd Console build fixes 2022-06-13 10:31:04 -06:00
Hariom Balharaandkodiakhq[bot] 5653282dea Fix Event-Type 404 in case of unintentional duplicates. (#3049)
* Fix sort order to ensure correct event-type is picked when duplicates

* Refetch after mutation to ensure that after positioning is changed, UI is updated

* Dont rely on hashmap for ordering.

Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com>
2022-06-13 14:25:05 +01:00
Hariom BalharaandPeer Richelsen 624a7a036d Make absolute URL and consider if its a team event or non team event (#3047)
Co-authored-by: Peer Richelsen <peeroke@gmail.com>
2022-06-13 12:18:51 +00:00
Peer Richelsen 5c3d399ccb added margin bottom to event-types (#3048) 2022-06-13 13:25:49 +02:00
github-actions[bot]andCrowdin Bot 0a308eb13d New Crowdin translations by Github Action (#3040)
Co-authored-by: Crowdin Bot <support+bot@crowdin.com>
2022-06-13 12:40:22 +02:00
zomars e487f295da Disabled videoBusyTimes 2022-06-12 15:35:40 -06:00
zomars 63983c9d60 Prevents caldav recurring events errors to unblock availability 2022-06-12 15:23:14 -06:00
zomars 2e61eb41b2 Merge branch 'production' 2022-06-12 11:43:04 -06:00
sean-brydon ad4bcfafce Manage Link showing for organisers (#3037) 2022-06-12 15:33:14 +00:00
alannnc 2faf7e6806 Fix onboarding calendar connection (#3036) 2022-06-12 16:19:35 +01:00
Choongkyu Kim a2bb210ebd Update README to reflect nodejs version pinning (#3043) 2022-06-11 22:51:19 -06:00
zomars f3d49fe59e Fixed empty array as truthy 2022-06-11 16:40:00 -06:00
zomars fa4ecf09fb Fixes tsconfigs for embeds 2022-06-11 16:27:11 -06:00
zomars 78d340786f Logs busytimes by category 2022-06-11 16:22:08 -06:00
zomars 7abd8adf9c Logs busytimes by category 2022-06-11 16:21:20 -06:00
zomars 17b8ec65e4 Zoom refactoring 2022-06-11 16:15:34 -06:00
c03ff0a543 Fixes slack verification and timeout errors (#2972)
* Fixing slack create event

* Fixes verify working 90% of the time :S

* Verify V2

* Fixing verify - not needed on interaction payload

* Fixing verifcation + response

* Fix verifcation

* DM user error/success

* Remove random 200

* Timeout return

* Adding Zod schema verification

* Added validations, cleanup

* Type fixes

* Update event.ts

Co-authored-by: Peer Richelsen <peeroke@gmail.com>
Co-authored-by: zomars <zomars@me.com>
Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com>
2022-06-11 22:30:52 +01:00
Leo Giovanetti 8fa0d0f8bb CalDav Setup page (#3038) 2022-06-11 19:33:04 +02:00
sean-brydon 567a7c8f12 Adding UI for Requires Confirmation (#3017) 2022-06-10 17:32:54 -06:00
514fca7a53 Recurring event improvements (#2750)
* Loading state and rejected bookings gone

* Listing fixes

* Tweaking upcoming vs recurring bookings tabs

* Tweaking new emails to avoid recurringEvent param

* Tweaks to support recurring events in common flows

* Missed one renderEmail

* Removing uneeded references

* Reverting manual plural fixes

* Refactoring recurring event strings

* Correcting merge issues

* Relying on newly introduced obj

* Fixing mobile

* Final tweaks

* Latest fixes

Co-authored-by: Peer Richelsen <peeroke@gmail.com>
Co-authored-by: Bailey Pumfleet <pumfleet@hey.com>
Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com>
2022-06-10 17:38:06 -03:00
zomars 67a7c578b1 Update console 2022-06-10 14:25:27 -06:00
0df0b6a0f2 Fix/wipe vital app revision (#2983)
* Fixes for both apps regarding event update/delete

* Added wipe my cal test

* Added eslint ignore

* Fix test

* Merge both test into a single test

* remove duplicated line

* Using prisma from calcom pkg and removing optional chaining from current invocations

Co-authored-by: Peer Richelsen <peeroke@gmail.com>
Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com>
2022-06-10 19:16:10 +00:00
Omar López 22d2bae46b Availabilty consolitadion (#3010) 2022-06-10 12:38:46 -06:00
Hariom BalharaandPeer Richelsen 1f1e364a30 Add consistent publish command and update versions to published version (#3008)
* Add consistent publish command and update versions to published version

* v1.0.8

* Bump version to released version

Co-authored-by: Peer Richelsen <peeroke@gmail.com>
2022-06-10 09:49:38 +00:00
65d8b2d45c You have no {{status}} bookings unexpectedly capitalized (#3021)
Co-authored-by: gitstart <gitstart@users.noreply.github.com>
Co-authored-by: Bailey Pumfleet <pumfleet@hey.com>
Co-authored-by: Peer Richelsen <peeroke@gmail.com>
2022-06-10 11:36:07 +02:00
Omar LópezandLeo Giovanetti b11398f551 Recurring event fixes (#3030)
* Incorporates recurringEvent into calEvent

* Recurrent event fixes

* Update event.ts

* type fixes

* Update zod-utils.ts

* Adding more recurringEvent to calEvent and other fixes

* Moving away from heavy 3rd party enum

* Fixing test

* Renaming as suggested and fixes

Co-authored-by: Leo Giovanetti <hello@leog.me>
2022-06-09 18:32:34 -06:00
Leo Giovanetti 8cd420173c Tweaks requested by Ciarán (#3009)
* Tweaks requested

* Missing recurring event details in mobile view

* Removing bg-white
2022-06-09 20:49:09 +00:00
github-actions[bot]andCrowdin Bot d276763b11 New Crowdin translations by Github Action (#3032)
Co-authored-by: Crowdin Bot <support+bot@crowdin.com>
2022-06-09 13:51:55 +02:00
Peer Richelsen 0f0513b8b7 added no-scrollbar utility (#3031)
* added no-scrollbar utility

* added responsive variants

* undo prettier on global.css
2022-06-09 04:46:03 -06:00
Hariom Balharaandkodiakhq[bot] a9e519f643 Improvement: Add React to Embed Snippet Generator (#3018)
Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com>
2022-06-09 10:35:18 +05:30
github-actions[bot]andCrowdin Bot 8f86e0b164 New Crowdin translations by Github Action (#3023)
Co-authored-by: Crowdin Bot <support+bot@crowdin.com>
2022-06-08 21:11:28 +02:00
zomars ac3a4bcaab Adds failsafe for calendar credentials without externaId set 2022-06-08 12:23:48 -06:00
zomars 205c774ca3 Prevent flatMap type errors in @calcom/core 2022-06-08 12:04:42 -06:00
abe5d53fc1 Disable dark mode on the success page only for the organizer (#3001)
* disable darkmode only for organizer

* disable dark mode when user comes from user dashboard

* move Theme to shell

* fix build errors

* sort dates for recurring bookings

* new parameter if user comes from booking an event

Co-authored-by: CarinaWolli <wollencarina@gmail.com>
Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com>
2022-06-08 16:02:09 +02:00
Peer RichelsenandJoe Au-Yeung 289cdefc27 overflow scroll to mobile settings (#3014)
Co-authored-by: Joe Au-Yeung <65426560+joeauyeung@users.noreply.github.com>
2022-06-08 13:49:55 +00:00
1d96933f5f New Crowdin translations by Github Action (#3016)
Co-authored-by: Crowdin Bot <support+bot@crowdin.com>
Co-authored-by: Peer Richelsen <peeroke@gmail.com>
2022-06-08 15:42:56 +02:00
github-actions[bot] 2e1cadb5da New Crowdin translations by Github Action (#3015) 2022-06-08 09:44:08 +01:00
Jatin Ranka 30e35fe068 Fix: updated env file path for db setup (#2937) 2022-06-08 09:43:01 +01:00
GitStart 7151c65f1a [CAL-1277]: When clicking a deleted type event while it's "deleting", it sends you to 500 error (#2968) 2022-06-08 09:42:00 +01:00
Omar López 3a2224a4e4 Update bookingReminder.ts (#3007) 2022-06-08 09:37:06 +01:00
Leo Giovanettiandkodiakhq[bot] 33a4bb797d Fixes plural issue with locales (#3011)
* Fixes

* Covering rest of locales

Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com>
2022-06-08 09:32:52 +02:00
Carina WollendorferandCarinaWolli b8cd4c32ac add all missing information to mobile view (#3013)
Co-authored-by: CarinaWolli <wollencarina@gmail.com>
2022-06-08 07:11:34 +00:00
Hariom Balharaandkodiakhq[bot] bb4875443a Add app-store:watch a dependency of web:dev (#3005)
Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com>
2022-06-07 16:57:27 +00:00
Peer Richelsen d1cd83acea renaming "opt-in" to "requires confirmation #2 attempt (#2999)
* second try

* nit

* nit
2022-06-07 18:22:37 +02:00
Alex van Andel 5a84adcd8a Fixes 0 issue by boolean cast (#3004) 2022-06-07 10:10:30 -06:00
Joe Au-Yeung 55d6f1ee35 Change order that the page is prefilled (#3003) 2022-06-07 09:46:07 -06:00
zomars e863b71dfa Email language fixes 2022-06-07 08:49:39 -06:00
Joe Au-Yeung 0f5550680a Add username and email to feedback email (#3002)
* Add username and email to feedback email

* Fix type error
2022-06-07 08:39:47 -06:00
e77ddc3d2e Trailing unlocking node <17 (#2711)
* Trailing unlocking node <17

* Updated apps/web package.json

* Updated .nvmrc -> v16 :)

Co-authored-by: Peer Richelsen <peeroke@gmail.com>
Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com>
2022-06-07 11:53:11 +01:00
Peer Richelsen c3b7b32af5 fixed flex of event-types (#2994) 2022-06-07 10:14:27 +01:00
Syed Ali Shahbaz f4f953cca1 fix (#2992) 2022-06-07 08:41:25 +00:00
Hariom BalharaandPeer Richelsen e2ef7216a8 Add licenses to embeds (#2984)
* Add license to embed

* add repo links as well

Co-authored-by: Peer Richelsen <peeroke@gmail.com>
2022-06-07 08:25:55 +00:00
Hariom Balharaandkodiakhq[bot] 18e0f13605 [Feature] App Store CLI - Make it super easy to add an app. (#2917)
Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com>
2022-06-07 11:43:32 +05:30
zomars 51b86b1d97 Update telemetry.ts 2022-06-06 15:33:38 -06:00
zomars 875e279def v1.6.3 2022-06-06 14:23:10 -06:00
zomars 88db424a16 Update _getStaticProps.tsx 2022-06-06 13:52:57 -06:00
zomars a8aeac22ee Update App.tsx 2022-06-06 13:50:34 -06:00
zomars 13f20dd7cf additionInformation => additionalInformation 2022-06-06 13:49:10 -06:00
Omar Lópezandalannnc 41c5ad45fd Apply suggestions from code review
Co-authored-by: alannnc <alannnc@gmail.com>
2022-06-06 13:42:59 -06:00
zomars 7fec9d64fa Email cleanup 2022-06-06 13:39:54 -06:00
Omar López c95b8d0048 Delete _getStaticProps.tsx 2022-06-06 13:30:44 -06:00
Omar López f65edba982 Update vital.json 2022-06-06 13:27:49 -06:00
Omar López 94c3bc7f19 Update vital.json 2022-06-06 13:25:13 -06:00
Omar López bfd27f0d94 Update vital.json 2022-06-06 13:23:49 -06:00
zomars 67b96d990c Update invite.ts 2022-06-06 12:59:57 -06:00
ba04533de3 Linting fixes round #1 (#2906)
* Fixes round #1

* disabled any warning for intentional typing of AsyncReturnType

* Whacked MetaMask add / remove button

* types, not great, not terrible, better than any

* Fixed typo in CheckboxField and wrapped description in <label>

* Feedback

Co-authored-by: Peer Richelsen <peeroke@gmail.com>
Co-authored-by: zomars <zomars@me.com>
Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com>
2022-06-06 18:24:37 +00:00
zomars 547b40913f Merge branch 'production'
# Conflicts:
#	.env.example
#	.github/workflows/e2e-embed.yml
#	apps/web/components/EmptyScreen.tsx
#	apps/web/components/SettingsShell.tsx
#	apps/web/components/Shell.tsx
#	apps/web/components/booking/BookingListItem.tsx
#	apps/web/components/booking/pages/AvailabilityPage.tsx
#	apps/web/ee/components/LicenseRequired.tsx
#	apps/web/ee/components/apiKeys/ApiKeyListContainer.tsx
#	apps/web/ee/components/support/HelpMenuItem.tsx
#	apps/web/lib/emails/templates/attendee-request-reschedule-email.ts
#	apps/web/lib/emails/templates/attendee-rescheduled-email.ts
#	apps/web/lib/emails/templates/attendee-scheduled-email.ts
#	apps/web/lib/emails/templates/organizer-request-reschedule-email.ts
#	apps/web/lib/emails/templates/organizer-rescheduled-email.ts
#	apps/web/lib/emails/templates/organizer-scheduled-email.ts
#	apps/web/pages/_app.tsx
#	apps/web/pages/apps/installed.tsx
#	apps/web/pages/event-types/[type].tsx
#	apps/web/public/static/locales/en/common.json
#	apps/web/server/routers/viewer/bookings.tsx
#	packages/app-store/vital/lib/templates/attendee-request-reschedule-email.ts
#	packages/app-store/vital/lib/templates/base-template.ts
#	packages/app-store/vital/lib/templates/organizer-request-reschedule-email.ts
#	packages/app-store/wipemycalother/lib/templates/attendee-request-reschedule-email.ts
#	packages/app-store/wipemycalother/lib/templates/base-template.ts
#	packages/app-store/wipemycalother/lib/templates/organizer-request-reschedule-email.ts
#	packages/ee/server/checkLicense.ts
#	packages/emails/email-manager.ts
#	packages/embeds/embed-core/package.json
#	packages/embeds/embed-snippet/package.json
#	packages/embeds/vite.config.js
#	packages/lib/constants.ts
#	packages/types/environment.d.ts
#	yarn.lock
2022-06-06 11:58:32 -06:00
Omar Lópezandkodiakhq[bot] 15d5333cf6 Refactor emails to use JSX as templating engine (#2915)
* Init Maizzle

* Initial template JSX conversion and testing

* WIP

* WIP

* WIP

* WIP

* WIP

* Migrated AttendeeRescheduledEmail

* WIP

* WIP

* DRY

* Cleanup

* Cleanup

* Cleanup

* Migrate feedback email

* Migrates ForgotPasswordEmail

* Migrates OrganizerCancelledEmail

* Migrated OrganizerLocationChangeEmail

* Formatting

* Migrated AttendeeRequestRescheduledEmail

* Migrates OrganizerPaymentRefundFailedEmail

* Migrates OrganizerRequestEmail

* Migrates OrganizerRequestReminderEmail

* Fixes type-check

* Moved email-manager to package

* Import fixes

* Removed duplicate email code from vital app

* Removed duplicate email code from wipemycal

* Build/type fixes

* Fixes web email imports

* Fixes build

* Embed build fixes

* Update AttendeeAwaitingPaymentEmail.tsx

* Update default-cookies.ts

* Revert "Embed build fixes"

This reverts commit 8d693e99aca6dfe92d5cbb27ffa962545c3e9389.

* Embed build fixes

# Conflicts:
#	packages/embeds/embed-core/package.json

* dep and email date fixes

* Update attendee-scheduled-email.ts

* Update package.json

* Update [...nextauth].tsx

* Update email.ts

* Prevents /api/email on production builds

Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com>
2022-06-06 17:49:56 +00:00
Joe Au-Yeung ad101e0a31 Address feedback of feedback feature (#2981) 2022-06-06 13:40:02 -04:00
Omar Lópezandkodiakhq[bot] 12d66cb9df Booking confirm endpoint refactoring (#2949)
* Adds new default handler and responder

* Moved confirm endpoint

* Fixes availability for unconfirmed bookings

* Cleanup

* Update _patch.ts

* Prevent too much diffs

* Adds missing BookingStatus

* Migrates confirmed & rejected to status

* Adds requiresConfirmation icon to listing

* Adds booking status migration

* Adds migrations to remove confirmed/rejected

* Undo refactor

* Sets the organizer as "accepted" in gCal

* Update getBusyTimes.ts

Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com>
2022-06-06 10:54:47 -06:00
3b321e5d3c New Crowdin translations by Github Action (#2980)
Co-authored-by: Crowdin Bot <support+bot@crowdin.com>
Co-authored-by: Peer Richelsen <peeroke@gmail.com>
2022-06-06 17:33:13 +02:00
Carina Wollendorfer d0ac4d41ed fix language issue on booking page (#2973) 2022-06-06 14:30:41 +01:00
983c970069 Add more variables to event names and a dynamic field (#2898)
Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com>
Co-authored-by: Alan <alannnc@gmail.com>
Co-authored-by: Bailey Pumfleet <pumfleet@hey.com>
2022-06-06 08:48:13 -04:00
3189f8b77a New Crowdin translations by Github Action (#2966)
Co-authored-by: Crowdin Bot <support+bot@crowdin.com>
Co-authored-by: Peer Richelsen <peeroke@gmail.com>
2022-06-06 12:07:20 +02:00
Hariom Balharaandkodiakhq[bot] 079016052d Add embed preview tests (#2969)
Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com>
2022-06-06 12:06:27 +02:00
Hariom Balhara f0a5b7734f [Hotfix]Fixes 3 issues related to 404 links (#2977) 2022-06-06 09:41:11 +00:00
Hariom Balhara 03e787ad5a Fixes 3 issues related to 404 links (#2979) 2022-06-06 11:40:56 +02:00
Syed Ali Shahbaz dd09854932 Hotfix: fixed callback URL for team invite email (#2978) 2022-06-06 14:59:46 +05:30
Syed Ali Shahbaz b9428301b6 Hotfix: fixed callback URL for team invite email (#2975) 2022-06-06 14:07:53 +05:30
zomars 2344a4da13 Update yarn.lock 2022-06-05 16:42:26 -06:00
zomars 4652878e6c tsc fixes 2022-06-05 16:35:39 -06:00
zomars 4efc2914af Embed build fixes 2022-06-05 13:55:58 -06:00
zomars 9866e12a84 Update default-cookies.ts 2022-06-05 13:54:13 -06:00
github-actions[bot]andCrowdin Bot 8998e41104 New Crowdin translations by Github Action (#2964)
Co-authored-by: Crowdin Bot <support+bot@crowdin.com>
2022-06-05 09:00:08 +02:00
zomars 0a64715d84 Fallbacks to Cal Video when missing credentials for location 2022-06-04 11:32:43 -06:00
zomars 879619e075 Fallbacks to Cal Video when missing credentials for location 2022-06-04 11:23:56 -06:00
Hariom Balhara 16cab18163 Fix preview not working (#2962) 2022-06-04 07:31:13 -06:00
456ba9db04 fix: saml update/delete only owner team (#2948)
Co-authored-by: Agusti Fernandez Pardo <git@agusti.me>
Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com>
2022-06-04 07:31:10 -06:00
Hariom Balhara 1c89afc7ad Fix preview not working (#2962) 2022-06-04 07:17:02 -06:00
16836d0cfb fix: saml update/delete only owner team (#2948)
Co-authored-by: Agusti Fernandez Pardo <git@agusti.me>
Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com>
2022-06-03 23:13:50 +00:00
zomars 2c65e39482 Ignores vital for now 2022-06-03 14:18:43 -06:00
65dc7c5b65 New Crowdin translations by Github Action (#2959)
Co-authored-by: Crowdin Bot <support+bot@crowdin.com>
Co-authored-by: Peer Richelsen <peeroke@gmail.com>
2022-06-03 22:04:54 +02:00
eb02efb25a New Crowdin translations by Github Action (#2834)
Co-authored-by: Crowdin Bot <support+bot@crowdin.com>
Co-authored-by: Peer Richelsen <peeroke@gmail.com>
2022-06-03 22:01:49 +02:00
864a873c57 Images in slider will have fixed height, variable width (#2916)
* Images in slider will have fixed height, variable width

* fix spacing

* remove extra whitespace

* fix whitespace lint errors

* fix whitespace lint error

* fix width for images in app store slider

Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com>
Co-authored-by: Peer Richelsen <peeroke@gmail.com>
2022-06-03 22:01:00 +02:00
Peer Richelsen fcba3bec03 added email to ee helper (#2958) 2022-06-03 21:59:40 +02:00
zomars 4569a96e78 Update index.ts 2022-06-03 13:21:46 -06:00
zomars debbd980d9 Fixes preview deploys 2022-06-03 12:48:47 -06:00
zomars d5e40faeb5 Adds booking reportUsage for enterprise 2022-06-03 12:33:53 -06:00
zomars 10edc1f4ac Update next.config.js 2022-06-03 10:50:48 -06:00
Peer Richelsen 42c49a8263 renamed integratin to app and extracted into common.json (#2951) 2022-06-03 14:57:50 +00:00
7b0d5811d6 Improve meeting url information in booking detail view (#2943)
* change meeting url text for booking detail view

* improve for wen conferencing details for different booking status

Co-authored-by: CarinaWolli <wollencarina@gmail.com>
Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com>
2022-06-03 11:28:33 +00:00
9d1e6f23db Fixing spaces and wraps for event type legend (#2941)
* Fixing spaces and wraps

* Spacing wrapped items

* fix lint errors

Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com>
Co-authored-by: CarinaWolli <wollencarina@gmail.com>
2022-06-03 11:15:29 +00:00
Carina WollendorferandCarinaWolli b4f3680876 disable confirm button when recurring mutation is loading (#2950)
Co-authored-by: CarinaWolli <wollencarina@gmail.com>
2022-06-03 12:52:10 +02:00
zomars 7536473c9d Allows telemetry opt-out 2022-06-02 14:06:13 -06:00
zomars fd8e4ef890 licenseCheck fixes 2022-06-02 13:49:12 -06:00
zomars c8a16ce43b Call prod console only on prod non staging deploys 2022-06-02 13:40:16 -06:00
zomars 887bd66a33 All prod builds should call prod console 2022-06-02 13:34:32 -06:00
zomars eeb9ff662e Adds cors to checkLicense 2022-06-02 13:20:48 -06:00
zomars 262df1a1b2 Updates console 2022-06-02 13:20:35 -06:00
zomars 3919d87486 Adds license to telemetry 2022-06-02 11:53:02 -06:00
zomars 6f203d14e3 Submodule updates 2022-06-02 10:20:29 -06:00
Vladimir KlimontovichandArt Sk 456a4ba581 Telemetry improvements (#2935)
* next-collect initial setup

* naming changes

* WIP

* WIP: added cookie name

* telemetry update

* fixes

* telemetry eventTypes fix

* tmp jitsu config for testing

* tmp jitsu key update (for tests)

* deploy commit

* cookieName fixes

* telemetry credentials update

* NextCollect updated to latest canary; added TELEMETRY_KEY to config

* TELEMETRY_KEY fix

removed browser_user_agent field from event

* removed _middleware.ts for test deploy

* _middleware.ts restored

* next-collect version bump

* yarn.lock fix

* Added license consent property, set default telemetry endpoint

* Switched to stable version of next-collect; restored LicenseProvider accidentally deleted during merge

* Switched to stable version of next-collect; restored LicenseProvider accidentally deleted during merge

* Updated to latest version of next-collect

* - Updated to latest version of next-collect
- Few improvements in event collection: isTeamBooking for all events, page_url for all events
- Do not send second page event on re-render of /team/[slug]

* Revert booking confirmed tracking

* Applied prettier + fix lint

Co-authored-by: Art Sk <kirsan007@gmail.com>
2022-06-02 10:19:01 -06:00
60d6c7be51 fix: owners can't be edited by admins (#2942)
* fix: owners can't be edited by admins

* fix: removec omment

Co-authored-by: Agusti Fernandez Pardo <git@agusti.me>
Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com>
2022-06-02 09:39:23 -06:00
zomars 0f273c5efc Update package.json 2022-06-01 15:46:48 -06:00
33a45a8af5 Installed Apps page revamp (#2751)
* First round of changes

* Some missing styling

* Last round of core changes

* Color tweaks

* Improving code readability

* Reverting unneeded changes

* Reverting yarn.lock

* Removing yarn.lock

* Empty state updated

* Fixing webhook test

* Cleaning up code

* Fixing test and simplifying code a bit

* Merging API Keys into developer section

* Unifying Empty Screen with monorepo version

* Cleaning up

* Installed apps logic consistency + cleaning up

* Type fixes

* Apply suggestions from code review

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

* Improvements, still WIP

* Update apps/web/pages/apps/installed.tsx

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

* Apply suggestions from code review

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

* App active install status

* Apple Calendar setup, Daily.co preinstalled

* Final pass

* Minor tweaks

* Conflicts with migration ignored

* Fixing merge

* Fixing merge yet again

* Adopting main changes

* Removing unneeded data-testid

* Fixing reported bugs

* Simplifying webhook query

* Moving teams settings tab to second

Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com>
Co-authored-by: zomars <zomars@me.com>
Co-authored-by: alannnc <alannnc@gmail.com>
Co-authored-by: Peer Richelsen <peeroke@gmail.com>
2022-06-01 14:24:41 -03:00
sean-brydon 6179b0cc56 Fixing Spacing + text color (#2938)
* Fixing Spacing + text color

* Fix overflow

* Fixing mobile text color
2022-06-01 14:58:46 +02:00
alannncandkodiakhq[bot] 9ded50b5fc Fix/infinite booking list (#2931)
Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com>
2022-06-01 09:33:14 +05:30
7c34be272f Invalid Payment URL gives 500 (#2857)
Co-authored-by: gitstart <gitstart@users.noreply.github.com>
Co-authored-by: Júlio Piubello da Silva Cabral <julio.piubello@gitstart.dev>
2022-05-31 14:40:12 +01:00
6145c7ad90 Bug - Admin Shell Duplicated (#2933)
* Fix additional shell in admin

* Update headings

Co-authored-by: Peer Richelsen <peeroke@gmail.com>
Co-authored-by: Bailey Pumfleet <pumfleet@hey.com>
2022-05-31 14:36:20 +01:00
Syed Ali Shahbaz 5225fc4317 A few booking page UI fixes (#2932) 2022-05-31 13:20:51 +02:00
Hariom Balhara 514cff7b3c Fix: Embed Tests - Handle superfast switching to next month bug (#2929)
* Wait for more time for next month dates to fully render

* Add comments

* Wait for rendering of current month as well

* Fix retries

* Fix speed issue with non embed tests asw ell
2022-05-31 09:32:41 +00:00
Hariom Balhara eb6e092a21 Improve dx command (#2918) 2022-05-30 17:47:58 -06:00
Hariom Balhara 7d2c0ab405 Improve dx command (#2918) 2022-05-30 23:11:22 +01:00
+22 01631e808f v1.6.2 (#2926)
* Turbo fixes

* Make apps single pages public

* fixed /booking skeleton (#2722)

* fixed /booking skeleton

* nit

* Type fixes

* Test fixes

* Update playwright.config.ts

* More test fixes

* Update dynamic-booking-pages.test.ts

* add invite link to Zapier setup page (#2696)

* add invite link and toaster to zapier setup page

* create env variable for invite link and save in database

* fetch invite link form getStaticProps

* add getStaticPath method

* clean code

* Moves app setup and index page

* Moves Loader to ui

* Trying new way to handle dynamic app store pages

* Cleanup

* Update tailwind.config.js

* zapier invite link fixes

* Tests fixes

Co-authored-by: CarinaWolli <wollencarina@gmail.com>
Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com>
Co-authored-by: zomars <zomars@me.com>

* Add more embed events (#2719)

* Add more embed events

* Add more embed events

Co-authored-by: Peer Richelsen <peeroke@gmail.com>

* adds availability select loader (#2718)

* Improve logs and Fix unwanted 500 to reduce noise in logs (#2674)

* Improve logs

* Fix unintentional 500

Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com>

* Change date format for RecurringBookings (#2707)

* Change date format for RecurringBookings

* Missing bookingId query param

Co-authored-by: Leo Giovanetti <hello@leog.me>
Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com>

* added giphy description (#2730)

* fixes #2732 (#2732)

* Hotfix : Fix Infinite loading of Bookings (#2729)

* Add more embed events

* Add more embed events

* Fix nextCursor calculation logic

Co-authored-by: Peer Richelsen <peeroke@gmail.com>

* Hotfix: Success page for recurring event (#2725)

* Merge pull request #2672 from calcom/main

v1.5.4

* Turbo fixes

* Make apps single pages public

* Fix preview.html not built and thus served during depooy (#2713)

* Hotfix: Success page layout broken due to duplicate "When" (#2716)

* Update BookingPage.tsx

* Reverting unchaged lines

* Fixing recurrenceRule for ICS files

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

* Fix preview.html not built and thus served during depooy (#2727)

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

* Allow deletion of a disabled event (#2737)

* allows deletion of disabled event

* some visual fixes

Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com>

* Multiple E2E improvements

* Parallelizes some tests

* Update booking-pages.test.ts

* E2E and paid bookings fixes

* Add 'free' and 'workingElsewhere' as a non-blocking event (#2652)

* Add 'free' and 'workingElsewhere' to non-blocking event - this will allow bookings at these times

* Update CalendarService.ts

Co-authored-by: zomars <zomars@me.com>
Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com>

* TODO marks blocking test to be fixed

* Update testUtils.ts

* Update testUtils.ts

* getBusyTimes consolidation

* Fixes delete-me test

* E2E fixing attemps

* Adjusting Zapier endpoints for publishing integration (#2728)

* add /me endpoint for zapier API testing

* remove cacellationReason from listBookings response

Co-authored-by: CarinaWolli <wollencarina@gmail.com>
Co-authored-by: Peer Richelsen <peeroke@gmail.com>
Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com>
Co-authored-by: Omar López <zomars@me.com>

* Fix reschedule not happening in calendar if two calendards are there (#2733)

Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com>
Co-authored-by: Peer Richelsen <peeroke@gmail.com>

* Increases timeout temporarily

* Merge pull request #2745 from calcom/apps/multiple-categories

Allow apps to belong to multiple categories

* Build fixes

* Populate msteams key in db (#2743)

* Populate msteams key in db

* Fix calendar credentials to teams

* Clarify account dialog

Co-authored-by: Omar López <zomars@me.com>
Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com>
Co-authored-by: Bailey Pumfleet <pumfleet@hey.com>

* Improving Email DRYness (#2486)

* Email DRY

* WIP

* Improve email DRYness

Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com>

* E2E fixtures (#2747)

* Sign in button should be changed or disabled after click #2654 (#2749)

Co-authored-by: gitstart <gitstart@users.noreply.github.com>

* Fixing ESLint warnings (#2723)

* Fixing warnings

* Reverting and disabling ESLint in some cases

* Reverting Next Images

* Reverting file, bad merge

* Targeting ESLint to line

* Additional warnings

* New warning squished

* More tweaks and major fixes

* Uneeded conf

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

* Fix/avoid multiple schedule deletions (#2602)

* Prevents users from deleting the same schedule multiple times due to delay before the schedule disappears. It also applies the same fix to team disband.

Schedule deletion:
![schedule_deletion_new_behaving](https://user-images.githubusercontent.com/42497300/165126805-b3090268-c1a6-418a-b06e-06bd8446da03.gif)

Team disband:
![team_disband_new_behaving](https://user-images.githubusercontent.com/42497300/165127043-7e083e94-e4c9-4e88-90a2-47d31bdd92e6.gif)

Fixes issue [#2569](https://github.com/calcom/cal.com/issues/2569)

Bug fix (non-breaking change which fixes an issue)

**apps/web/components/LightLoader.tsx** → this file was created in order to make a light color loading spinner available. It's necessary when we need to display a loading spinner above dark backgrounds.

**apps/web/components/availability/ScheduleListItem.tsx** → this component was created in order to give a schedule list item its own state.

* Removing a "setTimeout" that was only used for testing purposes

* Adding a code review suggestion to my modifications

* Changing loading style

* Cleanup

* Avoids using unnecessary state

* Revert "Adding a code review suggestion to my modifications"

This reverts commit b5e40062d71157ca1d9384fb1f5c30d50625809d.

* Reverts some changes

* Renames isLoading

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

* Added check on create eventtype to see is user has slug that already exists (#2757)

* Added check on create eventtype to see is user has slug that already exists, added error check on onError

* revert yarn.lock back

* Catches prisma known error instead of making an additional query

Co-authored-by: zomars <zomars@me.com>

* Fix white border (#2761)

* fix: remove hardcoded redirect in signin url email verification (#2764)

Co-authored-by: Agusti Fernandez Pardo <git@agusti.me>

* Bad UX when user wants to set the default Event Type Title #2245 (#2760)

Co-authored-by: gitstart <gitstart@users.noreply.github.com>

* Skip sending emails in E2E

* Users Phone Number Option (#2669)

* Users Phone Number Option

* Implemented improvments

* Add validation to form

Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com>
Co-authored-by: zomars <zomars@me.com>

* Fix/unpaid unconfirmed (#2553)

* Fix merge errors

* Errors prettier/prettier

* Update apps/web/pages/api/book/event.ts

Co-authored-by: Miguel Nieto A <39246879+miguelnietoa@users.noreply.github.com>

* Update apps/web/pages/api/book/event.ts

Co-authored-by: Miguel Nieto A <39246879+miguelnietoa@users.noreply.github.com>

* Update apps/web/pages/api/integrations.ts

Co-authored-by: Miguel Nieto A <39246879+miguelnietoa@users.noreply.github.com>

* Fix merge errors

* Errors prettier/prettier

* Update apps/web/pages/api/book/confirm.ts

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

* Modal window before delete stripe integration

* ESLint Report

* Test fixes

Co-authored-by: Miguel Nieto A <39246879+miguelnietoa@users.noreply.github.com>
Co-authored-by: alannnc <alannnc@gmail.com>
Co-authored-by: zomars <zomars@me.com>

* Mutually exclusive options (#2755)

Co-authored-by: Omar López <zomars@me.com>
Co-authored-by: Peer Richelsen <peeroke@gmail.com>
Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com>

* Readd steps to create a new user #2665 (#2759)

Co-authored-by: gitstart <gitstart@users.noreply.github.com>

* remove redundant conditional expressions (#2756)

* remove redundant conditional expressions

* remove redundant conditional expression

Co-authored-by: Syed Ali Shahbaz <52925846+alishaz-polymath@users.noreply.github.com>

* Fix adds redirect callback that support app.cal.com (#2768)

* Fix adds redirect callback that support app.cal.com

* Update apps/web/pages/api/auth/[...nextauth].tsx

Check origin of website and baseurl

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

* fix: lint issue extra space removed

Co-authored-by: Agusti Fernandez Pardo <git@agusti.me>
Co-authored-by: Omar López <zomars@me.com>
Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com>

* respect local set timezone and update url on mismatch (#2506)

* ensure `timeZone()` will make its way to the URL

fixes https://github.com/calcom/cal.com/issues/2482

* keep `timeZone()` and the offset from URL in sync

Co-authored-by: Syed Ali Shahbaz <52925846+alishaz-polymath@users.noreply.github.com>
Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com>

* Squashed commit of the following:

commit 27540b09ce
Author: Agusti Fernandez Pardo <me@agusti.me>
Date:   Mon May 16 17:34:13 2022 +0200

    fix: remove hardcoded redirect in signin url email verification (#2764)

    Co-authored-by: Agusti Fernandez Pardo <git@agusti.me>

commit ae15a7d739
Author: Hariom Balhara <hariombalhara@gmail.com>
Date:   Tue May 10 14:30:43 2022 +0530

    Fix time issue

commit 2a5a89fe50
Author: Leo Giovanetti <hello@leog.me>
Date:   Wed May 11 10:21:46 2022 -0300

    Missing fix for success page

commit 2ce1e78053
Author: Leo Giovanetti <hello@leog.me>
Date:   Wed May 11 10:12:59 2022 -0300

    Hotfix: Success page for recurring event (#2725)

    * Merge pull request #2672 from calcom/main

    v1.5.4

    * Turbo fixes

    * Make apps single pages public

    * Fix preview.html not built and thus served during depooy (#2713)

    * Hotfix: Success page layout broken due to duplicate "When" (#2716)

    * Update BookingPage.tsx

    * Reverting unchaged lines

    * Fixing recurrenceRule for ICS files

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

commit 2d6d1cb444
Author: Hariom Balhara <hariombalhara@gmail.com>
Date:   Tue May 10 14:49:46 2022 +0530

    Hotfix: Success page layout broken due to duplicate "When" (#2716)

commit ef68f4f4f8
Author: Hariom Balhara <hariombalhara@gmail.com>
Date:   Tue May 10 10:54:20 2022 +0530

    Fix preview.html not built and thus served during depooy (#2713)

commit 18c28cc3fd
Author: zomars <zomars@me.com>
Date:   Mon May 9 16:17:07 2022 -0600

    Make apps single pages public

commit d40e8caff9
Author: zomars <zomars@me.com>
Date:   Mon May 9 16:08:03 2022 -0600

    Turbo fixes

commit 3161cc4d45
Merge: ed808c3be 4099a477d
Author: zomars <zomars@me.com>
Date:   Mon May 9 14:58:33 2022 -0600

    Merge branch 'main' into production

commit ed808c3be6
Author: Omar López <zomars@me.com>
Date:   Mon May 9 14:56:23 2022 -0600

    Merge pull request #2672 from calcom/main

    v1.5.4

* Typo

* Typo

* Update apps/web/pages/apps/categories/[category].tsx

* Apply suggestions from code review

* Alert to describe exclusion of options (#2770)

* Alert to describe exclusion of options

* Update apps/web/pages/event-types/[type].tsx

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

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

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

* Formatting

Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com>
Co-authored-by: Omar López <zomars@me.com>

* fix: split time correctly if the local working hours are just across mid night (#2766)

Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com>

* Update crowdin.yml

* New Crowdin translations by Github Action (#2773)

* New Crowdin translations by Github Action

* Update vital.json

* Update vital.json

Co-authored-by: Crowdin Bot <support+bot@crowdin.com>
Co-authored-by: Omar López <zomars@me.com>

* Add Google cal extneral calendar id to booking reference (#2671)

* Set google cal event id to use our uid

* Save calendar external id to bookingRef

* Pass external calendar ids to update and delete

* Create migration

* Fix type errors

* Fix prisma url

Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com>
Co-authored-by: Omar López <zomars@me.com>

* v1.6

* v1.6

* 2FA submit disabled (#2790)

* fixing the hyperlink for open startup (#2777)

Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com>

* Add login event (#2784)

Co-authored-by: Bailey Pumfleet <pumfleet@hey.com>

* Fixes infinite loop

* Fixes infinite loop

* Fixes infinite loop

* Update all Yarn dependencies (2022-05-16) (#2769)

* Update all Yarn dependencies (2022-05-16)

* Upgrade dependencies

* Removes deprecated packages

* Upgrades deps

* Updates submodules

* Update yarn.lock

* Linting

* Linting

* Update website

* Build fixes

* TODO: fix this

* Module resolving

* Type fixes

* Intercom fixes on SSG

* Fixes infinite loop

* Upgrades to React 18

* Type fixes

* Locks node version to 14

* Upgrades daily-js

* Readds missing types

* Upgrades playwright

* Noop when intercom is not installed

* Update website

* Removed yarn.lock in favor of monorepo

Co-authored-by: depfu[bot] <23717796+depfu[bot]@users.noreply.github.com>
Co-authored-by: zomars <zomars@me.com>

* Create ci.yml

* Update ci.yml

* Reintroduces typescript-eslint

Buckle up!

* Type fixes

* Update ci.yml

* Update api

* Update admin

* Reusable inferSSRProps

* Linting

* Linting

* Prisma fixes

* Update ci.yml

* Cache testing

* Update e2e.yml

* Update DatePicker.tsx

* Update e2e.yml

* Revert "Linting"

This reverts commit adf817766e.

* Revert "Linting"

This reverts commit 1b59dacd64.

* Linting

* Update e2e.yml

* Ci updates

* Add team Id to hash url (#2803)

* Fix missing tabs - Embed (#2804)

* Fix missing tabs

* Fix Eslint error

* Fix Eslint errors

* Add import statement (#2812)

* Add import statement

* Update apps/docs/next.config.js

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

* Show success page if booking was deleted on calendar (#2808)

* Add exception to 410

* Fix type error

* Add GoogelCalError type

* only show invite link for app.cal.dev (#2807)

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

* fix: update eslint config to test .ts and .js separately (#2805)

* fix: update eslint config

* fix: update ts ignore

* fix: update eslint config

* Update TeamAvailabilityScreen.tsx

* Type fixes

* Update useIntercom.ts

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

* fix: sync api to latest commit (#2810)

Co-authored-by: Agusti Fernandez Pardo <git@agusti.me>
Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com>

* Embed React improvements (#2782)

* Add off support. Add getApi export.

* Add publish command

* Add embed-snippet in prod deps

* Update README

* Update package.json

Co-authored-by: Bailey Pumfleet <pumfleet@hey.com>
Co-authored-by: zomars <zomars@me.com>
Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com>

* Consolidates test-results

* Add vscode tasks.json (#2801)

Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com>

* save additional inputs as json + view details of booking (#2796)

* move custom inputs from description to own json object

* show custom inputs on success page

* fix type error

* add custom inputs to email and webhook

* add custom inputs to all emails

* add values for custom inputs when rescheduling

* add custom input everywhere description is shown

* fix bug with boolean value

* fix issues with null values

* disable custom inputs and add notes for organizer

* don't show custom input with empty string

* don't show custom inputs with empty string in calender event and email

* add link to booking details page

* redirect to success page to see booking details

* add functionality to cancel and reschedule booking

* fix bookings that require confirmation

* clean code

* fix infinite lopp in useEffect of success page

* show web conference details message when integration as location

* improve design of cancelling event

* clean code

* disable darkmode for organizer on booking details page

* fix dark mode for cancelling booking

* fix build error

* Fixes infinite loop

* Fixes infinite loop

* Fixes infinite loop

* Update all Yarn dependencies (2022-05-16) (#2769)

* Update all Yarn dependencies (2022-05-16)

* Upgrade dependencies

* Removes deprecated packages

* Upgrades deps

* Updates submodules

* Update yarn.lock

* Linting

* Linting

* Update website

* Build fixes

* TODO: fix this

* Module resolving

* Type fixes

* Intercom fixes on SSG

* Fixes infinite loop

* Upgrades to React 18

* Type fixes

* Locks node version to 14

* Upgrades daily-js

* Readds missing types

* Upgrades playwright

* Noop when intercom is not installed

* Update website

* Removed yarn.lock in favor of monorepo

Co-authored-by: depfu[bot] <23717796+depfu[bot]@users.noreply.github.com>
Co-authored-by: zomars <zomars@me.com>

* Create ci.yml

* Update ci.yml

* Reintroduces typescript-eslint

Buckle up!

* Type fixes

* Update ci.yml

* Update api

* Update admin

* Reusable inferSSRProps

* Linting

* Linting

* Prisma fixes

* Update ci.yml

* Cache testing

* Update e2e.yml

* Update DatePicker.tsx

* Update e2e.yml

* Revert "Linting"

This reverts commit adf817766e.

* Revert "Linting"

This reverts commit 1b59dacd64.

* Linting

* Update e2e.yml

* Ci updates

* Add team Id to hash url (#2803)

* Fix missing tabs - Embed (#2804)

* Fix missing tabs

* Fix Eslint error

* Fix Eslint errors

* Add import statement (#2812)

* Add import statement

* Update apps/docs/next.config.js

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

* Show success page if booking was deleted on calendar (#2808)

* Add exception to 410

* Fix type error

* Add GoogelCalError type

* only show invite link for app.cal.dev (#2807)

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

* fix: update eslint config to test .ts and .js separately (#2805)

* fix: update eslint config

* fix: update ts ignore

* fix: update eslint config

* Update TeamAvailabilityScreen.tsx

* Type fixes

* Update useIntercom.ts

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

* fix: sync api to latest commit (#2810)

Co-authored-by: Agusti Fernandez Pardo <git@agusti.me>
Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com>

* Embed React improvements (#2782)

* Add off support. Add getApi export.

* Add publish command

* Add embed-snippet in prod deps

* Update README

* Update package.json

Co-authored-by: Bailey Pumfleet <pumfleet@hey.com>
Co-authored-by: zomars <zomars@me.com>
Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com>

* Consolidates test-results

* Type fixes

* Abstracts minimal booking select

* Type fixes

* Update listBookings.ts

* Update common.json

* Update bookingReminder.ts

* Consolidates isOutOfBounds

* Update webhookResponse-chromium.txt

* Update TableActions.tsx

* Type fixes

* Update BookingPage.tsx

* Update webhookResponse-chromium.txt

Co-authored-by: CarinaWolli <wollencarina@gmail.com>
Co-authored-by: Alex van Andel <me@alexvanandel.com>
Co-authored-by: Bailey Pumfleet <pumfleet@hey.com>
Co-authored-by: zomars <zomars@me.com>
Co-authored-by: depfu[bot] <23717796+depfu[bot]@users.noreply.github.com>
Co-authored-by: sean-brydon <55134778+sean-brydon@users.noreply.github.com>
Co-authored-by: Hariom Balhara <hariombalhara@gmail.com>
Co-authored-by: Joe Au-Yeung <65426560+joeauyeung@users.noreply.github.com>
Co-authored-by: iamkun <kunhello@outlook.com>
Co-authored-by: Agusti Fernandez Pardo <me@agusti.me>
Co-authored-by: Agusti Fernandez Pardo <git@agusti.me>
Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com>

* Update check-types.yml

* adding organizer as attendee to google calendar events (#2779)

* Fix auto-select and close of dropdown (#2819)

* fixes dynamic color and typefix for tfunction after react upgrade (#2821)

* New Crowdin translations by Github Action (#2791)

Co-authored-by: Crowdin Bot <support+bot@crowdin.com>

* Relocates admin to console

# Conflicts:
#	apps/admin

* Relocates admin to console

* Fix login submit (#2849)

* fix: long string overflowing calendar div (#2842)

Co-authored-by: gitstart <gitstart@users.noreply.github.com>
Co-authored-by: Júlio Piubello da Silva Cabral <julio.piubello@gitstart.dev>

* Adding labels (#2783)

Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com>

* Wrong username is identified if query params are present and user doesn't exist (#2838)

Co-authored-by: gitstart <gitstart@users.noreply.github.com>
Co-authored-by: Júlio Piubello da Silva Cabral <julio.piubello@gitstart.dev>

* Meet/Zoom Email Clarification (#2828)

* Add clarificaiton to email

* Update apps/web/lib/emails/templates/organizer-scheduled-email.ts

* Add to attendee scheduled email

Co-authored-by: Omar López <zomars@me.com>
Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com>

* Request the inclusion Assuncion Time Zone (#2840)

Co-authored-by: gitstart <gitstart@users.noreply.github.com>
Co-authored-by: Júlio Piubello da Silva Cabral <julio.piubello@gitstart.dev>

* Fix UI of dialog (#2788)

* removed large mandatory height and scroll

* added z index using css

* cleanup

* fixed TS errors

* extract dialog out of dropdown

* Adds custom loading text to confirmation dialog

* rename update

* utilizing mutation loading state

Co-authored-by: Peer Richelsen <peeroke@gmail.com>
Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com>

* Hotfix: Fixing Security Issues (#2848)

* Fixing Privilege Escalation

* Fixing critical obj ref in availability

* Fixing reschedule security issue

Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com>
Co-authored-by: Peer Richelsen <peeroke@gmail.com>

* Merge production to main

* Update vital.json

* Update vital.json

* Fix login page CTA disabled state (#2832)

* fix(ui/login): better disabled state for login CTA

The fix involves tracking the form submission with a dedicated state `submitInProgress` with React.
`formState` from `react-hook-form` does not take time taken for the network call into account. For example,
if the api takes 5 seconds to complete, we would expect the `formState.isSubmitting` to be true for `5`
seconds. But, surprisingly this is not the case and `formState` from `react-hook-form` resolves
immediately after it makes a successful connection to the endpoint.

A dedicated state (with `useState`) is introduced that is enabled when the user clicks on the login CTA, and disabled when the api call is resolved, either successfully or with an error.

* Update login.tsx

* Update login.tsx

* Fixes isSubmitting state

Co-authored-by: zomars <zomars@me.com>

* Playwright binaries shouldn't be on deps

* Playwright binaries shouldn't be on deps

* Fix infinite renders on event-type edit page (#2820)

* Updates submodules

* Makes sure to hash post-install cache

* Add seats to event types (#2485)

* Add seatsPerTimeSlot to event type schema

* Add seats per time slot to event type form

* Book event and render seats

* Pass booking uid for seats

* Disable requires confirmation if seats are enabled

* Fix type errors

* Update submodules

* Fix type errors

* Fix type errors

* Fix duplicate string

* Fix duplicate string

* Fix schema and migration file

* Fix render seats

* Fix bookinguid typos

* Remove console.log

* Fix type error

* Fix mobile formatting

* Update apps/web/lib/hooks/useSlots.ts

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

* Update apps/web/lib/hooks/useSlots.ts

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

* Added translation for seats available text

Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com>
Co-authored-by: zomars <zomars@me.com>
Co-authored-by: alannnc <alannnc@gmail.com>

* Redesign help menu item (#2710)

* Seperate help menu item and contact menu item

* Add menu items

* Install react-popover

* Render contact only if support keys are present

* Adjust contact support links

* Add translations

* Add embed changes

* Adjust menu if helped is pressed

* Add items to help menu

* Change button color on selection

* Create endpoint

* Create feedback table

* Create migration file

* Write feedback to db

* Remove logs

* Add response message

* Send feedback email

* Disable submit if no rating and after submit

* Add translations

* Fix padding

* Clean up

* Clean up

* Add user feedback email to .env example

* Lint fixes and styles

* Changed onClick function to a named function and fix style

* Fix ids order

* Removed commented code and changed textarea id and name

* Fix id orders

* Change to AND operator

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

* Add user relation to feedback

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

* Add migration files

* Change rating to strings

* Change rating to strings

* Fix type errors

* WIP success & error messages

* Change success and error to boolans

* Style messages

* Add await

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

* Remove duplicate string

* Refactor import statement

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

* Change opacity of emojis

* added support@cal.com email for feedback

* Add success toast

* Update .env.example

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

* Add tCRP route

* tCRP send email

* tCRP send email

Co-authored-by: Alan <alannnc@gmail.com>
Co-authored-by: Omar López <zomars@me.com>
Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com>
Co-authored-by: Peer Richelsen <peeroke@gmail.com>

* fixed labels for seats, removes shadow from event-type inputs (#2862)

* fixed labels for seats

* minor fixes, removed shadow from all event-type inputs

* Render input field on pro accounts (#2859)

Co-authored-by: Joe Au-Yeung <65426560+joeauyeung@users.noreply.github.com>

* Submodule sync

* sec-001 fixes (#2866) (#2867)

* sec-001 fixes (#2866)

* sec-001 fixes

* Typo

* Fixes paid bookings

# Conflicts:
#	apps/web/ee/components/stripe/Payment.tsx

* Hotfix: Fixing Security Issues (#2848) (#2850)

* sec-001 fixes (#2866)

* sec-001 fixes

* Typo

* Fixes paid bookings

* fixes issues with date of recurring events on booking detail page (#2872)

* fixes date not showing for confirmed recurring event

* only show all events on upcoming bookings

Co-authored-by: CarinaWolli <wollencarina@gmail.com>

* Resolve if can't find event on google cal (#2860)

* Resolve if can't find event on google cal

* Change order of  console.error

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

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

* Disable Impersonation Option (#2880)

* Disable Impersonation

* Update Description Copy

Co-authored-by: Peer Richelsen <peeroke@gmail.com>

* Fix deleted event when on different cal (404) (#2882)

* Fix/email shows false (#2879)

* Webhook sec fixes (#2883)

* Webhook sec fixes

* Revert changes

* Feat/Display location information publicly  (#2752)

* Updating checkbox field to reflect new designs

* Include Infobadge option checkbox

* Checkbox Field + i18n

* Default checked - true

* Sync with router

* Extracting Types

* Update filtering logic

* Add UI to booking page

* Default address/link

* Update hashedlink page

* Tidy up

* Video icon

* Add nullish check

* Update to use RHF controller

Co-authored-by: Peer Richelsen <peeroke@gmail.com>
Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com>

* Fix 500 errors if data is invalid (#2886)

* Check in middleware to ensure authorization for all endpoints (#2885)

Co-authored-by: Alex van Andel <me@alexvanandel.com>

* Fix bug to check opt in bookings (#2889)

* Fix bug to check opt in bookings

* Implemented value, onChange instead of form access

Co-authored-by: Alex van Andel <me@alexvanandel.com>

* remove unused imports (#2892)

* Cascades impersonations on user delete (#2891)

Co-authored-by: Alex van Andel <me@alexvanandel.com>

* Ensures json fields on each call (#2893)

Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com>

* Redundant conditional expression (#2894)

* remove redundant conditional expressions

* remove redundant conditional expressions

* License server (#2379)

* WIP License server

* WIP

* Moves locations to App Store and Core

* LocationType fixes

* Runs db migrations post-deploy

* WIP

* WIP

* Cleanup

* WIP

* WIP

* Decouples translations from NavTabs

* Adds admin submodule

* Adds admin submodule

* Sync dependencies

* WIP

* WIP

* Updates submodules

* Renames package

* Updates submodules

* Adds scripts for console

* Updates license checker URL

* Updates admin

* Adds staging/prod admin console links

* Update yarn.lock

* Update NavTabs.tsx

* WIP

* Update admin

* WIP

* Adds hint to InputField

* Update admin

* Adds turbo admin dependecies

* Update admin

* Prevents redirection on form submit

* Form warning fixes

* Update admin

* Form fixes

* Update yarn.lock

* Update admin

* Update admin

* Update admin

* Adds withLicenseRequired HOC

* Adds LicenseRequired to EE components

* Admin deploy fix?

* Updates submodules

* Use relative inside lib

* type fixes

* Fixes turbo race condition

* Relocates admin to console

* Relocates admin to console

* Update console

* Update api

* Update turbo.json

* Update ErrorBoundary.tsx

* Update defaultEvents.ts

* Update checkLicense.ts

* Update yarn.lock

* Skip on E2E

Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com>

* Update turbo.json

* Reverts license check on payment

Since it's a public page

* Submodule sync

* fix: overflowing text on teams page - using tailwind line-clamp (#2843)

Co-authored-by: gitstart <gitstart@users.noreply.github.com>
Co-authored-by: Júlio Piubello da Silva Cabral <julio.piubello@gitstart.dev>

* Fix @calcom/embed-react installation with TS project (#2870)

* Fix failing builds (#2908)

* Update turbo.json

* Change location of booking (#2658)

* add functionality to change location in booking and send out mail

* add i18n

* change location with dropdown like in event-types

* small fixes and code clean up

* clean code

* improve format of current Location string

* clean code

* clear selection when dialog closed

* added mutation and changed props (first working verison)

* clean code

* clean code

* clean code

* clean code

* fix typo

* change maxHeight of select

* use useWatch for selectedLocation

* pass default values with props

* set current location directly in useState

* clear selected values when updating location

* fix trpc query for credentialst

* change icons for editing booking

* improve naming of variables

* remove unnecessary orderBy

* use locationOptionsToString method

* fix current location naming for Cal Video

* add phone input

* save phone number as location of booking

* remove input field for phone number for event-types

* fix redirection issue

* show previous selected location in event-type

* remove attendee number from selection for booking

* make first letter of location lowercase

* remove input field for attendee phone number

* clear Errors when changing location type

* set location details to optional

* clean code

* fixing issue that dropdown doesn't close when dialog opens

* clean code

* make overflow visibile in dialog

* fix existing bug with address not showing in event-type settings

* fix issue with losing focus after validation

* close rejection dialog

* small spelling fixes

* fix issue with LocationChangeEmail

* fix failing E2E test

* fix failing E2E test

* fix E2E test

* bug fix for saving user phone, and other minor changes

* merge main

* improve text

* fix UI of booking list

* Delete admin

* remove selection after update and submit

* add translation for error message

* add default values for checkbox

* add "your phone number" to locations on booking page

* remove duplicate attributes from viewer.bookings

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

* check if user is authorized to make changes to booking

* remove location string

* clan code for displayLocaitonPublicly checkbox

* fetch locationOptions on server side

* remove trpc query for credentials

* fix phone number input

* fix labels of host and attendee phone number for booking page

* Migrates edit location to tRPC

* Link elemnt should only be used in `a` tags

* Adds missin router

* Migrates locationOptions to tRPC query

* Type fixes

Co-authored-by: CarinaWolli <wollencarina@gmail.com>
Co-authored-by: Alan <alannnc@gmail.com>
Co-authored-by: Omar López <zomars@me.com>
Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com>

* added checkly and twitch badges

* Update README.md

* areas of expertise test

* Update CONTRIBUTING.md

* Update README.md (#2912)

* Update CONTRIBUTING.md

* Update CONTRIBUTING.md

* Update CONTRIBUTING.md

* Update CONTRIBUTING.md

* Update CONTRIBUTING.md

* Update CONTRIBUTING.md

* remove unsed imports (#2895)

Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com>

* Fix event-type preview links on Vercel Previews (#2919)

* Fix website url

* Fix avatar paths everywhere

* Fix linting errors

Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com>

* Cleanup & removed usages of sparingly used Text/ files (#2904)

* Update CONTRIBUTING.md

* Update CONTRIBUTING.md

* Fixed typo in CheckboxField and wrapped description in <label> (#2924)

* Fixed typo in CheckboxField and wrapped description in <label>

* Make functionality identical to before

* Fixed use of infomationIconText

* Fix lint error (needs refactor, out of scope)

* Payment amount input leading 0 (#2836)

Co-authored-by: gitstart <gitstart@users.noreply.github.com>
Co-authored-by: Júlio Piubello da Silva Cabral <julio.piubello@gitstart.dev>

* Allow less than 6 bookings and add proper min validation of 2+ (#2921)

Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com>

* fix(app-store): Giphy Ux fixes (#2746)

* fix(app-store): Giphy Ux fixes

* Add search placeholder

* Min height image on event type page

* Use regex in zod validation and fix design issues for figma row 1

* Add paddings as per discussion with Ciarán

* Fix getGiphyApiKey nomenclature

* Update apps/web/public/static/locales/en/common.json

* Update regex to be more readable and allow enter to search

Co-authored-by: Omar López <zomars@me.com>
Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com>
Co-authored-by: Joe Au-Yeung <65426560+joeauyeung@users.noreply.github.com>

* Add embed tests in CI (#2887)

* Add embed tests in CI

* Update e2e-embed.yml

* Run quick tests only

* Ignore certain folders

* Add embed-react tests as well

* Fix commands

* Dont run unit tests

* Update playwright.config.ts

* Update playwright.config.ts

* Update playwright.config.ts

* Create correct artifcats

* Create correct artifcats

* Fi ignore path

* Update package.json

* Add back embed-react typecheck

Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com>

* remove subtitle (#2925)

Co-authored-by: CarinaWolli <wollencarina@gmail.com>
Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com>

* Fix booking detail page for cancelled events (#2905)

* fix booking detail page for cancelled events

* Fix typo

* fix bug when now attendees exist in booking

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

* v1.6.2

* Add reschedule reason to DB and emails (#2909)

* Write reschedule reason to db

* Add reschedule reason to emails

* Add reschedule reason to request reschedule email

* Add reschedule reason to request reschedule email

* Add reschedule reason to request reschedule email

* Add reschedule reason to request reschedule email

* Write reschedule reason to db

* Add reschedule reason to emails

* No longer using rescheduleReason in favor of cancellationReason

* Update apps emails accordingly with reschedule reason

* Update reschedule.test.ts

Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com>
Co-authored-by: Alan <alannnc@gmail.com>
Co-authored-by: zomars <zomars@me.com>

* Update website

* Update HelpMenuItem.tsx

* Update event.ts

Co-authored-by: Peer Richelsen <peeroke@gmail.com>
Co-authored-by: Carina Wollendorfer <30310907+CarinaWolli@users.noreply.github.com>
Co-authored-by: CarinaWolli <wollencarina@gmail.com>
Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com>
Co-authored-by: Hariom Balhara <hariombalhara@gmail.com>
Co-authored-by: Syed Ali Shahbaz <52925846+alishaz-polymath@users.noreply.github.com>
Co-authored-by: Joe Au-Yeung <65426560+joeauyeung@users.noreply.github.com>
Co-authored-by: Leo Giovanetti <hello@leog.me>
Co-authored-by: Alex van Andel <me@alexvanandel.com>
Co-authored-by: Bailey Pumfleet <pumfleet@hey.com>
Co-authored-by: GitStart <1501599+gitstart@users.noreply.github.com>
Co-authored-by: gitstart <gitstart@users.noreply.github.com>
Co-authored-by: Arthur Cruz <42497300+arthur1041@users.noreply.github.com>
Co-authored-by: Mitchell Moore <47459168+Mitchell-Moore@users.noreply.github.com>
Co-authored-by: Agusti Fernandez Pardo <me@agusti.me>
Co-authored-by: Agusti Fernandez Pardo <git@agusti.me>
Co-authored-by: sean-brydon <55134778+sean-brydon@users.noreply.github.com>
Co-authored-by: andreaestefania12 <19562383+andreaestefania12@users.noreply.github.com>
Co-authored-by: Miguel Nieto A <39246879+miguelnietoa@users.noreply.github.com>
Co-authored-by: alannnc <alannnc@gmail.com>
Co-authored-by: Hashen <37979557+Hashen110@users.noreply.github.com>
Co-authored-by: buschco <colin@busch.dev>
Co-authored-by: iamkun <kunhello@outlook.com>
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: Crowdin Bot <support+bot@crowdin.com>
Co-authored-by: Ankit Gordhandas <agordhandas@gmail.com>
Co-authored-by: depfu[bot] <23717796+depfu[bot]@users.noreply.github.com>
Co-authored-by: Ken Miller <kemiller@users.noreply.github.com>
Co-authored-by: Júlio Piubello da Silva Cabral <julio.piubello@gitstart.dev>
Co-authored-by: Arun Kumar <palerdot@users.noreply.github.com>
Co-authored-by: Shrey Gupta <connectwithshrey@gmail.com>
2022-05-30 15:36:15 -06:00
Omar López 3af6b3b6b3 Update event.ts 2022-05-30 14:43:15 -06:00
Omar López bba9b755bc Update HelpMenuItem.tsx 2022-05-30 13:43:21 -06:00
zomars ef523bda51 Update website 2022-05-30 13:41:57 -06:00
0761e8664a Add reschedule reason to DB and emails (#2909)
* Write reschedule reason to db

* Add reschedule reason to emails

* Add reschedule reason to request reschedule email

* Add reschedule reason to request reschedule email

* Add reschedule reason to request reschedule email

* Add reschedule reason to request reschedule email

* Write reschedule reason to db

* Add reschedule reason to emails

* No longer using rescheduleReason in favor of cancellationReason

* Update apps emails accordingly with reschedule reason

* Update reschedule.test.ts

Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com>
Co-authored-by: Alan <alannnc@gmail.com>
Co-authored-by: zomars <zomars@me.com>
2022-05-30 13:40:29 -06:00
zomars 6b0cffa79a v1.6.2 2022-05-30 12:53:07 -06:00
zomars 843daad481 Merge branch 'production'
# Conflicts:
#	.vscode/tasks.json
#	apps/console
#	apps/web/components/NavTabs.tsx
#	apps/web/components/SettingsShell.tsx
#	apps/web/components/booking/BookingListItem.tsx
#	apps/web/components/ui/TableActions.tsx
#	apps/web/components/ui/form/CheckboxField.tsx
#	apps/web/lib/emails/templates/attendee-scheduled-email.ts
#	apps/web/lib/emails/templates/organizer-scheduled-email.ts
#	apps/web/lib/types/booking.ts
#	apps/web/package.json
#	apps/web/pages/event-types/[type].tsx
#	apps/web/pages/getting-started.tsx
#	apps/web/pages/success.tsx
#	apps/web/public/static/locales/en/common.json
#	packages/config/package.json
#	packages/embeds/embed-core/package.json
#	packages/embeds/embed-react/package.json
#	packages/embeds/embed-react/src/index.ts
#	packages/embeds/embed-snippet/package.json
#	packages/embeds/embed-snippet/src/index.ts
#	packages/lib/isPrismaObj.ts
#	packages/lib/package.json
#	packages/ui/Dialog.tsx
#	yarn.lock
2022-05-30 12:50:31 -06:00
375517486c Fix booking detail page for cancelled events (#2905)
* fix booking detail page for cancelled events

* Fix typo

* fix bug when now attendees exist in booking

Co-authored-by: CarinaWolli <wollencarina@gmail.com>
Co-authored-by: Alan <alannnc@gmail.com>
2022-05-30 20:17:50 +02:00
bc74014040 remove subtitle (#2925)
Co-authored-by: CarinaWolli <wollencarina@gmail.com>
Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com>
2022-05-30 17:26:58 +00:00
Hariom Balharaandkodiakhq[bot] 3035412cdc Add embed tests in CI (#2887)
* Add embed tests in CI

* Update e2e-embed.yml

* Run quick tests only

* Ignore certain folders

* Add embed-react tests as well

* Fix commands

* Dont run unit tests

* Update playwright.config.ts

* Update playwright.config.ts

* Update playwright.config.ts

* Create correct artifcats

* Create correct artifcats

* Fi ignore path

* Update package.json

* Add back embed-react typecheck

Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com>
2022-05-30 22:41:05 +05:30
f7cec8d71f fix(app-store): Giphy Ux fixes (#2746)
* fix(app-store): Giphy Ux fixes

* Add search placeholder

* Min height image on event type page

* Use regex in zod validation and fix design issues for figma row 1

* Add paddings as per discussion with Ciarán

* Fix getGiphyApiKey nomenclature

* Update apps/web/public/static/locales/en/common.json

* Update regex to be more readable and allow enter to search

Co-authored-by: Omar López <zomars@me.com>
Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com>
Co-authored-by: Joe Au-Yeung <65426560+joeauyeung@users.noreply.github.com>
2022-05-30 10:23:23 -06:00
Hariom Balharaandkodiakhq[bot] b22c562719 Allow less than 6 bookings and add proper min validation of 2+ (#2921)
Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com>
2022-05-30 09:46:05 -06:00
e493b16466 Payment amount input leading 0 (#2836)
Co-authored-by: gitstart <gitstart@users.noreply.github.com>
Co-authored-by: Júlio Piubello da Silva Cabral <julio.piubello@gitstart.dev>
2022-05-30 09:28:32 -06:00
Alex van Andel d1f117f17a Fixed typo in CheckboxField and wrapped description in <label> (#2924)
* Fixed typo in CheckboxField and wrapped description in <label>

* Make functionality identical to before

* Fixed use of infomationIconText

* Fix lint error (needs refactor, out of scope)
2022-05-30 14:51:18 +00:00
Peer Richelsen af5bc9d530 Update CONTRIBUTING.md 2022-05-30 12:44:28 +02:00
Peer Richelsen d94267cdc1 Update CONTRIBUTING.md 2022-05-30 12:37:57 +02:00
Alex van Andel a15fe78ddb Cleanup & removed usages of sparingly used Text/ files (#2904) 2022-05-30 11:36:23 +02:00
Hariom Balharaandkodiakhq[bot] e270be1b87 Fix event-type preview links on Vercel Previews (#2919)
* Fix website url

* Fix avatar paths everywhere

* Fix linting errors

Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com>
2022-05-30 07:57:48 +00:00
Hashenandkodiakhq[bot] 8fe969d3b8 remove unsed imports (#2895)
Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com>
2022-05-30 05:19:22 +00:00
Omar López 9fced41cd0 Update CONTRIBUTING.md 2022-05-28 16:56:03 -06:00
Omar López b3e9a38231 Update CONTRIBUTING.md 2022-05-28 16:54:01 -06:00
Omar López c144c365de Update CONTRIBUTING.md 2022-05-28 16:46:24 -06:00
Omar López 00e728e968 Update CONTRIBUTING.md 2022-05-28 12:50:52 -06:00
Omar López be92cc3563 Update CONTRIBUTING.md 2022-05-28 11:37:58 -06:00
Omar López 99c6b92bfe Update CONTRIBUTING.md 2022-05-28 10:35:07 -06:00
Hashen ce0fb6c09e Update README.md (#2912) 2022-05-28 18:20:28 +02:00
Peer Richelsen dfd6bc1523 Update CONTRIBUTING.md 2022-05-28 18:10:56 +02:00
Peer Richelsen a542930b87 areas of expertise test 2022-05-28 18:07:10 +02:00
Peer Richelsen 46752bd0d8 Update README.md 2022-05-28 11:26:38 +02:00
Peer Richelsen 0458203281 added checkly and twitch badges 2022-05-28 11:26:11 +02:00
7b01bae829 Change location of booking (#2658)
* add functionality to change location in booking and send out mail

* add i18n

* change location with dropdown like in event-types

* small fixes and code clean up

* clean code

* improve format of current Location string

* clean code

* clear selection when dialog closed

* added mutation and changed props (first working verison)

* clean code

* clean code

* clean code

* clean code

* fix typo

* change maxHeight of select

* use useWatch for selectedLocation

* pass default values with props

* set current location directly in useState

* clear selected values when updating location

* fix trpc query for credentialst

* change icons for editing booking

* improve naming of variables

* remove unnecessary orderBy

* use locationOptionsToString method

* fix current location naming for Cal Video

* add phone input

* save phone number as location of booking

* remove input field for phone number for event-types

* fix redirection issue

* show previous selected location in event-type

* remove attendee number from selection for booking

* make first letter of location lowercase

* remove input field for attendee phone number

* clear Errors when changing location type

* set location details to optional

* clean code

* fixing issue that dropdown doesn't close when dialog opens

* clean code

* make overflow visibile in dialog

* fix existing bug with address not showing in event-type settings

* fix issue with losing focus after validation

* close rejection dialog

* small spelling fixes

* fix issue with LocationChangeEmail

* fix failing E2E test

* fix failing E2E test

* fix E2E test

* bug fix for saving user phone, and other minor changes

* merge main

* improve text

* fix UI of booking list

* Delete admin

* remove selection after update and submit

* add translation for error message

* add default values for checkbox

* add "your phone number" to locations on booking page

* remove duplicate attributes from viewer.bookings

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

* check if user is authorized to make changes to booking

* remove location string

* clan code for displayLocaitonPublicly checkbox

* fetch locationOptions on server side

* remove trpc query for credentials

* fix phone number input

* fix labels of host and attendee phone number for booking page

* Migrates edit location to tRPC

* Link elemnt should only be used in `a` tags

* Adds missin router

* Migrates locationOptions to tRPC query

* Type fixes

Co-authored-by: CarinaWolli <wollencarina@gmail.com>
Co-authored-by: Alan <alannnc@gmail.com>
Co-authored-by: Omar López <zomars@me.com>
Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com>
2022-05-27 23:27:41 +00:00
zomars b869e70a7f Update turbo.json 2022-05-27 13:49:13 -06:00
Omar Lópezandkodiakhq[bot] 411497575a Ensures json fields on each call (#2893)
Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com>
2022-05-27 11:14:08 -06:00
Hariom Balhara e1bf425c1c Fix failing builds (#2908) 2022-05-27 11:07:02 -06:00
Hariom Balhara 445cdd7cbf Fix @calcom/embed-react installation with TS project (#2870) 2022-05-27 09:37:02 -06:00
d6678f9b3a fix: overflowing text on teams page - using tailwind line-clamp (#2843)
Co-authored-by: gitstart <gitstart@users.noreply.github.com>
Co-authored-by: Júlio Piubello da Silva Cabral <julio.piubello@gitstart.dev>
2022-05-27 12:38:50 +02:00
zomars 01025fa34c Submodule sync 2022-05-26 13:31:55 -06:00
zomars b973f971a7 Reverts license check on payment
Since it's a public page
2022-05-26 12:05:51 -06:00
zomars 2f832800fc Update turbo.json 2022-05-26 11:44:23 -06:00
Omar Lópezandkodiakhq[bot] 9df4867fca License server (#2379)
* WIP License server

* WIP

* Moves locations to App Store and Core

* LocationType fixes

* Runs db migrations post-deploy

* WIP

* WIP

* Cleanup

* WIP

* WIP

* Decouples translations from NavTabs

* Adds admin submodule

* Adds admin submodule

* Sync dependencies

* WIP

* WIP

* Updates submodules

* Renames package

* Updates submodules

* Adds scripts for console

* Updates license checker URL

* Updates admin

* Adds staging/prod admin console links

* Update yarn.lock

* Update NavTabs.tsx

* WIP

* Update admin

* WIP

* Adds hint to InputField

* Update admin

* Adds turbo admin dependecies

* Update admin

* Prevents redirection on form submit

* Form warning fixes

* Update admin

* Form fixes

* Update yarn.lock

* Update admin

* Update admin

* Update admin

* Adds withLicenseRequired HOC

* Adds LicenseRequired to EE components

* Admin deploy fix?

* Updates submodules

* Use relative inside lib

* type fixes

* Fixes turbo race condition

* Relocates admin to console

* Relocates admin to console

* Update console

* Update api

* Update turbo.json

* Update ErrorBoundary.tsx

* Update defaultEvents.ts

* Update checkLicense.ts

* Update yarn.lock

* Skip on E2E

Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com>
2022-05-26 11:07:14 -06:00
Hashen 6940c8d6cc Redundant conditional expression (#2894)
* remove redundant conditional expressions

* remove redundant conditional expressions
2022-05-26 16:41:05 +00:00
Omar Lópezandkodiakhq[bot] 24a3bfdf78 Ensures json fields on each call (#2893)
Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com>
2022-05-26 16:01:12 +00:00
Omar LópezandAlex van Andel 9710c6faa6 Cascades impersonations on user delete (#2891)
Co-authored-by: Alex van Andel <me@alexvanandel.com>
2022-05-26 15:48:02 +00:00
Hashen a0a4ff6ce6 remove unused imports (#2892) 2022-05-26 15:38:47 +00:00
Joe Au-YeungandAlex van Andel c67338bb3f Fix bug to check opt in bookings (#2889)
* Fix bug to check opt in bookings

* Implemented value, onChange instead of form access

Co-authored-by: Alex van Andel <me@alexvanandel.com>
2022-05-26 16:24:19 +01:00
Hariom BalharaandAlex van Andel 727c6f723e Check in middleware to ensure authorization for all endpoints (#2885)
Co-authored-by: Alex van Andel <me@alexvanandel.com>
2022-05-26 13:52:25 +00:00
Hariom Balhara 40c81ee405 Fix 500 errors if data is invalid (#2886) 2022-05-26 08:38:10 +00:00
7c3090bc23 Feat/Display location information publicly (#2752)
* Updating checkbox field to reflect new designs

* Include Infobadge option checkbox

* Checkbox Field + i18n

* Default checked - true

* Sync with router

* Extracting Types

* Update filtering logic

* Add UI to booking page

* Default address/link

* Update hashedlink page

* Tidy up

* Video icon

* Add nullish check

* Update to use RHF controller

Co-authored-by: Peer Richelsen <peeroke@gmail.com>
Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com>
2022-05-25 14:34:08 -06:00
Omar López 1bd6d03352 Webhook sec fixes (#2883)
* Webhook sec fixes

* Revert changes
2022-05-25 13:31:29 -06:00
Omar López 058550ba3d Webhook sec fixes (#2883)
* Webhook sec fixes

* Revert changes
2022-05-25 19:26:42 +00:00
Alex van Andel 6c248bb9f0 Fix deleted event when on different cal (404) (#2882) 2022-05-25 11:12:49 -06:00
29b09ce85d Resolve if can't find event on google cal (#2860)
* Resolve if can't find event on google cal

* Change order of  console.error

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

Co-authored-by: Omar López <zomars@me.com>
Co-authored-by: Peer Richelsen <peeroke@gmail.com>
2022-05-25 11:12:49 -06:00
Carina Wollendorfer ba4d2425cf Fix/email shows false (#2879) 2022-05-25 17:42:08 +01:00
Alex van Andel 49b361ab9c Fix deleted event when on different cal (404) (#2882) 2022-05-25 10:40:33 -06:00
sean-brydonandPeer Richelsen 1bf009f5f5 Disable Impersonation Option (#2880)
* Disable Impersonation

* Update Description Copy

Co-authored-by: Peer Richelsen <peeroke@gmail.com>
2022-05-25 15:21:18 +00:00
e16eee68b0 Resolve if can't find event on google cal (#2860)
* Resolve if can't find event on google cal

* Change order of  console.error

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

Co-authored-by: Omar López <zomars@me.com>
Co-authored-by: Peer Richelsen <peeroke@gmail.com>
2022-05-25 08:29:38 -06:00
Carina WollendorferandCarinaWolli 07aa2e88a1 fixes issues with date of recurring events on booking detail page (#2872)
* fixes date not showing for confirmed recurring event

* only show all events on upcoming bookings

Co-authored-by: CarinaWolli <wollencarina@gmail.com>
2022-05-25 11:24:01 +02:00
zomars dc934ed8ca Fixes paid bookings 2022-05-24 19:31:29 -06:00
Omar López 29bb6711bb sec-001 fixes (#2866)
* sec-001 fixes

* Typo
2022-05-24 19:31:29 -06:00
Alex van Andel 94966b1643 Hotfix: Fixing Security Issues (#2848) (#2850) 2022-05-24 19:31:29 -06:00
Omar López 7548233a96 sec-001 fixes (#2866) (#2867)
* sec-001 fixes (#2866)

* sec-001 fixes

* Typo

* Fixes paid bookings

# Conflicts:
#	apps/web/ee/components/stripe/Payment.tsx
2022-05-24 19:29:29 -06:00
zomars 9fba3f3767 Fixes paid bookings
# Conflicts:
#	apps/web/ee/components/stripe/Payment.tsx
2022-05-24 19:23:47 -06:00
Omar López db784f8333 sec-001 fixes (#2866)
* sec-001 fixes

* Typo
2022-05-24 18:25:14 -06:00
zomars a48a164e71 Submodule sync 2022-05-24 17:11:41 -06:00
Peer RichelsenandJoe Au-Yeung eacfdac016 fixed labels for seats, removes shadow from event-type inputs (#2862)
* fixed labels for seats

* minor fixes, removed shadow from all event-type inputs

* Render input field on pro accounts (#2859)

Co-authored-by: Joe Au-Yeung <65426560+joeauyeung@users.noreply.github.com>
2022-05-24 22:15:53 +02:00
323524b77c Redesign help menu item (#2710)
* Seperate help menu item and contact menu item

* Add menu items

* Install react-popover

* Render contact only if support keys are present

* Adjust contact support links

* Add translations

* Add embed changes

* Adjust menu if helped is pressed

* Add items to help menu

* Change button color on selection

* Create endpoint

* Create feedback table

* Create migration file

* Write feedback to db

* Remove logs

* Add response message

* Send feedback email

* Disable submit if no rating and after submit

* Add translations

* Fix padding

* Clean up

* Clean up

* Add user feedback email to .env example

* Lint fixes and styles

* Changed onClick function to a named function and fix style

* Fix ids order

* Removed commented code and changed textarea id and name

* Fix id orders

* Change to AND operator

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

* Add user relation to feedback

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

* Add migration files

* Change rating to strings

* Change rating to strings

* Fix type errors

* WIP success & error messages

* Change success and error to boolans

* Style messages

* Add await

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

* Remove duplicate string

* Refactor import statement

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

* Change opacity of emojis

* added support@cal.com email for feedback

* Add success toast

* Update .env.example

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

* Add tCRP route

* tCRP send email

* tCRP send email

Co-authored-by: Alan <alannnc@gmail.com>
Co-authored-by: Omar López <zomars@me.com>
Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com>
Co-authored-by: Peer Richelsen <peeroke@gmail.com>
2022-05-24 13:29:39 +00:00
c8d6c0dbdd Add seats to event types (#2485)
* Add seatsPerTimeSlot to event type schema

* Add seats per time slot to event type form

* Book event and render seats

* Pass booking uid for seats

* Disable requires confirmation if seats are enabled

* Fix type errors

* Update submodules

* Fix type errors

* Fix type errors

* Fix duplicate string

* Fix duplicate string

* Fix schema and migration file

* Fix render seats

* Fix bookinguid typos

* Remove console.log

* Fix type error

* Fix mobile formatting

* Update apps/web/lib/hooks/useSlots.ts

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

* Update apps/web/lib/hooks/useSlots.ts

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

* Added translation for seats available text

Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com>
Co-authored-by: zomars <zomars@me.com>
Co-authored-by: alannnc <alannnc@gmail.com>
2022-05-24 15:19:12 +02:00
zomars cc0ea19420 Makes sure to hash post-install cache 2022-05-23 13:59:03 -06:00
zomars a551aa0089 Updates submodules 2022-05-23 13:58:47 -06:00
Hariom Balhara 0ed0891d97 Fix infinite renders on event-type edit page (#2820) 2022-05-23 12:13:54 -06:00
Hariom Balhara f0a36f8194 Fix infinite renders on event-type edit page (#2820) 2022-05-23 18:59:09 +01:00
Alex van Andel 23576038aa Hotfix: Fixing Security Issues (#2848) (#2850) 2022-05-23 18:56:42 +01:00
zomars 0c44d9e0a6 Playwright binaries shouldn't be on deps 2022-05-23 11:46:15 -06:00
zomars 67770bf878 Playwright binaries shouldn't be on deps 2022-05-23 11:44:53 -06:00
+21 81d33b51bc v1.6.1 (#2851)
* Turbo fixes

* Make apps single pages public

* fixed /booking skeleton (#2722)

* fixed /booking skeleton

* nit

* Type fixes

* Test fixes

* Update playwright.config.ts

* More test fixes

* Update dynamic-booking-pages.test.ts

* add invite link to Zapier setup page (#2696)

* add invite link and toaster to zapier setup page

* create env variable for invite link and save in database

* fetch invite link form getStaticProps

* add getStaticPath method

* clean code

* Moves app setup and index page

* Moves Loader to ui

* Trying new way to handle dynamic app store pages

* Cleanup

* Update tailwind.config.js

* zapier invite link fixes

* Tests fixes

Co-authored-by: CarinaWolli <wollencarina@gmail.com>
Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com>
Co-authored-by: zomars <zomars@me.com>

* Add more embed events (#2719)

* Add more embed events

* Add more embed events

Co-authored-by: Peer Richelsen <peeroke@gmail.com>

* adds availability select loader (#2718)

* Improve logs and Fix unwanted 500 to reduce noise in logs (#2674)

* Improve logs

* Fix unintentional 500

Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com>

* Change date format for RecurringBookings (#2707)

* Change date format for RecurringBookings

* Missing bookingId query param

Co-authored-by: Leo Giovanetti <hello@leog.me>
Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com>

* added giphy description (#2730)

* fixes #2732 (#2732)

* Hotfix : Fix Infinite loading of Bookings (#2729)

* Add more embed events

* Add more embed events

* Fix nextCursor calculation logic

Co-authored-by: Peer Richelsen <peeroke@gmail.com>

* Hotfix: Success page for recurring event (#2725)

* Merge pull request #2672 from calcom/main

v1.5.4

* Turbo fixes

* Make apps single pages public

* Fix preview.html not built and thus served during depooy (#2713)

* Hotfix: Success page layout broken due to duplicate "When" (#2716)

* Update BookingPage.tsx

* Reverting unchaged lines

* Fixing recurrenceRule for ICS files

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

* Fix preview.html not built and thus served during depooy (#2727)

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

* Allow deletion of a disabled event (#2737)

* allows deletion of disabled event

* some visual fixes

Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com>

* Multiple E2E improvements

* Parallelizes some tests

* Update booking-pages.test.ts

* E2E and paid bookings fixes

* Add 'free' and 'workingElsewhere' as a non-blocking event (#2652)

* Add 'free' and 'workingElsewhere' to non-blocking event - this will allow bookings at these times

* Update CalendarService.ts

Co-authored-by: zomars <zomars@me.com>
Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com>

* TODO marks blocking test to be fixed

* Update testUtils.ts

* Update testUtils.ts

* getBusyTimes consolidation

* Fixes delete-me test

* E2E fixing attemps

* Adjusting Zapier endpoints for publishing integration (#2728)

* add /me endpoint for zapier API testing

* remove cacellationReason from listBookings response

Co-authored-by: CarinaWolli <wollencarina@gmail.com>
Co-authored-by: Peer Richelsen <peeroke@gmail.com>
Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com>
Co-authored-by: Omar López <zomars@me.com>

* Fix reschedule not happening in calendar if two calendards are there (#2733)

Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com>
Co-authored-by: Peer Richelsen <peeroke@gmail.com>

* Increases timeout temporarily

* Merge pull request #2745 from calcom/apps/multiple-categories

Allow apps to belong to multiple categories

* Build fixes

* Populate msteams key in db (#2743)

* Populate msteams key in db

* Fix calendar credentials to teams

* Clarify account dialog

Co-authored-by: Omar López <zomars@me.com>
Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com>
Co-authored-by: Bailey Pumfleet <pumfleet@hey.com>

* Improving Email DRYness (#2486)

* Email DRY

* WIP

* Improve email DRYness

Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com>

* E2E fixtures (#2747)

* Sign in button should be changed or disabled after click #2654 (#2749)

Co-authored-by: gitstart <gitstart@users.noreply.github.com>

* Fixing ESLint warnings (#2723)

* Fixing warnings

* Reverting and disabling ESLint in some cases

* Reverting Next Images

* Reverting file, bad merge

* Targeting ESLint to line

* Additional warnings

* New warning squished

* More tweaks and major fixes

* Uneeded conf

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

* Fix/avoid multiple schedule deletions (#2602)

* Prevents users from deleting the same schedule multiple times due to delay before the schedule disappears. It also applies the same fix to team disband.

Schedule deletion:
![schedule_deletion_new_behaving](https://user-images.githubusercontent.com/42497300/165126805-b3090268-c1a6-418a-b06e-06bd8446da03.gif)

Team disband:
![team_disband_new_behaving](https://user-images.githubusercontent.com/42497300/165127043-7e083e94-e4c9-4e88-90a2-47d31bdd92e6.gif)

Fixes issue [#2569](https://github.com/calcom/cal.com/issues/2569)

Bug fix (non-breaking change which fixes an issue)

**apps/web/components/LightLoader.tsx** → this file was created in order to make a light color loading spinner available. It's necessary when we need to display a loading spinner above dark backgrounds.

**apps/web/components/availability/ScheduleListItem.tsx** → this component was created in order to give a schedule list item its own state.

* Removing a "setTimeout" that was only used for testing purposes

* Adding a code review suggestion to my modifications

* Changing loading style

* Cleanup

* Avoids using unnecessary state

* Revert "Adding a code review suggestion to my modifications"

This reverts commit b5e40062d71157ca1d9384fb1f5c30d50625809d.

* Reverts some changes

* Renames isLoading

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

* Added check on create eventtype to see is user has slug that already exists (#2757)

* Added check on create eventtype to see is user has slug that already exists, added error check on onError

* revert yarn.lock back

* Catches prisma known error instead of making an additional query

Co-authored-by: zomars <zomars@me.com>

* Fix white border (#2761)

* fix: remove hardcoded redirect in signin url email verification (#2764)

Co-authored-by: Agusti Fernandez Pardo <git@agusti.me>

* Bad UX when user wants to set the default Event Type Title #2245 (#2760)

Co-authored-by: gitstart <gitstart@users.noreply.github.com>

* Skip sending emails in E2E

* Users Phone Number Option (#2669)

* Users Phone Number Option

* Implemented improvments

* Add validation to form

Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com>
Co-authored-by: zomars <zomars@me.com>

* Fix/unpaid unconfirmed (#2553)

* Fix merge errors

* Errors prettier/prettier

* Update apps/web/pages/api/book/event.ts

Co-authored-by: Miguel Nieto A <39246879+miguelnietoa@users.noreply.github.com>

* Update apps/web/pages/api/book/event.ts

Co-authored-by: Miguel Nieto A <39246879+miguelnietoa@users.noreply.github.com>

* Update apps/web/pages/api/integrations.ts

Co-authored-by: Miguel Nieto A <39246879+miguelnietoa@users.noreply.github.com>

* Fix merge errors

* Errors prettier/prettier

* Update apps/web/pages/api/book/confirm.ts

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

* Modal window before delete stripe integration

* ESLint Report

* Test fixes

Co-authored-by: Miguel Nieto A <39246879+miguelnietoa@users.noreply.github.com>
Co-authored-by: alannnc <alannnc@gmail.com>
Co-authored-by: zomars <zomars@me.com>

* Mutually exclusive options (#2755)

Co-authored-by: Omar López <zomars@me.com>
Co-authored-by: Peer Richelsen <peeroke@gmail.com>
Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com>

* Readd steps to create a new user #2665 (#2759)

Co-authored-by: gitstart <gitstart@users.noreply.github.com>

* remove redundant conditional expressions (#2756)

* remove redundant conditional expressions

* remove redundant conditional expression

Co-authored-by: Syed Ali Shahbaz <52925846+alishaz-polymath@users.noreply.github.com>

* Fix adds redirect callback that support app.cal.com (#2768)

* Fix adds redirect callback that support app.cal.com

* Update apps/web/pages/api/auth/[...nextauth].tsx

Check origin of website and baseurl

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

* fix: lint issue extra space removed

Co-authored-by: Agusti Fernandez Pardo <git@agusti.me>
Co-authored-by: Omar López <zomars@me.com>
Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com>

* respect local set timezone and update url on mismatch (#2506)

* ensure `timeZone()` will make its way to the URL

fixes https://github.com/calcom/cal.com/issues/2482

* keep `timeZone()` and the offset from URL in sync

Co-authored-by: Syed Ali Shahbaz <52925846+alishaz-polymath@users.noreply.github.com>
Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com>

* Squashed commit of the following:

commit 27540b09ce
Author: Agusti Fernandez Pardo <me@agusti.me>
Date:   Mon May 16 17:34:13 2022 +0200

    fix: remove hardcoded redirect in signin url email verification (#2764)

    Co-authored-by: Agusti Fernandez Pardo <git@agusti.me>

commit ae15a7d739
Author: Hariom Balhara <hariombalhara@gmail.com>
Date:   Tue May 10 14:30:43 2022 +0530

    Fix time issue

commit 2a5a89fe50
Author: Leo Giovanetti <hello@leog.me>
Date:   Wed May 11 10:21:46 2022 -0300

    Missing fix for success page

commit 2ce1e78053
Author: Leo Giovanetti <hello@leog.me>
Date:   Wed May 11 10:12:59 2022 -0300

    Hotfix: Success page for recurring event (#2725)

    * Merge pull request #2672 from calcom/main

    v1.5.4

    * Turbo fixes

    * Make apps single pages public

    * Fix preview.html not built and thus served during depooy (#2713)

    * Hotfix: Success page layout broken due to duplicate "When" (#2716)

    * Update BookingPage.tsx

    * Reverting unchaged lines

    * Fixing recurrenceRule for ICS files

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

commit 2d6d1cb444
Author: Hariom Balhara <hariombalhara@gmail.com>
Date:   Tue May 10 14:49:46 2022 +0530

    Hotfix: Success page layout broken due to duplicate "When" (#2716)

commit ef68f4f4f8
Author: Hariom Balhara <hariombalhara@gmail.com>
Date:   Tue May 10 10:54:20 2022 +0530

    Fix preview.html not built and thus served during depooy (#2713)

commit 18c28cc3fd
Author: zomars <zomars@me.com>
Date:   Mon May 9 16:17:07 2022 -0600

    Make apps single pages public

commit d40e8caff9
Author: zomars <zomars@me.com>
Date:   Mon May 9 16:08:03 2022 -0600

    Turbo fixes

commit 3161cc4d45
Merge: ed808c3be 4099a477d
Author: zomars <zomars@me.com>
Date:   Mon May 9 14:58:33 2022 -0600

    Merge branch 'main' into production

commit ed808c3be6
Author: Omar López <zomars@me.com>
Date:   Mon May 9 14:56:23 2022 -0600

    Merge pull request #2672 from calcom/main

    v1.5.4

* Typo

* Typo

* Update apps/web/pages/apps/categories/[category].tsx

* Apply suggestions from code review

* Alert to describe exclusion of options (#2770)

* Alert to describe exclusion of options

* Update apps/web/pages/event-types/[type].tsx

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

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

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

* Formatting

Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com>
Co-authored-by: Omar López <zomars@me.com>

* fix: split time correctly if the local working hours are just across mid night (#2766)

Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com>

* Update crowdin.yml

* New Crowdin translations by Github Action (#2773)

* New Crowdin translations by Github Action

* Update vital.json

* Update vital.json

Co-authored-by: Crowdin Bot <support+bot@crowdin.com>
Co-authored-by: Omar López <zomars@me.com>

* Add Google cal extneral calendar id to booking reference (#2671)

* Set google cal event id to use our uid

* Save calendar external id to bookingRef

* Pass external calendar ids to update and delete

* Create migration

* Fix type errors

* Fix prisma url

Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com>
Co-authored-by: Omar López <zomars@me.com>

* v1.6

* v1.6

* 2FA submit disabled (#2790)

* fixing the hyperlink for open startup (#2777)

Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com>

* Add login event (#2784)

Co-authored-by: Bailey Pumfleet <pumfleet@hey.com>

* Fixes infinite loop

* Fixes infinite loop

* Fixes infinite loop

* Update all Yarn dependencies (2022-05-16) (#2769)

* Update all Yarn dependencies (2022-05-16)

* Upgrade dependencies

* Removes deprecated packages

* Upgrades deps

* Updates submodules

* Update yarn.lock

* Linting

* Linting

* Update website

* Build fixes

* TODO: fix this

* Module resolving

* Type fixes

* Intercom fixes on SSG

* Fixes infinite loop

* Upgrades to React 18

* Type fixes

* Locks node version to 14

* Upgrades daily-js

* Readds missing types

* Upgrades playwright

* Noop when intercom is not installed

* Update website

* Removed yarn.lock in favor of monorepo

Co-authored-by: depfu[bot] <23717796+depfu[bot]@users.noreply.github.com>
Co-authored-by: zomars <zomars@me.com>

* Create ci.yml

* Update ci.yml

* Reintroduces typescript-eslint

Buckle up!

* Type fixes

* Update ci.yml

* Update api

* Update admin

* Reusable inferSSRProps

* Linting

* Linting

* Prisma fixes

* Update ci.yml

* Cache testing

* Update e2e.yml

* Update DatePicker.tsx

* Update e2e.yml

* Revert "Linting"

This reverts commit adf817766e.

* Revert "Linting"

This reverts commit 1b59dacd64.

* Linting

* Update e2e.yml

* Ci updates

* Add team Id to hash url (#2803)

* Fix missing tabs - Embed (#2804)

* Fix missing tabs

* Fix Eslint error

* Fix Eslint errors

* Add import statement (#2812)

* Add import statement

* Update apps/docs/next.config.js

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

* Show success page if booking was deleted on calendar (#2808)

* Add exception to 410

* Fix type error

* Add GoogelCalError type

* only show invite link for app.cal.dev (#2807)

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

* fix: update eslint config to test .ts and .js separately (#2805)

* fix: update eslint config

* fix: update ts ignore

* fix: update eslint config

* Update TeamAvailabilityScreen.tsx

* Type fixes

* Update useIntercom.ts

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

* fix: sync api to latest commit (#2810)

Co-authored-by: Agusti Fernandez Pardo <git@agusti.me>
Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com>

* Embed React improvements (#2782)

* Add off support. Add getApi export.

* Add publish command

* Add embed-snippet in prod deps

* Update README

* Update package.json

Co-authored-by: Bailey Pumfleet <pumfleet@hey.com>
Co-authored-by: zomars <zomars@me.com>
Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com>

* Consolidates test-results

* Add vscode tasks.json (#2801)

Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com>

* save additional inputs as json + view details of booking (#2796)

* move custom inputs from description to own json object

* show custom inputs on success page

* fix type error

* add custom inputs to email and webhook

* add custom inputs to all emails

* add values for custom inputs when rescheduling

* add custom input everywhere description is shown

* fix bug with boolean value

* fix issues with null values

* disable custom inputs and add notes for organizer

* don't show custom input with empty string

* don't show custom inputs with empty string in calender event and email

* add link to booking details page

* redirect to success page to see booking details

* add functionality to cancel and reschedule booking

* fix bookings that require confirmation

* clean code

* fix infinite lopp in useEffect of success page

* show web conference details message when integration as location

* improve design of cancelling event

* clean code

* disable darkmode for organizer on booking details page

* fix dark mode for cancelling booking

* fix build error

* Fixes infinite loop

* Fixes infinite loop

* Fixes infinite loop

* Update all Yarn dependencies (2022-05-16) (#2769)

* Update all Yarn dependencies (2022-05-16)

* Upgrade dependencies

* Removes deprecated packages

* Upgrades deps

* Updates submodules

* Update yarn.lock

* Linting

* Linting

* Update website

* Build fixes

* TODO: fix this

* Module resolving

* Type fixes

* Intercom fixes on SSG

* Fixes infinite loop

* Upgrades to React 18

* Type fixes

* Locks node version to 14

* Upgrades daily-js

* Readds missing types

* Upgrades playwright

* Noop when intercom is not installed

* Update website

* Removed yarn.lock in favor of monorepo

Co-authored-by: depfu[bot] <23717796+depfu[bot]@users.noreply.github.com>
Co-authored-by: zomars <zomars@me.com>

* Create ci.yml

* Update ci.yml

* Reintroduces typescript-eslint

Buckle up!

* Type fixes

* Update ci.yml

* Update api

* Update admin

* Reusable inferSSRProps

* Linting

* Linting

* Prisma fixes

* Update ci.yml

* Cache testing

* Update e2e.yml

* Update DatePicker.tsx

* Update e2e.yml

* Revert "Linting"

This reverts commit adf817766e.

* Revert "Linting"

This reverts commit 1b59dacd64.

* Linting

* Update e2e.yml

* Ci updates

* Add team Id to hash url (#2803)

* Fix missing tabs - Embed (#2804)

* Fix missing tabs

* Fix Eslint error

* Fix Eslint errors

* Add import statement (#2812)

* Add import statement

* Update apps/docs/next.config.js

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

* Show success page if booking was deleted on calendar (#2808)

* Add exception to 410

* Fix type error

* Add GoogelCalError type

* only show invite link for app.cal.dev (#2807)

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

* fix: update eslint config to test .ts and .js separately (#2805)

* fix: update eslint config

* fix: update ts ignore

* fix: update eslint config

* Update TeamAvailabilityScreen.tsx

* Type fixes

* Update useIntercom.ts

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

* fix: sync api to latest commit (#2810)

Co-authored-by: Agusti Fernandez Pardo <git@agusti.me>
Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com>

* Embed React improvements (#2782)

* Add off support. Add getApi export.

* Add publish command

* Add embed-snippet in prod deps

* Update README

* Update package.json

Co-authored-by: Bailey Pumfleet <pumfleet@hey.com>
Co-authored-by: zomars <zomars@me.com>
Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com>

* Consolidates test-results

* Type fixes

* Abstracts minimal booking select

* Type fixes

* Update listBookings.ts

* Update common.json

* Update bookingReminder.ts

* Consolidates isOutOfBounds

* Update webhookResponse-chromium.txt

* Update TableActions.tsx

* Type fixes

* Update BookingPage.tsx

* Update webhookResponse-chromium.txt

Co-authored-by: CarinaWolli <wollencarina@gmail.com>
Co-authored-by: Alex van Andel <me@alexvanandel.com>
Co-authored-by: Bailey Pumfleet <pumfleet@hey.com>
Co-authored-by: zomars <zomars@me.com>
Co-authored-by: depfu[bot] <23717796+depfu[bot]@users.noreply.github.com>
Co-authored-by: sean-brydon <55134778+sean-brydon@users.noreply.github.com>
Co-authored-by: Hariom Balhara <hariombalhara@gmail.com>
Co-authored-by: Joe Au-Yeung <65426560+joeauyeung@users.noreply.github.com>
Co-authored-by: iamkun <kunhello@outlook.com>
Co-authored-by: Agusti Fernandez Pardo <me@agusti.me>
Co-authored-by: Agusti Fernandez Pardo <git@agusti.me>
Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com>

* Update check-types.yml

* adding organizer as attendee to google calendar events (#2779)

* Fix auto-select and close of dropdown (#2819)

* fixes dynamic color and typefix for tfunction after react upgrade (#2821)

* New Crowdin translations by Github Action (#2791)

Co-authored-by: Crowdin Bot <support+bot@crowdin.com>

* Relocates admin to console

# Conflicts:
#	apps/admin

* Relocates admin to console

* Fix login submit (#2849)

* fix: long string overflowing calendar div (#2842)

Co-authored-by: gitstart <gitstart@users.noreply.github.com>
Co-authored-by: Júlio Piubello da Silva Cabral <julio.piubello@gitstart.dev>

* Adding labels (#2783)

Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com>

* Wrong username is identified if query params are present and user doesn't exist (#2838)

Co-authored-by: gitstart <gitstart@users.noreply.github.com>
Co-authored-by: Júlio Piubello da Silva Cabral <julio.piubello@gitstart.dev>

* Meet/Zoom Email Clarification (#2828)

* Add clarificaiton to email

* Update apps/web/lib/emails/templates/organizer-scheduled-email.ts

* Add to attendee scheduled email

Co-authored-by: Omar López <zomars@me.com>
Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com>

* Request the inclusion Assuncion Time Zone (#2840)

Co-authored-by: gitstart <gitstart@users.noreply.github.com>
Co-authored-by: Júlio Piubello da Silva Cabral <julio.piubello@gitstart.dev>

* Fix UI of dialog (#2788)

* removed large mandatory height and scroll

* added z index using css

* cleanup

* fixed TS errors

* extract dialog out of dropdown

* Adds custom loading text to confirmation dialog

* rename update

* utilizing mutation loading state

Co-authored-by: Peer Richelsen <peeroke@gmail.com>
Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com>

* Hotfix: Fixing Security Issues (#2848)

* Fixing Privilege Escalation

* Fixing critical obj ref in availability

* Fixing reschedule security issue

Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com>
Co-authored-by: Peer Richelsen <peeroke@gmail.com>

* Merge production to main

* Update vital.json

* Update vital.json

* Fix login page CTA disabled state (#2832)

* fix(ui/login): better disabled state for login CTA

The fix involves tracking the form submission with a dedicated state `submitInProgress` with React.
`formState` from `react-hook-form` does not take time taken for the network call into account. For example,
if the api takes 5 seconds to complete, we would expect the `formState.isSubmitting` to be true for `5`
seconds. But, surprisingly this is not the case and `formState` from `react-hook-form` resolves
immediately after it makes a successful connection to the endpoint.

A dedicated state (with `useState`) is introduced that is enabled when the user clicks on the login CTA, and disabled when the api call is resolved, either successfully or with an error.

* Update login.tsx

* Update login.tsx

* Fixes isSubmitting state

Co-authored-by: zomars <zomars@me.com>

* Playwright binaries shouldn't be on deps

Co-authored-by: Peer Richelsen <peeroke@gmail.com>
Co-authored-by: Carina Wollendorfer <30310907+CarinaWolli@users.noreply.github.com>
Co-authored-by: CarinaWolli <wollencarina@gmail.com>
Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com>
Co-authored-by: Hariom Balhara <hariombalhara@gmail.com>
Co-authored-by: Syed Ali Shahbaz <52925846+alishaz-polymath@users.noreply.github.com>
Co-authored-by: Joe Au-Yeung <65426560+joeauyeung@users.noreply.github.com>
Co-authored-by: Leo Giovanetti <hello@leog.me>
Co-authored-by: Alex van Andel <me@alexvanandel.com>
Co-authored-by: Bailey Pumfleet <pumfleet@hey.com>
Co-authored-by: GitStart <1501599+gitstart@users.noreply.github.com>
Co-authored-by: gitstart <gitstart@users.noreply.github.com>
Co-authored-by: Arthur Cruz <42497300+arthur1041@users.noreply.github.com>
Co-authored-by: Mitchell Moore <47459168+Mitchell-Moore@users.noreply.github.com>
Co-authored-by: Agusti Fernandez Pardo <me@agusti.me>
Co-authored-by: Agusti Fernandez Pardo <git@agusti.me>
Co-authored-by: sean-brydon <55134778+sean-brydon@users.noreply.github.com>
Co-authored-by: andreaestefania12 <19562383+andreaestefania12@users.noreply.github.com>
Co-authored-by: Miguel Nieto A <39246879+miguelnietoa@users.noreply.github.com>
Co-authored-by: alannnc <alannnc@gmail.com>
Co-authored-by: Hashen <37979557+Hashen110@users.noreply.github.com>
Co-authored-by: buschco <colin@busch.dev>
Co-authored-by: iamkun <kunhello@outlook.com>
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: Crowdin Bot <support+bot@crowdin.com>
Co-authored-by: Ankit Gordhandas <agordhandas@gmail.com>
Co-authored-by: depfu[bot] <23717796+depfu[bot]@users.noreply.github.com>
Co-authored-by: Ken Miller <kemiller@users.noreply.github.com>
Co-authored-by: Júlio Piubello da Silva Cabral <julio.piubello@gitstart.dev>
Co-authored-by: Arun Kumar <palerdot@users.noreply.github.com>
2022-05-23 11:42:29 -06:00
zomars 162c6c10a8 Playwright binaries shouldn't be on deps 2022-05-23 11:25:34 -06:00
Arun Kumarandzomars 7d7a1c5bbc Fix login page CTA disabled state (#2832)
* fix(ui/login): better disabled state for login CTA

The fix involves tracking the form submission with a dedicated state `submitInProgress` with React.
`formState` from `react-hook-form` does not take time taken for the network call into account. For example,
if the api takes 5 seconds to complete, we would expect the `formState.isSubmitting` to be true for `5`
seconds. But, surprisingly this is not the case and `formState` from `react-hook-form` resolves
immediately after it makes a successful connection to the endpoint.

A dedicated state (with `useState`) is introduced that is enabled when the user clicks on the login CTA, and disabled when the api call is resolved, either successfully or with an error.

* Update login.tsx

* Update login.tsx

* Fixes isSubmitting state

Co-authored-by: zomars <zomars@me.com>
2022-05-23 17:20:35 +00:00
Omar López 53a7b1cc37 Update vital.json 2022-05-23 10:00:52 -06:00
Omar López f9f4a5aeb9 Update vital.json 2022-05-23 10:00:16 -06:00
zomars 066fce9d73 Merge branch 'production' 2022-05-23 09:30:47 -06:00
zomars 3a1d8b8183 Merge production to main 2022-05-23 09:29:19 -06:00
38f23986ad Hotfix: Fixing Security Issues (#2848)
* Fixing Privilege Escalation

* Fixing critical obj ref in availability

* Fixing reschedule security issue

Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com>
Co-authored-by: Peer Richelsen <peeroke@gmail.com>
2022-05-23 11:29:29 +00:00
27422c351c Fix UI of dialog (#2788)
* removed large mandatory height and scroll

* added z index using css

* cleanup

* fixed TS errors

* extract dialog out of dropdown

* Adds custom loading text to confirmation dialog

* rename update

* utilizing mutation loading state

Co-authored-by: Peer Richelsen <peeroke@gmail.com>
Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com>
2022-05-23 13:17:00 +02:00
c5ad74f61c Request the inclusion Assuncion Time Zone (#2840)
Co-authored-by: gitstart <gitstart@users.noreply.github.com>
Co-authored-by: Júlio Piubello da Silva Cabral <julio.piubello@gitstart.dev>
2022-05-23 13:12:41 +02:00
0eff265682 Meet/Zoom Email Clarification (#2828)
* Add clarificaiton to email

* Update apps/web/lib/emails/templates/organizer-scheduled-email.ts

* Add to attendee scheduled email

Co-authored-by: Omar López <zomars@me.com>
Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com>
2022-05-23 11:54:24 +01:00
2560b72596 Wrong username is identified if query params are present and user doesn't exist (#2838)
Co-authored-by: gitstart <gitstart@users.noreply.github.com>
Co-authored-by: Júlio Piubello da Silva Cabral <julio.piubello@gitstart.dev>
2022-05-23 12:34:11 +02:00
sean-brydonandkodiakhq[bot] 7d7c61a1ab Adding labels (#2783)
Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com>
2022-05-23 09:11:04 +01:00
c92283f03d fix: long string overflowing calendar div (#2842)
Co-authored-by: gitstart <gitstart@users.noreply.github.com>
Co-authored-by: Júlio Piubello da Silva Cabral <julio.piubello@gitstart.dev>
2022-05-22 14:31:59 +02:00
Leo Giovanetti ba9be4e69d Fix login submit (#2849) 2022-05-22 14:28:18 +02:00
zomars b334586c3b Relocates admin to console 2022-05-20 17:40:51 -06:00
zomars a38c76e279 Relocates admin to console
# Conflicts:
#	apps/admin
2022-05-20 17:40:51 -06:00
github-actions[bot]andCrowdin Bot 6973d26153 New Crowdin translations by Github Action (#2791)
Co-authored-by: Crowdin Bot <support+bot@crowdin.com>
2022-05-20 16:42:47 +02:00
Syed Ali Shahbaz e62af90619 fixes dynamic color and typefix for tfunction after react upgrade (#2821) 2022-05-20 07:06:21 +00:00
Hariom Balhara e72cceff81 Fix auto-select and close of dropdown (#2819) 2022-05-19 08:50:17 +01:00
Ken Miller 1c296fb2d5 adding organizer as attendee to google calendar events (#2779) 2022-05-18 15:09:15 -06:00
zomars 1de50bd093 Update check-types.yml 2022-05-18 15:08:58 -06:00
+3 4b6c701c48 save additional inputs as json + view details of booking (#2796)
* move custom inputs from description to own json object

* show custom inputs on success page

* fix type error

* add custom inputs to email and webhook

* add custom inputs to all emails

* add values for custom inputs when rescheduling

* add custom input everywhere description is shown

* fix bug with boolean value

* fix issues with null values

* disable custom inputs and add notes for organizer

* don't show custom input with empty string

* don't show custom inputs with empty string in calender event and email

* add link to booking details page

* redirect to success page to see booking details

* add functionality to cancel and reschedule booking

* fix bookings that require confirmation

* clean code

* fix infinite lopp in useEffect of success page

* show web conference details message when integration as location

* improve design of cancelling event

* clean code

* disable darkmode for organizer on booking details page

* fix dark mode for cancelling booking

* fix build error

* Fixes infinite loop

* Fixes infinite loop

* Fixes infinite loop

* Update all Yarn dependencies (2022-05-16) (#2769)

* Update all Yarn dependencies (2022-05-16)

* Upgrade dependencies

* Removes deprecated packages

* Upgrades deps

* Updates submodules

* Update yarn.lock

* Linting

* Linting

* Update website

* Build fixes

* TODO: fix this

* Module resolving

* Type fixes

* Intercom fixes on SSG

* Fixes infinite loop

* Upgrades to React 18

* Type fixes

* Locks node version to 14

* Upgrades daily-js

* Readds missing types

* Upgrades playwright

* Noop when intercom is not installed

* Update website

* Removed yarn.lock in favor of monorepo

Co-authored-by: depfu[bot] <23717796+depfu[bot]@users.noreply.github.com>
Co-authored-by: zomars <zomars@me.com>

* Create ci.yml

* Update ci.yml

* Reintroduces typescript-eslint

Buckle up!

* Type fixes

* Update ci.yml

* Update api

* Update admin

* Reusable inferSSRProps

* Linting

* Linting

* Prisma fixes

* Update ci.yml

* Cache testing

* Update e2e.yml

* Update DatePicker.tsx

* Update e2e.yml

* Revert "Linting"

This reverts commit adf817766e.

* Revert "Linting"

This reverts commit 1b59dacd64.

* Linting

* Update e2e.yml

* Ci updates

* Add team Id to hash url (#2803)

* Fix missing tabs - Embed (#2804)

* Fix missing tabs

* Fix Eslint error

* Fix Eslint errors

* Add import statement (#2812)

* Add import statement

* Update apps/docs/next.config.js

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

* Show success page if booking was deleted on calendar (#2808)

* Add exception to 410

* Fix type error

* Add GoogelCalError type

* only show invite link for app.cal.dev (#2807)

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

* fix: update eslint config to test .ts and .js separately (#2805)

* fix: update eslint config

* fix: update ts ignore

* fix: update eslint config

* Update TeamAvailabilityScreen.tsx

* Type fixes

* Update useIntercom.ts

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

* fix: sync api to latest commit (#2810)

Co-authored-by: Agusti Fernandez Pardo <git@agusti.me>
Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com>

* Embed React improvements (#2782)

* Add off support. Add getApi export.

* Add publish command

* Add embed-snippet in prod deps

* Update README

* Update package.json

Co-authored-by: Bailey Pumfleet <pumfleet@hey.com>
Co-authored-by: zomars <zomars@me.com>
Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com>

* Consolidates test-results

* Type fixes

* Abstracts minimal booking select

* Type fixes

* Update listBookings.ts

* Update common.json

* Update bookingReminder.ts

* Consolidates isOutOfBounds

* Update webhookResponse-chromium.txt

* Update TableActions.tsx

* Type fixes

* Update BookingPage.tsx

* Update webhookResponse-chromium.txt

Co-authored-by: CarinaWolli <wollencarina@gmail.com>
Co-authored-by: Alex van Andel <me@alexvanandel.com>
Co-authored-by: Bailey Pumfleet <pumfleet@hey.com>
Co-authored-by: zomars <zomars@me.com>
Co-authored-by: depfu[bot] <23717796+depfu[bot]@users.noreply.github.com>
Co-authored-by: sean-brydon <55134778+sean-brydon@users.noreply.github.com>
Co-authored-by: Hariom Balhara <hariombalhara@gmail.com>
Co-authored-by: Joe Au-Yeung <65426560+joeauyeung@users.noreply.github.com>
Co-authored-by: iamkun <kunhello@outlook.com>
Co-authored-by: Agusti Fernandez Pardo <me@agusti.me>
Co-authored-by: Agusti Fernandez Pardo <git@agusti.me>
Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com>
2022-05-18 15:05:49 -06:00
Hariom Balharaandkodiakhq[bot] 463aff0702 Add vscode tasks.json (#2801)
Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com>
2022-05-18 17:07:43 +00:00
zomars c1cc93c164 Consolidates test-results 2022-05-18 10:54:36 -06:00
6148e89425 Embed React improvements (#2782)
* Add off support. Add getApi export.

* Add publish command

* Add embed-snippet in prod deps

* Update README

* Update package.json

Co-authored-by: Bailey Pumfleet <pumfleet@hey.com>
Co-authored-by: zomars <zomars@me.com>
Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com>
2022-05-18 16:25:30 +00:00
a7f7b29bae fix: sync api to latest commit (#2810)
Co-authored-by: Agusti Fernandez Pardo <git@agusti.me>
Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com>
2022-05-18 16:15:27 +00:00
Joe Au-Yeung afafd45223 Show success page if booking was deleted on calendar (#2808)
* Add exception to 410

* Fix type error

* Add GoogelCalError type
2022-05-18 10:13:01 -06:00
iamkunandOmar López 31aff64e42 fix: update eslint config to test .ts and .js separately (#2805)
* fix: update eslint config

* fix: update ts ignore

* fix: update eslint config

* Update TeamAvailabilityScreen.tsx

* Type fixes

* Update useIntercom.ts

Co-authored-by: Omar López <zomars@me.com>
2022-05-18 10:05:25 -06:00
952a149604 only show invite link for app.cal.dev (#2807)
Co-authored-by: CarinaWolli <wollencarina@gmail.com>
Co-authored-by: Omar López <zomars@me.com>
2022-05-18 09:35:54 -06:00
Joe Au-Yeung 3aa7387ff5 Show success page if booking was deleted on calendar (#2808)
* Add exception to 410

* Fix type error

* Add GoogelCalError type
2022-05-18 09:34:21 -06:00
Joe Au-YeungandOmar López f8007a4f01 Add import statement (#2812)
* Add import statement

* Update apps/docs/next.config.js

Co-authored-by: Omar López <zomars@me.com>
2022-05-18 09:11:28 -06:00
Hariom Balhara 1fb637d29d Fix missing tabs - Embed (#2804)
* Fix missing tabs

* Fix Eslint error

* Fix Eslint errors
2022-05-18 09:04:50 -06:00
sean-brydon 80954aa866 Add team Id to hash url (#2803) 2022-05-18 08:59:50 -06:00
sean-brydon 821105dccb Add team Id to hash url (#2803) 2022-05-18 08:59:23 -06:00
zomars 5a124cec72 Ci updates 2022-05-17 22:30:16 -06:00
zomars 86a4037088 Update e2e.yml 2022-05-17 22:23:29 -06:00
zomars faa2805ccc Linting 2022-05-17 22:11:06 -06:00
zomars ca3e309ad9 Revert "Linting"
This reverts commit 1b59dacd64.
2022-05-17 22:09:06 -06:00
zomars fc59338057 Revert "Linting"
This reverts commit adf817766e.
2022-05-17 22:09:06 -06:00
zomars 2d56096d8f Update e2e.yml 2022-05-17 22:05:24 -06:00
zomars 8545bfef67 Update DatePicker.tsx 2022-05-17 22:02:23 -06:00
zomars 8a9b7ca78c Update e2e.yml 2022-05-17 21:27:29 -06:00
zomars c910b41043 Cache testing 2022-05-17 21:24:47 -06:00
zomars d51aade461 Update ci.yml 2022-05-17 20:22:33 -06:00
zomars fa837a5d94 Prisma fixes 2022-05-17 19:54:50 -06:00
zomars 1b59dacd64 Linting 2022-05-17 16:13:20 -06:00
zomars adf817766e Linting 2022-05-17 16:02:31 -06:00
zomars 98d7d7a11c Reusable inferSSRProps 2022-05-17 16:01:58 -06:00
zomars 4fa380d7ed Update admin 2022-05-17 15:36:04 -06:00
zomars 39031123e1 Update api 2022-05-17 15:36:01 -06:00
zomars b718718bd6 Update ci.yml 2022-05-17 15:35:58 -06:00
zomars 0153bc583a Type fixes 2022-05-17 15:32:54 -06:00
zomars fbbda20792 Reintroduces typescript-eslint
Buckle up!
2022-05-17 13:53:29 -06:00
zomars ef8018d2f7 Update ci.yml 2022-05-17 13:41:27 -06:00
zomars 46cd74b0b8 Create ci.yml 2022-05-17 13:40:33 -06:00
depfu[bot]andzomars db01f7be19 Update all Yarn dependencies (2022-05-16) (#2769)
* Update all Yarn dependencies (2022-05-16)

* Upgrade dependencies

* Removes deprecated packages

* Upgrades deps

* Updates submodules

* Update yarn.lock

* Linting

* Linting

* Update website

* Build fixes

* TODO: fix this

* Module resolving

* Type fixes

* Intercom fixes on SSG

* Fixes infinite loop

* Upgrades to React 18

* Type fixes

* Locks node version to 14

* Upgrades daily-js

* Readds missing types

* Upgrades playwright

* Noop when intercom is not installed

* Update website

* Removed yarn.lock in favor of monorepo

Co-authored-by: depfu[bot] <23717796+depfu[bot]@users.noreply.github.com>
Co-authored-by: zomars <zomars@me.com>
2022-05-17 19:31:49 +00:00
zomars 25c550de3a Fixes infinite loop 2022-05-17 11:11:10 -06:00
zomars 683e8c4490 Fixes infinite loop 2022-05-17 11:10:57 -06:00
zomars a0296b8ccb Fixes infinite loop 2022-05-17 11:04:02 -06:00
zomars 6771960e9e Fixes infinite loop 2022-05-17 11:03:40 -06:00
zomars 1c4d2fae56 Fixes infinite loop 2022-05-17 10:53:10 -06:00
zomars 3b1dff3b83 Fixes infinite loop 2022-05-17 10:52:59 -06:00
Hariom BalharaandBailey Pumfleet 84967e5cdf Add login event (#2784)
Co-authored-by: Bailey Pumfleet <pumfleet@hey.com>
2022-05-17 17:22:57 +01:00
Ankit Gordhandasandkodiakhq[bot] 6b758eeffa fixing the hyperlink for open startup (#2777)
Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com>
2022-05-17 16:03:05 +00:00
Alex van Andelandsean-brydon 8265c65e4c 2FA submit disabled (#2790) (#2792)
Co-authored-by: sean-brydon <55134778+sean-brydon@users.noreply.github.com>
2022-05-17 18:55:16 +05:30
sean-brydon 676268b62d 2FA submit disabled (#2790) 2022-05-17 14:15:57 +01:00
zomars 9921c43c3f Update [user].ts 2022-05-16 17:24:29 -06:00
Omar López fc13a22162 Merge pull request #2772 from calcom/main
v1.6
2022-05-16 16:06:31 -06:00
zomars 6e2cb4f90d v1.6 2022-05-16 15:57:29 -06:00
zomars 8b0c7f579a v1.6 2022-05-16 15:55:16 -06:00
ad126efee8 Add Google cal extneral calendar id to booking reference (#2671)
* Set google cal event id to use our uid

* Save calendar external id to bookingRef

* Pass external calendar ids to update and delete

* Create migration

* Fix type errors

* Fix prisma url

Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com>
Co-authored-by: Omar López <zomars@me.com>
2022-05-16 14:20:09 -06:00
4e97d3ed72 New Crowdin translations by Github Action (#2773)
* New Crowdin translations by Github Action

* Update vital.json

* Update vital.json

Co-authored-by: Crowdin Bot <support+bot@crowdin.com>
Co-authored-by: Omar López <zomars@me.com>
2022-05-16 13:20:17 -06:00
zomars 57dee30526 Update crowdin.yml 2022-05-16 13:11:12 -06:00
iamkunandkodiakhq[bot] 0bfdf2f8ef fix: split time correctly if the local working hours are just across mid night (#2766)
Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com>
2022-05-16 19:03:33 +00:00
81d917e27a Alert to describe exclusion of options (#2770)
* Alert to describe exclusion of options

* Update apps/web/pages/event-types/[type].tsx

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

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

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

* Formatting

Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com>
Co-authored-by: Omar López <zomars@me.com>
2022-05-16 18:50:53 +00:00
Omar López 3421af10a9 Apply suggestions from code review 2022-05-16 12:36:26 -06:00
Omar López f75917d9c4 Update apps/web/pages/apps/categories/[category].tsx 2022-05-16 12:26:19 -06:00
zomars c05040795d Typo 2022-05-16 12:20:40 -06:00
zomars 7d1b13c88d Typo 2022-05-16 12:17:28 -06:00
Omar López f8785e78a5 Merge branch 'production' into main 2022-05-16 12:02:27 -06:00
zomars 9bd1246ada Squashed commit of the following:
commit 27540b09ce
Author: Agusti Fernandez Pardo <me@agusti.me>
Date:   Mon May 16 17:34:13 2022 +0200

    fix: remove hardcoded redirect in signin url email verification (#2764)

    Co-authored-by: Agusti Fernandez Pardo <git@agusti.me>

commit ae15a7d739
Author: Hariom Balhara <hariombalhara@gmail.com>
Date:   Tue May 10 14:30:43 2022 +0530

    Fix time issue

commit 2a5a89fe50
Author: Leo Giovanetti <hello@leog.me>
Date:   Wed May 11 10:21:46 2022 -0300

    Missing fix for success page

commit 2ce1e78053
Author: Leo Giovanetti <hello@leog.me>
Date:   Wed May 11 10:12:59 2022 -0300

    Hotfix: Success page for recurring event (#2725)

    * Merge pull request #2672 from calcom/main

    v1.5.4

    * Turbo fixes

    * Make apps single pages public

    * Fix preview.html not built and thus served during depooy (#2713)

    * Hotfix: Success page layout broken due to duplicate "When" (#2716)

    * Update BookingPage.tsx

    * Reverting unchaged lines

    * Fixing recurrenceRule for ICS files

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

commit 2d6d1cb444
Author: Hariom Balhara <hariombalhara@gmail.com>
Date:   Tue May 10 14:49:46 2022 +0530

    Hotfix: Success page layout broken due to duplicate "When" (#2716)

commit ef68f4f4f8
Author: Hariom Balhara <hariombalhara@gmail.com>
Date:   Tue May 10 10:54:20 2022 +0530

    Fix preview.html not built and thus served during depooy (#2713)

commit 18c28cc3fd
Author: zomars <zomars@me.com>
Date:   Mon May 9 16:17:07 2022 -0600

    Make apps single pages public

commit d40e8caff9
Author: zomars <zomars@me.com>
Date:   Mon May 9 16:08:03 2022 -0600

    Turbo fixes

commit 3161cc4d45
Merge: ed808c3be 4099a477d
Author: zomars <zomars@me.com>
Date:   Mon May 9 14:58:33 2022 -0600

    Merge branch 'main' into production

commit ed808c3be6
Author: Omar López <zomars@me.com>
Date:   Mon May 9 14:56:23 2022 -0600

    Merge pull request #2672 from calcom/main

    v1.5.4
2022-05-16 12:00:04 -06:00
60c97c9fa9 respect local set timezone and update url on mismatch (#2506)
* ensure `timeZone()` will make its way to the URL

fixes https://github.com/calcom/cal.com/issues/2482

* keep `timeZone()` and the offset from URL in sync

Co-authored-by: Syed Ali Shahbaz <52925846+alishaz-polymath@users.noreply.github.com>
Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com>
2022-05-16 17:57:53 +00:00
9c52e195ea Fix adds redirect callback that support app.cal.com (#2768)
* Fix adds redirect callback that support app.cal.com

* Update apps/web/pages/api/auth/[...nextauth].tsx

Check origin of website and baseurl

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

* fix: lint issue extra space removed

Co-authored-by: Agusti Fernandez Pardo <git@agusti.me>
Co-authored-by: Omar López <zomars@me.com>
Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com>
2022-05-16 17:44:44 +00:00
HashenandSyed Ali Shahbaz e4c5df7a2e remove redundant conditional expressions (#2756)
* remove redundant conditional expressions

* remove redundant conditional expression

Co-authored-by: Syed Ali Shahbaz <52925846+alishaz-polymath@users.noreply.github.com>
2022-05-16 11:26:32 -06:00
GitStartandgitstart 2eae40eff2 Readd steps to create a new user #2665 (#2759)
Co-authored-by: gitstart <gitstart@users.noreply.github.com>
2022-05-16 11:23:40 -06:00
9e662aa202 Mutually exclusive options (#2755)
Co-authored-by: Omar López <zomars@me.com>
Co-authored-by: Peer Richelsen <peeroke@gmail.com>
Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com>
2022-05-16 17:15:09 +00:00
f2a6d00348 Fix/unpaid unconfirmed (#2553)
* Fix merge errors

* Errors prettier/prettier

* Update apps/web/pages/api/book/event.ts

Co-authored-by: Miguel Nieto A <39246879+miguelnietoa@users.noreply.github.com>

* Update apps/web/pages/api/book/event.ts

Co-authored-by: Miguel Nieto A <39246879+miguelnietoa@users.noreply.github.com>

* Update apps/web/pages/api/integrations.ts

Co-authored-by: Miguel Nieto A <39246879+miguelnietoa@users.noreply.github.com>

* Fix merge errors

* Errors prettier/prettier

* Update apps/web/pages/api/book/confirm.ts

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

* Modal window before delete stripe integration

* ESLint Report

* Test fixes

Co-authored-by: Miguel Nieto A <39246879+miguelnietoa@users.noreply.github.com>
Co-authored-by: alannnc <alannnc@gmail.com>
Co-authored-by: zomars <zomars@me.com>
2022-05-16 10:27:36 -06:00
7fd149fd2e Users Phone Number Option (#2669)
* Users Phone Number Option

* Implemented improvments

* Add validation to form

Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com>
Co-authored-by: zomars <zomars@me.com>
2022-05-16 09:50:12 -06:00
zomars 3c37c2e774 Skip sending emails in E2E 2022-05-16 09:49:44 -06:00
GitStartandgitstart 84f19bb4df Bad UX when user wants to set the default Event Type Title #2245 (#2760)
Co-authored-by: gitstart <gitstart@users.noreply.github.com>
2022-05-16 09:44:19 -06:00
Agusti Fernandez PardoandAgusti Fernandez Pardo 27540b09ce fix: remove hardcoded redirect in signin url email verification (#2764)
Co-authored-by: Agusti Fernandez Pardo <git@agusti.me>
2022-05-16 09:38:45 -06:00
Agusti Fernandez PardoandAgusti Fernandez Pardo 549e38fb78 fix: remove hardcoded redirect in signin url email verification (#2764)
Co-authored-by: Agusti Fernandez Pardo <git@agusti.me>
2022-05-16 17:34:13 +02:00
Hariom Balhara 2655f816af Fix white border (#2761) 2022-05-16 12:38:22 +00:00
Mitchell Mooreandzomars 016023fa50 Added check on create eventtype to see is user has slug that already exists (#2757)
* Added check on create eventtype to see is user has slug that already exists, added error check on onError

* revert yarn.lock back

* Catches prisma known error instead of making an additional query

Co-authored-by: zomars <zomars@me.com>
2022-05-15 03:41:39 +00:00
2a53614723 Fix/avoid multiple schedule deletions (#2602)
* Prevents users from deleting the same schedule multiple times due to delay before the schedule disappears. It also applies the same fix to team disband.

Schedule deletion:
![schedule_deletion_new_behaving](https://user-images.githubusercontent.com/42497300/165126805-b3090268-c1a6-418a-b06e-06bd8446da03.gif)

Team disband:
![team_disband_new_behaving](https://user-images.githubusercontent.com/42497300/165127043-7e083e94-e4c9-4e88-90a2-47d31bdd92e6.gif)

Fixes issue [#2569](https://github.com/calcom/cal.com/issues/2569)

Bug fix (non-breaking change which fixes an issue)

**apps/web/components/LightLoader.tsx** → this file was created in order to make a light color loading spinner available. It's necessary when we need to display a loading spinner above dark backgrounds.

**apps/web/components/availability/ScheduleListItem.tsx** → this component was created in order to give a schedule list item its own state.

* Removing a "setTimeout" that was only used for testing purposes

* Adding a code review suggestion to my modifications

* Changing loading style

* Cleanup

* Avoids using unnecessary state

* Revert "Adding a code review suggestion to my modifications"

This reverts commit b5e40062d71157ca1d9384fb1f5c30d50625809d.

* Reverts some changes

* Renames isLoading

Co-authored-by: Alex van Andel <me@alexvanandel.com>
Co-authored-by: Omar López <zomars@me.com>
2022-05-14 12:47:23 -06:00
Leo GiovanettiandOmar López 212fd1bc14 Fixing ESLint warnings (#2723)
* Fixing warnings

* Reverting and disabling ESLint in some cases

* Reverting Next Images

* Reverting file, bad merge

* Targeting ESLint to line

* Additional warnings

* New warning squished

* More tweaks and major fixes

* Uneeded conf

Co-authored-by: Omar López <zomars@me.com>
2022-05-14 13:49:39 +00:00
GitStartandgitstart 93bd4ed79e Sign in button should be changed or disabled after click #2654 (#2749)
Co-authored-by: gitstart <gitstart@users.noreply.github.com>
2022-05-14 07:38:56 -06:00
Omar López 2bb6f33112 E2E fixtures (#2747) 2022-05-13 21:02:10 -06:00
Omar Lópezandkodiakhq[bot] 68e275ab07 Improving Email DRYness (#2486)
* Email DRY

* WIP

* Improve email DRYness

Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com>
2022-05-13 12:34:54 +00:00
498759890f Populate msteams key in db (#2743)
* Populate msteams key in db

* Fix calendar credentials to teams

* Clarify account dialog

Co-authored-by: Omar López <zomars@me.com>
Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com>
Co-authored-by: Bailey Pumfleet <pumfleet@hey.com>
2022-05-13 14:20:50 +02:00
zomars bf1f9b6a32 Build fixes 2022-05-12 13:54:46 -06:00
Joe Au-Yeung b69c1e46d1 Merge pull request #2745 from calcom/apps/multiple-categories
Allow apps to belong to multiple categories
2022-05-12 11:47:11 -06:00
zomars dcd2862e72 Increases timeout temporarily 2022-05-12 08:16:27 -06:00
7a08403636 Fix reschedule not happening in calendar if two calendards are there (#2733)
Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com>
Co-authored-by: Peer Richelsen <peeroke@gmail.com>
2022-05-12 09:33:15 +00:00
574f9cb5d4 Adjusting Zapier endpoints for publishing integration (#2728)
* add /me endpoint for zapier API testing

* remove cacellationReason from listBookings response

Co-authored-by: CarinaWolli <wollencarina@gmail.com>
Co-authored-by: Peer Richelsen <peeroke@gmail.com>
Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com>
Co-authored-by: Omar López <zomars@me.com>
2022-05-12 10:21:46 +01:00
zomars 613e42ce70 E2E fixing attemps 2022-05-11 21:07:22 -06:00
zomars 43f479299a Fixes delete-me test 2022-05-11 20:21:16 -06:00
zomars ecb3264b52 getBusyTimes consolidation 2022-05-11 19:49:21 -06:00
zomars e89520d7d6 Update testUtils.ts 2022-05-11 16:55:30 -06:00
zomars 892bb90d9d Update testUtils.ts 2022-05-11 16:39:45 -06:00
zomars a2ea08ba5f TODO marks blocking test to be fixed 2022-05-11 16:29:44 -06:00
50632dd9dd Add 'free' and 'workingElsewhere' as a non-blocking event (#2652)
* Add 'free' and 'workingElsewhere' to non-blocking event - this will allow bookings at these times

* Update CalendarService.ts

Co-authored-by: zomars <zomars@me.com>
Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com>
2022-05-11 20:47:42 +00:00
zomars 06702aa48a E2E and paid bookings fixes 2022-05-11 14:36:38 -06:00
zomars f2988870d5 Update booking-pages.test.ts 2022-05-11 12:03:22 -06:00
zomars f0ea8d30ca Parallelizes some tests 2022-05-11 11:19:22 -06:00
zomars c3909ccc70 Multiple E2E improvements 2022-05-11 10:46:52 -06:00
Hariom Balhara ae15a7d739 Fix time issue 2022-05-11 09:53:16 -06:00
Syed Ali Shahbazandkodiakhq[bot] 01e88b3807 Allow deletion of a disabled event (#2737)
* allows deletion of disabled event

* some visual fixes

Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com>
2022-05-11 14:14:08 +00:00
Hariom BalharaandOmar López effb9d56d9 Fix preview.html not built and thus served during depooy (#2727)
Co-authored-by: Omar López <zomars@me.com>
2022-05-11 14:01:49 +00:00
Leo Giovanetti 2a5a89fe50 Missing fix for success page 2022-05-11 07:50:30 -06:00
2ce1e78053 Hotfix: Success page for recurring event (#2725)
* Merge pull request #2672 from calcom/main

v1.5.4

* Turbo fixes

* Make apps single pages public

* Fix preview.html not built and thus served during depooy (#2713)

* Hotfix: Success page layout broken due to duplicate "When" (#2716)

* Update BookingPage.tsx

* Reverting unchaged lines

* Fixing recurrenceRule for ICS files

Co-authored-by: Omar López <zomars@me.com>
Co-authored-by: Hariom Balhara <hariombalhara@gmail.com>
2022-05-11 07:50:30 -06:00
3bbbc80511 Hotfix: Success page for recurring event (#2725)
* Merge pull request #2672 from calcom/main

v1.5.4

* Turbo fixes

* Make apps single pages public

* Fix preview.html not built and thus served during depooy (#2713)

* Hotfix: Success page layout broken due to duplicate "When" (#2716)

* Update BookingPage.tsx

* Reverting unchaged lines

* Fixing recurrenceRule for ICS files

Co-authored-by: Omar López <zomars@me.com>
Co-authored-by: Hariom Balhara <hariombalhara@gmail.com>
2022-05-11 10:12:59 -03:00
Hariom BalharaandPeer Richelsen 19128fb08e Hotfix : Fix Infinite loading of Bookings (#2729)
* Add more embed events

* Add more embed events

* Fix nextCursor calculation logic

Co-authored-by: Peer Richelsen <peeroke@gmail.com>
2022-05-11 10:35:43 +00:00
Peer Richelsen 0945bbe5cf fixes #2732 (#2732) 2022-05-11 12:04:04 +02:00
Peer Richelsen ced6975fc8 added giphy description (#2730) 2022-05-11 11:46:27 +02:00
fb436996c0 Change date format for RecurringBookings (#2707)
* Change date format for RecurringBookings

* Missing bookingId query param

Co-authored-by: Leo Giovanetti <hello@leog.me>
Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com>
2022-05-11 07:59:49 +00:00
Hariom Balharaandkodiakhq[bot] 50f1fe544e Improve logs and Fix unwanted 500 to reduce noise in logs (#2674)
* Improve logs

* Fix unintentional 500

Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com>
2022-05-11 05:41:09 +00:00
Syed Ali Shahbaz 746643bf8e adds availability select loader (#2718) 2022-05-11 05:26:06 +00:00
Hariom BalharaandPeer Richelsen 65a69ef1e4 Add more embed events (#2719)
* Add more embed events

* Add more embed events

Co-authored-by: Peer Richelsen <peeroke@gmail.com>
2022-05-11 05:14:08 +00:00
6483182ef6 add invite link to Zapier setup page (#2696)
* add invite link and toaster to zapier setup page

* create env variable for invite link and save in database

* fetch invite link form getStaticProps

* add getStaticPath method

* clean code

* Moves app setup and index page

* Moves Loader to ui

* Trying new way to handle dynamic app store pages

* Cleanup

* Update tailwind.config.js

* zapier invite link fixes

* Tests fixes

Co-authored-by: CarinaWolli <wollencarina@gmail.com>
Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com>
Co-authored-by: zomars <zomars@me.com>
2022-05-11 04:58:10 +00:00
zomars 784a91709c Update dynamic-booking-pages.test.ts 2022-05-10 22:46:22 -06:00
zomars 82a52e065f More test fixes 2022-05-10 22:28:48 -06:00
zomars a1f6738cf1 Update playwright.config.ts 2022-05-10 21:51:24 -06:00
zomars a231945842 Test fixes 2022-05-10 21:37:09 -06:00
zomars a507d5963c Type fixes 2022-05-10 21:35:44 -06:00
Peer Richelsen 92806d5257 fixed /booking skeleton (#2722)
* fixed /booking skeleton

* nit
2022-05-10 16:59:23 +02:00
Hariom Balhara 2d6d1cb444 Hotfix: Success page layout broken due to duplicate "When" (#2716) 2022-05-10 14:49:46 +05:30
Hariom Balhara ef68f4f4f8 Fix preview.html not built and thus served during depooy (#2713) 2022-05-10 10:54:20 +05:30
zomars 9440df4445 Make apps single pages public 2022-05-09 16:17:23 -06:00
zomars 4e0efb76cd Turbo fixes 2022-05-09 16:17:23 -06:00
zomars 18c28cc3fd Make apps single pages public 2022-05-09 16:17:07 -06:00
zomars d40e8caff9 Turbo fixes 2022-05-09 16:08:03 -06:00
zomars 3161cc4d45 Merge branch 'main' into production 2022-05-09 14:58:33 -06:00
Omar López ed808c3be6 Merge pull request #2672 from calcom/main
v1.5.4
2022-05-09 14:56:23 -06:00
zomars 4099a477d1 v1.5.4 2022-05-09 14:33:32 -06:00
zomars 6542da7e30 Formatting 2022-05-09 14:33:13 -06:00
Hariom Balharaandkodiakhq[bot] 8336611f54 Missing translation (#2697)
Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com>
2022-05-09 22:24:01 +02:00
zomars 819c6c96e8 Build fixes 2022-05-09 14:05:57 -06:00
zomars e9ff358ac2 Update BookingPage.tsx 2022-05-09 13:59:45 -06:00
zomars f79fd36c03 Merge branch 'production' 2022-05-09 13:58:18 -06:00
Alex van Andelandkodiakhq[bot] edd99cdeb2 Replaces member avatars with links to avatar.png endpoint (#2708)
* Replaces member avatars with links to avatar.png endpoint

* Replaced additional occurences

* Use WEBSITE_URL from @calcom/lib/constants instead

Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com>
2022-05-09 18:25:12 +00:00
Hariom Balharaandkodiakhq[bot] 9825754b32 Hotfix: blank page for booking embed in Incognito Chrome (#2700)
* Merge remote-tracking branch 'origin/main' into feat/success-url

* Fix localstorage access

* Fix Comments

* make custom eleemnt explicitly 100% in width to go full width in a flex type parent

Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com>
2022-05-09 18:12:47 +00:00
Omar López 6a18b40c97 Update package.json
Fixes v14 builds
2022-05-09 12:00:49 -06:00
Hariom Balhara d00f0bae1d All non recurring bookings were clubbed into one distinct booking (#2706) 2022-05-09 16:04:42 +00:00
sean-brydonandPeer Richelsen fb042a36b6 Fix Mobile UI for /settings/security (#2703)
* Fix Mobile UI

* Remove truncate

* Move buttons

Co-authored-by: Peer Richelsen <peeroke@gmail.com>
2022-05-09 13:43:27 +02:00
Peer Richelsen 6c27b04f83 fixed team dark mode (#2702) 2022-05-09 11:25:36 +00:00
Syed Ali Shahbazandkodiakhq[bot] 9322b4ab4c Flow, UX and other improvements for hash my url feature (#2644)
* added toast feedback

* updated flow

* locale

* updated locale data

* removed unused booking call for reschedule flow

* fixed hashedURL test

* test adjustment

* further test changes

* added check in test to click check only if unchecked

* Added private link quick copy button

* fixed spacing

* fix lint

* consistency

* moved create hash function out of component render

Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com>
2022-05-09 16:41:07 +05:30
Peer Richelsen 5464d4c010 Update README.md 2022-05-09 12:33:39 +02:00
351622c4a2 Add Invalid Email Error (#2637)
* Add error message UI

* Add border color

Co-authored-by: Peer Richelsen <peeroke@gmail.com>
Co-authored-by: Alex van Andel <me@alexvanandel.com>
2022-05-09 08:24:39 +00:00
Hariom Balhara 44736ac461 Fix turbo caching (#2695)
* Fix turbo cachin

* Improve tests stability
2022-05-07 08:54:30 +00:00
Hariom Balhara a2da95b12b Fix app (#2694) 2022-05-07 05:56:29 +00:00
zomars 8ae5b68504 Adds hint to input 2022-05-06 16:09:40 -06:00
zomars 1a3c3af072 Tooltip export fixes 2022-05-06 15:59:15 -06:00
zomars 5dde542952 Form fixes 2022-05-06 15:46:31 -06:00
zomars 4922a13b68 Form warning fixes 2022-05-06 15:44:57 -06:00
zomars a05860515e Form fixes 2022-05-06 15:44:51 -06:00
zomars 7399d6421e Form warning fixes 2022-05-06 15:30:46 -06:00
iamkunandkodiakhq[bot] 269dea70a1 fix: Booking page display time based on selected timezone (#2691)
Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com>
2022-05-06 19:28:09 +00:00
alannncandkodiakhq[bot] 46690fa72b fix/scroll-mobile-on-dialog (#2693)
* Added mobile first css props for scroll

* Fix submodule previous add

* Fix mobile first css for dialog

Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com>
2022-05-06 18:34:48 +00:00
8c9096b55b Vital App - Auto reschedule based on health data (#2500)
* Add vital integration

* Tidy up client_user_id creation

* Rename vital app to vitalother to follow name rules

* Added env var

* App vital reschedule

* Fix on app structure and api calls

* Implemented user identification from webhook

* WIP fix api call and read me

* Save vital settings via api

* Now saving userVitalSettings and trigger reschedule on selected param

* Added translations

* Fix type for vitalSettings

* Using api to get env vars required for url, fix display of vital settings

* Fix hours placeholder, translation not working

* Renames vital app

* Update seed-app-store.ts

* Update package.json

* Update yarn.lock

* Refactored env variables

* Update README.md

* Migrates to api_keys

* Extracts AppConfiguration

* vitalClient fixes

* Update index.ts

* Update metadata.ts

* Update index.ts

* Update metadata.ts

* Added namespace vital for translations

Co-authored-by: Maitham <maithamdib@gmail.com>
Co-authored-by: zomars <zomars@me.com>
Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com>
2022-05-06 17:21:30 +00:00
Hariom Balharaandkodiakhq[bot] 67cc3a6409 Embed Code Generator: Fix Preview HTML and Embed Lib path for production (#2688)
* Improve logging

* Improve logging

* Keep embed origin conigurable

* Make embed URL and embed origin conigurable through env

* Gitignore public embed

* Add fingerprint to preview as well

* Fix path

Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com>
2022-05-06 15:56:26 +00:00
83ec6d69eb fix query to list API keys (#2690)
Co-authored-by: CarinaWolli <wollencarina@gmail.com>
Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com>
2022-05-06 14:48:27 +00:00
Joe Au-Yeung 65a76b96c6 Add missing info to success page (#2680)
* Add missing info to success page

* Remove console.logs

* Add localized format to time
2022-05-06 08:15:05 -06:00
Hariom Balhara dd7f22e021 Fix border in dark theme (#2687) 2022-05-06 12:09:12 +02:00
zomars 1a06d9906b Fixes daily-video slug 2022-05-05 16:36:30 -06:00
zomars 6fb301970b Fixes daily-video slug 2022-05-05 16:34:26 -06:00
zomars 3baf7060f7 Adds console url to redirection whitelist 2022-05-05 16:29:38 -06:00
zomars 0b82b85166 Adds console url to redirection whitelist 2022-05-05 16:29:17 -06:00
zomars 82dfd807c8 All apps in DB are installed by default 2022-05-05 16:21:52 -06:00
zomars af9612968b Fixes missing slack credentials 2022-05-05 16:21:52 -06:00
zomars 70455f56a2 All apps in DB are installed by default 2022-05-05 16:18:28 -06:00
zomars f839fd2bb4 Fixes missing slack credentials 2022-05-05 16:15:40 -06:00
1a79e0624c Recurring Events (#2562)
* Init dev

* UI changes for recurring event + prisma

* Revisiting schema + changes WIP

* UI done, BE WIP

* Feature completion

* Unused query param removed

* Invalid comment removed

* Removed unused translation

* Update apps/web/public/static/locales/en/common.json

Thanks!

Co-authored-by: Peer Richelsen <peeroke@gmail.com>

* Success page changes

* More progress

* Email text tweaks + test + seed

* Tweaking emails + Cal Apps support WIP

* No app integration for now
Final email and pages tweaks to avoid recurring info showed

* Missing comment for clarity

* Yet again, comment

* Last minute fix

* Missing tooltip for upcoming bookings

* Fixing seed

* Fixing import

* Increasing timeout for e2e

* Fixing any

* Apply suggestions from code review

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

* Update apps/web/pages/d/[link]/book.tsx

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

* Code improvements

* More code improvements

* Reverting back number input arrows

* Update BookingPage.tsx

* Update BookingPage.tsx

* Adds fallback for sendOrganizerPaymentRefundFailedEmail

* Type overkill

* Type fixes

* Type fixes

* Nitpicks

* Update success.tsx

* Update success.tsx

* Update success.tsx

* Fixing types

Co-authored-by: Peer Richelsen <peeroke@gmail.com>
Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com>
Co-authored-by: Omar López <zomars@me.com>
2022-05-05 18:16:25 -03:00
iamkun 26e46ff06c fix: DatePicker to display the correct available hours (#2686) 2022-05-05 18:51:22 +00:00
71e67b50b2 Fix: Improve docs and mobile style of api docs (#2635)
* fix: adds servers in openapi, remove hack in snippets, update deps, make dynamic import to use latests swagger ui deps

* fix: remove unneded import

* fix: adds yarn dev commands for api and swagger

* fix: prisma not web before api

* fix: improve mobile docs api

* fix request snippets

* fix: custom more visible scrollbar for snippets in moible

* fix: remove comments and ugly scrollbar

* fix: types and remove lib url

* fix: install iframe-react-resizer in docs

* fix: remove web scope from yarn dev:api

* fix: remove json-schema autogenerated as wont be used

* fix: apiKeyAuth

* fix: swagger patch thx hariom

* fix: add api to env/example

Co-authored-by: Agusti Fernandez Pardo <git@agusti.me>
Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com>
Co-authored-by: zomars <zomars@me.com>
2022-05-05 09:36:02 -06:00
Hariom Balharaandkodiakhq[bot] 174ed9f6d1 Embed Snippet Generator (#2597)
* Add support to dynamically change the theme

* Add Embed UI in app

* Update UI as per Figma

* Dynamicaly update Embed Code

* Get differnet modes working in preview

* Support Embed on EventType Edit, Team Link Fix and Mobile unsupported

* Fix auto theme switch in Embed Snippet generator

* Fix types

* Self Review fixes

* Remove Embed from App section

* Move get query after the middleware to let middleware work on it

* Add sandboxes in the document

* Add error handling for embed loading

* Fix types

* Update snapshots and fix bug identified by tests

* UI Fixes

* Add Embed Tests

* Respond in preview to width and height

Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com>
2022-05-05 08:29:49 -06:00
Carina WollendorferandCarinaWolli 60146ed2c5 fix redirect to setup page (#2683)
Co-authored-by: CarinaWolli <wollencarina@gmail.com>
2022-05-05 09:32:08 +00:00
alannncandzomars df7abdfc06 Fix/reschedule on dynamic events (#2657)
* Reschedule for dynamic events

* Fix lint

* Handling attendee calendar event cancellation

Co-authored-by: zomars <zomars@me.com>
2022-05-05 01:03:36 +00:00
zomars 6ec2b20a23 Separates appStore env file 2022-05-04 16:13:28 -06:00
zomars 09d0f68c4c Update package.json 2022-05-04 16:09:58 -06:00
zomars d6b7311c66 Build fixes 2022-05-04 15:28:58 -06:00
zomars f1a2239c97 Linting and legibility 2022-05-04 15:28:58 -06:00
zomars 977ad141ee Extracts useMeQuery to own hook 2022-05-04 15:28:58 -06:00
Julián Sánchez 06f88eb5a3 Move method that gets the current user to a separate file 2022-05-04 15:28:58 -06:00
Julián Sánchez daf39a4095 Fix problem related to data types 2022-05-04 15:28:58 -06:00
Julián David Sánchez Gallego 0973d79c31 Update way to get the 'accepted' attribute 2022-05-04 15:28:58 -06:00
Julián David Sánchez Gallego 257481bad5 Update restriction to change the role of other Owners 2022-05-04 15:28:58 -06:00
Julián David Sánchez Gallego 68e08f13a1 Change plain strings 2022-05-04 15:28:58 -06:00
Julián David Sánchez Gallego 3234898892 Add restrictions to protect the owners and change their roles 2022-05-04 15:28:58 -06:00
Joe Au-Yeungandkodiakhq[bot] 82f7779a23 MS Teams title to state that a work/school account is required. (#2677)
Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com>
2022-05-04 14:45:30 -04:00
zomars bd9b83540b Jitsi slug fixes 2022-05-04 12:25:07 -06:00
zomars 4f0ee7b0b6 slug fixes 2022-05-04 12:25:07 -06:00
zomars 4437bfa840 Fix for undefined keys 2022-05-04 08:13:52 -06:00
zomars b9e34c99ca Jitsi slug fixes 2022-05-03 22:44:24 -06:00
zomars 71fa872d5c slug fixes 2022-05-03 22:38:48 -06:00
zomars 377857915f Space booking test 2022-05-03 22:36:07 -06:00
zomars ec5020ca3d Update index.ts 2022-05-03 22:30:46 -06:00
alannncandzomars f1bed08c13 feature/space-booking-app (#2673)
* Reschedule for dynamic events

* Fix lint

* feature/space-booking-app initial commit

* added loom video and fixes for main branch

* Revert previous commmit

* Renames spacebookingother to spacebooking

* Type and perf improvements

* Updated comment

* Update seed-app-store.ts

Co-authored-by: zomars <zomars@me.com>
2022-05-03 22:07:17 -06:00
alannncandzomars 2cb663cd6a feature/space-booking-app (#2673)
* Reschedule for dynamic events

* Fix lint

* feature/space-booking-app initial commit

* added loom video and fixes for main branch

* Revert previous commmit

* Renames spacebookingother to spacebooking

* Type and perf improvements

* Updated comment

* Update seed-app-store.ts

Co-authored-by: zomars <zomars@me.com>
2022-05-04 04:06:20 +00:00
fa1ca5fba0 Slack Signature Verification (#2667)
* Slack Verify

* Adding await

* Update slackVerify.ts

Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com>
Co-authored-by: zomars <zomars@me.com>
2022-05-03 23:40:01 +00:00
02b935bcde Feat/zapier app (#2623)
* create basic app structure

* add zapierSubscription model to prisma.schema

* change column name triggerEvent to lower case

* add zapier functionality + enpoints + adjust prisma.schema

* add subscriptionType + refactor code

* add app store information

* create setup page to generate api key

* clean code

* add copy functionality in setup page

* clean code

* add apiKeyType and delte key when uninstalled or new key generated

* clean code

* use Promise.all

* only approve zapier api key

* clean code

* fix findValidApiKey for api keys that don't expire

* fix migrations

* clean code

* small fixes

* add i18n

* add README.md file

* add setup guide to README.md

* fix yarn.lock

* Renames zapierother to zapier

* Typo

* Updates package name

* Rename fixes

* Adds zapier to the App Store seeder

* Adds missing zapier to apiHandlers

* Adds credential relationship to App

* Rename fixes

* Allows tailwind to pick up custom app-store components

* Consolidates zapier_setup_instructions

* Webhook fixes

* Uses app relationship instead of custom type

* Refactors sendPayload to accept webhook object

Instead of individual parameters

* refactoring

* Removes unused zapier check

* Update cancel.ts

* Refactoring

* Removes example comments

* Update InstallAppButton.tsx

* Type fixes

* E2E fixes

* Deletes all user zapier webhooks on integration removal

Co-authored-by: CarinaWolli <wollencarina@gmail.com>
Co-authored-by: zomars <zomars@me.com>
2022-05-03 23:16:59 +00:00
zomars b8d5c53813 Merge branch 'main' into production 2022-05-02 19:08:05 -06:00
zomars bb90fe0d4b Marks installed by default 2022-05-02 19:05:49 -06:00
zomars ba283e3dc0 Marks installed by default 2022-05-02 19:05:13 -06:00
zomars 9ae8a48dcd Type fixes 2022-05-02 18:21:29 -06:00
zomars 774f707c9f Type fixes 2022-05-02 18:21:09 -06:00
zomars a6417c5757 Moar fixes 2022-05-02 18:00:36 -06:00
zomars aebb610403 Moar fixes 2022-05-02 18:00:20 -06:00
zomars fdbfd759af App env fixes 2022-05-02 17:59:06 -06:00
zomars 0213f66eb6 App env fixes 2022-05-02 17:59:06 -06:00
zomars 1de385a410 App env fixes 2022-05-02 17:42:25 -06:00
zomars 6011b440a8 App env fixes 2022-05-02 17:31:07 -06:00
zomars de4b3c186e Hubspot fixes 2022-05-02 16:55:34 -06:00
zomars 4c8ff47ae7 Hubspot fixes 2022-05-02 16:50:52 -06:00
zomars 54269ba0bf v1.5.3 2022-05-02 16:21:11 -06:00
zomars 361579ba31 Migration seeder fixes 2022-05-02 16:21:11 -06:00
000785c29f Add Meta Mask to app store (#2650)
* Adds available apps

* Adds App Model

* WIP

* Create meta mask app folder

* Add description and images

* Remove credential from installed apps page

* Updates seeder script

* Seeder fixes

* lowercase categories

* Upgrades prisma

* WIP

* WIP

* Hopefully fixes circular deps

* Type fixes

* Fixes seeder

* Adds migration to connect Credentials to Apps

* Updates app store callbacks

* Updates google credentials

* Uses dirName from DB

* Type fixes

* Update reschedule.ts

* Seeder fixes

* Fixes categories listing

* Update index.ts

* Update schema.prisma

* Updates dependencies

* Renames giphy app

* Uses dynamic imports for app metadata

* Fixes credentials error

* Uses dynamic import for api handlers

* Dynamic import fixes

* Allows for simple folder names in app store

* Remove video adaptor

* Squashes app migrations

* seeder fixes

* Renames to metamask

* Updates metamask metadata

* Fixes dyamic imports

* Remove comments

* Create migration.sql

Co-authored-by: zomars <zomars@me.com>
Co-authored-by: Peer Richelsen <peeroke@gmail.com>
2022-05-02 16:21:11 -06:00
Omar López 2e6bc5e5b4 Fixes/app store keys in db (#2651)
* Adds available apps

* Adds App Model

* WIP

* Updates seeder script

* Seeder fixes

* lowercase categories

* Upgrades prisma

* WIP

* WIP

* Hopefully fixes circular deps

* Type fixes

* Fixes seeder

* Adds migration to connect Credentials to Apps

* Updates app store callbacks

* Updates google credentials

* Uses dirName from DB

* Type fixes

* Update reschedule.ts

* Seeder fixes

* Fixes categories listing

* Update index.ts

* Update schema.prisma

* Updates dependencies

* Renames giphy app

* Uses dynamic imports for app metadata

* Fixes credentials error

* Uses dynamic import for api handlers

* Dynamic import fixes

* Allows for simple folder names in app store

* Squashes app migrations

* seeder fixes

* Fixes dyamic imports

* Update apiHandlers.tsx
2022-05-02 16:21:11 -06:00
Shrey Gupta 11f6972ec9 feat(app-store): Add Giphy app (#2580) 2022-05-02 16:21:11 -06:00
Peer Richelsen df801b4205 Update README.md 2022-05-02 16:21:11 -06:00
Peer Richelsen 433f2bafd8 Update index.mdx 2022-05-02 16:21:11 -06:00
Peer Richelsen c5fc1a4648 Update PULL_REQUEST_TEMPLATE.md 2022-05-02 16:21:11 -06:00
sean-brydonandkodiakhq[bot] 33d486b160 Enable Autocomplete (#2645)
Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com>
2022-05-02 16:21:11 -06:00
Peer Richelsen 7e57c192ee added animations for dialog and tooltip (#2648)
* added animations for dialog and tooltip

* Update .env.example
2022-05-02 16:21:11 -06:00
Joe Au-Yeungandkodiakhq[bot] e4f7e26ad5 Hotfix - change calendar error message (#2643)
* Change calendar error message

* Change calendar error message

Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com>
2022-05-02 16:21:11 -06:00
89b4acdfaf Hash my url (#2484)
* disposable link model added

* disposable model updated

* added disposable slug availability page

* added disposable book page

* added disposable slug hook

* added disposable link booking flow

* updated schema

* checktype fix

* added checkfix and schema generated

* create link API added

* added one time link view on event type list

* adjusted schema

* fixed disposable visual indicator

* expired check and visual indicator added

* updated slug for disposable event type

* revised schema

* WIP

* revert desc

* revert --WIP

* rework based on change of plans

* further adjustments

* added eventtype option for hashed link

* added refresh and delete on update

* fixed update call conditions

* cleanup

* code improvement

* clean up

* Potential fix for 404

* backward compat for booking page

* fixes regular booking for user and team

* typefix

* updated path for Booking import

* checkfix

* e2e wip

* link err fix

* workaround for banner issue in event type update-test

* added regenerate hash check

* fixed test according to new testID

Co-authored-by: Hariom Balhara <hariombalhara@gmail.com>
Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com>
Co-authored-by: zomars <zomars@me.com>
2022-05-02 16:21:11 -06:00
alannncandkodiakhq[bot] d856ef53a7 Fix emails and cal event descriptions (#2634)
Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com>
2022-05-02 16:21:11 -06:00
3256d601db Fixes google meet url not appearing calendar invite (#2636)
* Update cal description

* Tidy up console logs

Co-authored-by: Syed Ali Shahbaz <52925846+alishaz-polymath@users.noreply.github.com>
Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com>
2022-05-02 16:21:11 -06:00
Afzal Sayedandkodiakhq[bot] 938f4f2b4d Pass userId while creating event-type (#2599)
Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com>
2022-05-02 16:21:11 -06:00
sean-brydon 6999ab09b6 Fixing Scope Name [Slack] (#2641) 2022-05-02 16:21:11 -06:00
Peer Richelsen c2d52bcfd2 consistency for tablet booking page (#2640) 2022-05-02 16:21:11 -06:00
Peer Richelsen d1c37f84aa fixed layout in insalled apps (#2639) 2022-05-02 16:21:11 -06:00
sean-brydon 83f9defc65 Unlock edit on reschedule (#2628) 2022-05-02 16:21:11 -06:00
c4dbab2637 Add new response if request contains account id (#2629)
Co-authored-by: Omar López <zomars@me.com>
Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com>
2022-05-02 16:21:11 -06:00
alannnc e76fafdccf Fix book event form schema validation (#2633) 2022-05-02 16:21:11 -06:00
sean-brydon 73e3e4e226 Adding validation for name and email (#2612) 2022-05-02 16:21:11 -06:00
6535d654d7 Add Event Types Test (#2610)
* Add Event Types Test

* Accept license for tests

* Accept license on preview

* Remove debugging code

* Add License consent flag

* Test fixes

* Update playwright.config.ts

* Update webhookResponse-chromium.txt

Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com>
Co-authored-by: zomars <zomars@me.com>
2022-05-02 16:21:11 -06:00
Hariom Balhara a224a46654 Make sure that absolute URL is of WEBAPP only (#2624) 2022-05-02 16:21:11 -06:00
Peer Richelsen 59c0784cd6 Update PULL_REQUEST_TEMPLATE.md 2022-05-02 16:21:11 -06:00
Peer Richelsen b544d5f781 Update PULL_REQUEST_TEMPLATE.md 2022-05-02 16:21:11 -06:00
Hariom Balharaandsean-brydon ebf1373339 Reduce Payload for Event-Types[Avoid 500] (#2627)
Co-authored-by: sean-brydon <55134778+sean-brydon@users.noreply.github.com>
2022-05-02 16:21:11 -06:00
sean-brydon 75a07f527e Fix scope (#2625) 2022-05-02 16:21:11 -06:00
alannnc 4b75bf7cce Fix/login with provider (#2594) 2022-05-02 16:21:11 -06:00
e260ba0e49 Swagger docs improved (#2607)
* fix: adds servers in openapi, remove hack in snippets, update deps, make dynamic import to use latests swagger ui deps

* fix: remove unneded import

* fix: adds yarn dev commands for api and swagger

Co-authored-by: Agusti Fernandez Pardo <git@agusti.me>
Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com>
2022-05-02 16:21:11 -06:00
sean-brydonandPeer Richelsen 95dfb5b538 Loader Components (#2616)
Co-authored-by: Peer Richelsen <peeroke@gmail.com>
2022-05-02 16:21:11 -06:00
7d3f070e27 Bug/email notes hidden (#2611)
* Fix Width

* Fixes email notes

* Fixing reschedule email

Co-authored-by: Peer Richelsen <peeroke@gmail.com>
Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com>
2022-05-02 16:21:11 -06:00
Hariom Balhara 01fdbaa990 Improve logs for 500 error in datadog for /book/event (#2593) 2022-05-02 16:21:11 -06:00
Hariom Balhara 05acd26efe Add debugging details (#2585) 2022-05-02 16:21:11 -06:00
1421b9c0af Feat/impersonate users (#2503)
Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com>
Co-authored-by: zomars <zomars@me.com>
2022-05-02 16:21:11 -06:00
sean-brydonandOmar López 6197ae25c6 Fix providerName (#2589)
Co-authored-by: Omar López <zomars@me.com>
2022-05-02 16:21:11 -06:00
zomars de0883b14b v1.5.3 2022-05-02 16:07:45 -06:00
zomars acc6db901c Migration seeder fixes 2022-05-02 16:02:45 -06:00
7f463830bd Add Meta Mask to app store (#2650)
* Adds available apps

* Adds App Model

* WIP

* Create meta mask app folder

* Add description and images

* Remove credential from installed apps page

* Updates seeder script

* Seeder fixes

* lowercase categories

* Upgrades prisma

* WIP

* WIP

* Hopefully fixes circular deps

* Type fixes

* Fixes seeder

* Adds migration to connect Credentials to Apps

* Updates app store callbacks

* Updates google credentials

* Uses dirName from DB

* Type fixes

* Update reschedule.ts

* Seeder fixes

* Fixes categories listing

* Update index.ts

* Update schema.prisma

* Updates dependencies

* Renames giphy app

* Uses dynamic imports for app metadata

* Fixes credentials error

* Uses dynamic import for api handlers

* Dynamic import fixes

* Allows for simple folder names in app store

* Remove video adaptor

* Squashes app migrations

* seeder fixes

* Renames to metamask

* Updates metamask metadata

* Fixes dyamic imports

* Remove comments

* Create migration.sql

Co-authored-by: zomars <zomars@me.com>
Co-authored-by: Peer Richelsen <peeroke@gmail.com>
2022-05-02 15:44:37 -06:00
Omar López 6a27fb2959 Fixes/app store keys in db (#2651)
* Adds available apps

* Adds App Model

* WIP

* Updates seeder script

* Seeder fixes

* lowercase categories

* Upgrades prisma

* WIP

* WIP

* Hopefully fixes circular deps

* Type fixes

* Fixes seeder

* Adds migration to connect Credentials to Apps

* Updates app store callbacks

* Updates google credentials

* Uses dirName from DB

* Type fixes

* Update reschedule.ts

* Seeder fixes

* Fixes categories listing

* Update index.ts

* Update schema.prisma

* Updates dependencies

* Renames giphy app

* Uses dynamic imports for app metadata

* Fixes credentials error

* Uses dynamic import for api handlers

* Dynamic import fixes

* Allows for simple folder names in app store

* Squashes app migrations

* seeder fixes

* Fixes dyamic imports

* Update apiHandlers.tsx
2022-05-02 14:39:35 -06:00
Shrey Gupta 21867c9cd4 feat(app-store): Add Giphy app (#2580) 2022-05-01 21:42:35 +01:00
Peer Richelsen 276821e0b5 Update README.md 2022-04-30 15:55:25 +02:00
Peer Richelsen 8028b1ddad Update index.mdx 2022-04-30 15:54:57 +02:00
Peer Richelsen 5abbd818d3 Update PULL_REQUEST_TEMPLATE.md 2022-04-30 14:51:23 +02:00
sean-brydonandkodiakhq[bot] 43944a7d31 Enable Autocomplete (#2645)
Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com>
2022-04-29 17:28:34 +00:00
Peer Richelsen 8bdc137917 added animations for dialog and tooltip (#2648)
* added animations for dialog and tooltip

* Update .env.example
2022-04-29 17:17:34 +00:00
Joe Au-Yeungandkodiakhq[bot] 02fb15228b Hotfix - change calendar error message (#2643)
* Change calendar error message

* Change calendar error message

Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com>
2022-04-28 20:45:27 +00:00
59a1db9068 Hash my url (#2484)
* disposable link model added

* disposable model updated

* added disposable slug availability page

* added disposable book page

* added disposable slug hook

* added disposable link booking flow

* updated schema

* checktype fix

* added checkfix and schema generated

* create link API added

* added one time link view on event type list

* adjusted schema

* fixed disposable visual indicator

* expired check and visual indicator added

* updated slug for disposable event type

* revised schema

* WIP

* revert desc

* revert --WIP

* rework based on change of plans

* further adjustments

* added eventtype option for hashed link

* added refresh and delete on update

* fixed update call conditions

* cleanup

* code improvement

* clean up

* Potential fix for 404

* backward compat for booking page

* fixes regular booking for user and team

* typefix

* updated path for Booking import

* checkfix

* e2e wip

* link err fix

* workaround for banner issue in event type update-test

* added regenerate hash check

* fixed test according to new testID

Co-authored-by: Hariom Balhara <hariombalhara@gmail.com>
Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com>
Co-authored-by: zomars <zomars@me.com>
2022-04-28 09:44:26 -06:00
alannncandkodiakhq[bot] 8e956893ca Fix emails and cal event descriptions (#2634)
Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com>
2022-04-28 15:05:29 +00:00
d960e03acf Fixes google meet url not appearing calendar invite (#2636)
* Update cal description

* Tidy up console logs

Co-authored-by: Syed Ali Shahbaz <52925846+alishaz-polymath@users.noreply.github.com>
Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com>
2022-04-28 14:54:31 +00:00
Afzal Sayedandkodiakhq[bot] 99666440cf Pass userId while creating event-type (#2599)
Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com>
2022-04-28 07:56:10 -06:00
sean-brydon f274c0bde3 Fixing Scope Name [Slack] (#2641) 2022-04-28 12:42:37 +00:00
Peer Richelsen d1082e55a4 consistency for tablet booking page (#2640) 2022-04-28 13:31:55 +02:00
Peer Richelsen af0d1980c6 fixed layout in insalled apps (#2639) 2022-04-28 13:22:40 +02:00
sean-brydon a6183e0ccf Unlock edit on reschedule (#2628) 2022-04-28 09:10:40 +00:00
eea40c69f7 Add new response if request contains account id (#2629)
Co-authored-by: Omar López <zomars@me.com>
Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com>
2022-04-27 21:34:04 +00:00
alannnc 13ae773868 Fix book event form schema validation (#2633) 2022-04-27 23:21:18 +02:00
sean-brydon 6f0fcc9d1b Adding validation for name and email (#2612) 2022-04-27 16:19:04 +01:00
7d98c0bb1c Add Event Types Test (#2610)
* Add Event Types Test

* Accept license for tests

* Accept license on preview

* Remove debugging code

* Add License consent flag

* Test fixes

* Update playwright.config.ts

* Update webhookResponse-chromium.txt

Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com>
Co-authored-by: zomars <zomars@me.com>
2022-04-27 08:58:04 -06:00
Hariom Balhara 82d77dc10f Make sure that absolute URL is of WEBAPP only (#2624) 2022-04-27 16:28:36 +02:00
Peer Richelsen ae1f35f515 Update PULL_REQUEST_TEMPLATE.md 2022-04-27 14:16:31 +02:00
Peer Richelsen 66f3fd2e07 Update PULL_REQUEST_TEMPLATE.md 2022-04-27 14:15:44 +02:00
Hariom Balharaandsean-brydon cf346f6aa3 Reduce Payload for Event-Types[Avoid 500] (#2627)
Co-authored-by: sean-brydon <55134778+sean-brydon@users.noreply.github.com>
2022-04-27 11:08:13 +00:00
sean-brydon 34d3aac4b0 Fix scope (#2625) 2022-04-27 16:27:39 +05:30
alannnc c22b6ca670 Fix/login with provider (#2594) 2022-04-26 15:12:08 +00:00
fa1b29a99f Swagger docs improved (#2607)
* fix: adds servers in openapi, remove hack in snippets, update deps, make dynamic import to use latests swagger ui deps

* fix: remove unneded import

* fix: adds yarn dev commands for api and swagger

Co-authored-by: Agusti Fernandez Pardo <git@agusti.me>
Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com>
2022-04-26 15:00:53 +00:00
sean-brydonandPeer Richelsen d61238c832 Loader Components (#2616)
Co-authored-by: Peer Richelsen <peeroke@gmail.com>
2022-04-26 14:11:02 +00:00
28b432058a Bug/email notes hidden (#2611)
* Fix Width

* Fixes email notes

* Fixing reschedule email

Co-authored-by: Peer Richelsen <peeroke@gmail.com>
Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com>
2022-04-26 13:46:20 +00:00
Hariom Balhara 4360ada3e4 Improve logs for 500 error in datadog for /book/event (#2593) 2022-04-26 11:31:57 +00:00
Hariom Balhara 5336bf3fe2 Add debugging details (#2585) 2022-04-26 11:15:57 +00:00
6d5db1cb3a Feat/impersonate users (#2503)
Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com>
Co-authored-by: zomars <zomars@me.com>
2022-04-26 14:18:17 +05:30
sean-brydonandOmar López 9fffaa20a2 Fix providerName (#2589)
Co-authored-by: Omar López <zomars@me.com>
2022-04-26 04:20:13 +00:00
sean-brydonandkodiakhq[bot] fd73a4ac92 Fix Width (#2587)
Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com>
2022-04-26 02:48:36 +00:00
sean-brydonandkodiakhq[bot] 29a6c70fc3 Heading Skeleton (#2601)
Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com>
2022-04-26 02:38:41 +00:00
96f6c644bd Improve create event-type flow (#2446)
* Improve create event-type flow

* Update form values when query changes

Co-authored-by: Syed Ali Shahbaz <52925846+alishaz-polymath@users.noreply.github.com>
Co-authored-by: Bailey Pumfleet <pumfleet@hey.com>
Co-authored-by: zomars <zomars@me.com>
Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com>
2022-04-26 02:13:15 +00:00
sean-brydonandPeer Richelsen 7c12bb1e20 Bug/i118n flicker (#2609)
* Fix Global Flicker

* Fixes Flicker + Null return

Co-authored-by: Peer Richelsen <peeroke@gmail.com>
2022-04-25 18:26:13 -06:00
Peer Richelsen 10e796f956 Revert "feat: disable select when loading (#2475)" (#2608)
This reverts commit 307b098f83.
2022-04-26 01:26:03 +02:00
sean-brydon 071077f2dc Fix Global Flicker (#2604) 2022-04-26 00:20:16 +02:00
sean-brydon afe957674c Adding avatar skeleton loader (#2600) 2022-04-25 20:18:07 +00:00
Carlos Gabriel 307b098f83 feat: disable select when loading (#2475) 2022-04-25 20:30:15 +02:00
sean-brydonandPeer Richelsen 95a793dd5a Skeleton Loaders Implementation (#2596)
* Skeleton Loaders

* Remove Href

* Fix Height Jumping around

* Subtle Colors

* feedback by ciaran

Co-authored-by: Peer Richelsen <peeroke@gmail.com>
2022-04-25 17:01:51 +00:00
sean-brydon a0057911c1 Fix back button (#2592) 2022-04-25 10:32:01 +02:00
Hariom Balhara 93c75b5fef Embed Miscellaneous Improvements and Fixes (#2499) 2022-04-25 10:03:00 +05:30
Afzal Sayed 53d7e57142 Fix update event type authorization (#2588) 2022-04-24 15:02:04 -06:00
Hariom Balhara 2c4a891a89 Add debugging details (#2582) 2022-04-23 18:45:46 +00:00
Joe Au-Yeung 8e0c7759be Update README.md (#2578) 2022-04-22 21:43:59 +02:00
Peer Richelsen 41dc01ea3c Update next-i18next.config.js (#2568) 2022-04-22 20:40:40 +02:00
Syed Ali Shahbaz 9c985edb6b away user fix (#2576) 2022-04-22 16:03:01 +01:00
Bailey Pumfleet 69ef309cb5 Update website submodule 2022-04-21 22:31:02 +01:00
Omar López f10bf38292 Removed deprecated JWT secrets (#2574) 2022-04-21 15:10:23 -06:00
Agusti Fernandez 02f68b104b fix: adds title to public-api docs (#2573) 2022-04-21 20:46:37 +00:00
8bc5a75249 Feature: Verify login on signup with magic link. (#2122)
* manual migration to rename verificationtoken, maybe it could be dropped and create a new table instead if we're not using it, will consult @zomars

* feat: rename verificationRequest --> verificationToken in schema.prisma

* fix: rename verificationRequest -> verificationToken in the codebase

* feat: add default cookies for next-auth

* fix: moves @lib/serverConfig to @calcom/lib so it can be called by website too

* fix: make self-certificate work in dev env by not rejecting tls in serverConfig

* fix verificationTokenToken typo

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

* Adds domain: .cal.com if not dev env in cookies

* Adds default-cookies to apps/web, and nextauth_domain to turbo website build deps"a

* update NEXTAUTH_DOMAIN to NEXTAUTH_COOKIE_DOMAIN

* Updates website submodule

* Removes deprecated env vars

* Consolidates auth logic in one place

* Updates website module

* Signup fixes

* Build fixes

* Updates example

* Updates example

* Fixes

* Fix Email Verification

* fix: move csrf-token cookiePrefix from __Host -> __Secure

* Removes console log

* Fixes link in email template

* Removed irrelevant coment

* Testing with a 32 bit secret

* Fixes for cookien in E2E

* E2E fixes

* Fixes Stripe tests locally

* Temp fix for E2E

Co-authored-by: Agusti Fernandez Pardo <git@agusti.me>
Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com>
Co-authored-by: Omar López <zomars@me.com>
Co-authored-by: Hariom Balhara <hariombalhara@gmail.com>
2022-04-21 14:32:25 -06:00
97e4cca252 Remove global app installed button (#2561)
* Remove global app installed button

* Add Jitsi add button

* Find app credentials based on variant

* Make huddle installable

* Remove default installed message from installed apps page

* Display Jitsi and Huddle as locations if installed

* Reverse global app changes and made Jitsi and Huddle non global

* Changes to app page refrence #2556

* Fix type errors

* Revert code

Co-authored-by: Peer Richelsen <peeroke@gmail.com>
Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com>
2022-04-21 12:17:56 -06:00
sean-brydonandPeer Richelsen 18d41b52a2 Add chat public scope to slack scopes (#2564)
Co-authored-by: Peer Richelsen <peeroke@gmail.com>
2022-04-21 19:04:38 +02:00
manuelguandPeer Richelsen 26c0f82edf fix: typo in slack app description (#2563)
Co-authored-by: Peer Richelsen <peeroke@gmail.com>
2022-04-21 17:25:43 +02:00
SiderealArtandPeer Richelsen c12436afb0 Update Traditional Chinese translation (#2566)
Co-authored-by: Peer Richelsen <peeroke@gmail.com>
2022-04-21 17:20:56 +02:00
milospuac fead885aa4 Create slack.mdx (#2565)
Documentation for our Slack commands
2022-04-21 14:26:29 +01:00
e680bb1548 Adding Scope for bot permissions (#2530)
Co-authored-by: Peer Richelsen <peeroke@gmail.com>
Co-authored-by: Bailey Pumfleet <pumfleet@hey.com>
2022-04-21 10:32:56 +01:00
alannncandOmar López 6e82d38249 Fix for appstore and wipemycal render (#2556)
* Fix for appstores and wipe-my-cal

* Fix email subject for reschedule

* Fix email subject for reschedule

* Fix api add wipemycal return

* Now we ask on a endpoint if app its installed

* Fix types

Co-authored-by: Omar López <zomars@me.com>
2022-04-20 23:37:25 +02:00
zomars 9f63299a1a Fixes hubspot metadata 2022-04-20 14:20:02 -06:00
zomars 702f31c935 Prepares prettier for local modules 2022-04-20 12:37:03 -06:00
zomars 08db282a07 Extracts EmptyScreen 2022-04-20 12:00:49 -06:00
zomars 080a394bb3 Renames package
# Conflicts:
#	package.json
2022-04-20 11:52:07 -06:00
zomars 8fb429e073 Renames package
# Conflicts:
#	package.json
2022-04-20 11:51:26 -06:00
Afzal Sayed 00a3ff89e4 Uniquely index event-type with teamId and slug (#2452) 2022-04-19 18:35:12 -06:00
Omar López 8f3b854559 Admin console (#2555)
* Adds admin submodule

* Adds admin submodule
2022-04-19 16:58:46 -06:00
Omar López 05edb144b2 Adds admin submodule (#2554) 2022-04-19 16:55:41 -06:00
8c173c840b fix(web): overflow with auto scroll instead of scroll (#2535)
* fix(readme): update setup steps

* fix(readme): update required node version in prerequisites section

* fix(web): overflow-auto instead of overflow-scroll

* Revert "fix(readme): update setup steps"

This reverts commit 2938d510c874e9298b82465baeae5af9181c01d8.

* Revert "fix(readme): update required node version in prerequisites section"

This reverts commit 848e1a153538475acb42daa6ddbd74dd474611f5.

Co-authored-by: Peer Richelsen <peeroke@gmail.com>
Co-authored-by: Bailey Pumfleet <pumfleet@hey.com>
2022-04-19 16:50:19 +01:00
Bailey Pumfleet b540f44d6c Create CODE_OF_CONDUCT.md 2022-04-19 14:27:44 +01:00
Agusti Fernandez 7493093a1a fix: dangling zero in api keys list (#2548) 2022-04-19 12:32:17 +01:00
Agusti Fernandez cf68541520 update swagger (#2547) 2022-04-19 10:50:40 +02:00
Peer Richelsen b4ee4413cc Update eventTypes.tsx (#2545) 2022-04-18 22:40:56 +02:00
Peer Richelsen f214830d0f Update README.mdx (#2544) 2022-04-18 22:08:49 +02:00
Peer Richelsen c92070a5a2 Update package.json 2022-04-18 19:53:49 +02:00
Hariom Balhara 102ca5403d Fix "Edit Booking" Icon (#2536) 2022-04-18 11:25:56 +01:00
Hariom Balhara 7fd57b88dc Fix mobile reschedule actions (#2534) 2022-04-17 17:37:16 +02:00
Hariom Balhara 5f57694148 Fix Mobile UI for Booking Availability Page. Make it consistent with booking page (#2533) 2022-04-17 13:25:11 +02:00
Peer Richelsen 73c97e85d4 overflow scroll for categories (#2502) 2022-04-16 20:37:19 +00:00
Syed Ali Shahbazandkodiakhq[bot] ccde0c20ab fixed avatargroup in mobile screens (#2498)
Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com>
2022-04-16 22:23:15 +02:00
sean-brydon d2d3c67144 Display most recent (#2529) 2022-04-16 13:51:44 +02:00
Agusti Fernandez 6d5af81f68 adds authorize to swagger docs to pass apiKey (#2524) 2022-04-16 08:22:22 +01:00
Hariom Balhara 2e9d4125ed Fix Embed Documentation (#2525) 2022-04-16 06:17:47 +00:00
Omar López 56c32beebc Update README.md 2022-04-15 21:02:35 -06:00
faa67e0bb6 Feature: Adds api keys to cal.com webapp (#2277)
* feat: add ApiKey model for new Api auth, owned by a user

* fix: remove metadata:Json and add note:String instead in new apiKey model

* fix: rename apiKey to apiKeys in moder User relation in schema.prisma

* feat: add hashedKey to apiKey and lastUsedAt datetime to keep track of usage of keys and makiung them securely stored in db

* fix 30 day -> 30 days in expiresAt

* feat: api keys frontend in security page

* adds hashedKey to api key model, add frontend api keys in security page

* Make frontend work to create api keys with or without expiry, note, defaults to 1 month expiry

* remove migration for now, add env.example to swagger, sync api

* feat: hashed api keys

* fix: minor refactor and cleanup in apiKeys generator

* add api key success modal

* sync apps/api

* feat: We have API Keys in Security =)

* remove swagger env from pr

* apps api sync

* remove comments in password section

* feat: migration for api keys schema

* sync api w main

* delete apps/api

* add back apps/api

* make min date and disabled optional props in datepicker

* feat fix type check errors

* fix : types

* fix: rmeove renaming of verificationrequest token indexes in migration

* fix: remove extra div

* Fixes for feedback in PR

* fix button />

* fix: rename weird naming of translation for you_will_only_view_it_once

* fix: remove ternary and use && to avoid null for false

* fix sync apps/api with main not old commit

* fix empty className

* fix: remove unused imports

* fix remove commented jsx fragment close

* fix rename editing

* improve translations

* feat: adds beta tag in security tab under api keys

* fix: use api keys everywhere

* fix: cleanup code in api keys

* fix: use watch and controller for neverexpires/datepicker

* Fixes: improve api key never expires

* add back change password h2 title section in security page

* fix update env API_KEY_ prefix default to cal_

* fix: improve eidt api keys modal

* fix: update edit mutation in viewer.apiKeys

* Update apps/web/ee/components/apiKeys/ApiKeyListItem.tsx

Co-authored-by: Alex van Andel <me@alexvanandel.com>

* fix: item: any to pass build

Co-authored-by: Agusti Fernandez Pardo <git@agusti.me>
Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com>
Co-authored-by: Omar López <zomars@me.com>
Co-authored-by: Alex van Andel <me@alexvanandel.com>
2022-04-15 20:58:34 -06:00
ffebe8e901 HubSpot App (#2380)
* Initial changes

* OAuth done and credentials stored

* Added "other" integrations

* Switching to hubspot api client

* Event creation for all attendees

* Update and delete done

* Doc update

* Fixing types

* App label is not mandatory

* Fixing bad merge: App label deleted

* Fixing bad automerge

* Removing  c.log

Co-authored-by: Omar López <zomars@me.com>
Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com>
2022-04-15 23:23:38 -03:00
Omar López 2cafe2d98e Update README.md 2022-04-15 20:12:24 -06:00
d03038d976 Fix: styling (#2523)
* remove vercel favicon and logo, remove empty space on top due to Head

* adds a negative margin-top to compensate for svg-assets

Co-authored-by: Agusti Fernandez Pardo <git@agusti.me>
Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com>
2022-04-16 01:58:07 +00:00
Agusti FernandezandAgusti Fernandez Pardo 7e392da78a remove vercel favicon and logo, remove empty space on top due to Head (#2522)
Co-authored-by: Agusti Fernandez Pardo <git@agusti.me>
2022-04-16 03:35:49 +02:00
Agusti FernandezandAgusti Fernandez Pardo f8f3456b92 Adds iframe to developer.cal.com (swagger-ui) into docs/public-api.mdx (#2518)
Co-authored-by: Agusti Fernandez Pardo <git@agusti.me>
2022-04-15 23:56:32 +00:00
Agusti FernandezandAgusti Fernandez Pardo 3b637eefaa adds redirect for /api to developer.cal.com (#2517)
Co-authored-by: Agusti Fernandez Pardo <git@agusti.me>
2022-04-15 14:19:52 -06:00
46e1d28881 improve styling on mobile for swagger docs (#2516)
Co-authored-by: Agusti Fernandez Pardo <git@agusti.me>
Co-authored-by: Peer Richelsen <peeroke@gmail.com>
2022-04-15 12:52:51 -06:00
Agusti Fernandez f23cc8b99f Adds env example and changes route (#2515) 2022-04-15 19:11:35 +01:00
Hariom Balhara 6843347dd7 Embed: Bump Versions and update Readmes and descriptions (#2507) 2022-04-15 18:55:36 +01:00
950 changed files with 40264 additions and 36615 deletions
+89
View File
@@ -0,0 +1,89 @@
# ********** INDEX **********
#
# - APP STORE
# - DAILY.CO VIDEO
# - GOOGLE CALENDAR/MEET/LOGIN
# - HUBSPOT
# - OFFICE 365
# - SLACK
# - STRIPE
# - TANDEM
# - ZOOM
# - GIPHY
# - VITAL
# - APP STORE **********************************************************************************************
# ⚠️ ⚠️ ⚠️ THESE WILL BE MIGRATED TO THE DATABASE TO PREVENT AWS's 4KB ENV QUOTA ⚠️ ⚠️ ⚠️
# - DAILY.CO VIDEO
DAILY_API_KEY=
DAILY_SCALE_PLAN=''
# - GOOGLE CALENDAR/MEET/LOGIN
# Needed to enable Google Calendar integration and Login with Google
# @see https://github.com/calendso/calendso#obtaining-the-google-api-credentials
GOOGLE_API_CREDENTIALS='{}'
# To enable Login with Google you need to:
# 1. Set `GOOGLE_API_CREDENTIALS` above
# 2. Set `GOOGLE_LOGIN_ENABLED` to `true`
# When self-hosting please ensure you configure the Google integration as an Internal app so no one else can login to your instance
# @see https://support.google.com/cloud/answer/6158849#public-and-internal&zippy=%2Cpublic-and-internal-applications
GOOGLE_LOGIN_ENABLED=false
# - HUBSPOT
# Used for the HubSpot integration
# @see https://github.com/calcom/cal.com/#obtaining-hubspot-client-id-and-secret
HUBSPOT_CLIENT_ID=""
HUBSPOT_CLIENT_SECRET=""
# - OFFICE 365
# Used for the Office 365 / Outlook.com Calendar / MS Teams integration
# @see https://github.com/calcom/cal.com/#Obtaining-Microsoft-Graph-Client-ID-and-Secret
MS_GRAPH_CLIENT_ID=
MS_GRAPH_CLIENT_SECRET=
# - SLACK
# @see https://github.com/calcom/cal.com/#obtaining-slack-client-id-and-secret-and-signing-secret
SLACK_SIGNING_SECRET=
SLACK_CLIENT_ID=
SLACK_CLIENT_SECRET=
# - STRIPE
NEXT_PUBLIC_STRIPE_PUBLIC_KEY= # pk_test_...
STRIPE_PRIVATE_KEY= # sk_test_...
STRIPE_WEBHOOK_SECRET= # whsec_...
STRIPE_CLIENT_ID= # ca_...
PAYMENT_FEE_FIXED=10 # Take 10 additional cents commission
PAYMENT_FEE_PERCENTAGE=0.005 # Take 0.5% commission
# - TANDEM
# Used for the Tandem integration -- contact support@tandem.chat for API access.
TANDEM_CLIENT_ID=""
TANDEM_CLIENT_SECRET=""
TANDEM_BASE_URL="https://tandem.chat"
# - ZOOM
# Used for the Zoom integration
# @see https://github.com/calcom/cal.com/#obtaining-zoom-client-id-and-secret
ZOOM_CLIENT_ID=
ZOOM_CLIENT_SECRET=
# - GIPHY
# Used for the Giphy integration
# @see https://support.giphy.com/hc/en-us/articles/360020283431-Request-A-GIPHY-API-Key
GIPHY_API_KEY=
# - VITAL
# Used for the vital integration
# @see https://github.com/calcom/cal.com/#obtaining-vital-api-keys
VITAL_API_KEY=
VITAL_WEBHOOK_SECRET=
# "sandbox" | "prod" | "production" | "development"
VITAL_DEVELOPMENT_MODE="sandbox"
# "us" | "eu"
VITAL_REGION="us"
# - ZAPIER
# Used for the Zapier integration
# @see https://github.com/calcom/cal.com/blob/main/packages/app-store/zapier/README.md
ZAPIER_INVITE_LINK=""
# *********************************************************************************************************
+19 -61
View File
@@ -5,14 +5,6 @@
# - SHARED
# - NEXTAUTH
# - E-MAIL SETTINGS
# - APP STORE
# - DAILY.CO VIDEO
# - GOOGLE CALENDAR/MEET/LOGIN
# - OFFICE 365
# - SLACK
# - STRIPE
# - TANDEM
# - ZOOM
# - LICENSE *************************************************************************************************
# Set this value to 'agree' to accept our license:
@@ -23,6 +15,9 @@
# - You can not repackage or sell the codebase
# - Acquire a commercial license to remove these terms by visiting: cal.com/sales
NEXT_PUBLIC_LICENSE_CONSENT=''
# To enable enterprise-only features, fill your license key in here.
# @see https://console.cal.com
CALCOM_LICENSE_KEY=
# ***********************************************************************************************************
# - DATABASE ************************************************************************************************
@@ -33,6 +28,8 @@ NEXT_PUBLIC_LICENSE_CONSENT=''
NEXT_PUBLIC_WEBAPP_URL='http://localhost:3000'
# Change to 'http://localhost:3001' if running the website simultaneously
NEXT_PUBLIC_WEBSITE_URL='http://localhost:3000'
NEXT_PUBLIC_CONSOLE_URL='http://localhost:3004'
NEXT_PUBLIC_EMBED_LIB_URL='http://localhost:3000/embed/embed.js'
# To enable SAML login, set both these variables
# @see https://github.com/calcom/cal.com/tree/main/packages/ee#setting-up-saml-login
@@ -47,15 +44,18 @@ PGSSLMODE=
# - NEXTAUTH
# @see: https://github.com/calendso/calendso/issues/263
# Required for Vercel hosting - set NEXTAUTH_URL to equal your BASE_URL
# @see: https://next-auth.js.org/configuration/options#nextauth_url
# Required for Vercel hosting - set NEXTAUTH_URL to equal your NEXT_PUBLIC_WEBAPP_URL
# NEXTAUTH_URL='http://localhost:3000'
NEXTAUTH_URL=
JWT_SECRET='secret'
# @see: https://next-auth.js.org/configuration/options#nextauth_secret
# You can use: `openssl rand -base64 32` to generate one
NEXTAUTH_SECRET=
# Used for cross-domain cookie authentication
NEXTAUTH_COOKIE_DOMAIN=.example.com
# Remove this var if you don't want Cal to collect anonymous usage
NEXT_PUBLIC_TELEMETRY_KEY=js.2pvs2bbpqq1zxna97wcml.oi2jzirnbj1ev4tc57c5r
# Set this to '1' if you don't want Cal to collect anonymous usage
CALCOM_TELEMETRY_DISABLED=
# ApiKey for cronjobs
CRON_API_KEY='0cc0e6c35519bba620c9360cfe3e68d0'
@@ -74,6 +74,9 @@ NEXT_PUBLIC_ZENDESK_KEY=
# Help Scout Config
NEXT_PUBLIC_HELPSCOUT_KEY=
# Inbox to send user feedback
SEND_FEEDBACK_EMAIL=
# This is used so we can bypass emails in auth flows for E2E testing
# Set it to "1" if you need to run E2E tests locally
NEXT_PUBLIC_IS_E2E=
@@ -83,6 +86,10 @@ NEXT_PUBLIC_STRIPE_PRO_PLAN_PRODUCT=
NEXT_PUBLIC_STRIPE_PRO_PLAN_PRICE=
NEXT_PUBLIC_STRIPE_PREMIUM_PLAN_PRICE=
NEXT_PUBLIC_STRIPE_FREE_PLAN_PRICE=
STRIPE_WEBHOOK_SECRET=
# Use for internal Public API Keys and optional
API_KEY_PREFIX=cal_
# ***********************************************************************************************************
# - E-MAIL SETTINGS *****************************************************************************************
@@ -107,52 +114,3 @@ EMAIL_SERVER_PASSWORD='<office365_password>'
## @see https://support.google.com/accounts/answer/185833
# EMAIL_SERVER_PASSWORD='<gmail_app_password>'
# **********************************************************************************************************
# - APP STORE **********************************************************************************************
# - DAILY.CO VIDEO
DAILY_API_KEY=
DAILY_SCALE_PLAN=''
# - GOOGLE CALENDAR/MEET/LOGIN
# Needed to enable Google Calendar integration and Login with Google
# @see https://github.com/calendso/calendso#obtaining-the-google-api-credentials
GOOGLE_API_CREDENTIALS='{}'
# To enable Login with Google you need to:
# 1. Set `GOOGLE_API_CREDENTIALS` above
# 2. Set `GOOGLE_LOGIN_ENABLED` to `true`
# When self-hosting please ensure you configure the Google integration as an Internal app so no one else can login to your instance
# @see https://support.google.com/cloud/answer/6158849#public-and-internal&zippy=%2Cpublic-and-internal-applications
GOOGLE_LOGIN_ENABLED=false
# - OFFICE 365
# Used for the Office 365 / Outlook.com Calendar / MS Teams integration
# @see https://github.com/calcom/cal.com/#Obtaining-Microsoft-Graph-Client-ID-and-Secret
MS_GRAPH_CLIENT_ID=
MS_GRAPH_CLIENT_SECRET=
# - SLACK
# @see https://github.com/calcom/cal.com/#obtaining-slack-client-id-and-secret-and-signing-secret
SLACK_SIGNING_SECRET=
SLACK_CLIENT_ID=
SLACK_CLIENT_SECRET=
# - STRIPE
NEXT_PUBLIC_STRIPE_PUBLIC_KEY= # pk_test_...
STRIPE_PRIVATE_KEY= # sk_test_...
STRIPE_WEBHOOK_SECRET= # whsec_...
STRIPE_CLIENT_ID= # ca_...
PAYMENT_FEE_FIXED=10 # Take 10 additional cents commission
PAYMENT_FEE_PERCENTAGE=0.005 # Take 0.5% commission
# - TANDEM
# Used for the Tandem integration -- contact support@tandem.chat to for API access.
TANDEM_CLIENT_ID=""
TANDEM_CLIENT_SECRET=""
TANDEM_BASE_URL="https://tandem.chat"
# - ZOOM
# Used for the Zoom integration
# @see https://github.com/calcom/cal.com/#obtaining-zoom-client-id-and-secret
ZOOM_CLIENT_ID=
ZOOM_CLIENT_SECRET=
# *********************************************************************************************************
+6
View File
@@ -4,6 +4,12 @@
Fixes # (issue)
<!-- Please provide a loom video for visual changes to speed up reviews
Loom Video: https://www.loom.com/
-->
**Environment**: Staging(main branch) / Production
## Type of change
<!-- Please delete options that are not relevant. -->
+7 -5
View File
@@ -1,6 +1,6 @@
name: Check types
on:
pull_request:
pull_request_target:
branches:
- main
jobs:
@@ -8,7 +8,7 @@ jobs:
name: Check types
strategy:
matrix:
node: ["14.x"]
node: ["16.x"]
os: [ubuntu-latest]
runs-on: ${{ matrix.os }}
@@ -16,11 +16,13 @@ jobs:
- name: Checkout repo
uses: actions/checkout@v2
with:
fetch-depth: 0
ref: ${{ github.event.pull_request.head.sha }}
fetch-depth: 2
- name: Use Node ${{ matrix.node }}
uses: actions/setup-node@v2
uses: actions/setup-node@v3
with:
node-version: ${{ matrix.node }}
- run: yarn
cache: "yarn"
- run: yarn --frozen-lockfile
- run: yarn type-check
+1 -1
View File
@@ -15,7 +15,7 @@ jobs:
uses: actions/checkout@v2
- name: crowdin action
uses: crowdin/github-action@1.4.2
uses: crowdin/github-action@1.4.9
with:
upload_translations: true
download_translations: true
+107
View File
@@ -0,0 +1,107 @@
name: E2E tests Embed
on:
pull_request_target: # So we can test on forks
branches:
- main
# Embed e2e - tests verify booking flow which is applicable to non-embed case also. So, don't ignore apps/web changes.
paths-ignore:
- apps/api/**
- apps/console/**
- apps/docs/**
- apps/swagger/**
- apps/website/**
- apps/web/public/**
- tests/**
- playwright/**
jobs:
test:
timeout-minutes: 20
name: Embed and booking flow(for non-embed as well)
strategy:
matrix:
node: ["16.x"]
os: [ubuntu-latest]
runs-on: ${{ matrix.os }}
env:
DATABASE_URL: postgresql://postgres:@localhost:5432/calendso
NEXT_PUBLIC_WEBAPP_URL: http://localhost:3000
NEXT_PUBLIC_WEBSITE_URL: http://localhost:3000
NEXTAUTH_SECRET: secret
GOOGLE_API_CREDENTIALS: ${{ secrets.CI_GOOGLE_API_CREDENTIALS }}
GOOGLE_LOGIN_ENABLED: true
# CRON_API_KEY: xxx
CALENDSO_ENCRYPTION_KEY: ${{ secrets.CI_CALENDSO_ENCRYPTION_KEY }}
NEXT_PUBLIC_STRIPE_PUBLIC_KEY: ${{ secrets.CI_NEXT_PUBLIC_STRIPE_PUBLIC_KEY }}
STRIPE_PRIVATE_KEY: ${{ secrets.CI_STRIPE_PRIVATE_KEY }}
STRIPE_CLIENT_ID: ${{ secrets.CI_STRIPE_CLIENT_ID }}
STRIPE_WEBHOOK_SECRET: ${{ secrets.CI_STRIPE_WEBHOOK_SECRET }}
PAYMENT_FEE_PERCENTAGE: 0.005
PAYMENT_FEE_FIXED: 10
SAML_DATABASE_URL: postgresql://postgres:@localhost:5432/calendso
SAML_ADMINS: pro@example.com
NEXTAUTH_URL: http://localhost:3000/api/auth
NEXT_PUBLIC_IS_E2E: 1
# EMAIL_FROM: e2e@cal.com
# EMAIL_SERVER_HOST: ${{ secrets.CI_EMAIL_SERVER_HOST }}
# EMAIL_SERVER_PORT: ${{ secrets.CI_EMAIL_SERVER_PORT }}
# EMAIL_SERVER_USER: ${{ secrets.CI_EMAIL_SERVER_USER }}
# EMAIL_SERVER_PASSWORD: ${{ secrets.CI_EMAIL_SERVER_PASSWORD }}
# MS_GRAPH_CLIENT_ID: xxx
# MS_GRAPH_CLIENT_SECRET: xxx
# ZOOM_CLIENT_ID: xxx
# ZOOM_CLIENT_SECRET: xxx
TURBO_TOKEN: ${{ secrets.TURBO_TOKEN }}
TURBO_TEAM: ${{ secrets.TURBO_TEAM }}
services:
postgres:
image: postgres:12.1
env:
POSTGRES_USER: postgres
POSTGRES_DB: calendso
ports:
- 5432:5432
steps:
- name: Checkout repo
uses: actions/checkout@v2
with:
ref: ${{ github.event.pull_request.head.sha }} # So we can test on forks
fetch-depth: 2
- run: echo 'NODE_OPTIONS="--max_old_space_size=4096"' >> $GITHUB_ENV
- name: Use Node ${{ matrix.node }}
uses: actions/setup-node@v3
with:
node-version: ${{ matrix.node }}
cache: "yarn"
- name: Cache playwright binaries
uses: actions/cache@v2
id: playwright-cache
with:
path: |
~/Library/Caches/ms-playwright
~/.cache/ms-playwright
${{ github.workspace }}/node_modules/playwright
key: cache-playwright-${{ hashFiles('**/yarn.lock') }}
restore-keys: cache-playwright-
- run: yarn --frozen-lockfile
- name: Install playwright deps
# if: steps.playwright-cache.outputs.cache-hit != 'true'
run: yarn playwright install --with-deps
- name: Run Tests
run: yarn turbo run embed-tests-update-snapshots:ci --scope=@calcom/embed-react --concurrency=1
- name: Upload embed-core results
if: ${{ always() }}
uses: actions/upload-artifact@v2
with:
name: test-results-core
path: packages/embeds/embed-core/playwright/results
- name: Upload embed-react results
if: ${{ always() }}
uses: actions/upload-artifact@v2
with:
name: test-results-react
path: packages/embeds/embed-react/playwright/results
+15 -27
View File
@@ -4,14 +4,14 @@ on:
branches:
- main
paths-ignore:
- public/static/locales/**
- apps/web/public/static/locales/**
jobs:
test:
timeout-minutes: 15
timeout-minutes: 20
name: Testing ${{ matrix.node }} and ${{ matrix.os }}
strategy:
matrix:
node: ["14.x"]
node: ["16.x"]
os: [ubuntu-latest]
runs-on: ${{ matrix.os }}
@@ -19,7 +19,7 @@ jobs:
DATABASE_URL: postgresql://postgres:@localhost:5432/calendso
NEXT_PUBLIC_WEBAPP_URL: http://localhost:3000
NEXT_PUBLIC_WEBSITE_URL: http://localhost:3000
JWT_SECRET: secret
NEXTAUTH_SECRET: secret
GOOGLE_API_CREDENTIALS: ${{ secrets.CI_GOOGLE_API_CREDENTIALS }}
GOOGLE_LOGIN_ENABLED: true
# CRON_API_KEY: xxx
@@ -43,6 +43,8 @@ jobs:
# MS_GRAPH_CLIENT_SECRET: xxx
# ZOOM_CLIENT_ID: xxx
# ZOOM_CLIENT_SECRET: xxx
TURBO_TOKEN: ${{ secrets.TURBO_TOKEN }}
TURBO_TEAM: ${{ secrets.TURBO_TEAM }}
services:
postgres:
image: postgres:12.1
@@ -58,23 +60,13 @@ jobs:
with:
ref: ${{ github.event.pull_request.head.sha }} # So we can test on forks
fetch-depth: 2
- run: echo 'NODE_OPTIONS="--max_old_space_size=4096"' >> $GITHUB_ENV
- name: Use Node ${{ matrix.node }}
uses: actions/setup-node@v2
uses: actions/setup-node@v3
with:
node-version: ${{ matrix.node }}
# cache: "yarn"
# cache-dependency-path: yarn.lock
cache: "yarn"
- name: Turbo Cache
id: turbo-cache
uses: actions/cache@v2
with:
path: .turbo
key: turbo-${{ github.job }}-${{ github.event.pull_request.head.ref }}-${{ github.event.pull_request.head.sha }}
restore-keys: |
turbo-${{ github.job }}-${{ github.event.pull_request.head.ref }}-
- run: yarn
- name: Cache playwright binaries
uses: actions/cache@v2
id: playwright-cache
@@ -82,22 +74,18 @@ jobs:
path: |
~/Library/Caches/ms-playwright
~/.cache/ms-playwright
**/node_modules/playwright
${{ github.workspace }}/node_modules/playwright
key: cache-playwright-${{ hashFiles('**/yarn.lock') }}
restore-keys: cache-playwright-
- run: yarn --frozen-lockfile
- name: Install playwright deps
if: steps.playwright-cache.outputs.cache-hit != 'true'
run: yarn playwright install --with-deps
- run: yarn test-e2e
- name: Upload videos
- name: Upload test results
if: ${{ always() }}
uses: actions/upload-artifact@v2
with:
name: videos
path: |
test-results
playwright/screenshots
playwright/videos
playwright/results
playwright/reports
name: test-results
path: test-results
+5 -6
View File
@@ -7,7 +7,7 @@ jobs:
lint:
strategy:
matrix:
node: ["14.x"]
node: ["16.x"]
os: [ubuntu-latest]
runs-on: ${{ matrix.os }}
@@ -18,16 +18,15 @@ jobs:
ref: ${{ github.event.pull_request.head.sha }}
fetch-depth: 2
- name: Use Node.js 14.x
uses: actions/setup-node@v2
- name: Use Node ${{ matrix.node }}
uses: actions/setup-node@v3
with:
node-version: ${{ matrix.node }}
# cache: "yarn"
# cache-dependency-path: yarn.lock
cache: "yarn"
- name: Install deps
if: steps.yarn-cache.outputs.cache-hit != 'true'
run: yarn
run: yarn --frozen-lockfile
- name: Lint
run: yarn lint:report
+5
View File
@@ -39,6 +39,7 @@ yarn-error.log*
.env.production.local
.env.*
!.env.example
!.env.appStore.example
# vercel
.vercel
@@ -71,3 +72,7 @@ dist
# Linting
lint-results
# Snaplet
.snaplet/snapshots
.snaplet/structure.d.ts
+4
View File
@@ -1,3 +1,7 @@
[submodule "apps/console"]
path = apps/console
url = https://github.com/calcom/console.git
branch = main
[submodule "apps/api"]
path = apps/api
url = https://github.com/calcom/api.git
+2
View File
@@ -2,3 +2,5 @@
. "$(dirname "$0")/_/husky.sh"
yarn lint-staged
yarn app-store:build && git add packages/app-store/*.generated.*
+1 -1
View File
@@ -1 +1 @@
14.17
v16
+4
View File
@@ -0,0 +1,4 @@
{
"projectId": "cl4u26bwz7962859ply7ibuo43t",
"databaseUrl": "postgresql://postgres@localhost:5450/calendso"
}
+3
View File
@@ -0,0 +1,3 @@
{
"version": "0.3.0"
}
+97
View File
@@ -0,0 +1,97 @@
// This transform config was generated by Snaplet.
// Snaplet found fields that may contain personally identifiable information (PII)
// and used that to populate this file.
import { copycat } from "@snaplet/copycat";
import type { Transform } from "./structure";
function hasStringProp<T extends string>(x: unknown, key: T): x is { [key in T]: string } {
return !!x && typeof x === "object" && key in x;
}
function replaceKeyIfExists<T extends string>(x: object, key: T) {
if (hasStringProp(x, key)) {
return { ...x, [key]: copycat.uuid(x[key]) };
}
return x;
}
function generateSlug(x: string) {
return copycat.words(x, { max: 3 }).split(" ").join("-");
}
function replaceSensitiveKeys(record: object) {
return {
...record,
...replaceKeyIfExists(record, "client_id"),
...replaceKeyIfExists(record, "client_secret"),
...replaceKeyIfExists(record, "public_key"),
...replaceKeyIfExists(record, "api_key"),
...replaceKeyIfExists(record, "signing_secret"),
...replaceKeyIfExists(record, "access_token"),
...replaceKeyIfExists(record, "refresh_token"),
...replaceKeyIfExists(record, "stripe_user_id"),
...replaceKeyIfExists(record, "stripe_publishable_key"),
...replaceKeyIfExists(record, "accessToken"),
...replaceKeyIfExists(record, "refreshToken"),
...replaceKeyIfExists(record, "bot_user_id"),
...replaceKeyIfExists(record, "app_id"),
};
}
const config: Transform = () => ({
public: {
_user_eventtype: ({ row }) => ({
A: copycat.int(row.A),
B: copycat.int(row.B),
}),
ApiKey: ({ row }) => ({
note: copycat.sentence(row.note),
}),
App: ({ row }) => ({
keys: replaceSensitiveKeys(row.keys),
}),
Attendee: ({ row }) => ({
email: copycat.email(row.email),
name: copycat.fullName(row.name),
timeZone: copycat.timezone(row.timeZone),
}),
Availability: ({ row }) => ({
// date: copycat.fullName(row.date),
}),
Credential: ({ row }) => ({
key: typeof row.key === "string" ? copycat.uuid(row.key) : replaceSensitiveKeys(row.key),
}),
EventType: ({ row }) => ({
slug: generateSlug(row.slug),
timeZone: copycat.timezone(row.timeZone),
}),
Feedback: ({ row }) => ({
// date: copycat.dateString(row.date),
}),
ResetPasswordRequest: ({ row }) => ({
email: copycat.email(row.email),
}),
Schedule: ({ row }) => ({
timeZone: copycat.timezone(row.timeZone),
}),
Team: ({ row }) => ({
bio: copycat.sentence(row.bio),
name: copycat.words(row.name, { max: 2 }),
slug: generateSlug(row.slug),
}),
users: ({ row }) => ({
bio: copycat.sentence(row.bio),
email: copycat.email(row.email),
name: copycat.fullName(row.name),
password: copycat.password(row.password),
timeZone: copycat.timezone(row.timeZone),
username: generateSlug(row.username),
}),
VerificationToken: ({ row }) => ({
token: copycat.uuid(row.token),
}),
},
});
export default config;
+2 -1
View File
@@ -7,6 +7,7 @@
"bradlc.vscode-tailwindcss", // hinting / autocompletion for tailwind
"ban.spellright", // Spell check for docs
"stripe.vscode-stripe", // stripe VSCode extension
"Prisma.prisma" // syntax|format|completion for prisma
"Prisma.prisma", // syntax|format|completion for prisma
"rebornix.project-snippets" // Share useful snippets between collaborators
]
}
+78
View File
@@ -0,0 +1,78 @@
{
"version": "2.0.0",
"presentation": {
"echo": false,
"reveal": "always",
"focus": false,
"panel": "dedicated",
"showReuseMessage": true
},
"tasks": [
{
"label": "Launch Cal.com Development terminals",
"dependsOn": [
"Web App(3000)",
"Website(3001)",
"Embed Core(3100)",
"Embed React(3101)",
"Prisma Studio(5555)",
"Maildev(587)"
],
// Mark as the default build task so cmd/ctrl+shift+b will create them
"group": {
"kind": "build",
"isDefault": true
},
// Try start the task on folder open
"runOptions": {
"runOn": "folderOpen"
}
},
{
// The name that shows up in terminal tab
"label": "Web App(3000)",
// The task will launch a shell
"type": "shell",
"command": "yarn dev",
// Set the shell type
// Mark as a background task to avoid the spinner animation on the terminal tab
"isBackground": false,
"problemMatcher": []
},
{
"label": "Website(3001)",
"type": "shell",
"command": "cd apps/website && yarn dev",
"isBackground": false,
"problemMatcher": []
},
{
"label": "Embed Core(3100)",
"type": "shell",
"command": "cd packages/embeds/embed-core && yarn dev",
"isBackground": false,
"problemMatcher": []
},
{
"label": "Embed React(3101)",
"type": "shell",
"command": "cd packages/embeds/embed-react && yarn dev",
"isBackground": false,
"problemMatcher": []
},
{
"label": "Prisma Studio(5555)",
"type": "shell",
"command": "yarn db-studio",
"isBackground": false,
"problemMatcher": []
},
{
"label": "Maildev(587)",
"type": "shell",
"command": "maildev -s 587",
"isBackground": false,
"problemMatcher": []
}
]
}
+128
View File
@@ -0,0 +1,128 @@
# Contributor Covenant Code of Conduct
## Our Pledge
We as members, contributors, and leaders pledge to make participation in our
community a harassment-free experience for everyone, regardless of age, body
size, visible or invisible disability, ethnicity, sex characteristics, gender
identity and expression, level of experience, education, socio-economic status,
nationality, personal appearance, race, religion, or sexual identity
and orientation.
We pledge to act and interact in ways that contribute to an open, welcoming,
diverse, inclusive, and healthy community.
## Our Standards
Examples of behavior that contributes to a positive environment for our
community include:
- Demonstrating empathy and kindness toward other people
- Being respectful of differing opinions, viewpoints, and experiences
- Giving and gracefully accepting constructive feedback
- Accepting responsibility and apologizing to those affected by our mistakes,
and learning from the experience
- Focusing on what is best not just for us as individuals, but for the
overall community
Examples of unacceptable behavior include:
- The use of sexualized language or imagery, and sexual attention or
advances of any kind
- Trolling, insulting or derogatory comments, and personal or political attacks
- Public or private harassment
- Publishing others' private information, such as a physical or email
address, without their explicit permission
- Other conduct which could reasonably be considered inappropriate in a
professional setting
## Enforcement Responsibilities
Community leaders are responsible for clarifying and enforcing our standards of
acceptable behavior and will take appropriate and fair corrective action in
response to any behavior that they deem inappropriate, threatening, offensive,
or harmful.
Community leaders have the right and responsibility to remove, edit, or reject
comments, commits, code, wiki edits, issues, and other contributions that are
not aligned to this Code of Conduct, and will communicate reasons for moderation
decisions when appropriate.
## Scope
This Code of Conduct applies within all community spaces, and also applies when
an individual is officially representing the community in public spaces.
Examples of representing our community include using an official e-mail address,
posting via an official social media account, or acting as an appointed
representative at an online or offline event.
## Enforcement
Instances of abusive, harassing, or otherwise unacceptable behavior may be
reported to the community leaders responsible for enforcement at
bailey@cal.com.
All complaints will be reviewed and investigated promptly and fairly.
All community leaders are obligated to respect the privacy and security of the
reporter of any incident.
## Enforcement Guidelines
Community leaders will follow these Community Impact Guidelines in determining
the consequences for any action they deem in violation of this Code of Conduct:
### 1. Correction
**Community Impact**: Use of inappropriate language or other behavior deemed
unprofessional or unwelcome in the community.
**Consequence**: A private, written warning from community leaders, providing
clarity around the nature of the violation and an explanation of why the
behavior was inappropriate. A public apology may be requested.
### 2. Warning
**Community Impact**: A violation through a single incident or series
of actions.
**Consequence**: A warning with consequences for continued behavior. No
interaction with the people involved, including unsolicited interaction with
those enforcing the Code of Conduct, for a specified period of time. This
includes avoiding interactions in community spaces as well as external channels
like social media. Violating these terms may lead to a temporary or
permanent ban.
### 3. Temporary Ban
**Community Impact**: A serious violation of community standards, including
sustained inappropriate behavior.
**Consequence**: A temporary ban from any sort of interaction or public
communication with the community for a specified period of time. No public or
private interaction with the people involved, including unsolicited interaction
with those enforcing the Code of Conduct, is allowed during this period.
Violating these terms may lead to a permanent ban.
### 4. Permanent Ban
**Community Impact**: Demonstrating a pattern of violation of community
standards, including sustained inappropriate behavior, harassment of an
individual, or aggression toward or disparagement of classes of individuals.
**Consequence**: A permanent ban from any sort of public interaction within
the community.
## Attribution
This Code of Conduct is adapted from the [Contributor Covenant][homepage],
version 2.0, available at
https://www.contributor-covenant.org/version/2/0/code_of_conduct.html.
Community Impact Guidelines were inspired by [Mozilla's code of conduct
enforcement ladder](https://github.com/mozilla/diversity).
[homepage]: https://www.contributor-covenant.org
For answers to common questions about this code of conduct, see the FAQ at
https://www.contributor-covenant.org/faq. Translations are available at
https://www.contributor-covenant.org/translations.
+17
View File
@@ -4,6 +4,23 @@ Contributions are what make the open source community such an amazing place to b
- Before jumping into a PR be sure to search [existing PRs](https://github.com/calcom/cal.com/pulls) or [issues](https://github.com/calcom/cal.com/issues) for an open or closed item that relates to your submission.
## Areas of expertise
### Legend
✅ = has knowledge
🥇 = is their main priority
⚠️ = is the only one with knowledge
👀 = has no knowledge but wants to be onboarded
<picture>
<source media="(prefers-color-scheme: dark)" srcset="https://dynamic-svgs.vercel.app/image.svg?dark">
<img alt="Areas of expertise table" src="https://dynamic-svgs.vercel.app/image.svg">
</picture>
## Developing
The development branch is `main`. This is the branch that all pull
+64 -37
View File
@@ -18,22 +18,26 @@
<a href="https://cal.com">Website</a>
·
<a href="https://github.com/calcom/cal.com/issues">Issues</a>
·
<a href="https://cal.com/roadmap">Roadmap</a>
</p>
</p>
<p align="center">
<a href="https://cal.com/slack"><img src="https://img.shields.io/badge/Slack-calendso.slack.com-%234A154B" alt="Join Cal.com Slack"></a>
<a href="https://www.producthunt.com/posts/calendso"><img src="https://img.shields.io/badge/Product%20Hunt-%231%20Product%20of%20the%20Month-%23DA552E" alt="Product Hunt"></a>
<a href="https://github.com/calcom/cal.com/stargazers"><img src="https://img.shields.io/github/stars/calcom/cal.com" alt="Github Stars"></a>
<a href="https://news.ycombinator.com/item?id=26817795"><img src="https://img.shields.io/badge/Hacker%20News-311-%23FF6600" alt="Hacker News"></a>
<a href="https://github.com/calcom/cal.com/blob/main/LICENSE"><img src="https://img.shields.io/badge/license-AGPLv3-purple" alt="License"></a>
<a href="https://github.com/calcom/cal.com/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://jitsu.com?utm_source=github/calcom/cal.com"><img src="https://img.shields.io/badge/Metrics_tracked_by-JITSU-AA00FF?logo=data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAA4AAAAOCAYAAAAfSC3RAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAACKSURBVHgBrZDRCYAwDEQv6gCOoKO4hOCXI9QVnEZwiY5iF5GaVClaBNtioCSUvCR3tMJaxIfZgW4AGUoEPVwgPZoS0Dmgg3NBVDFNbMIsmYCak3J1jDk9iCQvsKJvkzr71N81Gj6vDT/LU2P6RhY63jcafk3YJEbgeZpiFyc/5HJKv8Ef273NSfABGbQfUZhnOSAAAAAASUVORK5CYII=" alt="Jitsu Tracked"></a>
<a href="https://hub.docker.com/r/calendso/calendso"><img src="https://img.shields.io/docker/pulls/calendso/calendso"></a>
<a href="https://twitter.com/calcom"><img src="https://img.shields.io/twitter/follow/calcom?style=social"></a>
<a href="https://calendso.slack.com/archives/C02BY67GMMW"><img src="https://img.shields.io/badge/translations-contribute-brightgreen" /></a>
<a href="https://github.com/calcom/cal.com/stargazers"><img src="https://img.shields.io/github/stars/calcom/cal.com" alt="Github Stars"></a>
<a href="https://news.ycombinator.com/item?id=26817795"><img src="https://img.shields.io/badge/Hacker%20News-311-%23FF6600" alt="Hacker News"></a>
<a href="https://github.com/calcom/cal.com/blob/main/LICENSE"><img src="https://img.shields.io/badge/license-AGPLv3-purple" alt="License"></a>
<a href="https://github.com/calcom/cal.com/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://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>
<a href="https://twitter.com/calcom"><img src="https://img.shields.io/twitter/follow/calcom?style=flat"></a>
<a href="https://twitch.tv/calcomtv"><img src="https://img.shields.io/twitch/status/calcomtv?style=flat"></a>
<a href="https://calendso.slack.com/archives/C02BY67GMMW"><img src="https://img.shields.io/badge/translations-contribute-brightgreen" /></a>
<a href="https://www.contributor-covenant.org/version/1/4/code-of-conduct/ "><img src="https://img.shields.io/badge/Contributor%20Covenant-1.4-purple" /></a>
</p>
<!-- ABOUT THE PROJECT -->
@@ -80,7 +84,7 @@ To get a local copy up and running, please follow these simple steps.
Here is what you need to be able to run Cal.
- Node.js (Version: >=14.x <15)
- Node.js (Version: >=14.x <17)
- PostgreSQL
- Yarn _(recommended)_
@@ -90,7 +94,7 @@ Here is what you need to be able to run Cal.
### Setup
1. Clone the repo into a public GitHub repository (to comply with AGPLv3. To clone in a private repository, [acquire a commercial license](https://cal.com/sales))
1. Clone the repo into a public GitHub repository (or fork https://github.com/calcom/cal.com/fork). If you plan to distribute the code, keep the source code public to comply with [AGPLv3](https://github.com/calcom/cal.com/blob/main/LICENSE). To clone in a private repository, [acquire a commercial license](https://cal.com/sales))
```sh
git clone https://github.com/calcom/cal.com.git
@@ -102,19 +106,14 @@ Here is what you need to be able to run Cal.
cd cal.com
```
1. Copy `apps/web/.env.example` to `apps/web/.env`
```sh
cp apps/web/.env.example apps/web/.env
cp packages/prisma/.env.example packages/prisma/.env
```
1. Install packages with yarn
```sh
yarn
```
1. Use `openssl rand -base64 32` to generate a key and add it under `NEXTAUTH_SECRET` in the .env file.
#### Quick start with `yarn dx`
> - **Requires Docker and Docker Compose to be installed**
@@ -126,15 +125,15 @@ yarn dx
#### Development tip
> Add `NEXT_PUBLIC_DEBUG=1` anywhere in your `apps/web/.env` to get logging information for all the queries and mutations driven by **trpc**.
> Add `NEXT_PUBLIC_DEBUG=1` anywhere in your `.env` to get logging information for all the queries and mutations driven by **trpc**.
```sh
echo 'NEXT_PUBLIC_DEBUG=1' >> apps/web/.env
echo 'NEXT_PUBLIC_DEBUG=1' >> .env
```
#### Manual setup
1. Configure environment variables in the .env file. Replace `<user>`, `<pass>`, `<db-host>`, `<db-port>` with their applicable values
1. Configure environment variables in the `packages/prisma/.env` file. Replace `<user>`, `<pass>`, `<db-host>`, `<db-port>` with their applicable values
```
DATABASE_URL='postgresql://<user>:<pass>@<db-host>:<db-port>'
@@ -195,11 +194,11 @@ echo 'NEXT_PUBLIC_DEBUG=1' >> apps/web/.env
### E2E-Testing
Be sure to set the environment variable `NEXTAUTH_URL` to the correct value. If you are running locally, as the documentation within `.env.example` mentions, the value should be `http://localhost:3000`.
```sh
# In first terminal. Must run on port 3000.
yarn dx
# In second terminal
yarn workspace @calcom/web test-e2e
# In a terminal just run:
yarn test-e2e
# To open last HTML report run:
yarn workspace @calcom/web playwright-report
@@ -213,7 +212,13 @@ yarn workspace @calcom/web playwright-report
git pull
```
2. Apply database migrations by running <b>one of</b> the following commands:
1. Check if dependencies got added/updated/removed
```sh
yarn
```
1. Apply database migrations by running <b>one of</b> the following commands:
In a development environment, run:
@@ -229,16 +234,13 @@ yarn workspace @calcom/web playwright-report
yarn workspace @calcom/prisma db-deploy
```
3. Check the `.env.example` and compare it to your current `.env` file. In case there are any fields not present
in your current `.env`, add them there.
1. Check for `.env` variables changes
For the current version, especially check if the variable `BASE_URL` is present and properly set in your environment, for example:
```
BASE_URL='https://yourdomain.com'
```sh
yarn predev
```
4. Start the server. In a development environment, just do:
1. Start the server. In a development environment, just do:
```sh
yarn dev
@@ -251,7 +253,7 @@ yarn workspace @calcom/web playwright-report
yarn start
```
5. Enjoy the new version.
1. Enjoy the new version.
<!-- DEPLOYMENT -->
## Deployment
@@ -349,6 +351,7 @@ oauth_config:
bot:
- chat:write
- commands
- chat:write.public
settings:
interactivity:
is_enabled: true
@@ -391,6 +394,30 @@ Next make sure you have your app running `yarn dx`. Then in the slack chat type
4. Now paste the API key to your .env file into the `DAILY_API_KEY` field in your .env file.
5. If you have the [Daily Scale Plan](https://www.daily.co/pricing) set the `DAILY_SCALE_PLAN` variable to `true` in order to use features like video recording.
### Obtaining HubSpot Client ID and Secret
1. Open [HubSpot Developer](https://developer.hubspot.com/) and sign into your account, or create a new one.
2. From within the home of the Developer account page, go to "Manage apps".
3. Click "Create app" button top right.
4. Fill in any information you want in the "App info" tab
5. Go to tab "Auth"
6. Now copy the Client ID and Client Secret to your .env file into the `HUBSPOT_CLIENT_ID` and `HUBSPOT_CLIENT_SECRET` fields.
7. Set the Redirect URL for OAuth `<Cal.com URL>/api/integrations/hubspotothercalendar/callback` replacing Cal.com URL with the URI at which your application runs.
8. In the "Scopes" section at the bottom of the page, make sure you select "Read" and "Write" for scope called `crm.objects.contacts`
9. Click the "Save" button at the bottom footer.
10. You're good to go. Now you can see any booking in Cal.com created as a meeting in HubSpot for your contacts.
### Obtaining Vital API Keys
1. Open [Vital](https://tryvital.io/) and click Get API Keys.
1. Create a team with the team name you desire
1. Head to the configuration section on the sidebar of the dashboard
1. Click on API keys and you'll find your sandbox `api_key`.
1. Copy your `api_key` to `VITAL_API_KEY` in the .env.appStore file.
1. Open [Vital Webhooks](https://app.tryvital.io/team/{team_id}/webhooks) and add `<CALCOM BASE URL>/api/integrations/vital/webhook` as webhook for connected applications.
1. Select all events for the webhook you interested, e.g. `sleep_created`
1. Copy the webhook secret (`sec...`) to `VITAL_WEBHOOK_SECRET` in the .env.appStore file.
<!-- LICENSE -->
## License
@@ -411,6 +438,6 @@ Special thanks to these amazing projects which help power Cal.com:
- [Tailwind CSS](https://tailwindcss.com/)
- [Prisma](https://prisma.io/)
[<img src="https://jitsu.com/img/powered-by-jitsu.png?gh=true">](https://jitsu.com/?utm_source=cal.com-gihub)
<a href="https://jitsu.com/?utm_source=cal.com-gihub"><img height="40px" src="https://jitsu.com/img/powered-by-jitsu.png?gh=true" alt="Jitsu.com"></a>
Cal.com is an [open startup](https://jitsu.com) and [Jitsu](https://github.com/jitsucom/jitsu) (an open-source Segment alternative) helps us to track most of the usage metrics.
Cal.com is an [open startup](https://cal.com/open) and [Jitsu](https://github.com/jitsucom/jitsu) (an open-source Segment alternative) helps us to track most of the usage metrics.
+38
View File
@@ -0,0 +1,38 @@
# Security
Contact: security@cal.com
Based on [https://supabase.com/.well-known/security.txt](https://supabase.com/.well-known/security.txt)
At Cal.com, we consider the security of our systems a top priority. But no matter how much effort we put into system security, there can still be vulnerabilities present.
If you discover a vulnerability, we would like to know about it so we can take steps to address it as quickly as possible. We would like to ask you to help us better protect our clients and our systems.
## Out of scope vulnerabilities:
* Clickjacking on pages with no sensitive actions.
* Unauthenticated/logout/login CSRF.
* Attacks requiring MITM or physical access to a user's device.
* Any activity that could lead to the disruption of our service (DoS).
* Content spoofing and text injection issues without showing an attack vector/without being able to modify HTML/CSS.
* Email spoofing
* Missing DNSSEC, CAA, CSP headers
* Lack of Secure or HTTP only flag on non-sensitive cookies
* Deadlinks
## Please do the following:
* E-mail your findings to [security@cal.com](mailto:security@cal.com).
* Do not run automated scanners on our infrastructure or dashboard. If you wish to do this, contact us and we will set up a sandbox for you.
* Do not take advantage of the vulnerability or problem you have discovered, for example by downloading more data than necessary to demonstrate the vulnerability or deleting or modifying other people's data,
* Do not reveal the problem to others until it has been resolved,
* Do not use attacks on physical security, social engineering, distributed denial of service, spam or applications of third parties,
* Do provide sufficient information to reproduce the problem, so we will be able to resolve it as quickly as possible. Usually, the IP address or the URL of the affected system and a description of the vulnerability will be sufficient, but complex vulnerabilities may require further explanation.
## What we promise:
* We will respond to your report within 3 business days with our evaluation of the report and an expected resolution date,
* If you have followed the instructions above, we will not take any legal action against you in regard to the report,
* We will handle your report with strict confidentiality, and not pass on your personal details to third parties without your permission,
* We will keep you informed of the progress towards resolving the problem,
* In the public information concerning the problem reported, we will give your name as the discoverer of the problem (unless you desire otherwise), and
* We strive to resolve all problems as quickly as possible, and we would like to play an active role in the ultimate publication on the problem after it is resolved.
+5 -1
View File
@@ -18,7 +18,11 @@
"description": "Application Key for symmetric encryption and decryption. Must be 32 bytes for AES256 encryption algorithm.",
"value": "secret"
},
"JWT_SECRET": "secret"
"NEXTAUTH_SECRET": "secret",
"NEXTAUTH_URL": {
"description": "Replace HEROKU_APP_NAME with the name given to your app",
"value": "https://HEROKU_APP_NAME.herokuapp.com"
}
},
"scripts": {
"postdeploy": "cd packages/prisma && npx prisma migrate deploy"
Submodule
+1
Submodule apps/console added at e4d452c51e
+1 -1
View File
@@ -5,7 +5,7 @@
</a>
<a href="https://cal.com">Website</a>
·
<a href="https://github.com/calcom/docs/issues">Community Support</a>
<a href="https://github.com/calcom/cal.com/issues">Community Support</a>
</div>
# Cal.com Documentation
+21
View File
@@ -0,0 +1,21 @@
function getAnchor(text) {
return text
.toLowerCase()
.replace(/[^a-z0-9 ]/g, "")
.replace(/[ ]/g, "-")
.replace(/ /g, "%20");
}
export default function Anchor({ as, children }) {
const anchor = getAnchor(children);
const link = `#${anchor}`;
const Component = as || "div";
return (
<Component id={anchor}>
<a href={link} className="anchor-link">
§
</a>
{children}
</Component>
);
}
+33
View File
@@ -0,0 +1,33 @@
import { useState, useEffect } from "react";
// Define general type for useWindowSize hook, which includes width and height
export interface Size {
width: number | undefined;
height: number | undefined;
}
// Hook from: https://usehooks.com/useWindowSize/
export function useWindowSize(): Size {
// Initialize state with undefined width/height so server and client renders match
// Learn more here: https://joshwcomeau.com/react/the-perils-of-rehydration/
const [windowSize, setWindowSize] = useState<Size>({
width: undefined,
height: undefined,
});
useEffect(() => {
// Handler to call on window resize
function handleResize() {
// Set window width/height to state
setWindowSize({
width: window.innerWidth,
height: window.innerHeight,
});
}
// Add event listener
window.addEventListener("resize", handleResize);
// Call handler right away so state gets updated with initial window size
handleResize();
// Remove event listener on cleanup
return () => window.removeEventListener("resize", handleResize);
}, []); // Empty array ensures that effect is only run on mount
return windowSize;
}
+12 -1
View File
@@ -1,6 +1,17 @@
/* eslint-disable @typescript-eslint/no-var-requires */
const withNextra = require("nextra")({
theme: "nextra-theme-docs",
themeConfig: "./theme.config.js",
unstable_staticImage: true,
});
module.exports = withNextra();
module.exports = withNextra({
async rewrites() {
return [
// This redirects requests recieved at /api to /public-api to workaround nextjs default use of /api.
{
source: "/api",
destination: "/public-api",
},
];
},
});
+5 -4
View File
@@ -15,14 +15,15 @@
"author": "Cal.com, Inc.",
"license": "MIT",
"dependencies": {
"next": "^12.1.0",
"iframe-resizer-react": "^1.1.0",
"next": "^12.1.6",
"nextra": "^1.1.0",
"nextra-theme-docs": "^1.2.2",
"react": "^17.0.2",
"react-dom": "^17.0.2"
"react": "^18.1.0",
"react-dom": "^18.1.0"
},
"devDependencies": {
"@calcom/config": "*",
"eslint": "^8.10.0"
"eslint": "^8.15.0"
}
}
+1 -1
View File
@@ -12,6 +12,6 @@ This is also the home of our design system documentation and developer docs.
If you don't already know what Cal.com is about, please head over to [our website](https://cal.com), where you can learn more about the product before venturing into the documentation.
Want to help make these docs even better? This site is fully open source, and the source code is available on [GitHub](https://github.com/calcom/docs). You can also click the edit button at the bottom of any page to start editing the source code and start a pull request.
Want to help make these docs even better? This site is fully open source, and the source code is available on [GitHub](https://github.com/calcom/cal.com/tree/main/apps/docs). You can also click the edit button at the bottom of any page to start editing the source code and start a pull request.
<Bleed>![Telemedicine Example](https://cal.com/telemedicine-example.svg)</Bleed>
+90 -36
View File
@@ -2,17 +2,18 @@
title: Embed
---
import Anchor from "../../components/Anchor"
# Embed
The Embed allows your website visitors to book a meeting with you directly from your website.
## Install on any website
TODO: Mention possibility of installation through tag managers as well
Install the following Vanilla JS Snippet to get embed to work on any website. After that you can <a href="#popular-ways-in-which-you-can-embed-on-your-website">choose any of the ways</a> to show your Cal Link embedded on your website.
- _Step-1._ Install the Vanilla JS Snippet
```javascript
```html
<script>
(function (C, A, L) {
let p = function (a, ar) {
a.q.push(ar);
@@ -40,14 +41,10 @@ TODO: Mention possibility of installation through tag managers as well
}
p(cal, ar);
};
})(window, "https://cal.com/embed.js", "init");
```
- _Step-2_. Initialize it
```javascript
Cal("init)
```
})(window, "https://cal.com/embed.js", "init");
Cal("init")
</script>
```
## Install with a Framework
@@ -63,9 +60,9 @@ yarn add @calcom/embed-react
You can use Vanilla JS Snippet to install
## Popular ways in which you can embed on your website
<Anchor as="H2">Popular ways in which you can embed on your website</Anchor>
Assuming that you have followed the steps of installing and initializing the snippet, you can add show the embed in following ways:
Assuming that you have followed the steps of installing and initializing the snippet, you can show the embed in following ways:
### Inline
@@ -74,20 +71,29 @@ Show the embed inline inside a container element. It would take the width and he
<details>
<summary>_Vanilla JS_</summary>
```javascript
Cal("inline", {
elementOrSelector: "Your Embed Container Selector Path", // You can also provide an element directly
calLink: "jane", // The link that you want to embed. It would open https://cal.com/jane in embed
config: {
name: "John Doe", // Prefill Name
email: "johndoe@gmail.com", // Prefill Email
notes: "Test Meeting", // Prefill Notes
guests: ["janedoe@gmail.com", "test@gmail.com"], // Prefill Guests
theme: "dark", // "dark" or "light" theme
},
});
```
```html
<script>
Cal("inline", {
elementOrSelector: "Your Embed Container Selector Path", // You can also provide an element directly
calLink: "jane", // The link that you want to embed. It would open https://cal.com/jane in embed
config: {
name: "John Doe", // Prefill Name
email: "johndoe@gmail.com", // Prefill Email
notes: "Test Meeting", // Prefill Notes
guests: ["janedoe@gmail.com", "test@gmail.com"], // Prefill Guests
theme: "dark", // "dark" or "light" theme
},
});
</script>
*Sample sandbox*
```
<iframe src="https://codesandbox.io/embed/vanilla-js-inline-embed-r27n67?fontsize=14&hidenavigation=1&theme=dark"
style={{width:"100%", height:"500px", border:0, borderRadius: "4px", overflow:"hidden"}}
title="Cal Component - Embed Inline Demo[React][TypeScript]"
allow="accelerometer; ambient-light-sensor; camera; encrypted-media; geolocation; gyroscope; hid; microphone; midi; payment; usb; vr; xr-spatial-tracking"
sandbox="allow-forms allow-modals allow-popups allow-presentation allow-same-origin allow-scripts"
></iframe>
</details>
####
@@ -112,6 +118,14 @@ const MyComponent = () => (
);
```
*Sample sandbox*
<iframe src="https://codesandbox.io/embed/cal-component-embed-inline-demo-react-typescript-d1zlcn?fontsize=14&hidenavigation=1&theme=dark"
style={{width:"100%", height:"500px", border:0, borderRadius: "4px", overflow:"hidden"}}
title="Cal Component - Embed Inline Demo[React][TypeScript]"
allow="accelerometer; ambient-light-sensor; camera; encrypted-media; geolocation; gyroscope; hid; microphone; midi; payment; usb; vr; xr-spatial-tracking"
sandbox="allow-forms allow-modals allow-popups allow-presentation allow-same-origin allow-scripts"
></iframe>
</details>
### Popup on any existing element
@@ -124,9 +138,16 @@ To show the embed as a popup on clicking an element, add `data-cal-link` attribu
To show the embed as a popup on clicking an element, simply add `data-cal-link` attribute to the element.
*Sample sandbox*
<iframe src="https://codesandbox.io/embed/popup-on-click-of-an-existing-element-y9lcuo?fontsize=14&hidenavigation=1&theme=dark"
style={{width:"100%", height:"500px", border:0, borderRadius: "4px", overflow:"hidden"}}
title="Cal Component - Embed Inline Demo[React][TypeScript]"
allow="accelerometer; ambient-light-sensor; camera; encrypted-media; geolocation; gyroscope; hid; microphone; midi; payment; usb; vr; xr-spatial-tracking"
sandbox="allow-forms allow-modals allow-popups allow-presentation allow-same-origin allow-scripts"
></iframe>
<button data-cal-link="jane" data-cal-config="A valid config JSON"></button>
</details>
<details>
<summary>React</summary>
```jsx
@@ -135,11 +156,36 @@ To show the embed as a popup on clicking an element, simply add `data-cal-link`
const MyComponent = ()=> {
return <button data-cal-link="jane" data-cal-config='A valid config JSON'></button>
}
```
````
*Sample sandbox*
<iframe src="https://codesandbox.io/embed/embed-popup-on-click-of-an-existing-element-demo-react-sc967e?fontsize=14&hidenavigation=1&theme=dark"
style={{width:"100%", height:"500px", border:0, borderRadius: "4px", overflow:"hidden"}}
title="Cal Component - Embed Inline Demo[React][TypeScript]"
allow="accelerometer; ambient-light-sensor; camera; encrypted-media; geolocation; gyroscope; hid; microphone; midi; payment; usb; vr; xr-spatial-tracking"
sandbox="allow-forms allow-modals allow-popups allow-presentation allow-same-origin allow-scripts"
></iframe>
</details>
### Full Screen
### Floating pop-up button
```html
<script>
Cal("floatingButton", {
// The link that you want to embed. It would open https://cal.com/jane in embed
calLink: "jane",
});
</script>
```
*Sample sandbox*
<iframe src="https://codesandbox.io/embed/embed-floating-button-popup-all-websites-cg7pru?fontsize=14&hidenavigation=1&theme=dark"
style={{width:"100%", height:"500px", border:0, borderRadius: "4px", overflow:"hidden"}}
title="Cal Component - Embed Inline Demo[React][TypeScript]"
allow="accelerometer; ambient-light-sensor; camera; encrypted-media; geolocation; gyroscope; hid; microphone; midi; payment; usb; vr; xr-spatial-tracking"
sandbox="allow-forms allow-modals allow-popups allow-presentation allow-same-origin allow-scripts"
></iframe>
## Supported Instructions
@@ -149,8 +195,10 @@ Consider an instruction as a function with that name and that would be called wi
Appends embed inline as the child of the element.
```javascript
```html
<script>
Cal("inline", { elementOrSelector, calLink });
</script>
````
- `elementOrSelector` - Give it either a valid CSS selector or an HTMLElement instance directly
@@ -161,8 +209,10 @@ Cal("inline", { elementOrSelector, calLink });
Configure UI for embed. Make it look part of your webpage.
```javascript
```html
<script>
Cal("inline", { styles });
</script>
```
- `styles` - It supports styling for `body` and `eventTypeListItem`. Right now we support just background on these two.
@@ -173,15 +223,18 @@ Usage:
If you want to open cal link on some action. Make it pop open instantly by preloading it.
```javascript
```html
<script>
Cal("preload", { calLink });
</script>
```
- `calLink` - Cal Link that you want to embed e.g. john. Just give the username. No need to give the full URL [https://cal.com/john]()
## Actions
You can listen to an action that occurs in embedded cal link as follows. You can think of them as DOM events. We are avoiding the term events to not confuse it with Cal Events.
```javascript
You can listen to an action that occurs in embedded cal link as follows. You can think of them as DOM events. We are avoiding the term "events" to not confuse it with Cal Events.
```html
<script>
Cal("on", {
action: "ANY_ACTION_NAME",
callback: (e)=>{
@@ -191,11 +244,12 @@ Cal("on", {
const {data, type, namespace} = e.detail;
}
})
</script>
```
Following are the list of supported actions.
-
| action | description | properties |
| Action | Description | Properties |
|----------------------|------------------------------------------------------------------------------------------------------------------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| eventTypeSelected | When user chooses an event-type from the listing. | eventType:object // Event Type that has been selected" |
| bookingSuccessful | When the booking is successfully done. It might not be confirmed. | confirmed: boolean; //Whether confirmation from organizer is pending or not <br/><br/>eventType: "Object for Event Type that has been booked"; <br/><br/>date: string; // Date of Event <br/><br/>duration: number; //Duration of booked Event <br/><br/>organizer: object //Organizer details like name, timezone, email |
+21
View File
@@ -0,0 +1,21 @@
---
Title: Slack
---
# Slack
## Connecting
Connecting the bot is easy - If you are a workspace admin, the install button will add the bot to the workspace and also authorize your account with the bot. If you are a normal user, the install button will connect your Slack account with Cal.com. This will allow you to perform commands in Slack.
## Commands
`/today` - This command will display all meetings you have in your Cal.com profile for the current day. This will send a hidden message (not visible to anyone other than you) to the channel you issued the command in.
`/create-event` - It will display a modal allowing you to simply create a meeting invite with anyone in Slack. Success/Error information will be displayed in a private direct message from the bot.
`/links` - This command will post all your Cal.com meeting links into the current Slack channel you are in. **Note**: The bot needs to have permission to talk in the channel you are sending the message in. Otherwise, you won't be able to send your links.
As this is the beggining stage of our Slack integration, we plan on adding more commands in the future that will further improve your Cal.com experience.
## Self-Hosted
If you are using our self-hosted version, please refer to our documentation in
[cal.com/README.md](https://github.com/calcom/cal.com/blob/main/README.md#obtaining-slack-client-id-and-secret-and-signing-secret)
+1
View File
@@ -6,6 +6,7 @@
"event-types": "Event Types",
"teams": "Teams",
"integrations": "Integrations",
"public-api": "API",
"webhooks": "Webhooks",
"settings": "Settings",
"import": "Import",
+20
View File
@@ -0,0 +1,20 @@
import Bleed from 'nextra-theme-docs/bleed'
import Head from "next/head";
import IframeResizer from "iframe-resizer-react";
import {useWindowSize} from "../lib/useWindowSize";
<Bleed full>
<Head><title>Public API | Cal.com</title></Head>
<IframeResizer
autoResize
src={process.env.NEXT_PUBLIC_SWAGGER_DOCS_URL || "https://developer.cal.com"}
frameBorder="0"
style={{
width: useWindowSize().width > 768 ? "calc(100vw - 16rem)": "100vw",
minHeight: useWindowSize().width > 768 ? "100vh" : "200vh",
height: "auto",
border: 0,
}}
/>
</Bleed>
+1 -1
View File
@@ -18,7 +18,7 @@ You need a PostgresDB database hosted somewhere. [Heroku](https://www.heroku.com
git clone https://github.com/<your-fork>/cal.com.git
```
2. Copy the `.env.example` file in `apps/web`, rename it to `.env` and fill it with your settings ([See manual setup](https://github.com/calcom/cal.com#manual) and [Obtaining the Google API Credentials](https://github.com/calcom/cal.com#obtaining-the-google-api-credentials))
2. Copy the `.env.example` file in `apps/web`, rename it to `.env` and fill it with your settings ([See manual setup](https://github.com/calcom/cal.com#manual-setup) and [Obtaining the Google API Credentials](https://github.com/calcom/cal.com#obtaining-the-google-api-credentials))
3. Install packages with `yarn`
-3623
View File
File diff suppressed because it is too large Load Diff
View File
+1
View File
@@ -0,0 +1 @@
NEXT_PUBLIC_SWAGGER_DOCS_URL=http://localhost:3002/api/docs
+353
View File
@@ -0,0 +1,353 @@
import * as OpenAPISnippet from "openapi-snippet";
export const requestSnippets = {
generators: {
curl_bash: {
title: "cURL (bash)",
syntax: "bash",
},
curl_powershell: {
title: "cURL (PowerShell)",
syntax: "powershell",
},
curl_cmd: {
title: "cURL (CMD)",
syntax: "bash",
},
node: {
title: "Node",
syntax: "node",
},
},
defaultExpanded: true,
languages: ["node", "curl_bash"],
};
// Since swagger-ui-react was not configured to change the request snippets some workarounds required
// configuration will be added programatically
// Custom Plugin
export const SnippedGenerator = {
statePlugins: {
// extend some internals to gain information about current path, method and spec in the generator function metioned later
spec: {
wrapSelectors: {
requestFor: (ori, system) => (state, path, method) => {
return ori(path, method)
?.set("spec", state.get("json", {}))
?.setIn(["oasPathMethod", "path"], path)
?.setIn(["oasPathMethod", "method"], method);
},
mutatedRequestFor: (ori) => (state, path, method) => {
return ori(path, method)
?.set("spec", state.get("json", {}))
?.setIn(["oasPathMethod", "path"], path)
?.setIn(["oasPathMethod", "method"], method);
},
},
},
// extend the request snippets core plugin
requestSnippets: {
wrapSelectors: {
// add additional snippet generators here
getSnippetGenerators:
(ori, system) =>
(state, ...args) =>
ori(state, ...args)
// add node native snippet generator
// .set(
// // key
// "node_native",
// // config and generator function
// system.Im.fromJS({
// title: "NodeJs Native",
// syntax: "javascript",
// hostname: "test",
// fn: (req) => {
// // get extended info about request
// const { spec, oasPathMethod } = req.toJS();
// const { path, method } = oasPathMethod;
// // run OpenAPISnippet for target node
// const targets = ["node_native"];
// let snippet;
// try {
// // set request snippet content
// snippet = OpenAPISnippet.getEndpointSnippets(
// spec,
// path,
// method,
// targets
// // Since I don't know why hostname was undefinedundefined, I harcoded it here
// ).snippets[0].content;
// } catch (err) {
// // set to error in case it happens the npm package has some flaws
// snippet = JSON.stringify(snippet);
// }
// // return stringified snipped
// return snippet;
// },
// })
// )
.set(
// key
"node_fetch",
// config and generator function
system.Im.fromJS({
title: "NodeJS",
syntax: "javascript",
fn: (req) => {
// get extended info about request
const { spec, oasPathMethod } = req.toJS();
const { path, method } = oasPathMethod;
// run OpenAPISnippet for target node
const targets = ["node_fetch"];
let snippet;
try {
// set request snippet content
snippet = OpenAPISnippet.getEndpointSnippets(spec, path, method, targets).snippets[0]
.content;
} catch (err) {
// set to error in case it happens the npm package has some flaws
snippet = JSON.stringify(snippet);
}
// return stringified snipped
return snippet;
},
})
)
.set(
// key
"shell_httpie",
// config and generator function
system.Im.fromJS({
title: "HTTPie",
syntax: "bash",
fn: (req) => {
// get extended info about request
const { spec, oasPathMethod } = req.toJS();
const { path, method } = oasPathMethod;
// run OpenAPISnippet for target node
const targets = ["shell_httpie"];
let snippet;
try {
// set request snippet content
snippet = OpenAPISnippet.getEndpointSnippets(spec, path, method, targets).snippets[0]
.content;
} catch (err) {
// set to error in case it happens the npm package has some flaws
snippet = JSON.stringify(snippet);
}
// return stringified snipped
return snippet;
},
})
)
.set(
// key
"php_curl",
// config and generator function
system.Im.fromJS({
title: "PHP",
syntax: "php",
fn: (req) => {
// get extended info about request
const { spec, oasPathMethod } = req.toJS();
const { path, method } = oasPathMethod;
// run OpenAPISnippet for target node
const targets = ["php_curl"];
let snippet;
try {
// set request snippet content
snippet = OpenAPISnippet.getEndpointSnippets(spec, path, method, targets).snippets[0]
.content;
} catch (err) {
// set to error in case it happens the npm package has some flaws
snippet = JSON.stringify(snippet);
}
// return stringified snipped
return snippet;
},
})
)
.set(
// key
"java_okhttp",
// config and generator function
system.Im.fromJS({
title: "Java",
syntax: "java",
fn: (req) => {
// get extended info about request
const { spec, oasPathMethod } = req.toJS();
const { path, method } = oasPathMethod;
console.log(spec, oasPathMethod, path, method);
// run OpenAPISnippet for target node
const targets = ["java_okhttp"];
let snippet;
try {
// set request snippet content
snippet = OpenAPISnippet.getEndpointSnippets(spec, path, method, targets).snippets[0]
.content;
} catch (err) {
// set to error in case it happens the npm package has some flaws
snippet = JSON.stringify(snippet);
}
// return stringified snipped
return snippet;
},
})
)
// .set(
// // key
// "java",
// // config and generator function
// system.Im.fromJS({
// title: "Java (Unirest)",
// syntax: "java",
// fn: (req) => {
// // get extended info about request
// const { spec, oasPathMethod } = req.toJS();
// const { path, method } = oasPathMethod;
// // run OpenAPISnippet for target node
// const targets = ["java"];
// let snippet;
// try {
// // set request snippet content
// snippet = OpenAPISnippet.getEndpointSnippets(
// spec,
// path,
// method,
// targets
// ).snippets[0].content;
// } catch (err) {
// // set to error in case it happens the npm package has some flaws
// snippet = JSON.stringify(snippet);
// }
// // return stringified snipped
// return snippet;
// },
// })
// )
// .set(
// // key
// "c_libcurl",
// // config and generator function
// system.Im.fromJS({
// title: "C (libcurl) ",
// syntax: "bash",
// fn: (req) => {
// // get extended info about request
// const { spec, oasPathMethod } = req.toJS();
// const { path, method } = oasPathMethod;
// // run OpenAPISnippet for target node
// const targets = ["c_libcurl"];
// let snippet;
// try {
// // set request snippet content
// snippet = OpenAPISnippet.getEndpointSnippets(
// spec,
// path,
// method,
// targets
// ).snippets[0].content;
// } catch (err) {
// // set to error in case it happens the npm package has some flaws
// snippet = JSON.stringify(snippet);
// }
// // return stringified snipped
// return snippet;
// },
// })
// )
.set(
// key
"go_native",
// config and generator function
system.Im.fromJS({
title: "Go",
syntax: "bash",
fn: (req) => {
// get extended info about request
const { spec, oasPathMethod } = req.toJS();
const { path, method } = oasPathMethod;
// run OpenAPISnippet for target node
const targets = ["go_native"];
let snippet;
try {
// set request snippet content
snippet = OpenAPISnippet.getEndpointSnippets(spec, path, method, targets).snippets[0]
.content;
} catch (err) {
// set to error in case it happens the npm package has some flaws
snippet = JSON.stringify(snippet);
}
// return stringified snipped
return snippet;
},
})
)
.set(
// key
"ruby",
// config and generator function
system.Im.fromJS({
title: "Ruby",
syntax: "ruby",
fn: (req) => {
// get extended info about request
const { spec, oasPathMethod } = req.toJS();
const { path, method } = oasPathMethod;
// run OpenAPISnippet for target node
const targets = ["ruby"];
let snippet;
try {
// set request snippet content
snippet = OpenAPISnippet.getEndpointSnippets(spec, path, method, targets).snippets[0]
.content;
} catch (err) {
// set to error in case it happens the npm package has some flaws
snippet = JSON.stringify(snippet);
}
// return stringified snipped
return snippet;
},
})
)
.set(
// key
"python",
// config and generator function
system.Im.fromJS({
title: "Python",
syntax: "python",
fn: (req) => {
// get extended info about request
const { spec, oasPathMethod } = req.toJS();
const { path, method } = oasPathMethod;
// run OpenAPISnippet for target node
const targets = ["python"];
let snippet;
try {
// set request snippet content
snippet = OpenAPISnippet.getEndpointSnippets(spec, path, method, targets).snippets[0]
.content;
} catch (err) {
// set to error in case it happens the npm package has some flaws
snippet = JSON.stringify(snippet);
}
// return stringified snipped
return snippet;
},
})
),
},
},
},
};
+12 -10
View File
@@ -3,21 +3,23 @@
"version": "1.0.0",
"private": true,
"scripts": {
"dev": "next dev",
"dev": "PORT=4200 next dev",
"build": "next build",
"start": "next start"
"start": "PORT=4200 next start"
},
"dependencies": {
"highlight.js": "^11.5.1",
"isarray": "2.0.5",
"next": "12.1.4",
"react": "17.0.2",
"react-dom": "17.0.2",
"swagger-ui-react": "4.8.1"
"next": "12.1.6",
"openapi-snippet": "^0.13.0",
"react": "18.1.0",
"react-dom": "18.1.0",
"swagger-ui-react": "4.11.1"
},
"devDependencies": {
"@types/node": "16.11.26",
"@types/react": "17.0.43",
"@types/react-dom": "17.0.14",
"typescript": "4.6.3"
"@types/node": "16.9.1",
"@types/react": "18.0.9",
"@types/react-dom": "18.0.4",
"typescript": "4.6.4"
}
}
+3 -1
View File
@@ -1,5 +1,7 @@
import "highlight.js/styles/default.css";
import "swagger-ui-react/swagger-ui.css";
import "../styles/globals.css";
import "../styles/swagger-cal.css";
function MyApp({ Component, pageProps }) {
return <Component {...pageProps} />;
+21 -40
View File
@@ -1,45 +1,26 @@
import Head from "next/head";
import SwaggerUI from "swagger-ui-react";
import dynamic from "next/dynamic";
import { SwaggerUI } from "swagger-ui-react";
import { SnippedGenerator, requestSnippets } from "@lib/snippets";
const SwaggerUIDynamic: SwaggerUI & { url: string } = dynamic(() => import("swagger-ui-react"), {
ssr: false,
});
const requestSnippets = {
generators: {
curl_bash: {
title: "cURL (bash)",
syntax: "bash",
},
curl_powershell: {
title: "cURL (PowerShell)",
syntax: "powershell",
},
curl_cmd: {
title: "cURL (CMD)",
syntax: "bash",
},
node: {
title: "Node",
syntax: "node",
},
},
defaultExpanded: true,
languages: ["curl_bash"],
// e.g. only show curl bash = ["curl_bash"]
};
export default function APIDocs() {
return (
<div>
<Head>
<title>Cal.com - Docs - SwaggerUI</title>
<meta name="description" content="Generated by create next app" />
<link rel="icon" href="/favicon.ico" />
</Head>
<SwaggerUI
requestSnippets={requestSnippets}
requestSnippetsEnabled={true}
docExpansion="none"
operationsSorter="method"
filter={true}
url={process.env.NEXT_PUBLIC_SWAGGER_DOCS_URL || "https://api.cal.com/api/docs"}
/>
</div>
<SwaggerUIDynamic
url={process.env.NEXT_PUBLIC_SWAGGER_DOCS_URL || "https://api.cal.com/docs"}
persistAuthorization={true}
supportedSubmitMethods={["get", "post", "delete", "put", "options", "patch"]}
requestSnippetsEnabled={true}
requestSnippets={requestSnippets}
plugins={[SnippedGenerator]}
tryItOutEnabled={true}
syntaxHighlight={true}
enableCORS={false} // Doesn't seem to work either
docExpansion="list"
filter={true}
/>
);
}
Binary file not shown.

Before

Width:  |  Height:  |  Size: 15 KiB

After

Width:  |  Height:  |  Size: 15 KiB

-4
View File
@@ -1,4 +0,0 @@
<svg width="283" height="64" viewBox="0 0 283 64" fill="none"
xmlns="http://www.w3.org/2000/svg">
<path d="M141.04 16c-11.04 0-19 7.2-19 18s8.96 18 20 18c6.67 0 12.55-2.64 16.19-7.09l-7.65-4.42c-2.02 2.21-5.09 3.5-8.54 3.5-4.79 0-8.86-2.5-10.37-6.5h28.02c.22-1.12.35-2.28.35-3.5 0-10.79-7.96-17.99-19-17.99zm-9.46 14.5c1.25-3.99 4.67-6.5 9.45-6.5 4.79 0 8.21 2.51 9.45 6.5h-18.9zM248.72 16c-11.04 0-19 7.2-19 18s8.96 18 20 18c6.67 0 12.55-2.64 16.19-7.09l-7.65-4.42c-2.02 2.21-5.09 3.5-8.54 3.5-4.79 0-8.86-2.5-10.37-6.5h28.02c.22-1.12.35-2.28.35-3.5 0-10.79-7.96-17.99-19-17.99zm-9.45 14.5c1.25-3.99 4.67-6.5 9.45-6.5 4.79 0 8.21 2.51 9.45 6.5h-18.9zM200.24 34c0 6 3.92 10 10 10 4.12 0 7.21-1.87 8.8-4.92l7.68 4.43c-3.18 5.3-9.14 8.49-16.48 8.49-11.05 0-19-7.2-19-18s7.96-18 19-18c7.34 0 13.29 3.19 16.48 8.49l-7.68 4.43c-1.59-3.05-4.68-4.92-8.8-4.92-6.07 0-10 4-10 10zm82.48-29v46h-9V5h9zM36.95 0L73.9 64H0L36.95 0zm92.38 5l-27.71 48L73.91 5H84.3l17.32 30 17.32-30h10.39zm58.91 12v9.69c-1-.29-2.06-.49-3.2-.49-5.81 0-10 4-10 10V51h-9V17h9v9.2c0-5.08 5.91-9.2 13.2-9.2z" fill="#000"/>
</svg>

Before

Width:  |  Height:  |  Size: 1.1 KiB

+86
View File
@@ -14,3 +14,89 @@ a {
* {
box-sizing: border-box;
}
@media (max-width: 768px) {
.swagger-ui .opblock-tag {
font-size: 90% !important;
}
.swagger-ui .opblock .opblock-summary {
display: grid;
flex-direction: column;
}
.opblock-summary-path {
flex-shrink: 0;
max-width: 100% !important;
padding: 10px 5px !important;
}
.opblock-summary-description {
font-size: 16px !important;
padding: 0px 5px;
}
.swagger-ui .scheme-container .schemes {
align-items: center;
display: flex;
flex-direction: column;
}
.swagger-ui .info .title {
color: #3b4151;
font-family: sans-serif;
font-size: 22px;
}
.swagger-ui .scheme-container {
padding: 14px 0;
}
.swagger-ui .info {
margin: 10px 0;
}
.swagger-ui .auth-wrapper {
margin: 10px 0;
}
.swagger-ui .authorization__btn {
display: none;
}
.swagger-ui .opblock {
margin: 0 0 5px;
}
button.opblock-summary-control > svg {
display: none;
}
.swagger-ui .filter .operation-filter-input {
border: 2px solid #d8dde7;
margin: 5px 5px;
padding: 5px;
width: 100vw;
}
.swagger-ui .wrapper {
padding: 0 4px;
width: 100%;
}
.swagger-ui .info .title small {
top: 5px;
}
.swagger-ui a.nostyle, .swagger-ui a.nostyle:visited {
width: 100%;
}
div.request-snippets > div.curl-command > div:nth-child(1) {
overscroll-behavior: contain;
overflow-x: scroll;
}
.swagger-ui .opblock-body pre.microlight {
font-size: 9px;
}
.swagger-ui table tbody tr td {
padding: 0px 0 0;
vertical-align: none;
}
td.response-col_description > div > div > p {
font-size: 12px;
}
div.no-margin > div > div.responses-wrapper > div.responses-inner > div > div > table > tbody > tr {
display: flex;
width: 100vw;
flex-direction: column;
font-size: 60%;
}
div.no-margin > div > div.responses-wrapper > div.responses-inner > div > div > table > thead > tr {
display: none;
}
}
File diff suppressed because it is too large Load Diff
+5 -1
View File
@@ -13,7 +13,11 @@
"resolveJsonModule": true,
"isolatedModules": true,
"jsx": "preserve",
"incremental": true
"incremental": true,
"baseUrl": ".",
"paths": {
"@lib/*": ["lib/*"]
}
},
"include": ["next-env.d.ts", "**/*.ts", "**/*.tsx"],
"exclude": ["node_modules"]
File diff suppressed because it is too large Load Diff
+3
View File
@@ -61,3 +61,6 @@ yarn-error.log*
# Typescript
tsconfig.tsbuildinfo
# Autogenerated embed content
public/embed
@@ -0,0 +1,86 @@
import React from "react";
import Select from "react-select";
import { OptionProps } from "react-select";
import { InstallAppButton } from "@calcom/app-store/components";
import { useLocale } from "@calcom/lib/hooks/useLocale";
import type { App } from "@calcom/types/App";
import { Button } from "@calcom/ui";
import { QueryCell } from "@lib/QueryCell";
import { trpc } from "@lib/trpc";
interface AdditionalCalendarSelectorProps {
isLoading?: boolean;
}
const ImageOption = (optionProps: OptionProps<{ [key: string]: string; type: App["type"] }>) => {
const { data } = optionProps;
return (
<InstallAppButton
type={data.type}
render={(installProps) => {
return (
<Button {...installProps} className="w-full" color="minimal">
{/* eslint-disable @next/next/no-img-element */}
{data.image && (
<img className="float-left mr-3 inline h-5 w-5" src={data.image} alt={data.label} />
)}
<p>{data.label}</p>
</Button>
);
}}
/>
);
};
const AdditionalCalendarSelector = ({ isLoading }: AdditionalCalendarSelectorProps): JSX.Element | null => {
const { t } = useLocale();
const query = trpc.useQuery(["viewer.integrations", { variant: "calendar", onlyInstalled: true }]);
return (
<QueryCell
query={query}
success={({ data }) => {
const options = data.items.map((item) => ({
label: item.name,
slug: item.slug,
image: item.imageSrc,
type: item.type,
}));
return (
<Select
name={"additionalCalendar"}
placeholder={t("connect_additional_calendar")}
options={options}
styles={{
placeholder: (defaultStyles) => {
return {
...defaultStyles,
color: "#3E3E3E",
marginLeft: "3px",
};
},
control: (defaultStyles) => {
return {
...defaultStyles,
borderRadius: "2px",
"@media only screen and (min-width: 640px)": {
...(defaultStyles["@media only screen and (min-width: 640px)"] as object),
maxWidth: "320px",
},
};
},
}}
isSearchable={false}
className="mt-1 mb-2 block w-full min-w-0 flex-1 rounded-none rounded-r-sm border-gray-300 font-medium text-gray-700 sm:text-sm"
isLoading={isLoading}
components={{ Option: ImageOption }}
/>
);
}}
/>
);
};
export default AdditionalCalendarSelector;
+65 -20
View File
@@ -1,21 +1,22 @@
import {
BookOpenIcon,
CheckIcon,
DocumentTextIcon,
ExternalLinkIcon,
FlagIcon,
MailIcon,
PlusIcon,
ShieldCheckIcon,
} from "@heroicons/react/outline";
import { ChevronLeftIcon } from "@heroicons/react/solid";
import Link from "next/link";
import React from "react";
import React, { useEffect, useState } from "react";
import { InstallAppButton } from "@calcom/app-store/components";
import { useLocale } from "@calcom/lib/hooks/useLocale";
import { App as AppType } from "@calcom/types/App";
import { Button } from "@calcom/ui";
import { Button, SkeletonButton } from "@calcom/ui";
//import NavTabs from "@components/NavTabs";
import Shell from "@components/Shell";
import Badge from "@components/ui/Badge";
@@ -60,12 +61,40 @@ export default function App({
currency: "USD",
useGrouping: false,
}).format(price);
const [installedAppCount, setInstalledAppCount] = useState(0);
const [isLoading, setIsLoading] = useState(true);
useEffect(() => {
async function getInstalledApp(appCredentialType: string) {
const queryParam = new URLSearchParams();
queryParam.set("app-credential-type", appCredentialType);
try {
const result = await fetch(`/api/app-store/installed?${queryParam.toString()}`, {
method: "GET",
headers: {
"Content-Type": "application/json",
},
}).then((data) => {
setIsLoading(false);
return data;
});
if (result.status === 200) {
const res = await result.json();
setInstalledAppCount(res.count);
}
} catch (error) {
if (error instanceof Error) {
console.log(error.message);
}
}
}
getInstalledApp(type);
}, [type]);
const allowedMultipleInstalls = categories.indexOf("calendar") > -1;
return (
<>
<Shell large>
<Shell large isPublic>
<div className="-mx-4 md:-mx-8">
<div className="bg-gray-50 px-4">
<div className="bg-gray-50 px-8">
<Link href="/apps">
<a className="mt-2 inline-flex px-1 py-2 text-sm text-gray-500 hover:bg-gray-100 hover:text-gray-800">
<ChevronLeftIcon className="h-5 w-5" /> {t("browse_apps")}
@@ -73,7 +102,7 @@ export default function App({
</Link>
<div className="items-center justify-between py-4 sm:flex sm:py-8">
<div className="flex">
<img className="h-16 w-16" src={logo} alt={name} />
<img className="h-16 w-16 rounded-sm" src={logo} alt={name} />
<header className="px-4 py-2">
<h1 className="font-cal text-xl text-gray-900">{name}</h1>
<h2 className="text-sm text-gray-500">
@@ -83,19 +112,35 @@ export default function App({
</div>
<div className="mt-4 sm:mt-0 sm:text-right">
{isGlobal ? (
<Button color="secondary" disabled title="This app is globally installed">
{t("installed")}
</Button>
) : (
<InstallAppButton
type={type}
render={(buttonProps) => (
<Button data-testid="install-app-button" {...buttonProps}>
{t("install_app")}
{!isLoading ? (
isGlobal || (installedAppCount > 0 && allowedMultipleInstalls) ? (
<div className="space-x-3">
<Button StartIcon={CheckIcon} color="secondary" disabled>
{installedAppCount > 0
? t("active_install", { count: installedAppCount })
: t("globally_install")}
</Button>
)}
/>
<InstallAppButton
type={type}
render={(buttonProps) => (
<Button StartIcon={PlusIcon} data-testid="install-app-button" {...buttonProps}>
{t("add_another")}
</Button>
)}
/>
</div>
) : (
<InstallAppButton
type={type}
render={(buttonProps) => (
<Button data-testid="install-app-button" {...buttonProps}>
{t("install_app")}
</Button>
)}
/>
)
) : (
<SkeletonButton width="24" height="10" />
)}
{price !== 0 && (
<small className="block text-right">
@@ -111,7 +156,7 @@ export default function App({
<NavTabs tabs={tabs} linkProps={{ shallow: true }} /> */}
</div>
<div className="justify-between px-4 py-10 md:flex">
<div className="justify-between px-8 py-10 md:flex">
<div className="prose-sm prose mb-6">{body}</div>
<div className="md:max-w-80 flex-1 md:ml-8">
<h4 className="font-medium text-gray-900 ">{t("categories")}</h4>
+12 -14
View File
@@ -1,30 +1,28 @@
import { useSession } from "next-auth/react";
import React from "react";
import { useLocale } from "@calcom/lib/hooks/useLocale";
import NavTabs from "./NavTabs";
const tabs = [
{
name: "app_store",
href: "/apps",
},
{
name: "installed_apps",
href: "/apps/installed",
},
];
export default function AppsShell({ children }: { children: React.ReactNode }) {
const { t } = useLocale();
const { status } = useSession();
const tabs = [
{
name: t("app_store"),
href: "/apps",
},
{
name: t("installed_apps"),
href: "/apps/installed",
},
];
return (
<>
<div className="mb-12 block lg:hidden">
{status === "authenticated" && <NavTabs tabs={tabs} linkProps={{ shallow: true }} />}
</div>
<main>{children}</main>
<main className="pb-6">{children}</main>
</>
);
}
+19 -18
View File
@@ -1,26 +1,27 @@
import React from "react";
import { useLocale } from "@lib/hooks/useLocale";
import NavTabs from "./NavTabs";
export default function BookingsShell({ children }: { children: React.ReactNode }) {
const { t } = useLocale();
const tabs = [
{
name: t("upcoming"),
href: "/bookings/upcoming",
},
{
name: t("past"),
href: "/bookings/past",
},
{
name: t("cancelled"),
href: "/bookings/cancelled",
},
];
const tabs = [
{
name: "upcoming",
href: "/bookings/upcoming",
},
{
name: "recurring",
href: "/bookings/recurring",
},
{
name: "past",
href: "/bookings/past",
},
{
name: "cancelled",
href: "/bookings/cancelled",
},
];
export default function BookingsShell({ children }: { children: React.ReactNode }) {
return (
<>
<NavTabs tabs={tabs} linkProps={{ shallow: true }} />
+12 -2
View File
@@ -1,6 +1,6 @@
import { useEffect } from "react";
import { useBrandColors } from "@calcom/embed-core";
import { useBrandColors } from "@calcom/embed-core/embed-iframe";
const brandColor = "#292929";
const brandTextColor = "#ffffff";
@@ -274,7 +274,17 @@ const BrandColor = ({
"--brand-text-color-dark-mode",
getContrastingTextColor(darkVal, true)
);
}, [lightVal, darkVal]);
}, [
embedBrandingColors.highlightColor,
embedBrandingColors.lightestColor,
embedBrandingColors.lighterColor,
embedBrandingColors.lightColor,
embedBrandingColors.medianColor,
embedBrandingColors.darkColor,
embedBrandingColors.darkerColor,
lightVal,
darkVal,
]);
return null;
};
@@ -1,9 +1,9 @@
import classNames from "classnames";
import React, { useEffect, useState } from "react";
import Select from "react-select";
import Button from "@calcom/ui/Button";
import { useLocale } from "@calcom/lib/hooks/useLocale";
import { useLocale } from "@lib/hooks/useLocale";
import { trpc } from "@lib/trpc";
interface Props {
@@ -24,6 +24,22 @@ const DestinationCalendarSelector = ({
const query = trpc.useQuery(["viewer.connectedCalendars"]);
const [selectedOption, setSelectedOption] = useState<{ value: string; label: string } | null>(null);
// Extra styles to show prefixed text in react-select
const content = (hidePlaceholder = false) => {
if (!hidePlaceholder) {
return {
alignItems: "center",
display: "flex",
":before": {
content: `'${t("select_destination_calendar")}:'`,
display: "block",
marginRight: 8,
},
};
}
return {};
};
useEffect(() => {
const selected = query.data?.connectedCalendars
.map((connected) => connected.calendars ?? [])
@@ -52,23 +68,39 @@ const DestinationCalendarSelector = ({
})) ?? [];
return (
<div className="relative" title={`${t("select_destination_calendar")}: ${selectedOption?.label || ""}`}>
{/* There's no easy way to customize the displayed value for a Select, so we fake it. */}
{!hidePlaceholder && (
<div className="pointer-events-none absolute z-10 w-full">
<Button
size="sm"
color="secondary"
className="m-[1px] w-[calc(100%_-_40px)] overflow-hidden overflow-ellipsis whitespace-nowrap rounded-sm border-none leading-5">
{t("select_destination_calendar")}: {selectedOption?.label || ""}
</Button>
</div>
)}
<Select
name={"primarySelectedCalendar"}
placeholder={!hidePlaceholder ? `${t("select_destination_calendar")}:` : undefined}
options={options}
styles={{
placeholder: (styles) => ({ ...styles, ...content(hidePlaceholder) }),
singleValue: (styles) => ({ ...styles, ...content(hidePlaceholder) }),
option: (defaultStyles, state) => ({
...defaultStyles,
backgroundColor: state.isSelected
? state.isFocused
? "var(--brand-color)"
: "var(--brand-color)"
: state.isFocused
? "var(--brand-color-dark-mode)"
: "var(--brand-text-color)",
}),
control: (defaultStyles) => {
return {
...defaultStyles,
borderRadius: "2px",
"@media only screen and (min-width: 640px)": {
...(defaultStyles["@media only screen and (min-width: 640px)"] as object),
maxWidth: "320px",
},
};
},
}}
isSearchable={false}
className="mt-1 mb-2 block w-full min-w-0 flex-1 rounded-none rounded-r-md border-gray-300 sm:text-sm"
className={classNames(
"mt-1 mb-2 block w-full min-w-0 flex-1 rounded-none rounded-r-sm border-gray-300 sm:text-sm",
!hidePlaceholder && "font-medium"
)}
onChange={(option) => {
setSelectedOption(option);
if (!option) {
File diff suppressed because it is too large Load Diff
+1 -1
View File
@@ -4,7 +4,7 @@ import { useEffect } from "react";
import { trpc } from "@lib/trpc";
export function useViewerI18n() {
return trpc.useQuery(["viewer.i18n"], {
return trpc.useQuery(["viewer.public.i18n"], {
staleTime: Infinity,
});
}
+10 -6
View File
@@ -2,7 +2,7 @@ import { FormEvent, useCallback, useEffect, useState } from "react";
import Cropper from "react-easy-crop";
import Button from "@calcom/ui/Button";
import { DialogClose, DialogTrigger, Dialog, DialogContent } from "@calcom/ui/Dialog";
import { Dialog, DialogClose, DialogContent, DialogTrigger } from "@calcom/ui/Dialog";
import { Area, getCroppedImg } from "@lib/cropImage";
import { useFileReader } from "@lib/hooks/useFileReader";
@@ -71,15 +71,15 @@ export default function ImageUploader({
...props
}: ImageUploaderProps) {
const { t } = useLocale();
const [imageSrc, setImageSrc] = useState<string | null>();
const [croppedAreaPixels, setCroppedAreaPixels] = useState<Area | null>();
const [imageSrc, setImageSrc] = useState<string | null>(null);
const [croppedAreaPixels, setCroppedAreaPixels] = useState<Area | null>(null);
const [{ result }, setFile] = useFileReader({
method: "readAsDataURL",
});
useEffect(() => {
setImageSrc(props.imageSrc);
if (props.imageSrc) setImageSrc(props.imageSrc);
}, [props.imageSrc]);
const onInputFile = (e: FileEvent<HTMLInputElement>) => {
@@ -90,8 +90,9 @@ export default function ImageUploader({
};
const showCroppedImage = useCallback(
async (croppedAreaPixels) => {
async (croppedAreaPixels: Area | null) => {
try {
if (!croppedAreaPixels) return;
const croppedImage = await getCroppedImg(
result as string /* result is always string when using readAsDataUrl */,
croppedAreaPixels
@@ -134,7 +135,10 @@ export default function ImageUploader({
{t("no_target", { target })}
</p>
)}
{imageSrc && <img className="h-20 w-20 rounded-full" src={imageSrc} alt={target} />}
{imageSrc && (
// eslint-disable-next-line @next/next/no-img-element
<img className="h-20 w-20 rounded-full" src={imageSrc} alt={target} />
)}
</div>
)}
{result && <CropContainer imageSrc={result as string} onCropComplete={setCroppedAreaPixels} />}
+1 -7
View File
@@ -1,7 +1 @@
export default function Loader() {
return (
<div className="loader border-brand dark:border-darkmodebrand">
<span className="loader-inner bg-brand dark:bg-darkmodebrand"></span>
</div>
);
}
export { default } from "@calcom/ui/Loader";
+2
View File
@@ -3,8 +3,10 @@ export default function Logo({ small, icon }: { small?: boolean; icon?: boolean
<h1 className="inline">
<strong>
{icon ? (
// eslint-disable-next-line @next/next/no-img-element
<img className="mx-auto w-9" alt="Cal" title="Cal" src="/cal-com-icon-white.svg" />
) : (
// eslint-disable-next-line @next/next/no-img-element
<img
className={small ? "h-4 w-auto" : "h-5 w-auto"}
alt="Cal"
+69 -29
View File
@@ -1,49 +1,89 @@
import { AdminRequired } from "components/ui/AdminRequired";
import noop from "lodash/noop";
import Link, { LinkProps } from "next/link";
import { useRouter } from "next/router";
import React, { ElementType, FC } from "react";
import { FC, Fragment, MouseEventHandler } from "react";
import { useLocale } from "@calcom/lib/hooks/useLocale";
import classNames from "@lib/classNames";
import { SVGComponent } from "@lib/types/SVGComponent";
interface Props {
export interface NavTabProps {
tabs: {
name: string;
href: string;
icon?: ElementType;
/** If you want to change the path as per current tab */
href?: string;
/** If you want to change query param tabName as per current tab */
tabName?: string;
icon?: SVGComponent;
adminRequired?: boolean;
}[];
linkProps?: Omit<LinkProps, "href">;
}
const NavTabs: FC<Props> = ({ tabs, linkProps }) => {
const NavTabs: FC<NavTabProps> = ({ tabs, linkProps, ...props }) => {
const router = useRouter();
const { t } = useLocale();
return (
<>
<nav
className="-mb-px flex space-x-2 space-x-5 rtl:space-x-reverse sm:rtl:space-x-reverse"
aria-label="Tabs">
className="no-scrollbar -mb-px flex space-x-5 overflow-x-scroll rtl:space-x-reverse sm:rtl:space-x-reverse"
aria-label="Tabs"
{...props}>
{tabs.map((tab) => {
const isCurrent = router.asPath === tab.href;
if ((tab.tabName && tab.href) || (!tab.tabName && !tab.href)) {
throw new Error("Use either tabName or href");
}
let href = "";
let isCurrent;
if (tab.href) {
href = tab.href;
isCurrent = router.asPath === tab.href;
} else if (tab.tabName) {
href = "";
isCurrent = router.query.tabName === tab.tabName;
}
const onClick: MouseEventHandler = tab.tabName
? (e) => {
e.preventDefault();
router.push({
query: {
...router.query,
tabName: tab.tabName,
},
});
}
: noop;
const Component = tab.adminRequired ? AdminRequired : Fragment;
return (
<Link key={tab.name} href={tab.href} {...linkProps}>
<a
className={classNames(
isCurrent
? "border-neutral-900 text-neutral-900"
: "border-transparent text-gray-500 hover:border-gray-300 hover:text-gray-700",
"group inline-flex items-center border-b-2 py-4 px-1 text-sm font-medium"
)}
aria-current={isCurrent ? "page" : undefined}>
{tab.icon && (
<tab.icon
className={classNames(
isCurrent ? "text-neutral-900" : "text-gray-400 group-hover:text-gray-500",
"-ml-0.5 hidden h-5 w-5 ltr:mr-2 rtl:ml-2 sm:inline-block"
)}
aria-hidden="true"
/>
)}
<span>{tab.name}</span>
</a>
</Link>
<Component key={tab.name}>
<Link key={tab.name} href={href} {...linkProps}>
<a
onClick={onClick}
className={classNames(
isCurrent
? "border-neutral-900 text-neutral-900"
: "border-transparent text-gray-500 hover:border-gray-300 hover:text-gray-700",
"group inline-flex items-center border-b-2 py-4 px-1 text-sm font-medium"
)}
aria-current={isCurrent ? "page" : undefined}>
{tab.icon && (
<tab.icon
className={classNames(
isCurrent ? "text-neutral-900" : "text-gray-400 group-hover:text-gray-500",
"-ml-0.5 hidden h-5 w-5 ltr:mr-2 rtl:ml-2 sm:inline-block"
)}
aria-hidden="true"
/>
)}
<span>{t(tab.name)}</span>
</a>
</Link>
</Component>
);
})}
</nav>
+55 -31
View File
@@ -1,42 +1,66 @@
import { CreditCardIcon, KeyIcon, UserGroupIcon, UserIcon } from "@heroicons/react/solid";
import React from "react";
import {
CreditCardIcon,
KeyIcon,
LockClosedIcon,
UserGroupIcon,
UserIcon,
CodeIcon,
} from "@heroicons/react/solid";
import React, { ComponentProps } from "react";
import { useLocale } from "@lib/hooks/useLocale";
import ErrorBoundary from "@lib/ErrorBoundary";
import NavTabs from "./NavTabs";
import Shell from "./Shell";
export default function SettingsShell({ children }: { children: React.ReactNode }) {
const { t } = useLocale();
const tabs = [
{
name: t("profile"),
href: "/settings/profile",
icon: UserIcon,
},
{
name: t("security"),
href: "/settings/security",
icon: KeyIcon,
},
{
name: t("teams"),
href: "/settings/teams",
icon: UserGroupIcon,
},
{
name: t("billing"),
href: "/settings/billing",
icon: CreditCardIcon,
},
];
const tabs = [
{
name: "profile",
href: "/settings/profile",
icon: UserIcon,
},
{
name: "teams",
href: "/settings/teams",
icon: UserGroupIcon,
},
{
name: "security",
href: "/settings/security",
icon: KeyIcon,
},
{
name: "developer",
href: "/settings/developer",
icon: CodeIcon,
},
{
name: "billing",
href: "/settings/billing",
icon: CreditCardIcon,
},
{
name: "admin",
href: "/settings/admin",
icon: LockClosedIcon,
adminRequired: true,
},
];
export default function SettingsShell({
children,
...rest
}: { children: React.ReactNode } & ComponentProps<typeof Shell>) {
return (
<>
<Shell {...rest}>
<div className="sm:mx-auto">
<NavTabs tabs={tabs} />
</div>
<main className="max-w-4xl">{children}</main>
</>
<main className="max-w-4xl">
<>
<ErrorBoundary>{children}</ErrorBoundary>
</>
</main>
</Shell>
);
}
+175 -133
View File
@@ -10,16 +10,17 @@ import {
MapIcon,
MoonIcon,
ViewGridIcon,
QuestionMarkCircleIcon,
} from "@heroicons/react/solid";
import { UserPlan } from "@prisma/client";
import { SessionContextValue, signOut, useSession } from "next-auth/react";
import Link from "next/link";
import { useRouter } from "next/router";
import React, { Fragment, ReactNode, useEffect } from "react";
import React, { Fragment, ReactNode, useEffect, useState } from "react";
import { Toaster } from "react-hot-toast";
import { useIsEmbed } from "@calcom/embed-core";
import { useIsEmbed } from "@calcom/embed-core/embed-iframe";
import { useLocale } from "@calcom/lib/hooks/useLocale";
import { UserPlan } from "@calcom/prisma/client";
import Button from "@calcom/ui/Button";
import Dropdown, {
DropdownMenuContent,
@@ -31,30 +32,23 @@ import LicenseBanner from "@ee/components/LicenseBanner";
import TrialBanner from "@ee/components/TrialBanner";
import HelpMenuItem from "@ee/components/support/HelpMenuItem";
import ErrorBoundary from "@lib/ErrorBoundary";
import classNames from "@lib/classNames";
import { WEBAPP_URL } from "@lib/config/constants";
import { shouldShowOnboarding } from "@lib/getting-started";
import { collectPageParameters, telemetryEventTypes, useTelemetry } from "@lib/telemetry";
import useMeQuery from "@lib/hooks/useMeQuery";
import useTheme from "@lib/hooks/useTheme";
import { trpc } from "@lib/trpc";
import CustomBranding from "@components/CustomBranding";
import Loader from "@components/Loader";
import { HeadSeo } from "@components/seo/head-seo";
import ImpersonatingBanner from "@components/ui/ImpersonatingBanner";
import pkg from "../package.json";
import { useViewerI18n } from "./I18nLanguageHandler";
import Logo from "./Logo";
export function useMeQuery() {
const meQuery = trpc.useQuery(["viewer.me"], {
retry(failureCount) {
return failureCount > 3;
},
});
return meQuery;
}
function useRedirectToLoginIfUnauthenticated(isPublic = false) {
const { data: session, status } = useSession();
const loading = status === "loading";
@@ -69,7 +63,7 @@ function useRedirectToLoginIfUnauthenticated(isPublic = false) {
router.replace({
pathname: "/auth/login",
query: {
callbackUrl: `${WEBAPP_URL}/${location.pathname}${location.search}`,
callbackUrl: `${WEBAPP_URL}${location.pathname}${location.search}`,
},
});
}
@@ -125,9 +119,10 @@ const Layout = ({
status,
plan,
...props
}: LayoutProps & { status: SessionContextValue["status"]; plan?: UserPlan }) => {
}: LayoutProps & { status: SessionContextValue["status"]; plan?: UserPlan; isLoading: boolean }) => {
const isEmbed = useIsEmbed();
const router = useRouter();
const { t } = useLocale();
const navigation = [
{
@@ -204,7 +199,7 @@ const Layout = ({
</Link>
{/* logo icon for tablet */}
<Link href="/event-types">
<a className="md:inline lg:hidden">
<a className="text-center md:inline lg:hidden">
<Logo small icon />
</a>
</Link>
@@ -213,6 +208,7 @@ const Layout = ({
<Fragment key={item.name}>
<Link href={item.href}>
<a
aria-label={item.name}
className={classNames(
item.current
? "bg-neutral-100 text-neutral-900"
@@ -254,7 +250,7 @@ const Layout = ({
</div>
<TrialBanner />
<div
className="rounded-sm pb-2 pl-3 pt-2 pr-2 hover:bg-gray-100 lg:mx-2 lg:pl-2"
className="rounded-sm pt-2 pb-2 pl-3 pr-2 hover:bg-gray-100 lg:mx-2 lg:pl-2"
data-testid="user-dropdown-trigger">
<span className="hidden lg:inline">
<UserDropdown />
@@ -311,6 +307,7 @@ const Layout = ({
props.flexChildrenContainer && "flex flex-1 flex-col",
!props.large && "py-8"
)}>
<ImpersonatingBanner />
{!!props.backPath && (
<div className="mx-3 mb-8 sm:mx-8">
<Button
@@ -329,10 +326,21 @@ const Layout = ({
)}>
{props.HeadingLeftIcon && <div className="ltr:mr-4">{props.HeadingLeftIcon}</div>}
<div className="mb-8 w-full">
<h1 className="font-cal mb-1 text-xl font-bold capitalize tracking-wide text-gray-900">
{props.heading}
</h1>
<p className="min-h-10 text-sm text-neutral-500 ltr:mr-4 rtl:ml-4">{props.subtitle}</p>
{props.isLoading ? (
<>
<div className="mb-1 h-6 w-24 animate-pulse rounded-md bg-gray-200"></div>
<div className="mb-1 h-6 w-32 animate-pulse rounded-md bg-gray-200"></div>
</>
) : (
<>
<h1 className="font-cal mb-1 text-xl font-bold capitalize tracking-wide text-gray-900">
{props.heading}
</h1>
<p className="min-h-10 text-sm text-neutral-500 ltr:mr-4 rtl:ml-4">
{props.subtitle}
</p>
</>
)}
</div>
{props.CTA && <div className="mb-4 flex-shrink-0">{props.CTA}</div>}
</div>
@@ -342,7 +350,7 @@ const Layout = ({
"px-4 sm:px-6 md:px-8",
props.flexChildrenContainer && "flex flex-1 flex-col"
)}>
{props.children}
<ErrorBoundary>{!props.isLoading ? props.children : props.customLoader}</ErrorBoundary>
</div>
{/* show bottom navigation for md and smaller (tablet and phones) */}
{status === "authenticated" && (
@@ -403,19 +411,13 @@ type LayoutProps = {
// use when content needs to expand with flex
flexChildrenContainer?: boolean;
isPublic?: boolean;
customLoader?: ReactNode;
};
export default function Shell(props: LayoutProps) {
const router = useRouter();
const { loading, session } = useRedirectToLoginIfUnauthenticated(props.isPublic);
const { isRedirectingToOnboarding } = useRedirectToOnboardingIfNeeded();
const telemetry = useTelemetry();
useEffect(() => {
telemetry.withJitsu((jitsu) => {
return jitsu.track(telemetryEventTypes.pageView, collectPageParameters(router.asPath));
});
}, [telemetry, router.asPath]);
const { isReady, Theme } = useTheme("light");
const query = useMeQuery();
const user = query.data;
@@ -423,8 +425,14 @@ export default function Shell(props: LayoutProps) {
const i18n = useViewerI18n();
const { status } = useSession();
if (i18n.status === "loading" || query.status === "loading" || isRedirectingToOnboarding || loading) {
// show spinner whilst i18n is loading to avoid language flicker
const isLoading =
i18n.status === "loading" ||
query.status === "loading" ||
isRedirectingToOnboarding ||
loading ||
!isReady;
if (isLoading) {
return (
<div className="absolute z-50 flex h-screen w-full items-center bg-gray-50">
<Loader />
@@ -436,8 +444,9 @@ export default function Shell(props: LayoutProps) {
return (
<>
<Theme />
<CustomBranding lightVal={user?.brandColor} darkVal={user?.darkBrandColor} />
<MemoizedLayout plan={user?.plan} status={status} {...props} />
<MemoizedLayout plan={user?.plan} status={status} {...props} isLoading={isLoading} />
</>
);
}
@@ -452,21 +461,31 @@ function UserDropdown({ small }: { small?: boolean }) {
},
});
const utils = trpc.useContext();
const [helpOpen, setHelpOpen] = useState(false);
const [menuOpen, setMenuOpen] = useState(false);
const onHelpItemSelect = () => {
setHelpOpen(false);
setMenuOpen(false);
};
return (
<Dropdown>
<DropdownMenuTrigger asChild>
<Dropdown open={menuOpen} onOpenChange={() => setHelpOpen(false)}>
<DropdownMenuTrigger asChild onClick={() => setMenuOpen(true)}>
<button className="group flex w-full cursor-pointer appearance-none items-center text-left">
<span
className={classNames(
small ? "h-8 w-8" : "h-10 w-10",
"relative flex-shrink-0 rounded-full bg-gray-300 ltr:mr-3 rtl:ml-3"
)}>
<img
className="rounded-full"
src={process.env.NEXT_PUBLIC_WEBSITE_URL + "/" + user?.username + "/avatar.png"}
alt={user?.username || "Nameless User"}
/>
{
// eslint-disable-next-line @next/next/no-img-element
<img
className="rounded-full"
src={WEBAPP_URL + "/" + user?.username + "/avatar.png"}
alt={user?.username || "Nameless User"}
/>
}
{!user?.away && (
<div className="absolute bottom-0 right-0 h-3 w-3 rounded-full border-2 border-white bg-green-500"></div>
)}
@@ -478,10 +497,14 @@ function UserDropdown({ small }: { small?: boolean }) {
<span className="flex flex-grow items-center truncate">
<span className="flex-grow truncate text-sm">
<span className="block truncate font-medium text-gray-900">
{user?.username || "Nameless User"}
{user?.name || "Nameless User"}
</span>
<span className="block truncate font-normal text-neutral-500">
{user?.username ? `cal.com/${user.username}` : "No public page"}
{user?.username
? process.env.NEXT_PUBLIC_WEBSITE_URL === "https://cal.com"
? `cal.com/${user.username}`
: `/${user.username}`
: "No public page"}
</span>
</span>
<SelectorIcon
@@ -492,97 +515,116 @@ function UserDropdown({ small }: { small?: boolean }) {
)}
</button>
</DropdownMenuTrigger>
<DropdownMenuContent portalled={true}>
<DropdownMenuItem>
<a
onClick={() => {
mutation.mutate({ away: !user?.away });
utils.invalidateQueries("viewer.me");
}}
className="flex min-w-max cursor-pointer px-4 py-2 text-sm hover:bg-gray-100 hover:text-gray-900">
<MoonIcon
className={classNames(
user?.away
? "text-purple-500 group-hover:text-purple-700"
: "text-gray-500 group-hover:text-gray-700",
"h-5 w-5 flex-shrink-0 ltr:mr-3 rtl:ml-3"
)}
aria-hidden="true"
/>
{user?.away ? t("set_as_free") : t("set_as_away")}
</a>
</DropdownMenuItem>
<DropdownMenuSeparator className="h-px bg-gray-200" />
{user?.username && (
<DropdownMenuItem>
<a
target="_blank"
rel="noopener noreferrer"
href={`${process.env.NEXT_PUBLIC_WEBSITE_URL}/${user.username}`}
className="flex items-center px-4 py-2 text-sm text-gray-700">
<ExternalLinkIcon className="h-5 w-5 text-gray-500 ltr:mr-3 rtl:ml-3" /> {t("view_public_page")}
</a>
</DropdownMenuItem>
<DropdownMenuContent portalled={true} onInteractOutside={() => setMenuOpen(false)}>
{helpOpen ? (
<HelpMenuItem onHelpItemSelect={() => onHelpItemSelect()} />
) : (
<>
<DropdownMenuItem>
<a
onClick={() => {
mutation.mutate({ away: !user?.away });
utils.invalidateQueries("viewer.me");
}}
className="flex min-w-max cursor-pointer px-4 py-2 text-sm hover:bg-gray-100 hover:text-gray-900">
<MoonIcon
className={classNames(
user?.away
? "text-purple-500 group-hover:text-purple-700"
: "text-gray-500 group-hover:text-gray-700",
"h-5 w-5 flex-shrink-0 ltr:mr-3 rtl:ml-3"
)}
aria-hidden="true"
/>
{user?.away ? t("set_as_free") : t("set_as_away")}
</a>
</DropdownMenuItem>
<DropdownMenuSeparator className="h-px bg-gray-200" />
{user?.username && (
<DropdownMenuItem>
<a
target="_blank"
rel="noopener noreferrer"
href={`${process.env.NEXT_PUBLIC_WEBSITE_URL}/${user.username}`}
className="flex items-center px-4 py-2 text-sm text-gray-700">
<ExternalLinkIcon className="h-5 w-5 text-gray-500 ltr:mr-3 rtl:ml-3" />{" "}
{t("view_public_page")}
</a>
</DropdownMenuItem>
)}
<DropdownMenuSeparator className="h-px bg-gray-200" />
<DropdownMenuItem>
<a
href="https://cal.com/slack"
target="_blank"
rel="noreferrer"
className="flex px-4 py-2 text-sm text-gray-700 hover:bg-gray-100 hover:text-gray-900">
<svg
viewBox="0 0 2447.6 2452.5"
className={classNames(
"text-gray-500 group-hover:text-gray-700",
"mt-0.5 h-4 w-4 flex-shrink-0 ltr:mr-4 rtl:ml-4"
)}
xmlns="http://www.w3.org/2000/svg">
<g clipRule="evenodd" fillRule="evenodd">
<path
d="m897.4 0c-135.3.1-244.8 109.9-244.7 245.2-.1 135.3 109.5 245.1 244.8 245.2h244.8v-245.1c.1-135.3-109.5-245.1-244.9-245.3.1 0 .1 0 0 0m0 654h-652.6c-135.3.1-244.9 109.9-244.8 245.2-.2 135.3 109.4 245.1 244.7 245.3h652.7c135.3-.1 244.9-109.9 244.8-245.2.1-135.4-109.5-245.2-244.8-245.3z"
fill="currentColor"></path>
<path
d="m2447.6 899.2c.1-135.3-109.5-245.1-244.8-245.2-135.3.1-244.9 109.9-244.8 245.2v245.3h244.8c135.3-.1 244.9-109.9 244.8-245.3zm-652.7 0v-654c.1-135.2-109.4-245-244.7-245.2-135.3.1-244.9 109.9-244.8 245.2v654c-.2 135.3 109.4 245.1 244.7 245.3 135.3-.1 244.9-109.9 244.8-245.3z"
fill="currentColor"></path>
<path
d="m1550.1 2452.5c135.3-.1 244.9-109.9 244.8-245.2.1-135.3-109.5-245.1-244.8-245.2h-244.8v245.2c-.1 135.2 109.5 245 244.8 245.2zm0-654.1h652.7c135.3-.1 244.9-109.9 244.8-245.2.2-135.3-109.4-245.1-244.7-245.3h-652.7c-135.3.1-244.9 109.9-244.8 245.2-.1 135.4 109.4 245.2 244.7 245.3z"
fill="currentColor"></path>
<path
d="m0 1553.2c-.1 135.3 109.5 245.1 244.8 245.2 135.3-.1 244.9-109.9 244.8-245.2v-245.2h-244.8c-135.3.1-244.9 109.9-244.8 245.2zm652.7 0v654c-.2 135.3 109.4 245.1 244.7 245.3 135.3-.1 244.9-109.9 244.8-245.2v-653.9c.2-135.3-109.4-245.1-244.7-245.3-135.4 0-244.9 109.8-244.8 245.1 0 0 0 .1 0 0"
fill="currentColor"></path>
</g>
</svg>
{t("join_our_slack")}
</a>
</DropdownMenuItem>
<DropdownMenuItem>
<a
target="_blank"
rel="noopener noreferrer"
href="https://cal.com/roadmap"
className="flex items-center px-4 py-2 text-sm text-gray-700">
<MapIcon className="h-5 w-5 text-gray-500 ltr:mr-3 rtl:ml-3" /> {t("visit_roadmap")}
</a>
</DropdownMenuItem>
<button
className="flex w-full px-4 py-2 text-sm font-medium text-neutral-700 hover:bg-gray-100 hover:text-gray-900"
onClick={() => setHelpOpen(true)}>
<QuestionMarkCircleIcon
className={classNames(
"text-gray-500 group-hover:text-neutral-500",
"h-5 w-5 flex-shrink-0 ltr:mr-3"
)}
aria-hidden="true"
/>
{t("help")}
</button>
<DropdownMenuSeparator className="h-px bg-gray-200" />
<DropdownMenuItem>
<a
onClick={() => signOut({ callbackUrl: "/auth/logout" })}
className="flex cursor-pointer px-4 py-2 text-sm hover:bg-gray-100 hover:text-gray-900">
<LogoutIcon
className={classNames(
"text-gray-500 group-hover:text-gray-700",
"h-5 w-5 flex-shrink-0 ltr:mr-3 rtl:ml-3"
)}
aria-hidden="true"
/>
{t("sign_out")}
</a>
</DropdownMenuItem>
</>
)}
<DropdownMenuSeparator className="h-px bg-gray-200" />
<DropdownMenuItem>
<a
href="https://cal.com/slack"
target="_blank"
rel="noreferrer"
className="flex px-4 py-2 text-sm text-gray-700 hover:bg-gray-100 hover:text-gray-900">
<svg
viewBox="0 0 2447.6 2452.5"
className={classNames(
"text-gray-500 group-hover:text-gray-700",
"mt-0.5 h-4 w-4 flex-shrink-0 ltr:mr-4 rtl:ml-4"
)}
xmlns="http://www.w3.org/2000/svg">
<g clipRule="evenodd" fillRule="evenodd">
<path
d="m897.4 0c-135.3.1-244.8 109.9-244.7 245.2-.1 135.3 109.5 245.1 244.8 245.2h244.8v-245.1c.1-135.3-109.5-245.1-244.9-245.3.1 0 .1 0 0 0m0 654h-652.6c-135.3.1-244.9 109.9-244.8 245.2-.2 135.3 109.4 245.1 244.7 245.3h652.7c135.3-.1 244.9-109.9 244.8-245.2.1-135.4-109.5-245.2-244.8-245.3z"
fill="currentColor"></path>
<path
d="m2447.6 899.2c.1-135.3-109.5-245.1-244.8-245.2-135.3.1-244.9 109.9-244.8 245.2v245.3h244.8c135.3-.1 244.9-109.9 244.8-245.3zm-652.7 0v-654c.1-135.2-109.4-245-244.7-245.2-135.3.1-244.9 109.9-244.8 245.2v654c-.2 135.3 109.4 245.1 244.7 245.3 135.3-.1 244.9-109.9 244.8-245.3z"
fill="currentColor"></path>
<path
d="m1550.1 2452.5c135.3-.1 244.9-109.9 244.8-245.2.1-135.3-109.5-245.1-244.8-245.2h-244.8v245.2c-.1 135.2 109.5 245 244.8 245.2zm0-654.1h652.7c135.3-.1 244.9-109.9 244.8-245.2.2-135.3-109.4-245.1-244.7-245.3h-652.7c-135.3.1-244.9 109.9-244.8 245.2-.1 135.4 109.4 245.2 244.7 245.3z"
fill="currentColor"></path>
<path
d="m0 1553.2c-.1 135.3 109.5 245.1 244.8 245.2 135.3-.1 244.9-109.9 244.8-245.2v-245.2h-244.8c-135.3.1-244.9 109.9-244.8 245.2zm652.7 0v654c-.2 135.3 109.4 245.1 244.7 245.3 135.3-.1 244.9-109.9 244.8-245.2v-653.9c.2-135.3-109.4-245.1-244.7-245.3-135.4 0-244.9 109.8-244.8 245.1 0 0 0 .1 0 0"
fill="currentColor"></path>
</g>
</svg>
{t("join_our_slack")}
</a>
</DropdownMenuItem>
<DropdownMenuItem>
<a
target="_blank"
rel="noopener noreferrer"
href="https://cal.com/roadmap"
className="flex items-center px-4 py-2 text-sm text-gray-700">
<MapIcon className="h-5 w-5 text-gray-500 ltr:mr-3 rtl:ml-3" /> {t("visit_roadmap")}
</a>
</DropdownMenuItem>
<HelpMenuItem />
<DropdownMenuSeparator className="h-px bg-gray-200" />
<DropdownMenuItem>
<a
onClick={() => signOut({ callbackUrl: "/auth/logout" })}
className="flex cursor-pointer px-4 py-2 text-sm hover:bg-gray-100 hover:text-gray-900">
<LogoutIcon
className={classNames(
"text-gray-500 group-hover:text-gray-700",
"h-5 w-5 flex-shrink-0 ltr:mr-3 rtl:ml-3"
)}
aria-hidden="true"
/>
{t("sign_out")}
</a>
</DropdownMenuItem>
</DropdownMenuContent>
</Dropdown>
);
+7 -4
View File
@@ -1,4 +1,3 @@
import { StarIcon } from "@heroicons/react/solid";
import Link from "next/link";
import Button from "@calcom/ui/Button";
@@ -16,11 +15,15 @@ interface AppCardProps {
export default function AppCard(props: AppCardProps) {
return (
<Link href={"/apps/" + props.slug}>
<a className="block h-full rounded-sm border border-gray-300 p-5 hover:bg-neutral-50">
<a
className="block h-full rounded-sm border border-gray-300 p-5 hover:bg-neutral-50"
data-testid={`app-store-app-card-${props.slug}`}>
<div className="flex">
<img src={props.logo} alt={props.name + " Logo"} className="mb-4 h-12 w-12 rounded-sm" />
{
// eslint-disable-next-line @next/next/no-img-element
<img src={props.logo} alt={props.name + " Logo"} className="mb-4 h-12 w-12 rounded-sm" />
}
<Button
data-testid={`app-store-app-card-${props.slug}`}
color="secondary"
className="ml-auto flex self-start"
onClick={() => {
+1 -1
View File
@@ -15,7 +15,7 @@ export default function AppStoreCategories({
return (
<div className="mb-16">
<h2 className="mb-2 text-lg font-semibold text-gray-900">{t("popular_categories")}</h2>
<div className="grid-col-1 grid gap-3 md:grid-flow-col">
<div className="grid-col-1 grid w-full gap-3 overflow-scroll sm:grid-flow-col">
{categories.map((category) => (
<Link key={category.name} href={"/apps/categories/" + category.name}>
<a
@@ -0,0 +1,41 @@
import React from "react";
import { SkeletonText } from "@calcom/ui";
import { ShellSubHeading } from "@components/Shell";
function SkeletonLoader({ className }: { className?: string }) {
return (
<>
<ShellSubHeading title={<div className="h-6 w-32 rounded-sm bg-gray-100"></div>} {...{ className }} />
<ul className="-mx-4 animate-pulse divide-y divide-neutral-200 rounded-sm border border-gray-200 bg-white sm:mx-0 sm:overflow-hidden">
<SkeletonItem />
<SkeletonItem />
<SkeletonItem />
</ul>
</>
);
}
export default SkeletonLoader;
function SkeletonItem() {
return (
<li className="group flex w-full items-center justify-between p-3">
<div className="flex-grow truncate text-sm">
<div className="flex justify-start space-x-2">
<SkeletonText width="10" height="10"></SkeletonText>
<div className="space-y-2">
<SkeletonText height="4" width="32"></SkeletonText>
<SkeletonText height="4" width="16"></SkeletonText>
</div>
</div>
</div>
<div className="mt-4 hidden flex-shrink-0 sm:mt-0 sm:ml-5 lg:flex">
<div className="flex justify-between space-x-2 rtl:space-x-reverse">
<SkeletonText width="32" height="11"></SkeletonText>
</div>
</div>
</li>
);
}
+1 -1
View File
@@ -4,7 +4,7 @@ import "@glidejs/glide/dist/css/glide.theme.min.css";
import { ArrowLeftIcon, ArrowRightIcon } from "@heroicons/react/solid";
import { useEffect, useRef } from "react";
const Slider = <T extends unknown>({
const Slider = <T extends string | unknown>({
title = "",
className = "",
items,
+2 -4
View File
@@ -21,7 +21,7 @@ export default function SAMLLogin(props: Props) {
const methods = useFormContext();
const telemetry = useTelemetry();
const mutation = trpc.useMutation("viewer.samlTenantProduct", {
const mutation = trpc.useMutation("viewer.public.samlTenantProduct", {
onSuccess: async (data) => {
await signIn("saml", {}, { tenant: data.tenant, product: data.product });
},
@@ -40,9 +40,7 @@ export default function SAMLLogin(props: Props) {
event.preventDefault();
// track Google logins. Without personal data/payload
telemetry.withJitsu((jitsu) =>
jitsu.track(telemetryEventTypes.googleLogin, collectPageParameters())
);
telemetry.event(telemetryEventTypes.googleLogin, collectPageParameters());
if (!props.hostedCal) {
await signIn("saml", {}, { tenant: props.samlTenantID, product: props.samlProductID });
+9 -2
View File
@@ -29,8 +29,15 @@ export default function TwoFactor() {
<div className="mx-auto !mt-0 max-w-sm">
<p className="mb-4 text-sm text-gray-500">{t("2fa_enabled_instructions")}</p>
<input hidden type="hidden" value={value} {...methods.register("totpCode")} />
<div className="flex flex-row space-x-1">
<Input className={className} name="2fa1" inputMode="decimal" {...digits[0]} autoFocus />
<div className="flex flex-row justify-between">
<Input
className={className}
name="2fa1"
inputMode="decimal"
{...digits[0]}
autoFocus
autoComplete="one-time-code"
/>
<Input className={className} name="2fa2" inputMode="decimal" {...digits[1]} />
<Input className={className} name="2fa3" inputMode="decimal" {...digits[2]} />
<Input className={className} name="2fa4" inputMode="decimal" {...digits[3]} />
@@ -6,7 +6,7 @@ import { useLocale } from "@calcom/lib/hooks/useLocale";
import showToast from "@calcom/lib/notification";
import { Button } from "@calcom/ui";
import { Dialog, DialogClose, DialogContent, DialogTrigger } from "@calcom/ui/Dialog";
import { Form, TextField } from "@calcom/ui/form/fields";
import { Form } from "@calcom/ui/form/fields";
import { HttpError } from "@lib/core/http/error";
import { trpc } from "@lib/trpc";
@@ -46,20 +46,17 @@ export function NewScheduleButton({ name = "new-schedule" }: { name?: string })
</Button>
</DialogTrigger>
<DialogContent>
<div className="mb-4">
<div className="mb-8">
<h3 className="text-lg font-bold leading-6 text-gray-900" id="modal-title">
{t("add_new_schedule")}
</h3>
<div>
<p className="text-sm text-gray-500">{t("new_event_type_to_book_description")}</p>
</div>
</div>
<Form
form={form}
handleSubmit={(values) => {
createMutation.mutate(values);
}}>
<div className="mt-3 space-y-4">
<div className="mt-3 space-y-2">
<label htmlFor="label" className="block text-sm font-medium text-gray-700">
{t("name")}
</label>
+6 -10
View File
@@ -1,27 +1,22 @@
import { PlusIcon, TrashIcon } from "@heroicons/react/outline";
import { DuplicateIcon } from "@heroicons/react/solid";
import classNames from "classnames";
import dayjs, { Dayjs, ConfigType } from "dayjs";
import timezone from "dayjs/plugin/timezone";
import utc from "dayjs/plugin/utc";
import React, { useCallback, useEffect, useMemo, useState } from "react";
import { Controller, useFieldArray, useFormContext } from "react-hook-form";
import { GroupBase, Props, SingleValue } from "react-select";
import { GroupBase, Props } from "react-select";
import dayjs, { Dayjs, ConfigType } from "@calcom/dayjs";
import { useLocale } from "@calcom/lib/hooks/useLocale";
import Button from "@calcom/ui/Button";
import Dropdown, { DropdownMenuTrigger, DropdownMenuContent } from "@calcom/ui/Dropdown";
import { defaultDayRange } from "@lib/availability";
import { weekdayNames } from "@lib/core/i18n/weekday";
import useMeQuery from "@lib/hooks/useMeQuery";
import { TimeRange } from "@lib/types/schedule";
import { useMeQuery } from "@components/Shell";
import Select from "@components/ui/form/Select";
dayjs.extend(utc);
dayjs.extend(timezone);
/** Begin Time Increments For Select */
const increment = 15;
@@ -57,12 +52,13 @@ const useOptions = () => {
t = t.add(increment, "minutes");
}
return options;
}, []);
}, [timeFormat]);
const filter = useCallback(
({ offset, limit, current }: { offset?: ConfigType; limit?: ConfigType; current?: ConfigType }) => {
if (current) {
setFilteredOptions([options.find((option) => option.value === dayjs(current).toDate().valueOf())!]);
const currentOption = options.find((option) => option.value === dayjs(current).toDate().valueOf());
if (currentOption) setFilteredOptions([currentOption]);
} else
setFilteredOptions(
options.filter((option) => {
@@ -0,0 +1,75 @@
import { DotsHorizontalIcon, TrashIcon } from "@heroicons/react/solid";
import Link from "next/link";
import { Fragment } from "react";
import { availabilityAsString } from "@calcom/lib/availability";
import { useLocale } from "@calcom/lib/hooks/useLocale";
import { Availability } from "@calcom/prisma/client";
import { Button } from "@calcom/ui";
import Dropdown, { DropdownMenuContent, DropdownMenuItem, DropdownMenuTrigger } from "@calcom/ui/Dropdown";
import { inferQueryOutput } from "@lib/trpc";
export function ScheduleListItem({
schedule,
deleteFunction,
isDeleting = false,
}: {
schedule: inferQueryOutput<"viewer.availability.list">["schedules"][number];
deleteFunction: ({ scheduleId }: { scheduleId: number }) => void;
isDeleting: boolean;
}) {
const { t, i18n } = useLocale();
return (
<li key={schedule.id}>
<div className="flex items-center justify-between py-5 hover:bg-neutral-50 ltr:pl-4 rtl:pr-4 sm:ltr:pl-0 sm:rtl:pr-0">
<div className="group flex w-full items-center justify-between hover:bg-neutral-50 sm:px-6">
<Link href={"/availability/" + schedule.id}>
<a className="flex-grow truncate text-sm" title={schedule.name}>
<div>
<span className="truncate font-medium text-neutral-900">{schedule.name}</span>
{schedule.isDefault && (
<span className="ml-2 inline items-center rounded-sm bg-yellow-100 px-1.5 py-0.5 text-xs font-medium text-yellow-800">
{t("default")}
</span>
)}
</div>
<p className="mt-1 text-xs text-neutral-500">
{schedule.availability.map((availability: Availability) => (
<Fragment key={availability.id}>
{availabilityAsString(availability, i18n.language)}
<br />
</Fragment>
))}
</p>
</a>
</Link>
</div>
<Dropdown>
<DropdownMenuTrigger className="group mr-5 h-10 w-10 border border-transparent p-0 text-neutral-500 hover:border-gray-200">
<DotsHorizontalIcon className="h-5 w-5 group-hover:text-gray-800" />
</DropdownMenuTrigger>
<DropdownMenuContent>
<DropdownMenuItem>
<Button
disabled={isDeleting}
onClick={() => {
deleteFunction({
scheduleId: schedule.id,
});
}}
type="button"
color="warn"
className="w-full font-normal"
StartIcon={isDeleting ? undefined : TrashIcon}
loading={isDeleting}>
{isDeleting ? t("deleting") : t("delete_schedule")}
</Button>
</DropdownMenuItem>
</DropdownMenuContent>
</Dropdown>
</div>
</li>
);
}
@@ -0,0 +1,46 @@
import React from "react";
import { SkeletonText } from "@calcom/ui";
function SkeletonLoader() {
return (
<ul className="animate-pulse divide-y divide-neutral-200 border border-gray-200 bg-white sm:mx-0 sm:overflow-hidden">
<SkeletonItem />
<SkeletonItem />
<SkeletonItem />
</ul>
);
}
export default SkeletonLoader;
function SkeletonItem() {
return (
<li className="group flex w-full items-center justify-between px-2 py-[23px] sm:px-6">
<div className="flex-grow truncate text-sm">
<div className="flex flex-col space-y-2">
<SkeletonText width="32" height="4"></SkeletonText>
<SkeletonText width="32" height="2"></SkeletonText>
</div>
</div>
<div className="mt-4 hidden flex-shrink-0 sm:mt-0 sm:ml-5 lg:flex">
<div className="flex justify-between space-x-2 rtl:space-x-reverse">
<SkeletonText width="12" height="6"></SkeletonText>
</div>
</div>
</li>
);
}
export const AvailabilitySelectSkeletonLoader = () => {
return (
<li className="group flex w-full items-center justify-between rounded-sm border border-gray-200 px-[10px] py-3">
<div className="flex-grow truncate text-sm">
<div className="flex justify-between">
<SkeletonText width="32" height="4"></SkeletonText>
<SkeletonText width="4" height="4"></SkeletonText>
</div>
</div>
</li>
);
};
+72 -55
View File
@@ -1,61 +1,47 @@
import { ExclamationIcon } from "@heroicons/react/solid";
import { SchedulingType } from "@prisma/client";
import { Dayjs } from "dayjs";
import Link from "next/link";
import { useRouter } from "next/router";
import React, { FC, useEffect, useState } from "react";
import { FC, useEffect, useState } from "react";
import dayjs, { Dayjs } from "@calcom/dayjs";
import { useLocale } from "@calcom/lib/hooks/useLocale";
import { nameOfDay } from "@calcom/lib/weekday";
import { SkeletonContainer, SkeletonText } from "@calcom/ui";
import classNames from "@lib/classNames";
import { useLocale } from "@lib/hooks/useLocale";
import { useSlots } from "@lib/hooks/useSlots";
import { timeZone } from "@lib/clock";
import Loader from "@components/Loader";
import type { Slot } from "@server/routers/viewer/slots";
type AvailableTimesProps = {
timeFormat: string;
minimumBookingNotice: number;
beforeBufferTime: number;
afterBufferTime: number;
eventTypeId: number;
eventLength: number;
recurringCount: number | undefined;
eventTypeSlug: string;
slotInterval: number | null;
date: Dayjs;
users: {
username: string | null;
}[];
schedulingType: SchedulingType | null;
seatsPerTimeSlot?: number | null;
slots?: Slot[];
isLoading: boolean;
};
const AvailableTimes: FC<AvailableTimesProps> = ({
slots = [],
isLoading,
date,
eventLength,
eventTypeId,
eventTypeSlug,
slotInterval,
minimumBookingNotice,
recurringCount,
timeFormat,
users,
schedulingType,
beforeBufferTime,
afterBufferTime,
seatsPerTimeSlot,
}) => {
const { t, i18n } = useLocale();
const router = useRouter();
const { rescheduleUid } = router.query;
const { slots, loading, error } = useSlots({
date,
slotInterval,
eventLength,
schedulingType,
users,
minimumBookingNotice,
beforeBufferTime,
afterBufferTime,
eventTypeId,
});
const [brand, setBrand] = useState("#292929");
@@ -74,9 +60,8 @@ const AvailableTimes: FC<AvailableTimesProps> = ({
</span>
</span>
</div>
<div className="flex-grow overflow-y-auto md:h-[364px]">
{!loading &&
slots?.length > 0 &&
<div className="grid flex-grow grid-cols-2 gap-x-2 overflow-y-auto sm:block md:h-[364px]">
{slots.length > 0 &&
slots.map((slot) => {
type BookingURL = {
pathname: string;
@@ -86,9 +71,11 @@ const AvailableTimes: FC<AvailableTimesProps> = ({
pathname: "book",
query: {
...router.query,
date: slot.time.format(),
date: dayjs(slot.time).format(),
type: eventTypeId,
slug: eventTypeSlug,
/** Treat as recurring only when a count exist and it's not a rescheduling workflow */
count: recurringCount && !rescheduleUid ? recurringCount : undefined,
},
};
@@ -100,40 +87,70 @@ const AvailableTimes: FC<AvailableTimesProps> = ({
bookingUrl.query.user = slot.users;
}
// If event already has an attendee add booking id
if (slot.bookingUid) {
bookingUrl.query.bookingUid = slot.bookingUid;
}
return (
<div key={slot.time.format()}>
<Link href={bookingUrl}>
<a
<div key={dayjs(slot.time).format()}>
{/* Current there is no way to disable Next.js Links */}
{seatsPerTimeSlot && slot.attendees && slot.attendees >= seatsPerTimeSlot ? (
<div
className={classNames(
"text-bookingdarker hover:bg-brand hover:text-brandcontrast dark:hover:bg-darkmodebrand dark:hover:text-darkmodebrandcontrast mb-2 block rounded-sm border bg-white py-4 font-medium hover:text-white dark:border-transparent dark:bg-gray-600 dark:text-neutral-200 dark:hover:border-black",
"text-primary-500 mb-2 block rounded-sm border bg-white py-4 font-medium opacity-25 dark:border-transparent dark:bg-gray-600 dark:text-neutral-200 ",
brand === "#fff" || brand === "#ffffff" ? "border-brandcontrast" : "border-brand"
)}
data-testid="time">
{slot.time.format(timeFormat)}
</a>
</Link>
)}>
{dayjs(slot.time).tz(timeZone()).format(timeFormat)}
{!!seatsPerTimeSlot && <p className={`text-sm`}>{t("booking_full")}</p>}
</div>
) : (
<Link href={bookingUrl} prefetch={false}>
<a
className={classNames(
"text-primary-500 hover:bg-brand hover:text-brandcontrast dark:hover:bg-darkmodebrand dark:hover:text-darkmodebrandcontrast mb-2 block rounded-sm border bg-white py-4 font-medium hover:text-white dark:border-transparent dark:bg-gray-600 dark:text-neutral-200 dark:hover:border-black",
brand === "#fff" || brand === "#ffffff" ? "border-brandcontrast" : "border-brand"
)}
data-testid="time">
{dayjs(slot.time).tz(timeZone()).format(timeFormat)}
{!!seatsPerTimeSlot && (
<p
className={`${
slot.attendees && slot.attendees / seatsPerTimeSlot >= 0.8
? "text-rose-600"
: slot.attendees && slot.attendees / seatsPerTimeSlot >= 0.33
? "text-yellow-500"
: "text-emerald-400"
} text-sm`}>
{slot.attendees ? seatsPerTimeSlot - slot.attendees : seatsPerTimeSlot} /{" "}
{seatsPerTimeSlot} {t("seats_available")}
</p>
)}
</a>
</Link>
)}
</div>
);
})}
{!loading && !error && !slots.length && (
{!isLoading && !slots.length && (
<div className="-mt-4 flex h-full w-full flex-col content-center items-center justify-center">
<h1 className="my-6 text-xl text-black dark:text-white">{t("all_booked_today")}</h1>
</div>
)}
{loading && <Loader />}
{error && (
<div className="border-l-4 border-yellow-400 bg-yellow-50 p-4">
<div className="flex">
<div className="flex-shrink-0">
<ExclamationIcon className="h-5 w-5 text-yellow-400" aria-hidden="true" />
</div>
<div className="ltr:ml-3 rtl:mr-3">
<p className="text-sm text-yellow-700">{t("slots_load_fail")}</p>
</div>
</div>
</div>
{isLoading && !slots.length && (
<>
<SkeletonContainer className="mb-2">
<SkeletonText width="full" height="20" />
</SkeletonContainer>
<SkeletonContainer className="mb-2">
<SkeletonText width="full" height="20" />
</SkeletonContainer>
<SkeletonContainer className="mb-2">
<SkeletonText width="full" height="20" />
</SkeletonContainer>
</>
)}
</div>
</div>
+257 -80
View File
@@ -1,43 +1,76 @@
import { BanIcon, CheckIcon, ClockIcon, XIcon } from "@heroicons/react/outline";
import { PaperAirplaneIcon } from "@heroicons/react/outline";
import {
BanIcon,
CheckIcon,
ClockIcon,
LocationMarkerIcon,
PaperAirplaneIcon,
PencilAltIcon,
XIcon,
} from "@heroicons/react/outline";
import { RefreshIcon } from "@heroicons/react/solid";
import { BookingStatus } from "@prisma/client";
import dayjs from "dayjs";
import { useRouter } from "next/router";
import { useState } from "react";
import { useMutation } from "react-query";
import dayjs from "@calcom/dayjs";
import { parseRecurringEvent } from "@calcom/lib";
import classNames from "@calcom/lib/classNames";
import { useLocale } from "@calcom/lib/hooks/useLocale";
import showToast from "@calcom/lib/notification";
import { getEveryFreqFor } from "@calcom/lib/recurringStrings";
import Button from "@calcom/ui/Button";
import { Dialog, DialogClose, DialogContent, DialogFooter, DialogHeader } from "@calcom/ui/Dialog";
import { Tooltip } from "@calcom/ui/Tooltip";
import { TextArea } from "@calcom/ui/form/fields";
import { HttpError } from "@lib/core/http/error";
import { inferQueryOutput, trpc } from "@lib/trpc";
import useMeQuery from "@lib/hooks/useMeQuery";
import { linkValueToString } from "@lib/linkValueToString";
import { LocationType } from "@lib/location";
import { parseRecurringDates } from "@lib/parseDate";
import { inferQueryInput, inferQueryOutput, trpc } from "@lib/trpc";
import { useMeQuery } from "@components/Shell";
import { EditLocationDialog } from "@components/dialog/EditLocationDialog";
import { RescheduleDialog } from "@components/dialog/RescheduleDialog";
import TableActions, { ActionType } from "@components/ui/TableActions";
type BookingListingStatus = inferQueryInput<"viewer.bookings">["status"];
type BookingItem = inferQueryOutput<"viewer.bookings">["bookings"][number];
function BookingListItem(booking: BookingItem) {
type BookingItemProps = BookingItem & {
listingStatus: BookingListingStatus;
recurringCount?: number;
};
function BookingListItem(booking: BookingItemProps) {
// Get user so we can determine 12/24 hour format preferences
const query = useMeQuery();
const user = query.data;
const { t, i18n } = useLocale();
const utils = trpc.useContext();
const router = useRouter();
const [rejectionReason, setRejectionReason] = useState<string>("");
const [rejectionDialogIsOpen, setRejectionDialogIsOpen] = useState(false);
const mutation = useMutation(
async (confirm: boolean) => {
let body = {
id: booking.id,
confirmed: confirm,
language: i18n.language,
reason: rejectionReason,
};
/**
* Only pass down the recurring event id when we need to confirm the entire series, which happens in
* the "Recurring" tab, to support confirming discretionally in the "Recurring" tab.
*/
if (booking.listingStatus === "recurring" && booking.recurringEventId !== null) {
body = Object.assign({}, body, { recurringEventId: booking.recurringEventId });
}
const res = await fetch("/api/book/confirm", {
method: "PATCH",
body: JSON.stringify({
id: booking.id,
confirmed: confirm,
language: i18n.language,
reason: rejectionReason,
}),
body: JSON.stringify(body),
headers: {
"Content-Type": "application/json",
},
@@ -45,6 +78,7 @@ function BookingListItem(booking: BookingItem) {
if (!res.ok) {
throw new HttpError({ statusCode: res.status });
}
setRejectionDialogIsOpen(false);
},
{
async onSettled() {
@@ -54,51 +88,84 @@ function BookingListItem(booking: BookingItem) {
);
const isUpcoming = new Date(booking.endTime) >= new Date();
const isCancelled = booking.status === BookingStatus.CANCELLED;
const isConfirmed = booking.status === BookingStatus.ACCEPTED;
const isRejected = booking.status === BookingStatus.REJECTED;
const isPending = booking.status === BookingStatus.PENDING;
const pendingActions: ActionType[] = [
{
id: "reject",
label: t("reject"),
onClick: () => setRejectionDialogIsOpen(true),
label:
booking.listingStatus === "recurring" && booking.recurringEventId !== null
? t("reject_all")
: t("reject"),
onClick: () => {
setRejectionDialogIsOpen(true);
},
icon: BanIcon,
disabled: mutation.isLoading,
},
{
id: "confirm",
label: t("confirm"),
onClick: () => mutation.mutate(true),
label:
booking.listingStatus === "recurring" && booking.recurringEventId !== null
? t("confirm_all")
: t("confirm"),
onClick: () => {
mutation.mutate(true);
},
icon: CheckIcon,
disabled: mutation.isLoading,
color: "primary",
},
];
const bookedActions: ActionType[] = [
let bookedActions: ActionType[] = [
{
id: "cancel",
label: t("cancel"),
label:
booking.listingStatus === "recurring" && booking.recurringEventId !== null
? t("cancel_all_remaining")
: t("cancel"),
href: `/cancel/${booking.uid}`,
icon: XIcon,
},
{
id: "reschedule",
label: t("reschedule"),
icon: ClockIcon,
id: "edit_booking",
label: t("edit_booking"),
icon: PencilAltIcon,
actions: [
{
id: "edit",
label: t("edit_booking"),
id: "reschedule",
icon: ClockIcon,
label: t("reschedule_booking"),
href: `/reschedule/${booking.uid}`,
},
{
id: "reschedule_request",
icon: PaperAirplaneIcon,
iconClassName: "rotate-45 w-[18px] -ml-[2px]",
label: t("send_reschedule_request"),
onClick: () => setIsOpenRescheduleDialog(true),
onClick: () => {
setIsOpenRescheduleDialog(true);
},
},
{
id: "change_location",
label: t("edit_location"),
onClick: () => {
setIsOpenLocationDialog(true);
},
icon: LocationMarkerIcon,
},
],
},
];
if (booking.listingStatus === "recurring" && booking.recurringEventId !== null) {
bookedActions = bookedActions.filter((action) => action.id !== "edit_booking");
}
const RequestSentMessage = () => {
return (
<div className="ml-1 mr-8 flex text-gray-500" data-testid="request_reschedule_sent">
@@ -110,6 +177,80 @@ function BookingListItem(booking: BookingItem) {
const startTime = dayjs(booking.startTime).format(isUpcoming ? "ddd, D MMM" : "D MMMM YYYY");
const [isOpenRescheduleDialog, setIsOpenRescheduleDialog] = useState(false);
const [isOpenSetLocationDialog, setIsOpenLocationDialog] = useState(false);
const setLocationMutation = trpc.useMutation("viewer.bookings.editLocation", {
onSuccess: () => {
showToast(t("location_updated"), "success");
setIsOpenLocationDialog(false);
utils.invalidateQueries("viewer.bookings");
},
});
const saveLocation = (newLocationType: LocationType, details: { [key: string]: string }) => {
let newLocation = newLocationType as string;
if (
newLocationType === LocationType.InPerson ||
newLocationType === LocationType.Link ||
newLocationType === LocationType.UserPhone
) {
newLocation = details[Object.keys(details)[0]];
}
setLocationMutation.mutate({ bookingId: booking.id, newLocation });
};
// Calculate the booking date(s) and setup recurring event data to show
let recurringStrings: string[] = [];
let recurringDates: Date[] = [];
const today = new Date();
if (booking.recurringCount && booking.eventType.recurringEvent?.freq !== undefined) {
[recurringStrings, recurringDates] = parseRecurringDates(
{
startDate: booking.startTime,
recurringEvent: parseRecurringEvent(booking.eventType.recurringEvent),
recurringCount: booking.recurringCount,
},
i18n
);
if (booking.status === BookingStatus.PENDING) {
// Only take into consideration next up instances if booking is confirmed
recurringDates = recurringDates.filter((aDate) => aDate >= today);
recurringStrings = recurringDates.map((_, key) => recurringStrings[key]);
}
}
let location = booking.location || "";
if (location.includes("integration")) {
if (booking.status === BookingStatus.CANCELLED || booking.status === BookingStatus.REJECTED) {
location = t("web_conference");
} else if (isConfirmed) {
location = linkValueToString(booking.location, t);
} else {
location = t("web_conferencing_details_to_follow");
}
}
const onClick = () => {
router.push({
pathname: "/success",
query: {
date: booking.startTime,
// TODO: Booking when fetched should have id 0 already(for Dynamic Events).
type: booking.eventType.id || 0,
eventSlug: booking.eventType.slug,
user: user?.username || "",
name: booking.attendees[0] ? booking.attendees[0].name : undefined,
email: booking.attendees[0] ? booking.attendees[0].email : undefined,
location: location,
eventName: booking.eventType.eventName || "",
bookingId: booking.id,
recur: booking.recurringEventId,
reschedule: isConfirmed,
listingStatus: booking.listingStatus,
status: booking.status,
},
});
};
return (
<>
<RescheduleDialog
@@ -117,6 +258,12 @@ function BookingListItem(booking: BookingItem) {
setIsOpenDialog={setIsOpenRescheduleDialog}
bookingUId={booking.uid}
/>
<EditLocationDialog
booking={booking}
saveLocation={saveLocation}
isOpenDialog={isOpenSetLocationDialog}
setShowLocationModal={setIsOpenLocationDialog}
/>
{/* NOTE: Should refactor this dialog component as is being rendered multiple times */}
<Dialog open={rejectionDialogIsOpen} onOpenChange={setRejectionDialogIsOpen}>
@@ -151,72 +298,102 @@ function BookingListItem(booking: BookingItem) {
</DialogContent>
</Dialog>
<tr className="flex">
<td className="hidden whitespace-nowrap py-4 align-top ltr:pl-6 rtl:pr-6 sm:table-cell">
<div className="text-sm leading-6 text-gray-900">{startTime}</div>
<div className="text-sm text-gray-500">
{dayjs(booking.startTime).format(user && user.timeFormat === 12 ? "h:mma" : "HH:mm")} -{" "}
{dayjs(booking.endTime).format(user && user.timeFormat === 12 ? "h:mma" : "HH:mm")}
<tr className="flex hover:bg-neutral-50">
<td className="hidden align-top ltr:pl-6 rtl:pr-6 sm:table-cell sm:w-64" 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">
{dayjs(booking.startTime).format(user && user.timeFormat === 12 ? "h:mma" : "HH:mm")} -{" "}
{dayjs(booking.endTime).format(user && user.timeFormat === 12 ? "h:mma" : "HH:mm")}
</div>
<div className="text-sm text-gray-400">
{booking.recurringCount &&
booking.eventType?.recurringEvent?.freq &&
(booking.listingStatus === "recurring" || booking.listingStatus === "cancelled") && (
<div className="underline decoration-gray-400 decoration-dashed underline-offset-2">
<div className="flex">
<Tooltip
content={recurringStrings.map((aDate, key) => (
<p key={key}>{aDate}</p>
))}>
<div className="text-gray-600 dark:text-white">
<RefreshIcon className="float-left mr-1 mt-[2px] inline-block h-4 w-4 text-gray-400" />
<p className="pl-[21px]">
{booking.status === BookingStatus.ACCEPTED
? `${t("event_remaining", {
count: recurringDates.length,
})}`
: getEveryFreqFor({
t,
recurringEvent: booking.eventType.recurringEvent,
recurringCount: booking.recurringCount,
})}
</p>
</div>
</Tooltip>
</div>
</div>
)}
</div>
</div>
</td>
<td className={"flex-1 py-4 ltr:pl-4 rtl:pr-4" + (booking.rejected ? " line-through" : "")}>
<div className="sm:hidden">
{!booking.confirmed && !booking.rejected && (
<Tag className="mb-2 ltr:mr-2 rtl:ml-2">{t("unconfirmed")}</Tag>
)}
{!!booking?.eventType?.price && !booking.paid && (
<Tag className="mb-2 ltr:mr-2 rtl:ml-2">Pending payment</Tag>
)}
<div className="text-sm font-medium text-gray-900">
{startTime}:{" "}
<small className="text-sm text-gray-500">
{dayjs(booking.startTime).format("HH:mm")} - {dayjs(booking.endTime).format("HH:mm")}
</small>
<td className={"flex-1 ltr:pl-4 rtl:pr-4" + (isRejected ? " line-through" : "")} onClick={onClick}>
<div className="cursor-pointer py-4">
<div className="sm:hidden">
{isPending && <Tag className="mb-2 ltr:mr-2 rtl:ml-2">{t("unconfirmed")}</Tag>}
{!!booking?.eventType?.price && !booking.paid && (
<Tag className="mb-2 ltr:mr-2 rtl:ml-2">Pending payment</Tag>
)}
<div className="text-sm font-medium text-gray-900">
{startTime}:{" "}
<small className="text-sm text-gray-500">
{dayjs(booking.startTime).format("HH:mm")} - {dayjs(booking.endTime).format("HH:mm")}
</small>
</div>
</div>
</div>
<div
title={booking.title}
className={classNames(
"max-w-56 truncate text-sm font-medium leading-6 text-neutral-900 md:max-w-max",
isCancelled ? "line-through" : ""
)}>
{booking.eventType?.team && <strong>{booking.eventType.team.name}: </strong>}
{booking.title}
{!!booking?.eventType?.price && !booking.paid && (
<Tag className="hidden ltr:ml-2 rtl:mr-2 sm:inline-flex">Pending payment</Tag>
)}
{!booking.confirmed && !booking.rejected && (
<Tag className="hidden ltr:ml-2 rtl:mr-2 sm:inline-flex">{t("unconfirmed")}</Tag>
)}
</div>
{booking.description && (
<div className="max-w-52 md:max-w-96 truncate text-sm text-gray-500" title={booking.description}>
&quot;{booking.description}&quot;
<div
title={booking.title}
className={classNames(
"max-w-56 truncate text-sm font-medium leading-6 text-neutral-900 md:max-w-max",
isCancelled ? "line-through" : ""
)}>
{booking.eventType?.team && <strong>{booking.eventType.team.name}: </strong>}
{booking.title}
{!!booking?.eventType?.price && !booking.paid && (
<Tag className="hidden ltr:ml-2 rtl:mr-2 sm:inline-flex">Pending payment</Tag>
)}
{isPending && <Tag className="hidden ltr:ml-2 rtl:mr-2 sm:inline-flex">{t("unconfirmed")}</Tag>}
</div>
)}
{booking.description && (
<div
className="max-w-52 md:max-w-96 truncate text-sm text-gray-500"
title={booking.description}>
&quot;{booking.description}&quot;
</div>
)}
{booking.attendees.length !== 0 && (
<div className="text-sm text-gray-900 hover:text-blue-500">
<a href={"mailto:" + booking.attendees[0].email}>{booking.attendees[0].email}</a>
</div>
)}
{isCancelled && booking.rescheduled && (
<div className="mt-2 inline-block text-left text-sm md:hidden">
<RequestSentMessage />
</div>
)}
{booking.attendees.length !== 0 && (
<a
className="text-sm text-gray-900 hover:text-blue-500"
href={"mailto:" + booking.attendees[0].email}
onClick={(e) => e.stopPropagation()}>
{booking.attendees[0].email}
</a>
)}
{isCancelled && booking.rescheduled && (
<div className="mt-2 inline-block text-left text-sm md:hidden">
<RequestSentMessage />
</div>
)}
</div>
</td>
<td className="whitespace-nowrap py-4 text-right text-sm font-medium ltr:pr-4 rtl:pl-4">
{isUpcoming && !isCancelled ? (
<>
{!booking.confirmed && !booking.rejected && user!.id === booking.user!.id && (
<TableActions actions={pendingActions} />
)}
{booking.confirmed && !booking.rejected && <TableActions actions={bookedActions} />}
{!booking.confirmed && booking.rejected && (
<div className="text-sm text-gray-500">{t("rejected")}</div>
)}
{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}
{isCancelled && booking.rescheduled && (
@@ -0,0 +1,121 @@
import { XIcon } from "@heroicons/react/solid";
import { useRouter } from "next/router";
import { useState } from "react";
import { useLocale } from "@calcom/lib/hooks/useLocale";
import { RecurringEvent } from "@calcom/types/Calendar";
import { Button } from "@calcom/ui/Button";
import useTheme from "@lib/hooks/useTheme";
import { collectPageParameters, telemetryEventTypes, useTelemetry } from "@lib/telemetry";
type Props = {
booking: {
title?: string;
uid?: string;
};
profile: {
name: string | null;
slug: string | null;
};
recurringEvent: RecurringEvent | null;
team?: string | null;
setIsCancellationMode: (value: boolean) => void;
theme: string | null;
};
export default function CancelBooking(props: Props) {
const [cancellationReason, setCancellationReason] = useState<string>("");
const { t } = useLocale();
const router = useRouter();
const { booking, profile, team } = props;
const [loading, setLoading] = useState(false);
const telemetry = useTelemetry();
const [error, setError] = useState<string | null>(booking ? null : t("booking_already_cancelled"));
const { isReady, Theme } = useTheme(props.theme);
if (isReady) {
return (
<>
<Theme />
{error && (
<div>
<div className="mx-auto flex h-12 w-12 items-center justify-center rounded-full bg-red-100">
<XIcon className="h-6 w-6 text-red-600" />
</div>
<div className="mt-3 text-center sm:mt-5">
<h3 className="text-lg font-medium leading-6 text-gray-900" id="modal-title">
{error}
</h3>
</div>
</div>
)}
{!error && (
<div className="mt-5 sm:mt-6">
<label className="text-bookingdark font-medium dark:text-white">{t("cancellation_reason")}</label>
<textarea
placeholder={t("cancellation_reason_placeholder")}
value={cancellationReason}
onChange={(e) => setCancellationReason(e.target.value)}
className="mt-2 mb-3 w-full dark:border-gray-900 dark:bg-gray-700 dark:text-white sm:mb-3 "
rows={3}
/>
<div className="flex rtl:space-x-reverse">
{!props.recurringEvent && (
<div className="w-full">
<Button color="secondary" onClick={() => router.push("/reschedule/" + booking?.uid)}>
{t("reschedule_this")}
</Button>
</div>
)}
<div className="w-full space-x-2 text-right">
<Button color="secondary" onClick={() => props.setIsCancellationMode(false)}>
{t("nevermind")}
</Button>
<Button
data-testid="cancel"
onClick={async () => {
setLoading(true);
const payload = {
uid: booking?.uid,
reason: cancellationReason,
};
telemetry.event(telemetryEventTypes.bookingCancelled, collectPageParameters());
const res = await fetch("/api/cancel", {
body: JSON.stringify(payload),
headers: {
"Content-Type": "application/json",
},
method: "DELETE",
});
if (res.status >= 200 && res.status < 300) {
await router.push(
`/cancel/success?name=${props.profile.name}&title=${booking?.title}&eventPage=${
profile.slug
}&team=${team ? 1 : 0}&recurring=${!!props.recurringEvent}`
);
} else {
setLoading(false);
setError(
`${t("error_with_status_code_occured", { status: res.status })} ${t(
"please_try_again"
)}`
);
}
}}
loading={loading}>
{t("cancel_event")}
</Button>
</div>
</div>
</div>
)}
</>
);
}
return <></>;
}
+8 -55
View File
@@ -1,28 +1,22 @@
import { ChevronLeftIcon, ChevronRightIcon } from "@heroicons/react/solid";
import { EventType, PeriodType } from "@prisma/client";
import dayjs, { Dayjs } from "dayjs";
import dayjsBusinessTime from "dayjs-business-time";
import timezone from "dayjs/plugin/timezone";
import utc from "dayjs/plugin/utc";
import { PeriodType } from "@prisma/client";
import { memoize } from "lodash";
import { useEffect, useRef, useState } from "react";
import { useEmbedStyles } from "@calcom/embed-core";
import dayjs, { Dayjs } from "@calcom/dayjs";
import { useEmbedStyles } from "@calcom/embed-core/embed-iframe";
import { useLocale } from "@calcom/lib/hooks/useLocale";
import classNames from "@lib/classNames";
import { timeZone } from "@lib/clock";
import { weekdayNames } from "@lib/core/i18n/weekday";
import { doWorkAsync } from "@lib/doWorkAsync";
import isOutOfBounds from "@lib/isOutOfBounds";
import getSlots from "@lib/slots";
import { WorkingHours } from "@lib/types/schedule";
import Loader from "@components/Loader";
dayjs.extend(dayjsBusinessTime);
dayjs.extend(utc);
dayjs.extend(timezone);
type DatePickerProps = {
weekStart: string;
onDatePicked: (pickedDate: Dayjs) => void;
@@ -37,41 +31,6 @@ type DatePickerProps = {
minimumBookingNotice: number;
};
function isOutOfBounds(
time: dayjs.ConfigType,
{
periodType,
periodDays,
periodCountCalendarDays,
periodStartDate,
periodEndDate,
}: Pick<
EventType,
"periodType" | "periodDays" | "periodCountCalendarDays" | "periodStartDate" | "periodEndDate"
>
) {
const date = dayjs(time);
switch (periodType) {
case PeriodType.ROLLING: {
const periodRollingEndDay = periodCountCalendarDays
? dayjs().utcOffset(date.utcOffset()).add(periodDays!, "days").endOf("day")
: dayjs().utcOffset(date.utcOffset()).addBusinessTime(periodDays!, "days").endOf("day");
return date.endOf("day").isAfter(periodRollingEndDay);
}
case PeriodType.RANGE: {
const periodRangeStartDay = dayjs(periodStartDate).utcOffset(date.utcOffset()).endOf("day");
const periodRangeEndDay = dayjs(periodEndDate).utcOffset(date.utcOffset()).endOf("day");
return date.endOf("day").isBefore(periodRangeStartDay) || date.endOf("day").isAfter(periodRangeEndDay);
}
case PeriodType.UNLIMITED:
default:
return false;
}
}
function DatePicker({
weekStart,
onDatePicked,
@@ -94,7 +53,7 @@ function DatePicker({
const [isFirstMonth, setIsFirstMonth] = useState<boolean>(false);
const [daysFromState, setDays] = useState<
| {
disabled: Boolean;
disabled: boolean;
date: number;
}[]
| null
@@ -191,7 +150,7 @@ function DatePicker({
name: "DatePicker",
length: daysInMonth,
callback: (i: number) => {
let day = i + 1;
const day = i + 1;
days[daysInitialOffset + i] = {
disabled: isDisabledMemoized(day, {
browsingDate,
@@ -283,15 +242,9 @@ function DatePicker({
day.disabled ? { ...disabledDateButtonEmbedStyles } : { ...enabledDateButtonEmbedStyles }
}
className={classNames(
"absolute top-0 left-0 right-0 bottom-0 mx-auto w-full rounded-sm text-center",
"hover:border-brand hover:border dark:hover:border-white",
day.disabled
? "text-bookinglighter cursor-default font-light hover:border-0"
: "font-medium",
"hover:border-brand disabled:text-bookinglighter absolute top-0 left-0 right-0 bottom-0 mx-auto w-full rounded-sm text-center font-medium hover:border disabled:cursor-default disabled:font-light disabled:hover:border-0 dark:hover:border-white",
date && date.isSame(browsingDate.date(day.date), "day")
? "bg-brand text-brandcontrast dark:bg-darkmodebrand dark:text-darkmodebrandcontrast"
: !day.disabled
? " bg-gray-100 dark:bg-gray-600 dark:text-white"
? "bg-brand text-brandcontrast dark:bg-darkmodebrand dark:text-darkmodebrandcontrast disabled:bg-gray-100 disabled:dark:bg-gray-600 disabled:dark:text-white"
: ""
)}
data-testid="day"
@@ -0,0 +1,36 @@
import React from "react";
import { SkeletonText } from "@calcom/ui";
function SkeletonLoader() {
return (
<ul className="mt-6 animate-pulse divide-y divide-neutral-200 border border-gray-200 bg-white sm:mx-0 sm:overflow-hidden">
<SkeletonItem />
<SkeletonItem />
<SkeletonItem />
</ul>
);
}
export default SkeletonLoader;
function SkeletonItem() {
return (
<li className="group flex w-full items-center justify-between px-2 py-4 sm:px-6">
<div className="flex-grow truncate text-sm">
<div className="flex">
<div className="flex flex-col space-y-2">
<SkeletonText width="16" height="5" />
<SkeletonText width="32" height="4" />
</div>
</div>
</div>
<div className="mt-4 hidden flex-shrink-0 sm:mt-0 sm:ml-5 lg:flex">
<div className="flex justify-between space-x-2 rtl:space-x-reverse">
<SkeletonText width="16" height="6" />
<SkeletonText width="32" height="6" />
</div>
</div>
</li>
);
}
+2 -1
View File
@@ -1,10 +1,11 @@
import { FC, useEffect, useState } from "react";
import TimezoneSelect, { ITimezoneOption } from "react-timezone-select";
import Switch from "@calcom/ui/Switch";
import { useLocale } from "@lib/hooks/useLocale";
import TimezoneSelect, { ITimezoneOption } from "@components/ui/form/TimezoneSelect";
import { is24h, timeZone } from "../../lib/clock";
type Props = {
@@ -1,137 +1,376 @@
// Get router variables
import {
ArrowLeftIcon,
CalendarIcon,
ChevronDownIcon,
ChevronUpIcon,
ClipboardCheckIcon,
ClockIcon,
CreditCardIcon,
GlobeIcon,
InformationCircleIcon,
LocationMarkerIcon,
RefreshIcon,
VideoCameraIcon,
} from "@heroicons/react/solid";
import { EventType } from "@prisma/client";
import * as Collapsible from "@radix-ui/react-collapsible";
import { useContracts } from "contexts/contractsContext";
import dayjs, { Dayjs } from "dayjs";
import customParseFormat from "dayjs/plugin/customParseFormat";
import utc from "dayjs/plugin/utc";
import { TFunction } from "next-i18next";
import { useRouter } from "next/router";
import { useEffect, useMemo, useState } from "react";
import { FormattedNumber, IntlProvider } from "react-intl";
import { z } from "zod";
import { useEmbedStyles, useIsEmbed, useIsBackgroundTransparent, sdkActionManager } from "@calcom/embed-core";
import { AppStoreLocationType, LocationObject, LocationType } from "@calcom/app-store/locations";
import dayjs, { Dayjs } from "@calcom/dayjs";
import {
useEmbedNonStylesConfig,
useEmbedStyles,
useIsBackgroundTransparent,
useIsEmbed,
} from "@calcom/embed-core/embed-iframe";
import classNames from "@calcom/lib/classNames";
import { CAL_URL, WEBAPP_URL } from "@calcom/lib/constants";
import { yyyymmdd } from "@calcom/lib/date-fns";
import { useLocale } from "@calcom/lib/hooks/useLocale";
import { getRecurringFreq } from "@calcom/lib/recurringStrings";
import { localStorage } from "@calcom/lib/webstorage";
import DatePicker from "@calcom/ui/booker/DatePicker";
import { asStringOrNull } from "@lib/asStringOrNull";
import { timeZone } from "@lib/clock";
import { BASE_URL } from "@lib/config/constants";
import { timeZone as localStorageTimeZone } from "@lib/clock";
// import { timeZone } from "@lib/clock";
import { useExposePlanGlobally } from "@lib/hooks/useExposePlanGlobally";
import useTheme from "@lib/hooks/useTheme";
import { isBrandingHidden } from "@lib/isBrandingHidden";
import { parseDate } from "@lib/parseDate";
import { collectPageParameters, telemetryEventTypes, useTelemetry } from "@lib/telemetry";
import { detectBrowserTimeFormat } from "@lib/timeFormat";
import { trpc } from "@lib/trpc";
import CustomBranding from "@components/CustomBranding";
import AvailableTimes from "@components/booking/AvailableTimes";
import DatePicker from "@components/booking/DatePicker";
import TimeOptions from "@components/booking/TimeOptions";
import { HeadSeo } from "@components/seo/head-seo";
import AvatarGroup from "@components/ui/AvatarGroup";
import PoweredByCal from "@components/ui/PoweredByCal";
import { AvailabilityPageProps } from "../../../pages/[user]/[type]";
import { AvailabilityTeamPageProps } from "../../../pages/team/[slug]/[type]";
import type { AvailabilityPageProps } from "../../../pages/[user]/[type]";
import type { DynamicAvailabilityPageProps } from "../../../pages/d/[link]/[slug]";
import type { AvailabilityTeamPageProps } from "../../../pages/team/[slug]/[type]";
dayjs.extend(utc);
dayjs.extend(customParseFormat);
type Props = AvailabilityTeamPageProps | AvailabilityPageProps | DynamicAvailabilityPageProps;
type Props = AvailabilityTeamPageProps | AvailabilityPageProps;
export const locationKeyToString = (location: LocationObject, t: TFunction) => {
switch (location.type) {
case LocationType.InPerson:
return location.address || "In Person"; // If disabled address won't exist on the object
case LocationType.Link:
return location.link || "Link"; // If disabled link won't exist on the object
case LocationType.Phone:
return t("your_number");
case LocationType.UserPhone:
return t("phone_call");
case LocationType.GoogleMeet:
return "Google Meet";
case LocationType.Zoom:
return "Zoom";
case LocationType.Daily:
return "Cal Video";
case LocationType.Jitsi:
return "Jitsi";
case LocationType.Huddle01:
return "Huddle Video";
case LocationType.Tandem:
return "Tandem";
case LocationType.Teams:
return "Microsoft Teams";
default:
return null;
}
};
const AvailabilityPage = ({ profile, plan, eventType, workingHours, previousPage, booking }: Props) => {
const GoBackToPreviousPage = ({ slug }: { slug: string }) => {
const router = useRouter();
const [previousPage, setPreviousPage] = useState<string>();
useEffect(() => {
setPreviousPage(document.referrer);
}, []);
return previousPage === `${WEBAPP_URL}/${slug}` ? (
<div className="flex h-full flex-col justify-end">
<ArrowLeftIcon
className="h-4 w-4 text-black transition-opacity hover:cursor-pointer dark:text-white"
onClick={() => router.back()}
/>
<p className="sr-only">Go Back</p>
</div>
) : (
<></>
);
};
const useSlots = ({
eventTypeId,
startTime,
endTime,
timeZone,
}: {
eventTypeId: number;
startTime?: Dayjs;
endTime?: Dayjs;
timeZone: string;
}) => {
const { data, isLoading } = trpc.useQuery(
[
"viewer.public.slots.getSchedule",
{
eventTypeId,
startTime: startTime?.toISOString() || "",
timeZone,
endTime: endTime?.toISOString() || "",
},
],
{ enabled: !!startTime && !!endTime }
);
const [cachedSlots, setCachedSlots] = useState<NonNullable<typeof data>["slots"]>({});
useEffect(() => {
if (data?.slots) {
setCachedSlots((c) => ({ ...c, ...data?.slots }));
}
}, [data]);
return { slots: cachedSlots, isLoading };
};
const SlotPicker = ({
eventType,
timeFormat,
timeZone,
recurringEventCount,
seatsPerTimeSlot,
weekStart = 0,
}: {
eventType: Pick<EventType, "id" | "schedulingType" | "slug">;
timeFormat: string;
timeZone: string;
seatsPerTimeSlot?: number;
recurringEventCount?: number;
weekStart?: 0 | 1 | 2 | 3 | 4 | 5 | 6;
}) => {
const [selectedDate, setSelectedDate] = useState<Dayjs>();
const [browsingDate, setBrowsingDate] = useState<Dayjs>();
const { date, setQuery: setDate } = useRouterQuery("date");
const { month, setQuery: setMonth } = useRouterQuery("month");
const router = useRouter();
useEffect(() => {
if (!router.isReady) return;
// Etc/GMT is not actually a timeZone, so handle this select option explicitly to prevent a hard crash.
if (timeZone === "Etc/GMT") {
setBrowsingDate(dayjs.utc(month).startOf("month"));
if (date) {
setSelectedDate(dayjs.utc(date));
}
} else {
setBrowsingDate(dayjs(month).tz(timeZone, true).startOf("month"));
if (date) {
setSelectedDate(dayjs(date).tz(timeZone, true));
}
}
}, [router.isReady, month, date, timeZone]);
const { i18n, isLocaleReady } = useLocale();
const { slots: _1 } = useSlots({
eventTypeId: eventType.id,
startTime: selectedDate?.startOf("day"),
endTime: selectedDate?.endOf("day"),
timeZone,
});
const { slots: _2, isLoading } = useSlots({
eventTypeId: eventType.id,
startTime: browsingDate?.startOf("month"),
endTime: browsingDate?.endOf("month"),
timeZone,
});
const slots = useMemo(() => ({ ..._1, ..._2 }), [_1, _2]);
return (
<>
<DatePicker
isLoading={isLoading}
className={
"mt-8 w-full sm:mt-0 sm:min-w-[455px] " +
(selectedDate
? "sm:w-1/2 sm:border-r sm:pl-4 sm:pr-6 sm:dark:border-gray-700 md:w-1/3 "
: "sm:pl-4")
}
includedDates={Object.keys(slots).filter((k) => slots[k].length > 0)}
locale={isLocaleReady ? i18n.language : "en"}
selected={selectedDate}
onChange={(newDate) => {
setDate(newDate.format("YYYY-MM-DD"));
}}
onMonthChange={(newMonth) => {
setMonth(newMonth.format("YYYY-MM"));
}}
browsingDate={browsingDate}
weekStart={weekStart}
/>
{selectedDate && (
<AvailableTimes
isLoading={isLoading}
slots={slots[yyyymmdd(selectedDate.toDate())]}
date={selectedDate}
timeFormat={timeFormat}
eventTypeId={eventType.id}
eventTypeSlug={eventType.slug}
seatsPerTimeSlot={seatsPerTimeSlot}
recurringCount={recurringEventCount}
schedulingType={eventType.schedulingType}
users={[]}
/>
)}
</>
);
};
function TimezoneDropdown({
onChangeTimeFormat,
onChangeTimeZone,
timeZone,
}: {
onChangeTimeFormat: (newTimeFormat: string) => void;
onChangeTimeZone: (newTimeZone: string) => void;
timeZone?: string;
}) {
const [isTimeOptionsOpen, setIsTimeOptionsOpen] = useState(false);
useEffect(() => {
handleToggle24hClock(localStorage.getItem("timeOption.is24hClock") === "true");
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);
const handleSelectTimeZone = (newTimeZone: string) => {
onChangeTimeZone(newTimeZone);
localStorageTimeZone(newTimeZone);
setIsTimeOptionsOpen(false);
};
const handleToggle24hClock = (is24hClock: boolean) => {
onChangeTimeFormat(is24hClock ? "HH:mm" : "h:mma");
};
return (
<Collapsible.Root open={isTimeOptionsOpen} onOpenChange={setIsTimeOptionsOpen}>
<Collapsible.Trigger className="min-w-32 text-bookinglight mb-1 -ml-2 px-2 py-1 text-left dark:text-white">
<GlobeIcon className="mr-[10px] ml-[2px] -mt-1 inline-block h-4 w-4 text-gray-400" />
{timeZone || dayjs.tz.guess()}
{isTimeOptionsOpen ? (
<ChevronUpIcon className="ml-1 -mt-1 inline-block h-4 w-4" />
) : (
<ChevronDownIcon className="ml-1 -mt-1 inline-block h-4 w-4" />
)}
</Collapsible.Trigger>
<Collapsible.Content>
<TimeOptions onSelectTimeZone={handleSelectTimeZone} onToggle24hClock={handleToggle24hClock} />
</Collapsible.Content>
</Collapsible.Root>
);
}
const dateQuerySchema = z.object({
rescheduleUid: z.string().optional().default(""),
date: z.string().optional().default(""),
timeZone: z.string().optional().default(""),
});
const useRouterQuery = <T extends string>(name: T) => {
const router = useRouter();
const query = z.object({ [name]: z.string().optional() }).parse(router.query);
const setQuery = (newValue: string | number | null | undefined) => {
router.replace({ query: { ...router.query, [name]: newValue } }, undefined, { shallow: true });
};
return { [name]: query[name], setQuery } as {
[K in T]: string | undefined;
} & { setQuery: typeof setQuery };
};
const AvailabilityPage = ({ profile, eventType }: Props) => {
const router = useRouter();
const isEmbed = useIsEmbed();
const { rescheduleUid } = router.query;
const { isReady, Theme } = useTheme(profile.theme);
const { t, i18n } = useLocale();
const query = dateQuerySchema.parse(router.query);
const { rescheduleUid } = query;
const { Theme } = useTheme(profile.theme);
const { t } = useLocale();
const { contracts } = useContracts();
const availabilityDatePickerEmbedStyles = useEmbedStyles("availabilityDatePicker");
let isBackgroundTransparent = useIsBackgroundTransparent();
useExposePlanGlobally(plan);
const shouldAlignCentrallyInEmbed = useEmbedNonStylesConfig("align") !== "left";
const shouldAlignCentrally = !isEmbed || shouldAlignCentrallyInEmbed;
const isBackgroundTransparent = useIsBackgroundTransparent();
const [timeZone, setTimeZone] = useState<string>();
const [timeFormat, setTimeFormat] = useState(detectBrowserTimeFormat);
const [isAvailableTimesVisible, setIsAvailableTimesVisible] = useState<boolean>();
useEffect(() => {
setTimeZone(localStorageTimeZone() || dayjs.tz.guess());
}, []);
useEffect(() => {
setIsAvailableTimesVisible(!!query.date);
}, [query.date]);
// TODO: Improve this;
useExposePlanGlobally(eventType.users.length === 1 ? eventType.users[0].plan : "PRO");
// TODO: this needs to be extracted elsewhere
useEffect(() => {
if (eventType.metadata.smartContractAddress) {
const eventOwner = eventType.users[0];
if (!contracts[(eventType.metadata.smartContractAddress || null) as number])
router.replace(`/${eventOwner.username}`);
}
}, [contracts, eventType.metadata.smartContractAddress, router]);
}, [contracts, eventType.metadata.smartContractAddress, eventType.users, router]);
const selectedDate = useMemo(() => {
const dateString = asStringOrNull(router.query.date);
if (dateString) {
const offsetString = dateString.substr(11, 14); // hhmm
const offsetSign = dateString.substr(10, 1); // + or -
const offsetHour = offsetString.slice(0, -2);
const offsetMinute = offsetString.slice(-2);
const utcOffsetInMinutes =
(offsetSign === "-" ? -1 : 1) *
(60 * (offsetHour !== "" ? parseInt(offsetHour) : 0) +
(offsetMinute !== "" ? parseInt(offsetMinute) : 0));
const date = dayjs(dateString.substr(0, 10)).utcOffset(utcOffsetInMinutes, true);
return date.isValid() ? date : null;
}
return null;
}, [router.query.date]);
if (selectedDate) {
// Let iframe take the width available due to increase in max-width
sdkActionManager?.fire("__refreshWidth", {});
}
const [isTimeOptionsOpen, setIsTimeOptionsOpen] = useState(false);
const [timeFormat, setTimeFormat] = useState(detectBrowserTimeFormat);
const [recurringEventCount, setRecurringEventCount] = useState(eventType.recurringEvent?.count);
const telemetry = useTelemetry();
useEffect(() => {
handleToggle24hClock(localStorage.getItem("timeOption.is24hClock") === "true");
telemetry.withJitsu((jitsu) =>
jitsu.track(
telemetryEventTypes.pageView,
collectPageParameters("availability", { isTeamBooking: document.URL.includes("team/") })
)
);
if (top !== window) {
//page_view will be collected automatically by _middleware.ts
telemetry.event(
telemetryEventTypes.embedView,
collectPageParameters("/availability", { isTeamBooking: document.URL.includes("team/") })
);
}
}, [telemetry]);
const changeDate = (newDate: Dayjs) => {
router.replace(
{
query: {
...router.query,
date: newDate.format("YYYY-MM-DDZZ"),
},
},
undefined,
{
shallow: true,
}
);
};
// Recurring event sidebar requires more space
const maxWidth = isAvailableTimesVisible
? recurringEventCount
? "max-w-6xl"
: "max-w-5xl"
: recurringEventCount
? "max-w-4xl"
: "max-w-3xl";
const handleSelectTimeZone = (selectedTimeZone: string): void => {
if (selectedDate) {
changeDate(selectedDate.tz(selectedTimeZone, true));
}
timeZone(selectedTimeZone);
setIsTimeOptionsOpen(false);
};
const handleToggle24hClock = (is24hClock: boolean) => {
setTimeFormat(is24hClock ? "HH:mm" : "h:mma");
};
const timezoneDropdown = useMemo(
() => (
<TimezoneDropdown
onChangeTimeFormat={setTimeFormat}
timeZone={timeZone}
onChangeTimeZone={setTimeZone}
/>
),
[timeZone]
);
return (
<>
@@ -141,59 +380,98 @@ const AvailabilityPage = ({ profile, plan, eventType, workingHours, previousPage
description={`${rescheduleUid ? t("reschedule") : ""} ${eventType.title}`}
name={profile.name || undefined}
username={profile.slug || undefined}
// avatar={profile.image || undefined}
/>
<CustomBranding lightVal={profile.brandColor} darkVal={profile.darkBrandColor} />
<div>
<main
className={
className={classNames(
shouldAlignCentrally ? "mx-auto" : "",
isEmbed
? classNames("m-auto", selectedDate ? "max-w-5xl" : "max-w-3xl")
: "transition-max-width mx-auto my-0 duration-500 ease-in-out md:my-24 " +
(selectedDate ? "max-w-5xl" : "max-w-3xl")
}>
{isReady && (
<div
style={availabilityDatePickerEmbedStyles}
className={classNames(
isBackgroundTransparent ? "" : "bg-white dark:bg-gray-800 sm:dark:border-gray-600",
"border-bookinglightest rounded-sm md:border",
isEmbed ? "mx-auto" : selectedDate ? "max-w-5xl" : "max-w-3xl"
)}>
{/* mobile: details */}
<div className="block p-4 sm:p-8 md:hidden">
<div className="block items-center sm:flex sm:space-x-4">
<AvatarGroup
border="border-2 dark:border-gray-800 border-white"
items={
[
{ image: profile.image, alt: profile.name, title: profile.name },
...eventType.users
.filter((user) => user.name !== profile.name)
.map((user) => ({
title: user.name,
image: `${process.env.NEXT_PUBLIC_WEBSITE_URL}/${user.username}/avatar.png`,
alt: user.name || undefined,
})),
].filter((item) => !!item.image) as { image: string; alt?: string; title?: string }[]
}
size={9}
truncateAfter={5}
/>
<div className="mt-4 sm:-mt-2">
<p className="text-sm font-medium text-black dark:text-white">{profile.name}</p>
<div className="mt-2 flex gap-2 text-xl font-medium dark:text-gray-100">
? classNames(maxWidth)
: classNames("transition-max-width mx-auto my-0 duration-500 ease-in-out md:my-24", maxWidth)
)}>
<div
style={availabilityDatePickerEmbedStyles}
className={classNames(
isBackgroundTransparent ? "" : "bg-white dark:bg-gray-800 sm:dark:border-gray-600",
"border-bookinglightest rounded-md md:border",
isEmbed ? "mx-auto" : maxWidth
)}>
{/* mobile: details */}
<div className="block px-4 pt-4 sm:p-8 md:hidden">
<div>
<AvatarGroup
border="border-2 dark:border-gray-800 border-white"
items={
[
{ image: profile.image, alt: profile.name, title: profile.name },
...eventType.users
.filter((user) => user.name !== profile.name)
.map((user) => ({
title: user.name,
image: `${CAL_URL}/${user.username}/avatar.png`,
alt: user.name || undefined,
})),
].filter((item) => !!item.image) as { image: string; alt?: string; title?: string }[]
}
size={9}
truncateAfter={5}
/>
<div className="mt-4">
<p className="break-words text-sm font-medium text-black dark:text-white">{profile.name}</p>
<div className="mt-2 gap-2 dark:text-gray-100">
<h1 className="text-bookingdark mb-4 break-words text-xl font-semibold dark:text-white">
{eventType.title}
</h1>
<div className="flex flex-col space-y-4">
{eventType?.description && (
<p className="mb-2 text-gray-600 dark:text-white">
<p className="text-gray-600 dark:text-white">
<InformationCircleIcon className="mr-[10px] ml-[2px] -mt-1 inline-block h-4 w-4" />
{eventType.description}
</p>
)}
<div>
<ClockIcon className="mr-[10px] -mt-1 inline-block h-4 w-4" />
{eventType?.requiresConfirmation && (
<p className="text-gray-600 dark:text-white">
<ClipboardCheckIcon className="mr-[10px] ml-[2px] -mt-1 inline-block h-4 w-4" />
{t("requires_confirmation")}
</p>
)}
{eventType.locations.length === 1 && (
<p className="text-gray-600 dark:text-white">
{Object.values(AppStoreLocationType).includes(
eventType.locations[0].type as unknown as AppStoreLocationType
) ? (
<VideoCameraIcon className="mr-[10px] ml-[2px] -mt-1 inline-block h-4 w-4 text-gray-400" />
) : (
<LocationMarkerIcon className="mr-[10px] ml-[2px] -mt-1 inline-block h-4 w-4 text-gray-400" />
)}
{locationKeyToString(eventType.locations[0], t)}
</p>
)}
{eventType.locations.length > 1 && (
<div className="flex-warp flex text-gray-600 dark:text-white">
<div className="mr-[10px] ml-[2px] -mt-1 ">
<LocationMarkerIcon className="inline-block h-4 w-4 text-gray-400" />
</div>
<p>
{eventType.locations.map((el, i, arr) => {
return (
<span key={el.type}>
{locationKeyToString(el, t)}{" "}
{arr.length - 1 !== i && (
<span className="font-light"> {t("or_lowercase")} </span>
)}
</span>
);
})}
</p>
</div>
)}
<p className="text-gray-600 dark:text-white">
<ClockIcon className="mr-[10px] -mt-1 ml-[2px] inline-block h-4 w-4 text-gray-400" />
{eventType.length} {t("minutes")}
</div>
</p>
{eventType.price > 0 && (
<div className="text-gray-600 dark:text-white">
<CreditCardIcon className="mr-[10px] ml-[2px] -mt-1 inline-block h-4 w-4 dark:text-gray-400" />
@@ -206,50 +484,164 @@ const AvailabilityPage = ({ profile, plan, eventType, workingHours, previousPage
</IntlProvider>
</div>
)}
{!rescheduleUid && eventType.recurringEvent && (
<div className="text-gray-600 dark:text-white">
<RefreshIcon className="float-left mr-[10px] mt-1 ml-[2px] inline-block h-4 w-4 text-gray-400" />
<div className="ml-[27px]">
<p className="mb-1 -ml-2 inline px-2 py-1">
{getRecurringFreq({ t, recurringEvent: eventType.recurringEvent })}
</p>
<input
type="number"
min="1"
max={eventType.recurringEvent.count}
className="w-15 h-7 rounded-sm border-gray-300 bg-white text-gray-600 shadow-sm [appearance:textfield] ltr:mr-2 rtl:ml-2 dark:border-gray-500 dark:bg-gray-600 dark:text-white sm:text-sm"
defaultValue={eventType.recurringEvent.count}
onChange={(event) => {
setRecurringEventCount(parseInt(event?.target.value));
}}
/>
<p className="inline text-gray-600 dark:text-white">
{t("occurrence", {
count: recurringEventCount,
})}
</p>
</div>
</div>
)}
{timezoneDropdown}
<div className="md:hidden">
{/* Temp disabled booking?.startTime && rescheduleUid && (
<div>
<p
className="mt-8 text-gray-600 dark:text-white"
data-testid="former_time_p_mobile">
{t("former_time")}
</p>
<p className="text-gray-500 line-through dark:text-white">
<CalendarIcon className="mr-[10px] -mt-1 inline-block h-4 w-4 text-gray-400" />
{typeof booking.startTime === "string" &&
parseDate(dayjs(booking.startTime), i18n)}
</p>
</div>
)*/}
</div>
</div>
</div>
</div>
</div>
</div>
<div className="px-4 sm:flex sm:p-4 sm:py-5">
<div
className={
"hidden pr-8 sm:border-r sm:dark:border-gray-700 md:flex md:flex-col " +
(selectedDate ? "sm:w-1/3" : "sm:w-1/2")
}>
<AvatarGroup
border="border-2 dark:border-gray-800 border-white"
items={
[
{ image: profile.image, alt: profile.name, title: profile.name },
...eventType.users
.filter((user) => user.name !== profile.name)
.map((user) => ({
title: user.name,
alt: user.name,
image: `${process.env.NEXT_PUBLIC_WEBSITE_URL}/${user.username}/avatar.png`,
})),
].filter((item) => !!item.image) as { image: string; alt?: string; title?: string }[]
}
size={10}
truncateAfter={3}
/>
<h2 className="mt-3 font-medium text-gray-500 dark:text-gray-300">{profile.name}</h2>
<h1 className="font-cal mb-4 text-xl font-semibold text-gray-900 dark:text-white">
{eventType.title}
</h1>
<div className="p-4 sm:flex sm:py-5">
<div
className={
"hidden overflow-hidden pr-8 sm:border-r sm:dark:border-gray-700 md:flex md:flex-col " +
(isAvailableTimesVisible ? "sm:w-1/3" : recurringEventCount ? "sm:w-2/3" : "sm:w-1/2")
}>
<AvatarGroup
border="border-2 dark:border-gray-800 border-white"
items={
[
{ image: profile.image, alt: profile.name, title: profile.name },
...eventType.users
.filter((user) => user.name !== profile.name)
.map((user) => ({
title: user.name,
alt: user.name,
image: `${CAL_URL}/${user.username}/avatar.png`,
})),
].filter((item) => !!item.image) as { image: string; alt?: string; title?: string }[]
}
size={10}
truncateAfter={3}
/>
<h2 className="mt-3 break-words font-medium text-gray-500 dark:text-gray-300">
{profile.name}
</h2>
<h1 className="font-cal mb-4 break-words text-xl font-semibold text-gray-900 dark:text-white">
{eventType.title}
</h1>
<div className="flex flex-col space-y-4">
{eventType?.description && (
<p className="mb-2 text-gray-600 dark:text-white">
<InformationCircleIcon className="mr-[10px] ml-[2px] -mt-1 inline-block h-4 w-4 text-gray-400" />
{eventType.description}
<div className="flex text-gray-600 dark:text-white">
<div>
<InformationCircleIcon className="mr-[10px] ml-[2px] -mt-1 inline-block h-4 w-4 text-gray-400" />
</div>
<p>{eventType.description}</p>
</div>
)}
{eventType?.requiresConfirmation && (
<div className="flex text-gray-600 dark:text-white">
<div>
<ClipboardCheckIcon className="mr-[10px] ml-[2px] -mt-1 inline-block h-4 w-4 text-gray-400" />
</div>
{t("requires_confirmation")}
</div>
)}
{eventType.locations.length === 1 && (
<p className="text-gray-600 dark:text-white">
{Object.values(AppStoreLocationType).includes(
eventType.locations[0].type as unknown as AppStoreLocationType
) ? (
<VideoCameraIcon className="mr-[10px] ml-[2px] -mt-1 inline-block h-4 w-4 text-gray-400" />
) : (
<LocationMarkerIcon className="mr-[10px] ml-[2px] -mt-1 inline-block h-4 w-4 text-gray-400" />
)}
{locationKeyToString(eventType.locations[0], t)}
</p>
)}
<p className="mb-1 -ml-2 px-2 py-1 text-gray-600 dark:text-white">
{eventType.locations.length > 1 && (
<div className="flex-warp flex text-gray-600 dark:text-white">
<div className="mr-[10px] ml-[2px] -mt-1 ">
<LocationMarkerIcon className="inline-block h-4 w-4 text-gray-400" />
</div>
<p>
{eventType.locations.map((el, i, arr) => {
return (
<span key={el.type}>
{locationKeyToString(el, t)}{" "}
{arr.length - 1 !== i && (
<span className="font-light"> {t("or_lowercase")} </span>
)}
</span>
);
})}
</p>
</div>
)}
<p className="text-gray-600 dark:text-white">
<ClockIcon className="mr-[10px] -mt-1 ml-[2px] inline-block h-4 w-4 text-gray-400" />
{eventType.length} {t("minutes")}
</p>
{!rescheduleUid && eventType.recurringEvent && (
<div className="text-gray-600 dark:text-white">
<RefreshIcon className="float-left mr-[10px] mt-1 ml-[2px] inline-block h-4 w-4 text-gray-400" />
<div className="ml-[27px]">
<p className="mb-1 -ml-2 inline px-2 py-1">
{getRecurringFreq({ t, recurringEvent: eventType.recurringEvent })}
</p>
<input
type="number"
min="1"
max={eventType.recurringEvent.count}
className="w-15 h-7 rounded-sm border-gray-300 bg-white text-gray-600 shadow-sm [appearance:textfield] ltr:mr-2 rtl:ml-2 dark:border-gray-500 dark:bg-gray-600 dark:text-white sm:text-sm"
defaultValue={eventType.recurringEvent.count}
onChange={(event) => {
setRecurringEventCount(parseInt(event?.target.value));
}}
/>
<p className="inline text-gray-600 dark:text-white">
{t("occurrence", {
count: recurringEventCount,
})}
</p>
</div>
</div>
)}
{eventType.price > 0 && (
<p className="mb-1 -ml-2 px-2 py-1 text-gray-600 dark:text-white">
<p className="-ml-2 px-2 py-1 text-gray-600 dark:text-white">
<CreditCardIcon className="mr-[10px] ml-[2px] -mt-1 inline-block h-4 w-4 text-gray-400" />
<IntlProvider locale="en">
<FormattedNumber
@@ -260,20 +652,16 @@ const AvailabilityPage = ({ profile, plan, eventType, workingHours, previousPage
</IntlProvider>
</p>
)}
{timezoneDropdown}
</div>
<TimezoneDropdown />
{previousPage === `${BASE_URL}/${profile.slug}` && (
<div className="flex h-full flex-col justify-end">
<ArrowLeftIcon
className="h-4 w-4 text-black transition-opacity hover:cursor-pointer dark:text-white"
onClick={() => router.back()}
/>
<p className="sr-only">Go Back</p>
</div>
)}
{booking?.startTime && rescheduleUid && (
<GoBackToPreviousPage slug={profile.slug || ""} />
{/* Temporarily disabled - booking?.startTime && rescheduleUid && (
<div>
<p className="mt-8 mb-2 text-gray-600 dark:text-white" data-testid="former_time_p">
<p
className="mt-4 mb-3 text-gray-600 dark:text-white"
data-testid="former_time_p_desktop">
{t("former_time")}
</p>
<p className="text-gray-500 line-through dark:text-white">
@@ -281,68 +669,37 @@ const AvailabilityPage = ({ profile, plan, eventType, workingHours, previousPage
{typeof booking.startTime === "string" && parseDate(dayjs(booking.startTime), i18n)}
</p>
</div>
)}
</div>
<DatePicker
date={selectedDate}
periodType={eventType?.periodType}
periodStartDate={eventType?.periodStartDate}
periodEndDate={eventType?.periodEndDate}
periodDays={eventType?.periodDays}
periodCountCalendarDays={eventType?.periodCountCalendarDays}
onDatePicked={changeDate}
workingHours={workingHours}
weekStart={profile.weekStart || "Sunday"}
eventLength={eventType.length}
minimumBookingNotice={eventType.minimumBookingNotice}
/>
<div className="mt-4 ml-1 block sm:hidden">
<TimezoneDropdown />
</div>
{selectedDate && (
<AvailableTimes
timeFormat={timeFormat}
minimumBookingNotice={eventType.minimumBookingNotice}
eventTypeId={eventType.id}
eventTypeSlug={eventType.slug}
slotInterval={eventType.slotInterval}
eventLength={eventType.length}
date={selectedDate}
users={eventType.users}
schedulingType={eventType.schedulingType ?? null}
beforeBufferTime={eventType.beforeEventBuffer}
afterBufferTime={eventType.afterEventBuffer}
/>
)}
)*/}
</div>
{timeZone && (
<SlotPicker
weekStart={
typeof profile.weekStart === "string"
? ([
"Sunday",
"Monday",
"Tuesday",
"Wednesday",
"Thursday",
"Friday",
"Saturday",
].indexOf(profile.weekStart) as 0 | 1 | 2 | 3 | 4 | 5 | 6)
: profile.weekStart /* Allows providing weekStart as number */
}
eventType={eventType}
timeFormat={timeFormat}
timeZone={timeZone}
seatsPerTimeSlot={eventType.seatsPerTimeSlot || undefined}
recurringEventCount={recurringEventCount}
/>
)}
</div>
)}
</div>
{(!eventType.users[0] || !isBrandingHidden(eventType.users[0])) && !isEmbed && <PoweredByCal />}
</main>
</div>
</>
);
function TimezoneDropdown() {
return (
<Collapsible.Root open={isTimeOptionsOpen} onOpenChange={setIsTimeOptionsOpen}>
<Collapsible.Trigger className="min-w-32 mb-1 -ml-2 px-2 py-1 text-left text-gray-600 dark:text-white">
<GlobeIcon className="mr-[10px] ml-[2px] -mt-1 inline-block h-4 w-4 text-gray-400" />
{timeZone()}
{isTimeOptionsOpen ? (
<ChevronUpIcon className="ml-1 -mt-1 inline-block h-4 w-4" />
) : (
<ChevronDownIcon className="ml-1 -mt-1 inline-block h-4 w-4" />
)}
</Collapsible.Trigger>
<Collapsible.Content>
<TimeOptions onSelectTimeZone={handleSelectTimeZone} onToggle24hClock={handleToggle24hClock} />
</Collapsible.Content>
</Collapsible.Root>
);
}
};
export default AvailabilityPage;
+321 -102
View File
@@ -2,12 +2,15 @@ import {
CalendarIcon,
ClockIcon,
CreditCardIcon,
ExclamationCircleIcon,
ExclamationIcon,
InformationCircleIcon,
ClipboardCheckIcon,
RefreshIcon,
} from "@heroicons/react/solid";
import { zodResolver } from "@hookform/resolvers/zod";
import { EventTypeCustomInputType } from "@prisma/client";
import { useContracts } from "contexts/contractsContext";
import dayjs from "dayjs";
import { useSession } from "next-auth/react";
import dynamic from "next/dynamic";
import Head from "next/head";
@@ -17,22 +20,32 @@ 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";
import { useIsEmbed, useIsBackgroundTransparent } from "@calcom/embed-core";
import dayjs from "@calcom/dayjs";
import {
useEmbedNonStylesConfig,
useIsBackgroundTransparent,
useIsEmbed,
} from "@calcom/embed-core/embed-iframe";
import classNames from "@calcom/lib/classNames";
import { useLocale } from "@calcom/lib/hooks/useLocale";
import { HttpError } from "@calcom/lib/http-error";
import { getEveryFreqFor } from "@calcom/lib/recurringStrings";
import { createPaymentLink } from "@calcom/stripe/client";
import { Button } from "@calcom/ui/Button";
import { Tooltip } from "@calcom/ui/Tooltip";
import { EmailInput, Form } from "@calcom/ui/form/fields";
import { asStringOrNull } from "@lib/asStringOrNull";
import { timeZone } from "@lib/clock";
import { ensureArray } from "@lib/ensureArray";
import useTheme from "@lib/hooks/useTheme";
import { LocationType } from "@lib/location";
import { LocationObject, LocationType } from "@lib/location";
import createBooking from "@lib/mutations/bookings/create-booking";
import { parseDate } from "@lib/parseDate";
import createRecurringBooking from "@lib/mutations/bookings/create-recurring-booking";
import { parseDate, parseRecurringDates } from "@lib/parseDate";
import slugify from "@lib/slugify";
import { collectPageParameters, telemetryEventTypes, useTelemetry } from "@lib/telemetry";
@@ -41,14 +54,26 @@ import AvatarGroup from "@components/ui/AvatarGroup";
import type PhoneInputType from "@components/ui/form/PhoneInput";
import { BookPageProps } from "../../../pages/[user]/book";
import { HashLinkPageProps } from "../../../pages/d/[link]/book";
import { TeamBookingPageProps } from "../../../pages/team/[slug]/book";
declare global {
// eslint-disable-next-line no-var
var web3: {
currentProvider: {
selectedAddress: string;
};
};
}
/** These are like 40kb that not every user needs */
const PhoneInput = dynamic(
() => import("@components/ui/form/PhoneInput")
) as unknown as typeof PhoneInputType;
type BookingPageProps = BookPageProps | TeamBookingPageProps;
type BookingPageProps = (BookPageProps | TeamBookingPageProps | HashLinkPageProps) & {
locationLabels: Record<LocationType, string>;
};
type BookingFormValues = {
name: string;
@@ -57,9 +82,11 @@ type BookingFormValues = {
locationType?: LocationType;
guests?: string[];
phone?: string;
hostPhoneNumber?: string; // Maybe come up with a better way to name this to distingish between two types of phone numbers
customInputs?: {
[key: string]: string;
[key: string]: string | boolean;
};
rescheduleReason?: string;
};
const BookingPage = ({
@@ -67,34 +94,51 @@ const BookingPage = ({
booking,
profile,
isDynamicGroupBooking,
recurringEventCount,
locationLabels,
hasHashedBookingLink,
hashedLink,
}: BookingPageProps) => {
const { t, i18n } = useLocale();
const isEmbed = useIsEmbed();
const shouldAlignCentrallyInEmbed = useEmbedNonStylesConfig("align") !== "left";
const shouldAlignCentrally = !isEmbed || shouldAlignCentrallyInEmbed;
const router = useRouter();
const { contracts } = useContracts();
const { data: session } = useSession();
const isBackgroundTransparent = useIsBackgroundTransparent();
const telemetry = useTelemetry();
useEffect(() => {
if (top !== window) {
//page_view will be collected automatically by _middleware.ts
telemetry.event(
telemetryEventTypes.embedView,
collectPageParameters("/book", { isTeamBooking: document.URL.includes("team/") })
);
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);
useEffect(() => {
if (eventType.metadata.smartContractAddress) {
const eventOwner = eventType.users[0];
if (!contracts[(eventType.metadata.smartContractAddress || null) as number])
/* @ts-ignore */
router.replace(`/${eventOwner.username}`);
}
}, [contracts, eventType.metadata.smartContractAddress, router]);
}, [contracts, eventType.metadata.smartContractAddress, eventType.users, router]);
const mutation = useMutation(createBooking, {
onSuccess: async (responseData) => {
const { attendees, paymentUid } = responseData;
const { id, attendees, paymentUid } = responseData;
if (paymentUid) {
return await router.push(
createPaymentLink({
paymentUid,
date,
name: attendees[0].name,
email: attendees[0].email,
absolute: false,
})
);
@@ -122,6 +166,40 @@ const BookingPage = ({
email: attendees[0].email,
location,
eventName: profile.eventName || "",
bookingId: id,
isSuccessBookingPage: true,
},
});
},
});
const recurringMutation = useMutation(createRecurringBooking, {
onSuccess: async (responseData = []) => {
const { attendees = [], id, recurringEventId } = responseData[0] || {};
const location = (function humanReadableLocation(location) {
if (!location) {
return;
}
if (location.includes("integration")) {
return t("web_conferencing_details_to_follow");
}
return location;
})(responseData[0].location);
return router.push({
pathname: "/success",
query: {
date,
type: eventType.id,
eventSlug: eventType.slug,
recur: recurringEventId,
user: profile.slug,
reschedule: !!rescheduleUid,
name: attendees[0].name,
email: attendees[0].email,
location,
eventName: profile.eventName || "",
bookingId: id,
},
});
},
@@ -135,10 +213,9 @@ const BookingPage = ({
const eventTypeDetail = { isWeb3Active: false, ...eventType };
type Location = { type: LocationType; address?: string; link?: string };
// it would be nice if Prisma at some point in the future allowed for Json<Location>; as of now this is not the case.
const locations: Location[] = useMemo(
() => (eventType.locations as Location[]) || [],
const locations: LocationObject[] = useMemo(
() => (eventType.locations as LocationObject[]) || [],
[eventType.locations]
);
@@ -148,10 +225,8 @@ const BookingPage = ({
}
}, [router.query.guest]);
const telemetry = useTelemetry();
const locationInfo = (type: LocationType) => locations.find((location) => location.type === type);
const loggedInIsOwner = eventType?.users[0]?.name === session?.user?.name;
const loggedInIsOwner = eventType?.users[0]?.id === session?.user?.id;
const guestListEmails = !isDynamicGroupBooking
? booking?.attendees.slice(1).map((attendee) => attendee.email)
: [];
@@ -159,8 +234,8 @@ const BookingPage = ({
const defaultValues = () => {
if (!rescheduleUid) {
return {
name: loggedInIsOwner ? "" : session?.user?.name || (router.query.name as string) || "",
email: loggedInIsOwner ? "" : session?.user?.email || (router.query.email as string) || "",
name: (router.query.name as string) || (!loggedInIsOwner && session?.user?.name) || "",
email: (router.query.email as string) || (!loggedInIsOwner && session?.user?.email) || "",
notes: (router.query.notes as string) || "",
guests: ensureArray(router.query.guest) as string[],
customInputs: eventType.customInputs.reduce(
@@ -179,16 +254,36 @@ const BookingPage = ({
if (!primaryAttendee) {
return {};
}
const customInputType = booking.customInputs;
return {
name: primaryAttendee.name || "",
email: primaryAttendee.email || "",
guests: guestListEmails,
notes: booking.description || "",
rescheduleReason: "",
customInputs: eventType.customInputs.reduce(
(customInputs, input) => ({
...customInputs,
[input.id]: booking.customInputs
? booking.customInputs[input.label as keyof typeof customInputType]
: "",
}),
{}
),
};
};
const bookingFormSchema = z
.object({
name: z.string().min(1),
email: z.string().email(),
})
.passthrough();
const bookingForm = useForm<BookingFormValues>({
defaultValues: defaultValues(),
resolver: zodResolver(bookingFormSchema), // Since this isn't set to strict we only validate the fields in the schema
});
const selectedLocation = useWatch({
@@ -204,7 +299,9 @@ const BookingPage = ({
})(),
});
const getLocationValue = (booking: Pick<BookingFormValues, "locationType" | "phone">) => {
const getLocationValue = (
booking: Pick<BookingFormValues, "locationType" | "phone" | "hostPhoneNumber">
) => {
const { locationType } = booking;
switch (locationType) {
case LocationType.Phone: {
@@ -216,20 +313,34 @@ const BookingPage = ({
case LocationType.Link: {
return locationInfo(locationType)?.link || "";
}
case LocationType.UserPhone: {
return locationInfo(locationType)?.hostPhoneNumber || "";
}
// Catches all other location types, such as Google Meet, Zoom etc.
default:
return selectedLocation || "";
}
};
const bookEvent = (booking: BookingFormValues) => {
telemetry.withJitsu((jitsu) =>
jitsu.track(
telemetryEventTypes.bookingConfirmed,
collectPageParameters("/book", { isTeamBooking: document.URL.includes("team/") })
)
// Calculate the booking date(s)
let recurringStrings: string[] = [],
recurringDates: Date[] = [];
if (eventType.recurringEvent?.freq && recurringEventCount !== null) {
[recurringStrings, recurringDates] = parseRecurringDates(
{
startDate: date,
recurringEvent: eventType.recurringEvent,
recurringCount: parseInt(recurringEventCount.toString()),
},
i18n
);
}
const bookEvent = (booking: BookingFormValues) => {
telemetry.event(
top !== window ? telemetryEventTypes.embedBookingConfirmed : telemetryEventTypes.bookingConfirmed,
{ isTeamBooking: document.URL.includes("team/") }
);
// "metadata" is a reserved key to allow for connecting external users without relying on the email address.
// <...url>&metadata[user_id]=123 will be send as a custom input field as the hidden type.
@@ -244,38 +355,74 @@ const BookingPage = ({
{}
);
let web3Details;
let web3Details: Record<"userWallet" | "userSignature", string> | undefined;
if (eventTypeDetail.metadata.smartContractAddress) {
web3Details = {
// @ts-ignore
userWallet: window.web3.currentProvider.selectedAddress,
userSignature: contracts[(eventTypeDetail.metadata.smartContractAddress || null) as number],
};
}
mutation.mutate({
...booking,
web3Details,
start: dayjs(date).format(),
end: dayjs(date).add(eventType.length, "minute").format(),
eventTypeId: eventType.id,
eventTypeSlug: eventType.slug,
timeZone: timeZone(),
language: i18n.language,
rescheduleUid,
user: router.query.user,
location: getLocationValue(
booking.locationType ? booking : { ...booking, locationType: selectedLocation }
),
metadata,
customInputs: Object.keys(booking.customInputs || {}).map((inputId) => ({
label: eventType.customInputs.find((input) => input.id === parseInt(inputId))!.label,
value: booking.customInputs![inputId],
})),
});
if (recurringDates.length) {
// Identify set of bookings to one intance of recurring event to support batch changes
const recurringEventId = uuidv4();
const recurringBookings = recurringDates.map((recurringDate) => ({
...booking,
web3Details,
start: dayjs(recurringDate).format(),
end: dayjs(recurringDate).add(eventType.length, "minute").format(),
eventTypeId: eventType.id,
eventTypeSlug: eventType.slug,
recurringEventId,
// Added to track down the number of actual occurrences selected by the user
recurringCount: recurringDates.length,
timeZone: timeZone(),
language: i18n.language,
rescheduleUid,
user: router.query.user,
location: getLocationValue(
booking.locationType ? booking : { ...booking, locationType: selectedLocation }
),
metadata,
customInputs: Object.keys(booking.customInputs || {}).map((inputId) => ({
label: eventType.customInputs.find((input) => input.id === parseInt(inputId))?.label || "",
value: booking.customInputs && inputId in booking.customInputs ? booking.customInputs[inputId] : "",
})),
hasHashedBookingLink,
hashedLink,
}));
recurringMutation.mutate(recurringBookings);
} else {
mutation.mutate({
...booking,
web3Details,
start: dayjs(date).format(),
end: dayjs(date).add(eventType.length, "minute").format(),
eventTypeId: eventType.id,
eventTypeSlug: eventType.slug,
timeZone: timeZone(),
language: i18n.language,
rescheduleUid,
bookingUid: router.query.bookingUid as string,
user: router.query.user,
location: getLocationValue(
booking.locationType ? booking : { ...booking, locationType: selectedLocation }
),
metadata,
customInputs: Object.keys(booking.customInputs || {}).map((inputId) => ({
label: eventType.customInputs.find((input) => input.id === parseInt(inputId))?.label || "",
value: booking.customInputs && inputId in booking.customInputs ? booking.customInputs[inputId] : "",
})),
hasHashedBookingLink,
hashedLink,
});
}
};
const disableInput = !!rescheduleUid;
const disabledExceptForOwner = disableInput && !loggedInIsOwner;
const inputClassName =
"focus:border-brand block w-full rounded-sm border-gray-300 shadow-sm focus:ring-black disabled:bg-gray-200 disabled:hover:cursor-not-allowed dark:border-gray-900 dark:bg-gray-700 dark:text-white dark:selection:bg-green-500 disabled:dark:text-gray-500 sm:text-sm";
return (
<div>
@@ -298,16 +445,17 @@ const BookingPage = ({
<CustomBranding lightVal={profile.brandColor} darkVal={profile.darkBrandColor} />
<main
className={classNames(
isEmbed ? "mx-auto" : "mx-auto my-0 rounded-sm sm:my-24",
"max-w-3xl sm:border sm:dark:border-gray-600"
shouldAlignCentrally ? "mx-auto" : "",
isEmbed ? "" : "sm:my-24",
"my-0 max-w-3xl "
)}>
{isReady && (
<div
className={classNames(
"overflow-hidden",
"main overflow-hidden",
isEmbed ? "" : "border border-gray-200",
isBackgroundTransparent ? "" : "bg-white dark:border-0 dark:bg-gray-800",
"sm:rounded-sm"
isBackgroundTransparent ? "" : "dark:border-1 bg-white dark:bg-gray-800",
"rounded-md dark:border-gray-600 sm:border"
)}>
<div className="px-4 py-5 sm:flex sm:p-4">
<div className="sm:w-1/2 sm:border-r sm:dark:border-gray-700">
@@ -329,12 +477,33 @@ const BookingPage = ({
<h1 className="text-bookingdark mb-4 text-xl font-semibold dark:text-white">
{eventType.title}
</h1>
{!!eventType.seatsPerTimeSlot && (
<p
className={`${
booking && booking.attendees.length / eventType.seatsPerTimeSlot >= 0.5
? "text-rose-600"
: booking && booking.attendees.length / eventType.seatsPerTimeSlot >= 0.33
? "text-yellow-500"
: "text-emerald-400"
} mb-2`}>
{booking
? eventType.seatsPerTimeSlot - booking.attendees.length
: eventType.seatsPerTimeSlot}{" "}
/ {eventType.seatsPerTimeSlot} {t("seats_available")}
</p>
)}
{eventType?.description && (
<p className="text-bookinglight mb-2 dark:text-white">
<InformationCircleIcon className="mr-[10px] ml-[2px] -mt-1 inline-block h-4 w-4 text-gray-400" />
{eventType.description}
</p>
)}
{eventType?.requiresConfirmation && (
<p className="text-bookinglight mb-2 dark:text-white">
<ClipboardCheckIcon className="mr-[10px] ml-[2px] -mt-1 inline-block h-4 w-4 text-gray-400" />
{t("requires_confirmation")}
</p>
)}
<p className="text-bookinglight mb-2 dark:text-white">
<ClockIcon className="mr-[10px] -mt-1 ml-[2px] inline-block h-4 w-4 text-gray-400" />
{eventType.length} {t("minutes")}
@@ -351,10 +520,40 @@ const BookingPage = ({
</IntlProvider>
</p>
)}
<p className="text-bookinghighlight mb-4">
<CalendarIcon className="mr-[10px] ml-[2px] -mt-1 inline-block h-4 w-4" />
{parseDate(date, i18n)}
</p>
{!rescheduleUid && eventType.recurringEvent?.freq && recurringEventCount && (
<div className="mb-3 text-gray-600 dark:text-white">
<RefreshIcon className="mr-[10px] -mt-1 ml-[2px] inline-block h-4 w-4 text-gray-400" />
<p className="mb-1 -ml-2 inline px-2 py-1">
{getEveryFreqFor({
t,
recurringEvent: eventType.recurringEvent,
recurringCount: recurringEventCount,
})}
</p>
</div>
)}
<div className="text-bookinghighlight mb-4 flex">
<CalendarIcon className="mr-[10px] ml-[2px] inline-block h-4 w-4" />
<div className="-mt-1">
{(rescheduleUid || !eventType.recurringEvent?.freq) &&
parseDate(dayjs(date).tz(timeZone()), i18n)}
{!rescheduleUid &&
eventType.recurringEvent?.freq &&
recurringStrings.slice(0, 5).map((aDate, key) => <p key={key}>{aDate}</p>)}
{!rescheduleUid && eventType.recurringEvent?.freq && recurringStrings.length > 5 && (
<div className="flex">
<Tooltip
content={recurringStrings.slice(5).map((aDate, key) => (
<p key={key}>{aDate}</p>
))}>
<p className="text-gray-600 dark:text-white">
{t("plus_more", { count: recurringStrings.length - 5 })}
</p>
</Tooltip>
</div>
)}
</div>
</div>
{eventTypeDetail.isWeb3Active && eventType.metadata.smartContractAddress && (
<p className="text-bookinglight mb-1 -ml-2 px-2 py-1">
{t("requires_ownership_of_a_token") + " " + eventType.metadata.smartContractAddress}
@@ -380,15 +579,12 @@ const BookingPage = ({
</label>
<div className="mt-1">
<input
{...bookingForm.register("name")}
{...bookingForm.register("name", { required: true })}
type="text"
name="name"
id="name"
required
className={classNames(
"focus:border-brand block w-full rounded-sm border-gray-300 shadow-sm focus:ring-black dark:border-gray-900 dark:bg-gray-700 dark:text-white dark:selection:bg-green-500 sm:text-sm",
disableInput ? "bg-gray-200 dark:text-gray-500" : ""
)}
className={inputClassName}
placeholder={t("example_name")}
disabled={disableInput}
/>
@@ -405,13 +601,21 @@ const BookingPage = ({
{...bookingForm.register("email")}
required
className={classNames(
"focus:border-brand block w-full rounded-sm border-gray-300 shadow-sm focus:ring-black dark:border-gray-900 dark:bg-gray-700 dark:text-white dark:selection:bg-green-500 sm:text-sm",
disableInput ? "bg-gray-200 dark:text-gray-500" : ""
inputClassName,
bookingForm.formState.errors.email
? "border-red-700 focus:ring-red-700"
: " border-gray-300 dark:border-gray-900"
)}
placeholder="you@example.com"
type="search" // Disables annoying 1password intrusive popup (non-optimal, I know I know...)
disabled={disableInput}
/>
{bookingForm.formState.errors.email && (
<div className="mt-2 flex items-center text-sm text-red-700 ">
<ExclamationCircleIcon className="mr-2 h-3 w-3" />
<p>{t("email_validation_error")}</p>
</div>
)}
</div>
</div>
{locations.length > 1 && (
@@ -427,7 +631,6 @@ const BookingPage = ({
{...bookingForm.register("locationType", { required: true })}
value={location.type}
defaultChecked={selectedLocation === location.type}
disabled={disableInput}
/>
<span className="text-sm ltr:ml-2 rtl:mr-2 dark:text-gray-500">
{locationLabels[location.type]}
@@ -473,12 +676,9 @@ const BookingPage = ({
})}
id={"custom_" + input.id}
rows={3}
className={classNames(
"focus:border-brand block w-full rounded-sm border-gray-300 shadow-sm focus:ring-black dark:border-gray-900 dark:bg-gray-700 dark:text-white dark:selection:bg-green-500 sm:text-sm",
disableInput ? "bg-gray-200 dark:text-gray-500" : ""
)}
className={inputClassName}
placeholder={input.placeholder}
disabled={disableInput}
disabled={disabledExceptForOwner}
/>
)}
{input.type === EventTypeCustomInputType.TEXT && (
@@ -488,9 +688,9 @@ const BookingPage = ({
required: input.required,
})}
id={"custom_" + input.id}
className="focus:border-brand block w-full rounded-sm border-gray-300 shadow-sm focus:ring-black dark:border-gray-900 dark:bg-gray-700 dark:text-white dark:selection:bg-green-500 sm:text-sm"
className={inputClassName}
placeholder={input.placeholder}
disabled={disableInput}
disabled={disabledExceptForOwner}
/>
)}
{input.type === EventTypeCustomInputType.NUMBER && (
@@ -500,8 +700,9 @@ const BookingPage = ({
required: input.required,
})}
id={"custom_" + input.id}
className="focus:border-brand block w-full rounded-sm border-gray-300 shadow-sm focus:ring-black dark:border-gray-900 dark:bg-gray-700 dark:text-white dark:selection:bg-green-500 sm:text-sm"
className={inputClassName}
placeholder=""
disabled={disabledExceptForOwner}
/>
)}
{input.type === EventTypeCustomInputType.BOOL && (
@@ -512,8 +713,9 @@ const BookingPage = ({
required: input.required,
})}
id={"custom_" + input.id}
className="h-4 w-4 rounded border-gray-300 text-black focus:ring-black ltr:mr-2 rtl:ml-2"
className="h-4 w-4 rounded border-gray-300 text-black focus:ring-black disabled:bg-gray-200 ltr:mr-2 rtl:ml-2 disabled:dark:text-gray-500"
placeholder=""
disabled={disabledExceptForOwner}
/>
<label
htmlFor={"custom_" + input.id}
@@ -593,26 +795,36 @@ const BookingPage = ({
<label
htmlFor="notes"
className="mb-1 block text-sm font-medium text-gray-700 dark:text-white">
{t("additional_notes")}
{rescheduleUid ? t("reschedule_optional") : t("additional_notes")}
</label>
<textarea
{...bookingForm.register("notes")}
id="notes"
name="notes"
rows={3}
className={classNames(
"focus:border-brand block w-full rounded-sm border-gray-300 shadow-sm focus:ring-black dark:border-gray-900 dark:bg-gray-700 dark:text-white dark:selection:bg-green-500 sm:text-sm",
disableInput ? "bg-gray-200 dark:text-gray-500" : ""
)}
placeholder={t("share_additional_notes")}
disabled={disableInput}
/>
{rescheduleUid ? (
<textarea
{...bookingForm.register("rescheduleReason")}
id="rescheduleReason"
name="rescheduleReason"
rows={3}
className={inputClassName}
placeholder={t("reschedule_placeholder")}
disabled={disabledExceptForOwner}
/>
) : (
<textarea
{...bookingForm.register("notes")}
id="notes"
name="notes"
rows={3}
className={inputClassName}
placeholder={t("share_additional_notes")}
disabled={disabledExceptForOwner}
/>
)}
</div>
<div className="flex items-start space-x-2 rtl:space-x-reverse">
<Button
type="submit"
data-testid={rescheduleUid ? "confirm-reschedule-button" : "confirm-book-button"}
loading={mutation.isLoading}>
loading={mutation.isLoading || recurringMutation.isLoading}>
{rescheduleUid ? t("reschedule") : t("confirm")}
</Button>
<Button color="secondary" type="button" onClick={() => router.back()}>
@@ -620,22 +832,8 @@ const BookingPage = ({
</Button>
</div>
</Form>
{mutation.isError && (
<div
data-testid="booking-fail"
className="mt-2 border-l-4 border-yellow-400 bg-yellow-50 p-4">
<div className="flex">
<div className="flex-shrink-0">
<ExclamationIcon className="h-5 w-5 text-yellow-400" aria-hidden="true" />
</div>
<div className="ltr:ml-3 rtl:mr-3">
<p className="text-sm text-yellow-700">
{rescheduleUid ? t("reschedule_fail") : t("booking_fail")}{" "}
{(mutation.error as HttpError)?.message}
</p>
</div>
</div>
</div>
{(mutation.isError || recurringMutation.isError) && (
<ErrorMessage error={mutation.error || recurringMutation.error} />
)}
</div>
</div>
@@ -647,3 +845,24 @@ const BookingPage = ({
};
export default BookingPage;
function ErrorMessage({ error }: { error: unknown }) {
const { t } = useLocale();
const { query: { rescheduleUid } = {} } = useRouter();
return (
<div data-testid="booking-fail" className="mt-2 border-l-4 border-yellow-400 bg-yellow-50 p-4">
<div className="flex">
<div className="flex-shrink-0">
<ExclamationIcon className="h-5 w-5 text-yellow-400" aria-hidden="true" />
</div>
<div className="ltr:ml-3 rtl:mr-3">
<p className="text-sm text-yellow-700">
{rescheduleUid ? t("reschedule_fail") : t("booking_fail")}{" "}
{error instanceof HttpError || error instanceof Error ? error.message : "Unknown error"}
</p>
</div>
</div>
</div>
);
}
@@ -3,15 +3,16 @@ import { CheckIcon } from "@heroicons/react/solid";
import * as DialogPrimitive from "@radix-ui/react-dialog";
import React, { PropsWithChildren, ReactNode } from "react";
import { useLocale } from "@calcom/lib/hooks/useLocale";
import { Button } from "@calcom/ui/Button";
import { DialogClose, DialogContent } from "@calcom/ui/Dialog";
import { useLocale } from "@lib/hooks/useLocale";
export type ConfirmationDialogContentProps = {
confirmBtn?: ReactNode;
confirmBtnText?: string;
cancelBtnText?: string;
isLoading?: boolean;
loadingText?: string;
onConfirm?: (event: React.MouseEvent<HTMLElement, MouseEvent>) => void;
title: string;
variety?: "danger" | "warning" | "success";
@@ -25,6 +26,8 @@ export default function ConfirmationDialogContent(props: PropsWithChildren<Confi
confirmBtn = null,
confirmBtnText = t("confirm"),
cancelBtnText = t("cancel"),
loadingText = t("loading"),
isLoading = false,
onConfirm,
children,
} = props;
@@ -59,10 +62,14 @@ export default function ConfirmationDialogContent(props: PropsWithChildren<Confi
</div>
</div>
<div className="mt-5 flex flex-row-reverse gap-x-2 sm:mt-8">
<DialogClose onClick={onConfirm} asChild>
{confirmBtn || <Button color="primary">{confirmBtnText}</Button>}
<DialogClose disabled={isLoading} onClick={onConfirm} asChild>
{confirmBtn || (
<Button color="primary" loading={isLoading}>
{isLoading ? loadingText : confirmBtnText}
</Button>
)}
</DialogClose>
<DialogClose asChild>
<DialogClose disabled={isLoading} asChild>
<Button color="secondary">{cancelBtnText}</Button>
</DialogClose>
</div>
@@ -0,0 +1,75 @@
import { ExclamationIcon } from "@heroicons/react/outline";
import { CheckIcon } from "@heroicons/react/solid";
import * as DialogPrimitive from "@radix-ui/react-dialog";
import React, { PropsWithChildren } from "react";
import { useLocale } from "@calcom/lib/hooks/useLocale";
import { Button } from "@calcom/ui/Button";
import { DialogClose, DialogContent } from "@calcom/ui/Dialog";
export type DeleteStripeDialogContentProps = {
cancelAllBookingsBtnText?: string;
removeBtnText?: string;
cancelBtnText?: string;
onConfirm?: (event: React.MouseEvent<HTMLElement, MouseEvent>) => void;
onRemove?: (event: React.MouseEvent<HTMLElement, MouseEvent>) => void;
title: string;
variety?: "danger" | "warning" | "success";
};
export default function DeleteStripeDialogContent(props: PropsWithChildren<DeleteStripeDialogContentProps>) {
const { t } = useLocale();
const {
title,
variety,
cancelAllBookingsBtnText,
removeBtnText,
cancelBtnText = t("cancel"),
onConfirm,
onRemove,
children,
} = props;
return (
<DialogContent>
<div className="flex">
{variety && (
<div className="mt-0.5 ltr:mr-3">
{variety === "danger" && (
<div className="mx-auto rounded-full bg-red-100 p-2 text-center">
<ExclamationIcon className="h-5 w-5 text-red-600" />
</div>
)}
{variety === "warning" && (
<div className="mx-auto rounded-full bg-orange-100 p-2 text-center">
<ExclamationIcon className="h-5 w-5 text-orange-600" />
</div>
)}
{variety === "success" && (
<div className="mx-auto rounded-full bg-green-100 p-2 text-center">
<CheckIcon className="h-5 w-5 text-green-600" />
</div>
)}
</div>
)}
<div>
<DialogPrimitive.Title className="font-cal text-xl text-gray-900">{title}</DialogPrimitive.Title>
<DialogPrimitive.Description className="text-sm text-neutral-500">
{children}
</DialogPrimitive.Description>
</div>
</div>
<div className="mt-5 flex flex-row-reverse gap-x-2 sm:mt-8">
<DialogClose onClick={onConfirm} asChild>
<Button color="alert">{cancelAllBookingsBtnText}</Button>
</DialogClose>
<DialogClose onClick={onRemove} asChild>
<Button color="alert2">{removeBtnText}</Button>
</DialogClose>
<DialogClose asChild>
<Button color="secondary">{cancelBtnText}</Button>
</DialogClose>
</div>
</DialogContent>
);
}
@@ -0,0 +1,500 @@
import { LocationMarkerIcon } from "@heroicons/react/solid";
import { zodResolver } from "@hookform/resolvers/zod";
import { isValidPhoneNumber } from "libphonenumber-js";
import dynamic from "next/dynamic";
import { useEffect } from "react";
import { Controller, useForm, useWatch } from "react-hook-form";
import { z } from "zod";
import classNames from "@calcom/lib/classNames";
import { useLocale } from "@calcom/lib/hooks/useLocale";
import { Button } from "@calcom/ui";
import { Dialog, DialogContent } from "@calcom/ui/Dialog";
import { Form } from "@calcom/ui/form/fields";
import { QueryCell } from "@lib/QueryCell";
import { linkValueToString } from "@lib/linkValueToString";
import { LocationType } from "@lib/location";
import { LocationOptionsToString } from "@lib/locationOptions";
import { inferQueryOutput, trpc } from "@lib/trpc";
import CheckboxField from "@components/ui/form/CheckboxField";
import type PhoneInputType from "@components/ui/form/PhoneInput";
import Select from "@components/ui/form/Select";
const PhoneInput = dynamic(
() => import("@components/ui/form/PhoneInput")
) as unknown as typeof PhoneInputType;
type BookingItem = inferQueryOutput<"viewer.bookings">["bookings"][number];
type OptionTypeBase = {
label: string;
value: LocationType;
disabled?: boolean;
};
type LocationFormValues = {
locationType: LocationType;
locationAddress?: string;
locationLink?: string;
locationPhoneNumber?: string;
displayLocationPublicly?: boolean;
};
interface ISetLocationDialog {
saveLocation: (newLocationType: LocationType, details: { [key: string]: string }) => void;
selection?: OptionTypeBase;
booking?: BookingItem;
defaultValues?: {
type: LocationType;
address?: string | undefined;
link?: string | undefined;
hostPhoneNumber?: string | undefined;
displayLocationPublicly?: boolean | undefined;
}[];
setShowLocationModal: React.Dispatch<React.SetStateAction<boolean>>;
isOpenDialog: boolean;
setSelectedLocation?: (param: OptionTypeBase | undefined) => void;
}
export const EditLocationDialog = (props: ISetLocationDialog) => {
const {
saveLocation,
selection,
booking,
setShowLocationModal,
isOpenDialog,
defaultValues,
setSelectedLocation,
} = props;
const { t } = useLocale();
const locationsQuery = trpc.useQuery(["viewer.locationOptions"]);
useEffect(() => {
if (selection) {
locationFormMethods.setValue("locationType", selection?.value);
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [selection]);
const locationFormSchema = z.object({
locationType: z.string(),
locationAddress: z.string().optional(),
locationLink:
selection?.value === LocationType.Whereby
? z
.string()
.regex(/^http(s)?:\/\/www.whereby.com\/[a-zA-Z0-9]*/)
.optional()
: selection?.value === LocationType.Around
? z
.string()
.regex(/^http(s)?:\/\/www.around.co\/[a-zA-Z0-9]*/)
.optional()
: selection?.value === LocationType.Riverside
? z
.string()
.regex(/^http(s)?:\/\/www.riverside.fm\/studio\/[a-zA-Z0-9]*/)
.optional()
: z.string().url().optional(),
displayLocationPublicly: z.boolean().optional(),
locationPhoneNumber: z
.string()
.refine((val) => isValidPhoneNumber(val))
.optional(),
});
const locationFormMethods = useForm<LocationFormValues>({
mode: "onSubmit",
resolver: zodResolver(locationFormSchema),
});
const selectedLocation = useWatch({
control: locationFormMethods.control,
name: "locationType",
});
const LocationOptions =
selectedLocation === LocationType.InPerson ? (
<>
<div>
<label htmlFor="address" className="block text-sm font-medium text-gray-700">
{t("set_address_place")}
</label>
<div className="mt-1">
<input
type="text"
{...locationFormMethods.register("locationAddress")}
id="address"
required
className="block w-full rounded-sm border-gray-300 text-sm"
defaultValue={
defaultValues
? defaultValues.find(
(location: { type: LocationType }) => location.type === LocationType.InPerson
)?.address
: undefined
}
/>
</div>
{!booking && (
<div className="mt-3">
<Controller
name="displayLocationPublicly"
control={locationFormMethods.control}
render={() => (
<CheckboxField
defaultChecked={
defaultValues
? defaultValues.find((location) => location.type === LocationType.InPerson)
?.displayLocationPublicly
: undefined
}
description={t("display_location_label")}
onChange={(e) =>
locationFormMethods.setValue("displayLocationPublicly", e.target.checked)
}
informationIconText={t("display_location_info_badge")}></CheckboxField>
)}
/>
</div>
)}
</div>
</>
) : selectedLocation === LocationType.Link ? (
<div>
<label htmlFor="link" className="block text-sm font-medium text-gray-700">
{t("set_link_meeting")}
</label>
<div className="mt-1">
<input
type="text"
{...locationFormMethods.register("locationLink")}
required
id="link"
className="block w-full rounded-sm border-gray-300 sm:text-sm"
defaultValue={
defaultValues
? defaultValues.find(
(location: { type: LocationType }) => location.type === LocationType.Link
)?.link
: undefined
}
/>
{locationFormMethods.formState.errors.locationLink && (
<p className="mt-1 text-sm text-red-500">{t("url_start_with_https")}</p>
)}
</div>
{!booking && (
<div className="mt-3">
<Controller
name="displayLocationPublicly"
control={locationFormMethods.control}
render={() => (
<CheckboxField
description={t("display_location_label")}
defaultChecked={
defaultValues
? defaultValues.find((location) => location.type === LocationType.Link)
?.displayLocationPublicly
: undefined
}
onChange={(e) => locationFormMethods.setValue("displayLocationPublicly", e.target.checked)}
informationIconText={t("display_location_info_badge")}></CheckboxField>
)}
/>
</div>
)}
</div>
) : selectedLocation === LocationType.UserPhone ? (
<div>
<label htmlFor="phonenumber" className="block text-sm font-medium text-gray-700">
{t("set_your_phone_number")}
{locationFormMethods.formState?.errors?.locationPhoneNumber?.message}
</label>
<div className="mt-1">
<PhoneInput<LocationFormValues>
control={locationFormMethods.control}
name="locationPhoneNumber"
required
id="locationPhoneNumber"
placeholder={t("host_phone_number")}
defaultValue={
defaultValues
? defaultValues.find(
(location: { type: LocationType }) => location.type === LocationType.UserPhone
)?.hostPhoneNumber
: undefined
}
/>
{locationFormMethods.formState.errors.locationPhoneNumber && (
<p className="mt-1 text-sm text-red-500">Invalid input</p>
)}
</div>
</div>
) : selectedLocation === LocationType.Whereby ? (
<>
<div>
<label htmlFor="address" className="block text-sm font-medium text-gray-700">
{t("set_whereby_link")}
</label>
<div className="mt-1">
<input
type="text"
{...locationFormMethods.register("locationLink")}
id="wherebylink"
placeholder="https://www.whereby.com/cal"
required
className={"block w-full rounded-sm border-gray-300 text-sm"}
defaultValue={
defaultValues
? defaultValues.find(
(location: { type: LocationType }) => location.type === LocationType.Whereby
)?.address
: undefined
}
/>
</div>
{!booking && (
<div className="mt-3">
<Controller
name="displayLocationPublicly"
control={locationFormMethods.control}
render={() => (
<CheckboxField
defaultChecked={
defaultValues
? defaultValues.find((location) => location.type === LocationType.Whereby)
?.displayLocationPublicly
: undefined
}
description={t("display_location_label")}
onChange={(e) =>
locationFormMethods.setValue("displayLocationPublicly", e.target.checked)
}
informationIconText={t("display_location_info_badge")}></CheckboxField>
)}
/>
</div>
)}
</div>
</>
) : selectedLocation === LocationType.Around ? (
<>
<div>
<label htmlFor="address" className="block text-sm font-medium text-gray-700">
{t("set_around_link")}
</label>
<div className="mt-1">
<input
type="text"
{...locationFormMethods.register("locationLink")}
id="aroundlink"
placeholder="https://www.around.com/rick"
required
className={"block w-full rounded-sm border-gray-300 text-sm"}
defaultValue={
defaultValues
? defaultValues.find(
(location: { type: LocationType }) => location.type === LocationType.Around
)?.address
: undefined
}
/>
</div>
{!booking && (
<div className="mt-3">
<Controller
name="displayLocationPublicly"
control={locationFormMethods.control}
render={() => (
<CheckboxField
defaultChecked={
defaultValues
? defaultValues.find((location) => location.type === LocationType.Around)
?.displayLocationPublicly
: undefined
}
description={t("display_location_label")}
onChange={(e) =>
locationFormMethods.setValue("displayLocationPublicly", e.target.checked)
}
informationIconText={t("display_location_info_badge")}></CheckboxField>
)}
/>
</div>
)}
</div>
</>
) : selectedLocation === LocationType.Riverside ? (
<>
<div>
<label htmlFor="address" className="block text-sm font-medium text-gray-700">
{t("set_around_link")}
</label>
<div className="mt-1">
<input
type="text"
{...locationFormMethods.register("locationLink")}
id="aroundlink"
placeholder="https://www.riverside.fm/studio/rick"
required
className={"block w-full rounded-sm border-gray-300 text-sm"}
defaultValue={
defaultValues
? defaultValues.find(
(location: { type: LocationType }) => location.type === LocationType.Riverside
)?.address
: undefined
}
/>
</div>
{!booking && (
<div className="mt-3">
<Controller
name="displayLocationPublicly"
control={locationFormMethods.control}
render={() => (
<CheckboxField
defaultChecked={
defaultValues
? defaultValues.find((location) => location.type === LocationType.Riverside)
?.displayLocationPublicly
: undefined
}
description={t("display_location_label")}
onChange={(e) =>
locationFormMethods.setValue("displayLocationPublicly", e.target.checked)
}
informationIconText={t("display_location_info_badge")}></CheckboxField>
)}
/>
</div>
)}
</div>
</>
) : (
<p className="text-sm">{LocationOptionsToString(selectedLocation, t)}</p>
);
return (
<Dialog open={isOpenDialog}>
<DialogContent asChild>
<div className="inline-block transform rounded-sm bg-white px-4 pt-5 pb-4 text-left align-bottom shadow-xl transition-all sm:my-8 sm:w-full sm:max-w-lg sm:p-6 sm:align-middle">
<div className="mb-4 sm:flex sm:items-start">
<div className="bg-secondary-100 mx-auto flex h-12 w-12 flex-shrink-0 items-center justify-center rounded-full sm:mx-0 sm:h-10 sm:w-10">
<LocationMarkerIcon className="text-primary-600 h-6 w-6" />
</div>
<div className="mt-3 text-center sm:mt-0 sm:ml-4 sm:text-left">
<h3 className="text-lg font-medium leading-6 text-gray-900" id="modal-title">
{t("edit_location")}
</h3>
{!booking && (
<p className="text-sm text-gray-400">{t("this_input_will_shown_booking_this_event")}</p>
)}
</div>
<div className="mt-3 text-center sm:mt-0 sm:ml-4 sm:text-left"></div>
</div>
{booking && (
<>
<p className="mt-6 mb-2 ml-1 text-sm font-bold text-black">{t("current_location")}:</p>
<p className="mb-2 ml-1 text-sm text-black">{linkValueToString(booking.location, t)}</p>
</>
)}
<Form
form={locationFormMethods}
handleSubmit={async (values) => {
const { locationType: newLocation, displayLocationPublicly } = values;
let details = {};
if (newLocation === LocationType.InPerson) {
details = {
address: values.locationAddress,
displayLocationPublicly,
};
}
if (
newLocation === LocationType.Link ||
newLocation === LocationType.Whereby ||
newLocation === LocationType.Around ||
newLocation === LocationType.Riverside
) {
details = { link: values.locationLink, displayLocationPublicly };
}
if (newLocation === LocationType.UserPhone) {
details = { hostPhoneNumber: values.locationPhoneNumber };
}
saveLocation(newLocation, details);
setShowLocationModal(false);
setSelectedLocation?.(undefined);
locationFormMethods.unregister([
"locationType",
"locationLink",
"locationAddress",
"locationPhoneNumber",
]);
}}>
<QueryCell
query={locationsQuery}
success={({ data: locationOptions }) => {
if (!locationOptions.length) return null;
return (
<Controller
name="locationType"
control={locationFormMethods.control}
render={() => (
<Select
maxMenuHeight={150}
name="location"
defaultValue={selection}
options={
booking
? locationOptions.filter((location) => location.value !== "phone")
: locationOptions
}
isSearchable={false}
className="my-4 block w-full min-w-0 flex-1 rounded-sm border border-gray-300 sm:text-sm"
onChange={(val) => {
if (val) {
locationFormMethods.setValue("locationType", val.value);
locationFormMethods.unregister([
"locationLink",
"locationAddress",
"locationPhoneNumber",
]);
locationFormMethods.clearErrors([
"locationLink",
"locationPhoneNumber",
"locationAddress",
]);
setSelectedLocation?.(val);
}
}}
/>
)}
/>
);
}}
/>
{selectedLocation && LocationOptions}
<div className="mt-4 flex justify-end space-x-2">
<Button
onClick={() => {
setShowLocationModal(false);
setSelectedLocation?.(undefined);
locationFormMethods.unregister("locationType");
}}
type="button"
color="secondary">
{t("cancel")}
</Button>
<Button type="submit">{t("update")}</Button>
</div>
</Form>
</div>
</DialogContent>
</Dialog>
);
};
@@ -1,4 +1,4 @@
import { ClockIcon, XIcon } from "@heroicons/react/outline";
import { ClockIcon } from "@heroicons/react/outline";
import { RescheduleResponse } from "pages/api/book/request-reschedule";
import React, { useState, Dispatch, SetStateAction } from "react";
import { useMutation } from "react-query";
@@ -77,7 +77,7 @@ export const RescheduleDialog = (props: IRescheduleDialog) => {
/>
<DialogFooter>
<DialogClose>
<DialogClose asChild>
<Button color="secondary">{t("cancel")}</Button>
</DialogClose>
<Button
@@ -56,23 +56,32 @@ export default function CreateEventTypeButton(props: Props) {
: undefined;
const pageSlug = router.query.eventPage || props.options[0].slug;
const hasTeams = !!props.options.find((option) => option.teamId);
const title: string =
typeof router.query.title === "string" && router.query.title ? router.query.title : "";
const length: number =
typeof router.query.length === "string" && router.query.length ? parseInt(router.query.length) : 15;
const description: string =
typeof router.query.description === "string" && router.query.description ? router.query.description : "";
const slug: string = typeof router.query.slug === "string" && router.query.slug ? router.query.slug : "";
const type: string = typeof router.query.type == "string" && router.query.type ? router.query.type : "";
const form = useForm<z.infer<typeof createEventTypeInput>>({
resolver: zodResolver(createEventTypeInput),
});
const { setValue, watch, register } = form;
setValue("title", title);
setValue("length", length);
setValue("description", description);
setValue("slug", slug);
useEffect(() => {
if (!router.isReady) return;
const title: string =
typeof router.query.title === "string" && router.query.title ? router.query.title : "";
const length: number =
typeof router.query.length === "string" && router.query.length ? parseInt(router.query.length) : 15;
const description: string =
typeof router.query.description === "string" && router.query.description
? router.query.description
: "";
const slug: string = typeof router.query.slug === "string" && router.query.slug ? router.query.slug : "";
setValue("title", title);
setValue("length", length);
setValue("description", description);
setValue("slug", slug);
// If query params change, update the form
}, [router.isReady, router.query, setValue]);
useEffect(() => {
const subscription = watch((value, { name, type }) => {
@@ -86,7 +95,7 @@ export default function CreateEventTypeButton(props: Props) {
const createMutation = trpc.useMutation("viewer.eventTypes.create", {
onSuccess: async ({ eventType }) => {
await router.push("/event-types/" + eventType.id);
await router.replace("/event-types/" + eventType.id);
showToast(t("event_type_created_successfully", { eventTypeTitle: eventType.title }), "success");
},
onError: (err) => {
@@ -95,6 +104,11 @@ export default function CreateEventTypeButton(props: Props) {
showToast(message, "error");
}
if (err.data?.code === "BAD_REQUEST") {
const message = `${err.data.code}: URL already exists.`;
showToast(message, "error");
}
if (err.data?.code === "UNAUTHORIZED") {
const message = `${err.data.code}: You are not able to create this event`;
showToast(message, "error");
@@ -1,21 +1,23 @@
import { ClockIcon, CreditCardIcon, UserIcon, UsersIcon } from "@heroicons/react/solid";
import { SchedulingType } from "@prisma/client";
import { Prisma } from "@prisma/client";
import React from "react";
import {
ClipboardCheckIcon,
ClockIcon,
CreditCardIcon,
RefreshIcon,
UserIcon,
UsersIcon,
} from "@heroicons/react/solid";
import { Prisma, SchedulingType } from "@prisma/client";
import { useMemo } from "react";
import { FormattedNumber, IntlProvider } from "react-intl";
import { parseRecurringEvent } from "@calcom/lib";
import { useLocale } from "@calcom/lib/hooks/useLocale";
import { baseEventTypeSelect } from "@calcom/prisma/selects";
import classNames from "@lib/classNames";
import { useLocale } from "@lib/hooks/useLocale";
const eventTypeData = Prisma.validator<Prisma.EventTypeArgs>()({
select: {
id: true,
length: true,
price: true,
currency: true,
schedulingType: true,
description: true,
},
select: baseEventTypeSelect,
});
type EventType = Prisma.EventTypeGetPayload<typeof eventTypeData>;
@@ -28,6 +30,11 @@ export type EventTypeDescriptionProps = {
export const EventTypeDescription = ({ eventType, className }: EventTypeDescriptionProps) => {
const { t } = useLocale();
const recurringEvent = useMemo(
() => parseRecurringEvent(eventType.recurringEvent),
[eventType.recurringEvent]
);
return (
<>
<div className={classNames("text-neutral-500 dark:text-white", className)}>
@@ -37,26 +44,34 @@ export const EventTypeDescription = ({ eventType, className }: EventTypeDescript
{eventType.description.length > 100 && "..."}
</h2>
)}
<ul className="mt-2 flex space-x-4 rtl:space-x-reverse ">
<li className="flex whitespace-nowrap">
<ClockIcon className="mt-0.5 mr-1.5 inline h-4 w-4 text-neutral-400" aria-hidden="true" />
<ul className="mt-2 flex flex-wrap sm:flex-nowrap">
<li className="mr-4 mb-1 flex items-center whitespace-nowrap">
<ClockIcon className="mr-1.5 inline h-4 w-4 text-neutral-400" aria-hidden="true" />
{eventType.length}m
</li>
{eventType.schedulingType ? (
<li className="flex whitespace-nowrap">
<UsersIcon className="mt-0.5 mr-1.5 inline h-4 w-4 text-neutral-400" aria-hidden="true" />
<li className="mr-4 mb-1 flex items-center whitespace-nowrap">
<UsersIcon className="mr-1.5 inline h-4 w-4 text-neutral-400" aria-hidden="true" />
{eventType.schedulingType === SchedulingType.ROUND_ROBIN && t("round_robin")}
{eventType.schedulingType === SchedulingType.COLLECTIVE && t("collective")}
</li>
) : (
<li className="flex whitespace-nowrap">
<UserIcon className="mt-0.5 mr-1.5 inline h-4 w-4 text-neutral-400" aria-hidden="true" />
<li className="mr-4 mb-1 flex items-center whitespace-nowrap">
<UserIcon className="mr-1.5 inline h-4 w-4 text-neutral-400" aria-hidden="true" />
{t("1_on_1")}
</li>
)}
{recurringEvent?.count && recurringEvent.count > 0 && (
<li className="mr-4 mb-1 flex items-center whitespace-nowrap">
<RefreshIcon className="mr-1.5 inline h-4 w-4 text-neutral-400" aria-hidden="true" />
{t("repeats_up_to", {
count: recurringEvent.count,
})}
</li>
)}
{eventType.price > 0 && (
<li className="flex whitespace-nowrap">
<CreditCardIcon className="mt-0.5 mr-1.5 inline h-4 w-4 text-neutral-400" aria-hidden="true" />
<li className="mr-4 mb-1 flex items-center whitespace-nowrap">
<CreditCardIcon className="mr-1.5 inline h-4 w-4 text-neutral-400" aria-hidden="true" />
<IntlProvider locale="en">
<FormattedNumber
value={eventType.price / 100.0}
@@ -66,6 +81,12 @@ export const EventTypeDescription = ({ eventType, className }: EventTypeDescript
</IntlProvider>
</li>
)}
{eventType.requiresConfirmation && (
<li className="mr-4 mb-1 flex items-center whitespace-nowrap">
<ClipboardCheckIcon className="mr-1.5 inline h-4 w-4 text-neutral-400" aria-hidden="true" />
{t("requires_confirmation")}
</li>
)}
</ul>
</div>
</>
@@ -0,0 +1,141 @@
import type { FormValues } from "pages/event-types/[type]";
import { useState } from "react";
import { UseFormReturn } from "react-hook-form";
import { useLocale } from "@calcom/lib/hooks/useLocale";
import { Frequency } from "@calcom/prisma/zod-utils";
import { RecurringEvent } from "@calcom/types/Calendar";
import { Alert } from "@calcom/ui/Alert";
import Select from "@components/ui/form/Select";
type RecurringEventControllerProps = {
recurringEvent: RecurringEvent | null;
formMethods: UseFormReturn<FormValues>;
paymentEnabled: boolean;
onRecurringEventDefined: (value: boolean) => void;
};
export default function RecurringEventController({
recurringEvent,
formMethods,
paymentEnabled,
onRecurringEventDefined,
}: RecurringEventControllerProps) {
const { t } = useLocale();
const [recurringEventState, setRecurringEventState] = useState<RecurringEvent | null>(recurringEvent);
/* Just yearly-0, monthly-1 and weekly-2 */
const recurringEventFreqOptions = Object.entries(Frequency)
.filter(([key, value]) => isNaN(Number(key)) && Number(value) < 3)
.map(([key, value]) => ({
label: t(`${key.toString().toLowerCase()}`, { count: recurringEventState?.interval }),
value: value.toString(),
}));
return (
<div className="block items-start sm:flex">
<div className="min-w-48 mb-4 sm:mb-0">
<span className="flex text-sm font-medium text-neutral-700">{t("recurring_event")}</span>
</div>
<div className={!paymentEnabled ? "w-full" : ""}>
{paymentEnabled ? (
<Alert severity="warning" title={t("warning_payment_recurring_event")} />
) : (
<>
<div className="relative flex items-start">
<div className="flex h-5 items-center">
<input
onChange={(event) => {
onRecurringEventDefined(event?.target.checked);
if (!event?.target.checked) {
formMethods.setValue("recurringEvent", null);
setRecurringEventState(null);
} else {
const newVal = recurringEvent || {
interval: 1,
count: 12,
freq: Frequency.WEEKLY,
};
formMethods.setValue("recurringEvent", newVal);
setRecurringEventState(newVal);
}
}}
type="checkbox"
className="text-primary-600 h-4 w-4 rounded border-gray-300"
defaultChecked={recurringEventState !== null}
data-testid="recurring-event-check"
id="recurringEvent"
/>
</div>
<div className="text-sm ltr:ml-3 rtl:mr-3">
<label htmlFor="recurringEvent" className="text-neutral-900">
{t("recurring_event_description")}
</label>
</div>
</div>
{recurringEventState && (
<div data-testid="recurring-event-collapsible" className="mt-4 text-sm">
<div className="flex items-center">
<p className="mr-2 text-neutral-900">{t("repeats_every")}</p>
<input
type="number"
min="1"
max="20"
className="block w-16 rounded-sm border-gray-300 shadow-sm [appearance:textfield] ltr:mr-2 rtl:ml-2 sm:text-sm"
defaultValue={recurringEventState.interval}
onChange={(event) => {
const newVal = {
...recurringEventState,
interval: parseInt(event?.target.value),
};
formMethods.setValue("recurringEvent", newVal);
setRecurringEventState(newVal);
}}
/>
<Select
options={recurringEventFreqOptions}
value={recurringEventFreqOptions[recurringEventState.freq]}
isSearchable={false}
className="w-18 block min-w-0 rounded-sm sm:text-sm"
onChange={(event) => {
const newVal = {
...recurringEventState,
freq: parseInt(event?.value || `${Frequency.WEEKLY}`),
};
formMethods.setValue("recurringEvent", newVal);
setRecurringEventState(newVal);
}}
/>
</div>
<div className="mt-4 flex items-center">
<p className="mr-2 text-neutral-900">{t("max")}</p>
<input
type="number"
min="1"
max="20"
className="block w-16 rounded-sm border-gray-300 shadow-sm [appearance:textfield] ltr:mr-2 rtl:ml-2 sm:text-sm"
defaultValue={recurringEventState.count}
onChange={(event) => {
const newVal = {
...recurringEventState,
count: parseInt(event?.target.value),
};
formMethods.setValue("recurringEvent", newVal);
setRecurringEventState(newVal);
}}
/>
<p className="mr-2 text-neutral-900">
{t("occurrence", {
count: recurringEventState.count,
})}
</p>
</div>
</div>
)}
</>
)}
</div>
</div>
);
}
@@ -0,0 +1,63 @@
import { LinkIcon } from "@heroicons/react/outline";
import { ClockIcon, DotsHorizontalIcon, ExternalLinkIcon, UserIcon } from "@heroicons/react/solid";
import React from "react";
import { SkeletonAvatar, SkeletonContainer, SkeletonText } from "@calcom/ui";
function SkeletonLoader() {
return (
<SkeletonContainer>
<div className="mb-4 flex items-center">
<SkeletonAvatar width="8" height="8"></SkeletonAvatar>
<div className="space-y-1">
<SkeletonText height="4" width="16"></SkeletonText>
<SkeletonText height="4" width="24"></SkeletonText>
</div>
</div>
<ul className="divide-y divide-neutral-200 border border-gray-200 bg-white sm:mx-0 sm:overflow-hidden">
<SkeletonItem />
<SkeletonItem />
<SkeletonItem />
</ul>
</SkeletonContainer>
);
}
export default SkeletonLoader;
function SkeletonItem() {
return (
<li className="group flex w-full items-center justify-between px-4 py-4 sm:px-6">
<div className="flex-grow truncate text-sm">
<div>
<SkeletonText width="32" height="5"></SkeletonText>
</div>
<div className="">
<ul className="mt-2 flex space-x-4 rtl:space-x-reverse ">
<li className="flex items-center whitespace-nowrap">
<ClockIcon className="mt-0.5 mr-1.5 inline h-4 w-4 text-gray-200"></ClockIcon>
<SkeletonText width="12" height="4"></SkeletonText>
</li>
<li className="flex items-center whitespace-nowrap">
<UserIcon className="mt-0.5 mr-1.5 inline h-4 w-4 text-gray-200"></UserIcon>
<SkeletonText width="16" height="4"></SkeletonText>
</li>
</ul>
</div>
</div>
<div className="mt-4 hidden flex-shrink-0 sm:mt-0 sm:ml-5 sm:flex">
<div className="flex justify-between rtl:space-x-reverse">
<div className="btn-icon appearance-none">
<ExternalLinkIcon className="h-5 w-5" />
</div>
<div className="btn-icon appearance-none">
<LinkIcon className="h-5 w-5" />
</div>
<div className="btn-icon appearance-none">
<DotsHorizontalIcon className="h-5 w-5" />
</div>
</div>
</div>
</li>
);
}
@@ -2,18 +2,20 @@ import { Fragment } from "react";
import { useMutation } from "react-query";
import { InstallAppButton } from "@calcom/app-store/components";
import { useLocale } from "@calcom/lib/hooks/useLocale";
import showToast from "@calcom/lib/notification";
import { Alert } from "@calcom/ui/Alert";
import Button from "@calcom/ui/Button";
import Switch from "@calcom/ui/Switch";
import { QueryCell } from "@lib/QueryCell";
import { useLocale } from "@lib/hooks/useLocale";
import { trpc } from "@lib/trpc";
import { inferQueryOutput, trpc } from "@lib/trpc";
import AdditionalCalendarSelector from "@components/AdditionalCalendarSelector";
import DestinationCalendarSelector from "@components/DestinationCalendarSelector";
import { List } from "@components/List";
import { ShellSubHeading } from "@components/Shell";
import SkeletonLoader from "@components/apps/SkeletonLoader";
import DisconnectIntegration from "./DisconnectIntegration";
import IntegrationListItem from "./IntegrationListItem";
@@ -21,6 +23,7 @@ import SubHeadingTitleWithConnections from "./SubHeadingTitleWithConnections";
type Props = {
onChanged: () => unknown | Promise<unknown>;
fromOnboarding?: boolean;
};
function CalendarSwitch(props: {
@@ -92,10 +95,44 @@ function CalendarSwitch(props: {
);
}
function CalendarList(props: Props) {
const { t } = useLocale();
const query = trpc.useQuery(["viewer.integrations", { variant: "calendar", onlyInstalled: false }]);
return (
<QueryCell
query={query}
success={({ data }) => (
<List>
{data.items.map((item) => (
<IntegrationListItem
key={item.title}
title={item.title}
imageSrc={item.imageSrc}
description={item.description}
actions={
<InstallAppButton
type={item.type}
render={(buttonProps) => (
<Button color="secondary" {...buttonProps}>
{t("connect")}
</Button>
)}
onChanged={() => props.onChanged()}
/>
}
/>
))}
</List>
)}
/>
);
}
function ConnectedCalendarsList(props: Props) {
const { t } = useLocale();
const query = trpc.useQuery(["viewer.connectedCalendars"], { suspense: true });
const { fromOnboarding } = props;
return (
<QueryCell
query={query}
@@ -124,22 +161,27 @@ function ConnectedCalendarsList(props: Props) {
onOpenChange={props.onChanged}
/>
}>
<ul className="space-y-2 p-4">
{item.calendars.map((cal) => (
<CalendarSwitch
key={cal.externalId}
externalId={cal.externalId}
title={cal.name || "Nameless calendar"}
type={item.integration.type}
defaultSelected={cal.isSelected}
/>
))}
</ul>
{!fromOnboarding && (
<>
<p className="px-4 pt-4 text-sm text-neutral-500">{t("toggle_calendars_conflict")}</p>
<ul className="space-y-2 p-4">
{item.calendars.map((cal) => (
<CalendarSwitch
key={cal.externalId}
externalId={cal.externalId}
title={cal.name || "Nameless calendar"}
type={item.integration.type}
defaultSelected={cal.isSelected}
/>
))}
</ul>
</>
)}
</IntegrationListItem>
) : (
<Alert
severity="warning"
title="Something went wrong"
title={t("calendar_error")}
message={item.error?.message}
actions={
<DisconnectIntegration
@@ -163,83 +205,82 @@ function ConnectedCalendarsList(props: Props) {
);
}
function CalendarList(props: Props) {
export function CalendarListContainer(props: {
heading?: boolean;
items?: inferQueryOutput<"viewer.integrations">["items"];
fromOnboarding?: boolean;
}) {
const { t } = useLocale();
const query = trpc.useQuery(["viewer.integrations"]);
return (
<QueryCell
query={query}
success={({ data }) => (
<List>
{data.calendar.items.map((item) => (
<IntegrationListItem
key={item.title}
title={item.title}
imageSrc={item.imageSrc}
description={item.description}
actions={
<InstallAppButton
type={item.type}
render={(buttonProps) => (
<Button color="secondary" {...buttonProps}>
{t("connect")}
</Button>
)}
onChanged={() => props.onChanged()}
/>
}
/>
))}
</List>
)}
/>
);
}
export function CalendarListContainer(props: { heading?: false }) {
const { t } = useLocale();
const { heading = true } = props;
const { heading = true, fromOnboarding } = props;
const utils = trpc.useContext();
const onChanged = () =>
Promise.allSettled([
utils.invalidateQueries(["viewer.integrations"]),
utils.invalidateQueries(["viewer.integrations", { variant: "calendar", onlyInstalled: true }], {
exact: true,
}),
utils.invalidateQueries(["viewer.connectedCalendars"]),
]);
const query = trpc.useQuery(["viewer.connectedCalendars"]);
const installedCalendars = trpc.useQuery([
"viewer.integrations",
{ variant: "calendar", onlyInstalled: true },
]);
const mutation = trpc.useMutation("viewer.setDestinationCalendar");
return (
<>
{heading && (
<ShellSubHeading
className="mt-10 mb-0"
title={
<SubHeadingTitleWithConnections
title="Calendars"
numConnections={query.data?.connectedCalendars.length}
/>
}
subtitle={t("configure_how_your_event_types_interact")}
actions={
<div className="sm:min-w-80 block max-w-full">
<DestinationCalendarSelector
onChange={mutation.mutate}
isLoading={mutation.isLoading}
value={query.data?.destinationCalendar?.externalId}
/>
</div>
}
/>
)}
<ConnectedCalendarsList onChanged={onChanged} />
{!!query.data?.connectedCalendars.length && (
<ShellSubHeading
className="mt-6"
title={<SubHeadingTitleWithConnections title={t("connect_an_additional_calendar")} />}
/>
)}
<CalendarList onChanged={onChanged} />
</>
<QueryCell
query={query}
customLoader={<SkeletonLoader className="mt-10" />}
success={({ data }) => {
return (
<>
{(!!data.connectedCalendars.length || !!installedCalendars.data?.items.length) && (
<>
{heading && (
<ShellSubHeading
className="mt-10 mb-0"
title={
<SubHeadingTitleWithConnections
title="Calendars"
numConnections={data.connectedCalendars.length}
/>
}
subtitle={t("configure_how_your_event_types_interact")}
actions={
<div className="flex flex-col xl:flex-row xl:space-x-5">
<div className="sm:min-w-80 block max-w-full">
<DestinationCalendarSelector
onChange={mutation.mutate}
isLoading={mutation.isLoading}
value={data.destinationCalendar?.externalId}
/>
</div>
{!!data.connectedCalendars.length && (
<div className="sm:min-w-80 inline max-w-full">
<AdditionalCalendarSelector isLoading={mutation.isLoading} />
</div>
)}
</div>
}
/>
)}
<ConnectedCalendarsList onChanged={onChanged} fromOnboarding={fromOnboarding} />
</>
)}
{fromOnboarding && (
<>
{!!query.data?.connectedCalendars.length && (
<ShellSubHeading
className="mt-4"
title={<SubHeadingTitleWithConnections title={t("connect_additional_calendar")} />}
/>
)}
<CalendarList onChanged={onChanged} />
</>
)}
</>
);
}}
/>
);
}
@@ -1,10 +1,13 @@
import { useState } from "react";
import { useMutation } from "react-query";
import { useLocale } from "@calcom/lib/hooks/useLocale";
import showToast from "@calcom/lib/notification";
import { ButtonBaseProps } from "@calcom/ui/Button";
import { Dialog } from "@calcom/ui/Dialog";
import { trpc } from "@lib/trpc";
import ConfirmationDialogContent from "@components/dialog/ConfirmationDialogContent";
export default function DisconnectIntegration(props: {
@@ -13,43 +16,35 @@ export default function DisconnectIntegration(props: {
render: (renderProps: ButtonBaseProps) => JSX.Element;
onOpenChange: (isOpen: boolean) => unknown | Promise<unknown>;
}) {
const { id } = props;
const { t } = useLocale();
const [modalOpen, setModalOpen] = useState(false);
const mutation = useMutation(
async () => {
const res = await fetch("/api/integrations", {
method: "DELETE",
body: JSON.stringify({ id: props.id }),
headers: {
"Content-Type": "application/json",
},
});
if (!res.ok) {
throw new Error("Something went wrong");
}
return res.json();
const mutation = trpc.useMutation("viewer.deleteCredential", {
onSettled: async () => {
await props.onOpenChange(modalOpen);
},
{
async onSettled() {
await props.onOpenChange(modalOpen);
},
onSuccess(data) {
showToast(data.message, "success");
setModalOpen(false);
},
}
);
onSuccess: () => {
showToast("Integration deleted successfully", "success");
setModalOpen(false);
},
onError: () => {
throw new Error("Something went wrong");
},
});
return (
<>
<Dialog open={modalOpen} onOpenChange={setModalOpen}>
<ConfirmationDialogContent
variety="danger"
title="Disconnect Integration"
confirmBtnText="Yes, disconnect integration"
title={t("remove_app")}
confirmBtnText={t("yes_remove_app")}
cancelBtnText="Cancel"
onConfirm={() => {
mutation.mutate();
mutation.mutate({ id });
}}>
Are you sure you want to disconnect this integration?
{t("are_you_sure_you_want_to_remove_this_app")}
</ConfirmationDialogContent>
</Dialog>
{props.render({
@@ -0,0 +1,69 @@
import { useState } from "react";
import { useMutation } from "react-query";
import showToast from "@calcom/lib/notification";
import { ButtonBaseProps } from "@calcom/ui/Button";
import { Dialog } from "@calcom/ui/Dialog";
import DeleteStripeDialogContent from "@components/dialog/DeleteStripeDialogContent";
export default function DisconnectStripeIntegration(props: {
/** Integration credential id */
id: number;
render: (renderProps: ButtonBaseProps) => JSX.Element;
onOpenChange: (isOpen: boolean) => unknown | Promise<unknown>;
}) {
const [modalOpen, setModalOpen] = useState(false);
const mutation = useMutation(
async (action: string) => {
const res = await fetch("/api/integrations", {
method: "DELETE",
body: JSON.stringify({ id: props.id, action }),
headers: {
"Content-Type": "application/json",
},
});
if (!res.ok) {
throw new Error("Something went wrong");
}
return res.json();
},
{
async onSettled() {
await props.onOpenChange(modalOpen);
},
onSuccess(data) {
showToast(data.message, "success");
setModalOpen(false);
},
}
);
return (
<>
<Dialog open={modalOpen} onOpenChange={setModalOpen}>
<DeleteStripeDialogContent
variety="warning"
title="Disconnect Stripe Integration"
cancelAllBookingsBtnText="Cancel all bookings"
removeBtnText="Remove payment"
cancelBtnText="Cancel"
onConfirm={() => {
mutation.mutate("cancel");
}}
onRemove={() => {
mutation.mutate("remove");
}}>
If you have unpaid and unconfirmed bookings, you must choose to cancel them or remove the required
payment field.
</DeleteStripeDialogContent>
</Dialog>
{props.render({
onClick() {
setModalOpen(true);
},
disabled: modalOpen,
loading: mutation.isLoading,
})}
</>
);
}
@@ -14,7 +14,10 @@ function IntegrationListItem(props: {
return (
<ListItem expanded={!!props.children} className={classNames("flex-col")}>
<div className={classNames("flex w-full flex-1 items-center space-x-2 p-3 rtl:space-x-reverse")}>
{props.imageSrc && <img className="h-10 w-10" src={props.imageSrc} alt={props.title} />}
{
// eslint-disable-next-line @next/next/no-img-element
props.imageSrc && <img className="h-10 w-10" src={props.imageSrc} alt={props.title} />
}
<div className="flex-grow truncate pl-2">
<ListItemTitle component="h3">{props.title}</ListItemTitle>
<ListItemText component="p">{props.description}</ListItemText>
@@ -35,7 +35,7 @@ const CustomInputTypeForm: FC<Props> = (props) => {
defaultValues,
});
const selectedInputType = useWatch({ name: "type", control });
const selectedInputOption = inputOptions.find((e) => selectedInputType === e.value)!;
const selectedInputOption = inputOptions.find((e) => selectedInputType === e.value);
const onCancel = () => {
props.onCancel();
@@ -56,13 +56,13 @@ const ChangePasswordSection = () => {
return (
<>
<div className="mt-6">
<h2 className="font-cal text-lg font-medium leading-6 text-gray-900">{t("change_password")}</h2>
</div>
<form className="divide-y divide-gray-200 lg:col-span-9" onSubmit={changePasswordHandler}>
<div className="py-6 lg:pb-8">
<div className="flex">
<div className="w-1/2 ltr:mr-2 rtl:ml-2">
<div className="py-6 lg:pb-5">
<div className="my-3">
<h2 className="font-cal text-lg font-medium leading-6 text-gray-900">{t("change_password")}</h2>
</div>
<div className="flex flex-col space-y-2 sm:flex-row sm:space-y-0">
<div className="w-full ltr:mr-2 rtl:ml-2 sm:w-1/2">
<label htmlFor="current_password" className="block text-sm font-medium text-gray-700">
{t("current_password")}
</label>
@@ -79,7 +79,7 @@ const ChangePasswordSection = () => {
/>
</div>
</div>
<div className="ml-2 w-1/2">
<div className="w-full sm:w-1/2">
<label htmlFor="new_password" className="block text-sm font-medium text-gray-700">
{t("new_password")}
</label>
@@ -98,10 +98,11 @@ const ChangePasswordSection = () => {
</div>
</div>
{errorMessage && <p className="mt-1 text-sm text-red-700">{errorMessage}</p>}
<div className="flex justify-end py-8">
<Button type="submit">{t("save")}</Button>
<div className="flex py-8 sm:justify-end">
<Button color="secondary" type="submit">
{t("save")}
</Button>
</div>
<hr className="mt-4" />
</div>
</form>
</>
@@ -0,0 +1,55 @@
import { useLocale } from "@calcom/lib/hooks/useLocale";
import showToast from "@calcom/lib/notification";
import Button from "@calcom/ui/Button";
import { trpc } from "@lib/trpc";
import Badge from "@components/ui/Badge";
const DisableUserImpersonation = ({ disableImpersonation }: { disableImpersonation: boolean }) => {
const utils = trpc.useContext();
const { t } = useLocale();
const mutation = trpc.useMutation("viewer.updateProfile", {
onSuccess: async () => {
showToast(t("your_user_profile_updated_successfully"), "success");
await utils.invalidateQueries(["viewer.me"]);
},
async onSettled() {
await utils.invalidateQueries(["viewer.public.i18n"]);
},
});
return (
<>
<div className="flex flex-col justify-between pt-9 pl-2 sm:flex-row">
<div>
<div className="flex flex-row items-center">
<h2 className="font-cal text-lg font-medium leading-6 text-gray-900">
{t("user_impersonation_heading")}
</h2>
<Badge className="ml-2 text-xs" variant={!disableImpersonation ? "success" : "gray"}>
{!disableImpersonation ? t("enabled") : t("disabled")}
</Badge>
</div>
<p className="mt-1 text-sm text-gray-500">{t("user_impersonation_description")}</p>
</div>
<div className="mt-5 sm:mt-0 sm:self-center">
<Button
type="submit"
color="secondary"
onClick={() =>
!disableImpersonation
? mutation.mutate({ disableImpersonation: true })
: mutation.mutate({ disableImpersonation: false })
}>
{!disableImpersonation ? t("disable") : t("enable")}
</Button>
</div>
</div>
</>
);
};
export default DisableUserImpersonation;
@@ -150,7 +150,10 @@ const EnableTwoFactorModal = ({ onEnable, onCancel }: EnableTwoFactorModalProps)
<WithStep step={SetupStep.DisplayQrCode} current={step}>
<>
<div className="flex justify-center">
<img src={dataUri} />
{
// eslint-disable-next-line @next/next/no-img-element
<img src={dataUri} alt="" />
}
</div>
<p className="text-center font-mono text-xs">{secret}</p>
</>
@@ -173,6 +176,7 @@ const EnableTwoFactorModal = ({ onEnable, onCancel }: EnableTwoFactorModalProps)
inputMode="numeric"
onInput={(e) => setTotpCode(e.currentTarget.value)}
className="block w-full rounded-sm border-gray-300 shadow-sm sm:text-sm"
autoComplete="one-time-code"
/>
</div>
@@ -17,21 +17,25 @@ const TwoFactorAuthSection = ({ twoFactorEnabled }: { twoFactorEnabled: boolean
return (
<>
<div className="flex flex-row items-center">
<h2 className="font-cal text-lg font-medium leading-6 text-gray-900">{t("2fa")}</h2>
<Badge className="ml-2 text-xs" variant={enabled ? "success" : "gray"}>
{enabled ? t("enabled") : t("disabled")}
</Badge>
<div className="flex flex-col justify-between pt-9 pl-2 sm:flex-row">
<div>
<div className="flex flex-row items-center">
<h2 className="font-cal text-lg font-medium leading-6 text-gray-900">{t("2fa")}</h2>
<Badge className="ml-2 text-xs" variant={enabled ? "success" : "gray"}>
{enabled ? t("enabled") : t("disabled")}
</Badge>
</div>
<p className="mt-1 text-sm text-gray-500">{t("add_an_extra_layer_of_security")}</p>
</div>
<div className="mt-5 sm:mt-0 sm:self-center">
<Button
type="submit"
color="secondary"
onClick={() => (enabled ? setDisableModalOpen(true) : setEnableModalOpen(true))}>
{enabled ? t("disable") : t("enable")}
</Button>
</div>
</div>
<p className="mt-1 text-sm text-gray-500">{t("add_an_extra_layer_of_security")}</p>
<Button
className="mt-6"
type="submit"
onClick={() => (enabled ? setDisableModalOpen(true) : setEnableModalOpen(true))}>
{enabled ? t("disable") : t("enable")} {t("2fa")}
</Button>
{enableModalOpen && (
<EnableTwoFactorModal
onEnable={() => {
@@ -1,6 +1,5 @@
import { MembershipRole } from "@prisma/client";
import { useState } from "react";
import React, { SyntheticEvent, useEffect } from "react";
import { SyntheticEvent, useMemo, useState } from "react";
import { useLocale } from "@calcom/lib/hooks/useLocale";
import Button from "@calcom/ui/Button";
@@ -11,31 +10,44 @@ import ModalContainer from "@components/ui/ModalContainer";
import Select from "@components/ui/form/Select";
type MembershipRoleOption = {
label: string;
value: MembershipRole;
label?: string;
};
const options: MembershipRoleOption[] = [{ value: "MEMBER" }, { value: "ADMIN" }];
export default function MemberChangeRoleModal(props: {
isOpen: boolean;
currentMember: MembershipRole;
memberId: number;
teamId: number;
initialRole: MembershipRole;
onExit: () => void;
}) {
useEffect(() => {
options.forEach((option, i) => {
options[i].label = t(option.value.toLowerCase());
});
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);
const { t } = useLocale();
const [role, setRole] = useState(
options.find((option) => option.value === props.initialRole || MembershipRole.MEMBER)!
const options = useMemo(() => {
return [
{
label: t("member"),
value: MembershipRole.MEMBER,
},
{
label: t("admin"),
value: MembershipRole.ADMIN,
},
{
label: t("owner"),
value: MembershipRole.OWNER,
},
].filter(({ value }) => value !== MembershipRole.OWNER || props.currentMember === MembershipRole.OWNER);
}, [t, props.currentMember]);
const [role, setRole] = useState<MembershipRoleOption>(
options.find((option) => option.value === props.initialRole) || {
label: t("member"),
value: MembershipRole.MEMBER,
}
);
const [errorMessage, setErrorMessage] = useState("");
const { t } = useLocale();
const utils = trpc.useContext();
const changeRoleMutation = trpc.useMutation("viewer.teams.changeMemberRole", {
@@ -57,7 +69,6 @@ export default function MemberChangeRoleModal(props: {
role: role.value,
});
}
return (
<ModalContainer isOpen={props.isOpen} onExit={props.onExit}>
<>
@@ -1,10 +1,10 @@
import { UserIcon } from "@heroicons/react/outline";
import { InformationCircleIcon } from "@heroicons/react/solid";
import { MembershipRole } from "@prisma/client";
import React, { useState, useEffect, SyntheticEvent, useMemo } from "react";
import React, { useState, SyntheticEvent, useMemo } from "react";
import Button from "@calcom/ui/Button";
import { Dialog, DialogContent, DialogFooter, DialogHeader } from "@calcom/ui/Dialog";
import { Dialog, DialogContent, DialogFooter } from "@calcom/ui/Dialog";
import { TextField } from "@calcom/ui/form/fields";
import { useLocale } from "@lib/hooks/useLocale";
@@ -16,6 +16,7 @@ import Select from "@components/ui/form/Select";
type MemberInvitationModalProps = {
isOpen: boolean;
team: TeamWithMembers | null;
currentMember: MembershipRole;
onExit: () => void;
};
@@ -24,7 +25,7 @@ type MembershipRoleOption = {
label?: string;
};
const _options: MembershipRoleOption[] = [{ value: "MEMBER" }, { value: "ADMIN" }];
const _options: MembershipRoleOption[] = [{ value: "MEMBER" }, { value: "ADMIN" }, { value: "OWNER" }];
export default function MemberInvitationModal(props: MemberInvitationModalProps) {
const [errorMessage, setErrorMessage] = useState("");
@@ -100,7 +101,7 @@ export default function MemberInvitationModal(props: MemberInvitationModalProps)
</label>
<Select
defaultValue={options[0]}
options={options}
options={props.currentMember !== MembershipRole.OWNER ? options.slice(0, 2) : options}
id="role"
name="role"
className="mt-1 block w-full rounded-sm border-gray-300 shadow-sm sm:text-sm"

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