Compare commits

...
242 Commits
Author SHA1 Message Date
Alex van Andel b83ee2d57d v2.9.2
release.yml / release (push) Canceled after 0s
2023-05-23 02:32:41 +02:00
Shivam KalraandPeer Richelsen 5f39bbe730 feat: mirotalk app-store setup (#9010)
Co-authored-by: Peer Richelsen <peeroke@gmail.com>
2023-05-23 00:00:47 +00:00
Peer Richelsen cf3d8cb4bb fixed password input widht (#9049) 2023-05-22 23:30:54 +00:00
fbe0018d01 fix: cancelled booking doesn't show the booker (#8203)
* fix: remove attendee deletion

* chore: add test id

* test: add e2e

* Fix data-testid placeholder

* Fix prettier error

---------

Co-authored-by: Peer Richelsen <peeroke@gmail.com>
Co-authored-by: alannnc <alannnc@gmail.com>
2023-05-22 23:15:06 +00:00
6586ed4d87 change bg of date-input field (#9043)
Co-authored-by: rkreddy99 <rreddy@e2clouds.com>
Co-authored-by: Peer Richelsen <peeroke@gmail.com>
2023-05-22 23:03:13 +00:00
Nafees Nazik 81e57afcf4 fix: user undefined (#9022) 2023-05-22 23:02:54 +00:00
Alex van Andel 5cc530593b Update lockfile
release.yml / release (push) Canceled after 0s
2023-05-23 00:26:22 +02:00
Nafees Nazik 4111f78431 feat: make branding hideable in the new booker (#9033)
* feat: make branding hideable

* fix: typo
2023-05-22 21:54:43 +00:00
Udit Takkar def80ea4cf fix: reject icon color (#9031)
Signed-off-by: Udit Takkar <udit.07814802719@cse.mait.ac.in>
2023-05-22 21:53:37 +00:00
2fc4676f6d fix: [CAL-1726] UI: seats input focus too wide (#8999)
Co-authored-by: alannnc <alannnc@gmail.com>
Co-authored-by: Peer Richelsen <peeroke@gmail.com>
2023-05-22 18:02:49 +00:00
Peer Richelsen 318bafaab8 Update LICENSE 2023-05-22 18:56:17 +01:00
Peer Richelsen fc10c29037 Update LICENSE 2023-05-22 18:54:09 +01:00
Riyan MohammadandUdit Takkar ccb7b1f9ac Optimize conditional rendering (#9009)
* Optimize conditional rendering

Declared a variable called isAdmin. The check session.data?.user.role === "ADMIN" is repeated multiple times. You can store this value in a variable to avoid redundant checks.

* Update AppsLayout.tsx

Removed extra line space to match prettier format

* fix: lint error

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

---------

Signed-off-by: Udit Takkar <udit.07814802719@cse.mait.ac.in>
Co-authored-by: Udit Takkar <udit.07814802719@cse.mait.ac.in>
2023-05-22 13:51:22 +00:00
Peer Richelsen c6c6544f50 Update package.json 2023-05-22 14:21:25 +01:00
Hariom Balhara 8a6b93a747 Fix: Embed - Auto theme configured using embed config doesn't work when there is non-system theme configured in appearance. (#9030)
* Differentiate b/w auto theme and unspecified theme

* Fix TS
2023-05-22 11:17:56 +00:00
alannnc ff6c6ccec0 Replacing bookingAttendees for bookingUid (#8997) 2023-05-22 09:30:24 +00:00
c8db177f7d fix: team member search error (#8982)
Co-authored-by: sean-brydon <55134778+sean-brydon@users.noreply.github.com>
Co-authored-by: alannnc <alannnc@gmail.com>
Co-authored-by: Carina Wollendorfer <30310907+CarinaWolli@users.noreply.github.com>
2023-05-22 09:29:28 +00:00
Nafees Nazikandalannnc 8871e1eb21 fix: wrong locale in attendee email ics (#8945)
* fix: pass attendee translator function

* fix: type

* fix: t

* fix: t

---------

Co-authored-by: alannnc <alannnc@gmail.com>
2023-05-22 06:14:44 +00:00
Shivam KalraandPeer Richelsen 92b2d57871 feat: 8x8 app-store setup (#9015)
* feat: 8x8 app-store setup

* fix: regex remove optional protocol, -imageSrc

* Update packages/app-store/eightxeight/config.json

* Update packages/app-store/eightxeight/config.json

---------

Co-authored-by: Peer Richelsen <peer@cal.com>
2023-05-21 18:21:30 +00:00
Alex van Andel 77623c72c5 Bump lockfile 2023-05-20 12:52:55 +02:00
3239976e18 Fix: Profile update refresh issues (#8570)
* profile update refresh fixes

* updated avatar based on logged in user

* lint & types check fixes

* fixed settings layout to fetch udpated session

* pushing the 8448 changes to separate PR

* removing hook not required

* Removed extra code

---------

Co-authored-by: Keyur Patel <keyur.patel@difx.io>
Co-authored-by: Alan <alannnc@gmail.com>
2023-05-20 00:37:58 +00:00
611939ffe8 remove todo to issue action (#8903)
Co-authored-by: Alex van Andel <me@alexvanandel.com>
Co-authored-by: alannnc <alannnc@gmail.com>
2023-05-19 22:53:11 +00:00
1b8ecbe449 [CAL-1008] Fix 'All Bookings' filter not getting selected after coming from 'Your Bookings' (#8902)
* [CAL-1008] Fix 'All Bookings' filter not getting selected after coming from 'Your Bookings'

* Remove optional param from removeAllQueryParams function

* Remove setQuery from the extraction

---------

Co-authored-by: Joe Au-Yeung <65426560+joeauyeung@users.noreply.github.com>
Co-authored-by: alannnc <alannnc@gmail.com>
2023-05-19 22:50:57 +00:00
cd4882429d fix: impersonation switch active state (#8924)
* fix: switch

* fix: checked

---------

Co-authored-by: Hariom Balhara <hariombalhara@gmail.com>
Co-authored-by: alannnc <alannnc@gmail.com>
2023-05-19 21:23:12 +00:00
zomars 4fd2d80637 Linting 2023-05-19 14:07:25 -07:00
a343d934fe Replacement PR for closed PR #8960 (#8980)
* fix focus ring on number of seats

* Adding yarn.lock back

* checkout yarn.lock from main

---------

Co-authored-by: Sean Brydon <sean@cal.com>
Co-authored-by: sean-brydon <55134778+sean-brydon@users.noreply.github.com>
Co-authored-by: alannnc <alannnc@gmail.com>
2023-05-19 20:30:30 +00:00
Hariom Balharaandalannnc 933cc739bd Add config support in floatingButton api (#8986)
Co-authored-by: alannnc <alannnc@gmail.com>
2023-05-19 20:10:19 +00:00
Sanu Dutta c7c75ff4d3 enable search in select and adding border bottom color (#8988)
* searchable select

* divider color subtle
2023-05-19 19:43:01 +00:00
Kamalika 41f1920a7a Borders Fixed with border-subtle (#8990) 2023-05-19 16:43:41 +00:00
Carina WollendorferandCarinaWolli e4836ea8f3 make sure to also trigger when cancelled is null (#8992)
Co-authored-by: CarinaWolli <wollencarina@gmail.com>
2023-05-19 14:41:44 +00:00
Hariom Balhara bfa30aa504 Implement UpgradeTip in App install flow (#8968) 2023-05-19 09:52:17 +00:00
Carina WollendorferandCarinaWolli b36043b637 Fixes SMS workflow actions for premium users (#8983)
* fix sms actions for users with premium user names

* code clean up

---------

Co-authored-by: CarinaWolli <wollencarina@gmail.com>
2023-05-19 08:10:11 +00:00
ASHOK-SINGH 75026289fd Fix- Calendar override with the wrong dates and time (#8936) 2023-05-19 07:22:26 +00:00
Parth Sharma 80649c9f1a fix height issue (#8973) 2023-05-19 06:46:06 +00:00
Isaiah Hamilton 7dd75afb63 fix button width (#8979) 2023-05-19 06:25:44 +00:00
Crowdin Bot f66e4aeeed New Crowdin translations by Github Action 2023-05-19 00:45:20 +00:00
Rama Krishna Reddyandrkreddy99 8225e61710 fix redirect after adding ping.gg (#8972)
Co-authored-by: rkreddy99 <rreddy@e2clouds.com>
2023-05-19 00:22:07 +00:00
Jeroen Reumkens 175fc4fcf3 CAL-1673: Use dark/light colors from user profile settings in booker (#8905)
* CAL-1673: Use dark/light colors from user profile settings in booker

* Use system theme for dynamic booking, instead of theme set by first user.
2023-05-18 06:16:51 +00:00
shaharyarshamshiandJoe Au-Yeung f20a5df322 Guide to setup enviroment variable added in contributing mardown file (#8911)
* Guide to setup enviroment variable added in contributing mardown file

* linting error

* Update CONTRIBUTING.md

* linting error

---------

Co-authored-by: Joe Au-Yeung <65426560+joeauyeung@users.noreply.github.com>
2023-05-17 15:11:28 -07:00
62544931b2 updated language of raycast instructions (#8908)
Co-authored-by: Keith Williams <keithwillcode@gmail.com>
Co-authored-by: Peer Richelsen <peeroke@gmail.com>
2023-05-17 19:10:25 +01:00
Alex van Andel f6ad1d6ed5 Bump lockfile 2023-05-17 16:25:03 +02:00
d22b1072b5 change datepicker styles to fix dark mode issue (#8886)
Co-authored-by: Peer Richelsen <peeroke@gmail.com>
Co-authored-by: Keith Williams <keithwillcode@gmail.com>
2023-05-17 13:12:52 +00:00
4b356dd937 chore: extended slugify function (#8740)
Co-authored-by: sean-brydon <55134778+sean-brydon@users.noreply.github.com>
Co-authored-by: Omar López <zomars@me.com>
2023-05-17 13:05:14 +00:00
1f51199a7b issue#8601: fix (#8713)
Co-authored-by: Peer Richelsen <peeroke@gmail.com>
Co-authored-by: Omar López <zomars@me.com>
2023-05-17 12:57:12 +00:00
Crowdin Bot b80a631998 New Crowdin translations by Github Action 2023-05-17 13:15:49 +00:00
Crowdin Bot bef4422080 New Crowdin translations by Github Action 2023-05-17 13:14:27 +00:00
cfd1a72c64 [CAL-1545] replace heroicons with lucide.dev (#8599)
* fix linting

* [CAL-1545] replace heroicons with lucide.dev

* [CAL-1545] replace heroicons with lucide.dev

* [CAL-1545] replace heroicons with lucide.dev

---------

Co-authored-by: gitstart-calcom <gitstart@users.noreply.github.com>
Co-authored-by: Efraín Rochín <roae.85@gmail.com>
Co-authored-by: Peer Richelsen <peeroke@gmail.com>
Co-authored-by: Keith Williams <keithwillcode@gmail.com>
2023-05-17 12:47:44 +00:00
23b3a6661c Add feature to offset start times for event types (#8506)
* Add offsetStart column to EventType

* Update buildSlots to support offset start times

* Add "Offset Start Time" to edit event types form

* Fix offset events not appearing on availability selector

* Guard against negative offsetStart values

* Lock offsetStart field for managed event types

* EventLimits UI tweaks for "Offset start times"

* EventLimits UI: Fix offsetStart preview not always updating

* Remove unnecessary ctx from getSchedule.test.ts

---------

Co-authored-by: Joe Au-Yeung <65426560+joeauyeung@users.noreply.github.com>
Co-authored-by: Peer Richelsen <peeroke@gmail.com>
2023-05-17 11:56:55 +00:00
Hariom Balhara b8b6c48d7d Improvements: Prefill Routing Forms and connect prefilling with Booking Form (#8780)
* Support prefilling routing form and prefilling Booking form through routing form

* Use Option Value as is instead of lowercasing

* Fix prefill validation issue

* Add prefill tests

* Fix Routing Form tests

* Small fix
2023-05-17 08:47:48 +00:00
Crowdin Bot 81655f9988 New Crowdin translations by Github Action 2023-05-17 08:47:19 +00:00
Nafees Nazik ff74822c48 Fix: locale and time format in attendee email (#8941)
* feat: add locale prop

* feat: add locale prop

* feat: add locale prop

* fix: time format
2023-05-17 08:17:09 +00:00
Jeroen Reumkens 8ec178debd CAL-1591: Remember form values in new booker form when user navigates back and forth between timeslots and form (#8920) 2023-05-16 20:34:15 +00:00
Hariom BalharaandOmar López f881061d8d Fully handle booking pages with conflicting themes being opened together (#8921)
* Handle booking pages with conflicting themes being opened together

* Add comments

---------

Co-authored-by: Omar López <zomars@me.com>
2023-05-16 19:41:47 +00:00
Crowdin Bot 2525559d6b New Crowdin translations by Github Action 2023-05-16 11:27:38 +00:00
Carina WollendorferandCarinaWolli 38fb7a3f77 fix locked toggle (#8926)
Co-authored-by: CarinaWolli <wollencarina@gmail.com>
2023-05-16 11:04:03 +00:00
Alex van Andel 08956e54c5 Fix yarn.lock (missing lockfile commit in #8769) 2023-05-16 00:51:24 +02:00
ea65a2a27e fix: add exp in /meeting-tokens (#8869)
* fix: add exp in /meeting-tokens

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

* hijacking this PR to add a NIT change lol

---------

Signed-off-by: Udit Takkar <udit.07814802719@cse.mait.ac.in>
Co-authored-by: Peer Richelsen <peer@cal.com>
Co-authored-by: Peer Richelsen <peeroke@gmail.com>
2023-05-15 20:15:05 +00:00
Crowdin Bot 0d45cfb7ea New Crowdin translations by Github Action
release.yml / release (push) Canceled after 0s
2023-05-15 16:13:08 +00:00
Alex van Andel a4fc25e260 v2.9.0 2023-05-15 18:12:07 +02:00
Jeroen ReumkensandAlex van Andel 796c932311 CAL-1550: Align form submit button of new booker to bottom (#8896)
Co-authored-by: Alex van Andel <me@alexvanandel.com>
2023-05-15 15:02:16 +00:00
Jeroen Reumkens 4137f63ec7 CAL-1664: Improve flash of toggle group when rerendering (#8900)
* CAL-1664: Improve flash of toggle group when rerendering, because active element moves into position.

* Added back newline
2023-05-15 14:38:02 +00:00
Jeroen Reumkens 2147cc82a5 CAL-1557: Improve timeformat selector alignment in new booker (#8898) 2023-05-15 14:37:23 +00:00
Crowdin Bot 40e646e9a4 New Crowdin translations by Github Action 2023-05-15 14:22:54 +00:00
cb2225259c Enabling workflows for managed events (#8446)
* Enabling workflows for managed events

* Disabling fields for workflow when readonly

* Disabling event type workflows if readonly

* Installing auth app

* Reverting yarn.lock

* Again reverting yarn

* Showing user workflows in managed event type

* Reusing existing code to show all workflows

* Further extending workflow support

* Added unit test

* Fixing workflow assignment

* Fixing locked workflows for children MET

* Update packages/features/ee/workflows/components/EventWorkflowsTab.tsx

Co-authored-by: Carina Wollendorfer <30310907+CarinaWolli@users.noreply.github.com>

* Personal workflows fix, matching count numbers

* Fixing menu items for managed event types

* Fixing type checks

* Fixing empty activeOn select

* Fixing unit test

* handling active workflows for MET

* Fixing MET slug nit

* Embed option in action restored for non-MET

* Correcting mobile view when hidden

* More adjustments

* fix sms reminder field for children

* remove console.log

---------

Co-authored-by: Carina Wollendorfer <30310907+CarinaWolli@users.noreply.github.com>
Co-authored-by: CarinaWolli <wollencarina@gmail.com>
2023-05-15 13:56:26 +00:00
372cd94d9f Gitpod setup And Bio Detail Overflow Bug Fixed (#8824)
* feat: Add Gitpod setup and update README.md

* fix: Fix overflow issue in bio details with word-wrap property

* minor changes in gitpod script

* updated gitpod url for cal

* gitpod url fixed in markdown

* fix: lint errors

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

* added vscode extensions and  enabled prebuilds to reduce waiting time

---------

Signed-off-by: Udit Takkar <udit.07814802719@cse.mait.ac.in>
Co-authored-by: Peer Richelsen <peeroke@gmail.com>
Co-authored-by: Udit Takkar <udit.07814802719@cse.mait.ac.in>
2023-05-15 13:18:31 +00:00
Vedant Jainandsean-brydon c7c282f30f [fix] : select options marginal space (#8892)
Co-authored-by: sean-brydon <55134778+sean-brydon@users.noreply.github.com>
2023-05-15 10:25:33 +00:00
959488910f fix: strip markdown from meta description tag in users page (#8769)
* fix: remove markdown validation

* feat: use markdown stripped bio

* fix: use remove markdown

* fix: type errors

---------

Co-authored-by: alannnc <alannnc@gmail.com>
Co-authored-by: Peer Richelsen <peeroke@gmail.com>
2023-05-15 07:44:23 +00:00
Hariom Balhara 0ca0cc3265 Add eventTypeSelected event (#8894) 2023-05-15 06:30:08 +00:00
69bc12187e Fixed dark mode bugs in the availability section (#8630)
* Fixed dark mode bugs in the availability section

* Reverted the tooltip change for delete button

* Updated tooltip of delete button conditionally based on isLastSchedule flag

* fix: disabled button state

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

---------

Signed-off-by: Udit Takkar <udit.07814802719@cse.mait.ac.in>
Co-authored-by: Udit Takkar <udit.07814802719@cse.mait.ac.in>
Co-authored-by: sean-brydon <55134778+sean-brydon@users.noreply.github.com>
2023-05-14 17:46:19 +00:00
Abdurrahman RajabandCarina Wollendorfer 5e772530b2 Feat: select all days in schedule (#8796)
* feat: add select all

* fix: fix deleted days

* chore: add i18n select all

* chore: check all days when select all

* chore: use calcom checkbox

---------

Co-authored-by: Carina Wollendorfer <30310907+CarinaWolli@users.noreply.github.com>
2023-05-14 16:00:55 +00:00
Peer Richelsen 3088b1174a only border top for bottom nav (#8882) 2023-05-14 11:06:10 +00:00
Santosh Kuchetti fadf12b2bd Star not centered issue #8519 (#8872)
* modifications for the issues #8159 are done

* modifications for the issue #8519 are made
2023-05-13 09:51:16 +00:00
sean-brydon c81f30b092 Fix hidden label breaking layout (#8867) 2023-05-13 09:50:00 +00:00
Hariom Balharaandzomars 476119d627 Add changesets/cli to release embed (#8126)
* Add dep versions

* Release new version for embeds

* Add prepublish

* Use prepare script which works with both npm and yarn

* Add changesets correctly

* Add embed publishing command

---------

Co-authored-by: zomars <zomars@me.com>
2023-05-13 08:22:31 +00:00
Crowdin Bot 040f03a9b5 New Crowdin translations by Github Action 2023-05-13 04:31:26 +00:00
Shivang SharmaandOmar López b552bf6956 Fix: #8528 Moved the data checks to superRefine (#8749)
* Fix: #8528 Moved the data checks to superRefine

* Resolved lint isseu

* Updated to parse from safeParse

* added new line

---------

Co-authored-by: Omar López <zomars@me.com>
2023-05-13 04:11:12 +00:00
82d3c4370d cancel and schedule reminders when workflow activated/deactivated on event type (#8757)
* add switches to advanced even type settings

* only show switches when workflow is enabled

* check in event type update handler if user is allowed to disable standard emails

* don't send emails if disabled

* remove  reminders when workflow is deactivated on event type

* make sure emails can't be disabled if no workflow exist

* send workflow emails to all attendees

* code clean up

* add translations

* always send to all attendees when scheduling reminders

* schedule reminders if event type gets activated on workflow

* schedule reminders (commented code)

* change text

* schedule reminders for all attendees not just first one

---------

Co-authored-by: CarinaWolli <wollencarina@gmail.com>
Co-authored-by: Joe Au-Yeung <65426560+joeauyeung@users.noreply.github.com>
Co-authored-by: zomars <zomars@me.com>
2023-05-12 17:31:01 +00:00
492b4d3e97 Refactor/readme.md (#8723)
* Update README.md 

Removed 
- Heroku DB setup section (since it's no longer free). 
Added
- Section for setting up local DB.
- Some other minor details.

* Minor grammer fixes

---------

Co-authored-by: vaibhav bisht <vaibhav@aus.co.in>
Co-authored-by: Keith Williams <keithwillcode@gmail.com>
2023-05-12 10:39:03 -06:00
0ae319d206 a11y: Exit the lexical Editor and button a11y on tab index (#8139)
* a11y: Exit the lexical Editor and button a11y on tab index

Signed-off-by: GurkiranSingh <gurkiransinghk@gmail.com>

* chore: Updated lexical to v0.9.0

Signed-off-by: GurkiranSingh <gurkiransinghk@gmail.com>

* chore: Added ErrorBoundary for Lexical RichTextPlugin

Signed-off-by: GurkiranSingh <gurkiransinghk@gmail.com>

* chore: yarn install changes

Signed-off-by: GurkiranSingh <gurkiransinghk@gmail.com>

* fix: merge conflicts

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

* Update yarn.lock

---------

Signed-off-by: GurkiranSingh <gurkiransinghk@gmail.com>
Signed-off-by: Udit Takkar <udit.07814802719@cse.mait.ac.in>
Co-authored-by: Udit Takkar <udit.07814802719@cse.mait.ac.in>
Co-authored-by: Peer Richelsen <peeroke@gmail.com>
Co-authored-by: zomars <zomars@me.com>
2023-05-12 10:28:14 -06:00
Hariom Balhara 749311be2a Pull latest main in every submodule (#8537)
* Update to latest main so that yarn.lock is always correct

* Update git-setup.sh
2023-05-12 10:20:32 -06:00
Crowdin Bot 3cce4e5009 New Crowdin translations by Github Action 2023-05-12 15:46:20 +00:00
Mendy Landa 341f82ccb9 chore: removed duplicate value in className @ Tooltip.tsx (#8865) 2023-05-12 09:45:32 -06:00
Pranjal Goyal e028a339f5 Adding icon.svg and renaming config file (#8859) 2023-05-12 12:57:09 +00:00
sean-brydonandBailey Pumfleet c55e432bc3 Feat/team invite flow (#8804)
* completeOnboarding drives invite flow changes

* Username prefil - force getting started when acc doesnt exist

* Change subtitle text and unique error on multiple invites

* User exists and no password set - generate signup link still

* Fix callback param

* Update packages/trpc/server/routers/viewer/teams/inviteMember.handler.ts

* Fix spacing

* Add password hints

* Fix translations

---------

Co-authored-by: Bailey Pumfleet <bailey@pumfleet.co.uk>
2023-05-12 12:52:09 +00:00
Hariom BalharaandJoe Au-Yeung f47c3cd538 Fix/ Routing Form Routes (#8827)
* Reuse split routes

* Add cache

* Update formMutation.handler.ts

---------

Co-authored-by: Joe Au-Yeung <65426560+joeauyeung@users.noreply.github.com>
2023-05-12 12:01:05 +00:00
Nafees Nazik 4b70a20941 fix: overflow (#8858) 2023-05-12 10:55:11 +00:00
Hariom Balhara c873b83965 Unstage enums file (#8836) 2023-05-12 05:02:42 +00:00
Hariom Balhara ff859737ec Improvement/AppStore: Remove seeding from app-store-cli. (#8486)
* Remove seeding from cli

* Self review fixes

* Fix TS error
2023-05-12 04:59:15 +00:00
AnsariandPeer Richelsen 607ef71f9f fix: teams upgrade banner on smaller screens (#8786)
* background image fix 📲

* object image position change 🖼

* Duplicate Deleted Field 🎭

---------

Co-authored-by: Peer Richelsen <peeroke@gmail.com>
2023-05-12 00:23:11 +00:00
24dd4002fa fixed color of status bar for pwa (#8583)
* fixed color of status bar for pwa

* Apply suggestions from code review

* Apply suggestions from code review

---------

Co-authored-by: Peer Richelsen <peer@cal.com>
Co-authored-by: Peer Richelsen <peeroke@gmail.com>
2023-05-11 23:50:11 +00:00
Praveen DiasandJoe Au-Yeung 078c9ddca5 Improved API key error message for SendGrid setup page (#8847)
Co-authored-by: Joe Au-Yeung <65426560+joeauyeung@users.noreply.github.com>
2023-05-11 23:04:10 +00:00
alannnc b44e5a7aae Fix no video reference on google-meet (#8849) 2023-05-11 22:49:10 +00:00
4374da08e2 #8701 CAL-1621 new booker dialog grow in height (#8774)
* increase scrollable height

* Fix react-select version - import esm error

* Increase booking form modal height

* Update packages/features/bookings/Booker/components/BookEventForm/BookEventForm.tsx

* Match design specs

* nit change

* Trying to fix type errors

---------

Co-authored-by: Peer Richelsen <peeroke@gmail.com>
Co-authored-by: Peer Richelsen <peer@cal.com>
Co-authored-by: Alex van Andel <me@alexvanandel.com>
2023-05-11 17:31:51 +00:00
Crowdin Bot 98b531e6b5 New Crowdin translations by Github Action 2023-05-11 16:26:01 +00:00
74414db760 feat: add meta and seo tags for new booker component (#8697)
* feat: add hidden to select

* feat: add hide branding to store

* fix: remove branding from store

* feat: prefetch data

* feat: use meta tags

* fix: remove branding from store

* fix: prefetching

* refactor: useEvent hook

* fix: type

* fix :booker seo

* fix: type error

---------

Co-authored-by: Peer Richelsen <peeroke@gmail.com>
Co-authored-by: Jeroen Reumkens <hello@jeroenreumkens.nl>
2023-05-11 16:02:13 +00:00
sean-brydon bdf3e34ea1 Feat/onboarding video step connection (#8838)
* UI work - WIP scrollable area

* Add translations - refactor some components

* Add installed text

* Disable if there is no currently installed

* Extract loader

* Fix conditional

* Fix E2E

* fix typo
2023-05-11 13:20:39 +00:00
Jeroen Reumkens 738e0f3e50 CAL-1553: Show dates for multi occurence event instead of input to change occurences, during booking step. Also make form less wide and meta a bit wider during booker step (in small view only), so form looks better and dates fit on a single line for the multiple occurences. When split over multiple lines they would otherwise take up a lot of unneccesary space. (#8834) 2023-05-11 11:51:41 +00:00
Jeroen Reumkens 16ae19abdb CAL-1624: Timezone select layout improvements when typing (#8832) 2023-05-11 08:19:26 +00:00
a2e18ae9ba deleted fields in duplicate form 🎭 (#8808)
* deleted fields in duplicate form  🎭

* Fixed duplicate deleted fields

* Update packages/app-store/routing-forms/trpc/_router.ts

---------

Co-authored-by: Hariom Balhara <hariombalhara@gmail.com>
Co-authored-by: Keith Williams <keithwillcode@gmail.com>
2023-05-11 07:42:37 +00:00
e2cfd0d1d1 Webex integration (#7651)
* start webex app creation

* webex integration wip

* fix lint errors

* fix lint errors

* add webex env vars in appStore.example

* webex app wip

* fix lint errors

* edit webex oauth scopes

* add location in webex app config

* add site url placeholder and regex in webex config location

* debug translateEvent

* fix utc formatting for event start time, add test boilerplate for webex, add envs

* fix location and datetime formatting

* get correct videoCredentials for deleteMeeting

* Move webex specific readme content to webex README

* Fix app not visible in app-store

* Delete setup route

* add webex icon

* delete prev icon

* webex api fix

* add app screenshots

* Revert tests changes as they dont run

* Use config instead of hardcoding vales

* Update README

* Remove all env variables related to WEBEX app. They can be added through settings->admin->apps interface

* update from origin

* fix icon path

* update webex readme

* Update yarn.lock

* update webex readme

* Remove unnecessary URL from webex

* revert changes in cancel booking handler

* simply webex zod schemas, logs for debugging

---------

Co-authored-by: Peer Richelsen <peeroke@gmail.com>
Co-authored-by: Hariom Balhara <hariombalhara@gmail.com>
2023-05-11 07:14:32 +00:00
Crowdin Bot 067b77faf1 New Crowdin translations by Github Action 2023-05-11 04:07:21 +00:00
Ashray ShettyandAlex van Andel 740c01ac29 align text "Date overrides" with corresponding svg (#8819)
Co-authored-by: Alex van Andel <me@alexvanandel.com>
2023-05-11 03:45:14 +00:00
asadath1395andBailey Pumfleet 97cfd1ffa7 Fix delete icon background color in availability (#8810)
Co-authored-by: Bailey Pumfleet <bailey@pumfleet.co.uk>
2023-05-10 15:15:13 +00:00
Jithil P Ponnan a7b2cfc90f fix: cal-1647 alignment issues (#8817) 2023-05-10 15:05:46 +00:00
d067b0782a feat: add RECORDING_READY webhook (#8277)
* feat: add RECORDING_READY webhook

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

* fix: type errors and improvements

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

---------

Signed-off-by: Udit Takkar <udit.07814802719@cse.mait.ac.in>
Co-authored-by: Keith Williams <keithwillcode@gmail.com>
Co-authored-by: Hariom Balhara <hariombalhara@gmail.com>
2023-05-10 14:56:31 +00:00
203a36e2b5 Make Jitsi Host configurable (#8636)
* Closes #1847 - adds an environment variable `JITSI_HOST_URL` to configure the Host URL for self hosted instances

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

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

* Replace Tab with spaces

* Add JITSI_HOST_URL env

* Remote Tabs for Spaces

* Support jitsi_host key

* Remove ENV, add Interface jitsi host URL and fallback

* Fix linting issues

* Clean code

* add missing await

* Add configurable meeting slug

* Refactor to jitsiHost, remove slug generator

* zod default doesnt work right now. So remove it

---------

Co-authored-by: Udit Takkar <53316345+Udit-takkar@users.noreply.github.com>
Co-authored-by: Hariom Balhara <hariombalhara@gmail.com>
2023-05-10 14:46:14 +00:00
Hariom Balhara f5a38c3f89 Add missing zoho-bigin import (#8798) 2023-05-10 14:37:16 +00:00
Keith Williams f179c23cc5 v2.8.13
release.yml / release (push) Canceled after 0s
2023-05-10 11:26:52 -03:00
Jeroen Reumkens 9f83885e8c CAL-1577: Improved input addon styles. (#8803) 2023-05-10 08:59:32 +00:00
Syed Ali Shahbaz 8ffb5529e6 Use user profile timezone from DB as fallback for CalDAV all-day events (#8755)
* adds timezone pull from user profile in DB

* minor fixes

* fixes promise return type

* comments and minor fixes

* minor improvement

* fix return type

* changes for help in debugging
2023-05-10 08:44:15 +00:00
Jon@1599 2e686d03fa feat: allow only team users to record daily meetings (#8799) 2023-05-10 08:28:49 +00:00
Jeroen Reumkens cc3be0a6ac CAL-1623 CAL-1620: Improve animation for booker, and push mini calendar down in fullscreen views (#8773)
* CAL-1623 CAL-1620: Improve animation for booker, and push mini calendar down in fullscreen views

* Updated yarn.lock
2023-05-10 08:26:59 +00:00
ec3a3268c9 Resolved[#8732] Adding Trim to remove extra space (#8736)
* Resolved[#8732] Adding Trim to remove extra space

* fix: improve code

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

* chore: add lowercase

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

* chore: use lowercase

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

---------

Signed-off-by: Udit Takkar <udit.07814802719@cse.mait.ac.in>
Co-authored-by: Udit Takkar <53316345+Udit-takkar@users.noreply.github.com>
Co-authored-by: Udit Takkar <udit.07814802719@cse.mait.ac.in>
2023-05-10 07:45:15 +00:00
Udit Takkar 77eed5611e fix: use useTeamsPlan hook (#8789)
* fix: use useTeamsPlan hook

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

* fix: z index bug on dialog

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

---------

Signed-off-by: Udit Takkar <udit.07814802719@cse.mait.ac.in>
2023-05-10 07:11:01 +00:00
Crowdin Bot a827d1defb New Crowdin translations by Github Action 2023-05-10 04:27:42 +00:00
Hariom Balhara b08a62d30b Allow booking responses to have the data from variantsConfig (#8718) 2023-05-10 03:59:51 +00:00
d6fb0df64f perf: tRPC procedures and middleware refactor (#8419)
* trpc procedures an middleware refactor

* allow use sessionMiddleware without a req object

* sync with the new tRPC structure

* tRPC refactor on routing form app

* import Prisma from @prisma/client

* Lazy load apps from appstore

* remove unrelated changes

* Add types for PaymentService

* type fixes

* Merge branch 'main' into roae85/cal-1514-set-the-user-session-only-on-the

* fix typo

* remove console.log

* remove explicit types from apstore object

* linter fixes

---------

Co-authored-by: Keith Williams <keithwillcode@gmail.com>
Co-authored-by: Hariom Balhara <hariombalhara@gmail.com>
2023-05-09 19:27:05 +00:00
Crowdin Bot 03548d8381 New Crowdin translations by Github Action 2023-05-09 17:41:16 +00:00
Carina WollendorferandCarinaWolli 36d8554fd5 disable standard confirmation emails if workflow exists (#8747)
* add switches to advanced even type settings

* only show switches when workflow is enabled

* check in event type update handler if user is allowed to disable standard emails

* don't send emails if disabled

* make sure emails can't be disabled if no workflow exist

* send workflow emails to all attendees

* code clean up

* add translations

* always send to all attendees when scheduling reminders

* change text

---------

Co-authored-by: CarinaWolli <wollencarina@gmail.com>
2023-05-09 17:08:14 +00:00
sean-brydonandUdit Takkar 6fc9e9315d Bug/checkbox calendar sync state (#8677)
* switch wip

* Implement calendar switch component

* Checked default

* Add spinner to improve UX

* Add connected calendar reivaluate

* Remove local state

* Move back to middleware

* Fix spacing issue

* fix: spacing

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

---------

Signed-off-by: Udit Takkar <udit.07814802719@cse.mait.ac.in>
Co-authored-by: Udit Takkar <udit.07814802719@cse.mait.ac.in>
2023-05-09 17:53:23 +01:00
Ashray ShettyandBailey Pumfleet 6eb8119a82 Added the 'Add' button (#8777)
Co-authored-by: Bailey Pumfleet <bailey@pumfleet.co.uk>
2023-05-09 17:45:53 +01:00
Keith Williams f4c613e6d1 Enable workflows on merge_group (#8781)
* Enable workflows on merge_group

* Reverting back to pull_request_target
2023-05-09 17:43:07 +01:00
Nafees NazikandHariom Balhara 082507aea5 fix: location select logo in dark mode (#8633)
* fix: logo

* fix: icon on booker

---------

Co-authored-by: Hariom Balhara <hariombalhara@gmail.com>
2023-05-09 15:27:09 +00:00
Leo GiovanettiandJoe Au-Yeung 90c1270e3d Fixing availability for MET (#8662)
* Fixing availability for MET

* Removing unneeded code

* Fixing unit tests

* Lint fixes

---------

Co-authored-by: Joe Au-Yeung <j.auyeung419@gmail.com>
2023-05-09 11:15:13 -03:00
Joe Au-Yeungandalannnc 94917dbb1e Disable reserve slot on seated events (#8761)
* Disable reserve slot on seated events

* Move seats and reserve logic to backend

* Pass booking attendees

* Type fix

* Create booking when two users choose a slot before booking is created

* Update packages/trpc/server/routers/viewer/slots/reserveSlot.handler.ts

---------

Co-authored-by: alannnc <alannnc@gmail.com>
2023-05-09 11:02:19 +01:00
Carina WollendorferandCarinaWolli fbbcc401cb fix START_TIME variable + allow sms for self hosted (#8762)
Co-authored-by: CarinaWolli <wollencarina@gmail.com>
2023-05-09 07:50:17 +00:00
swaraj bachu af7d7ec678 fixed ui bug (#8741) 2023-05-09 08:45:45 +01:00
Reckson Zirsangzela Khiangte 3b7d85852a Bug: Change color variable for dark mode (#8758) 2023-05-09 08:44:17 +01:00
Peer RichelsenandUdit Takkar 5362cd66b4 added gradients to dark dashboard and dark booking page (#8459)
* added gradients to dark dashboard and dark booking page

* removed bg of timezone dropdown for dak

* added gradient to confirmation screen

* only gradient in dashboard

* fix: prettier

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

---------

Signed-off-by: Udit Takkar <udit.07814802719@cse.mait.ac.in>
Co-authored-by: Udit Takkar <udit.07814802719@cse.mait.ac.in>
2023-05-08 16:03:24 -03:00
Zoheb AhmedandAlex van Andel 2907405d4e Fixes Bold/Italics Issue (#8613)
Co-authored-by: Alex van Andel <me@alexvanandel.com>
2023-05-08 14:11:25 +02:00
3c46c39114 feat: catch emails sent locally using Mailhog (#8470)
* feat: added mailhog to catch emails sent locally

* fix: added new line at the end of packages/emails/docker-compose.yml

* chore: removed EMAIL_SERVER_USER and EMAIL_SERVER_PASSWORD for local usage with Mailhog

---------

Co-authored-by: Keith Williams <keithwillcode@gmail.com>
Co-authored-by: Peer Richelsen <peeroke@gmail.com>
2023-05-06 19:08:04 -03:00
Manish Roy c6ab889b98 handles scenario where defaultschedule is nil (#8714) 2023-05-06 08:52:54 +01:00
Hariom Balhara a2e2b0ed34 Fix broken appsRouter (#8719) 2023-05-06 08:50:52 +01:00
bc38b3bc55 enhance Timezone Component with Box Shadow (#8582)
Co-authored-by: Udit Takkar <udit.07814802719@cse.mait.ac.in>
Co-authored-by: Udit Takkar <53316345+Udit-takkar@users.noreply.github.com>
Co-authored-by: Peer Richelsen <peeroke@gmail.com>
2023-05-05 21:38:19 +00:00
Jeroen Reumkens 7611d5c24e CAL-1555: Show correct team avatars (#8665) 2023-05-05 21:44:21 +01:00
5d2fd7aafb [Symbolic Link Issues] Added instructions for setup on windows (#8574)
Co-authored-by: Hariom Balhara <hariombalhara@gmail.com>
Co-authored-by: Keith Williams <keithwillcode@gmail.com>
Co-authored-by: Peer Richelsen <peeroke@gmail.com>
Co-authored-by: Syed Ali Shahbaz <52925846+alishaz-polymath@users.noreply.github.com>
2023-05-05 21:43:40 +01:00
b9ade55ac1 Update README.md (#8679)
Co-authored-by: sean-brydon <55134778+sean-brydon@users.noreply.github.com>
Co-authored-by: Hariom Balhara <hariombalhara@gmail.com>
Co-authored-by: Peer Richelsen <peeroke@gmail.com>
2023-05-05 21:41:47 +01:00
Jeroen Reumkens d7051c4a3f Centered small_calendar view vertically (#8712) 2023-05-05 21:39:00 +01:00
Jeroen Reumkens ab50067194 Set selecteddate to today when switching layout. Before we were getting the current layout from the store, which would actually be the OLD layout you were switching from 😅 (#8711) 2023-05-05 16:42:47 +00:00
cdba1920fc refactor: split up routers to separate lambdas (#8041)
* split up routers to separate lambdas

* fix responsemeta

* move

* add typeguards to make sure all endpoints are covered in the approuter

* prettier

* move slotsrouter

* split ssg/ssr

* make sure correct headers are sent on viewer.public

* make sure correct headers are sent + use ctx.prisma

* Fixed new prefetch broken by merge

* Fixes after merge

* Created separate API route for all tRPC routers

* More fixes from refactor

* Fixed tRPC query for slots

* Put back extra line

* Fixed type checks

* Removed Endpoint type check since it loads from client

* Reverted change in getSchedule test

* Fix trpc routes in expectations

* Fix one more route test

---------

Co-authored-by: Efraín Rochín <roae.85@gmail.com>
Co-authored-by: Alex van Andel <me@alexvanandel.com>
Co-authored-by: Peer Richelsen <peeroke@gmail.com>
Co-authored-by: Keith Williams <keithwillcode@gmail.com>
Co-authored-by: zomars <zomars@me.com>
Co-authored-by: Hariom Balhara <hariombalhara@gmail.com>
2023-05-05 13:19:10 -03:00
Jeroen Reumkens 98a3508b8f CAL-1552: Add newline in front of time for selected timeslot in booker meta. (#8669) 2023-05-05 16:55:54 +01:00
Alex van Andel 446f384405 Add publishHandler user.id (#8703) 2023-05-05 15:36:33 +00:00
Jeroen Reumkensandsean-brydon be79b8ecd6 CAL-1554: remove gap between form and event meta on now booker due to css grid alignment (#8667)
Co-authored-by: sean-brydon <55134778+sean-brydon@users.noreply.github.com>
2023-05-05 12:38:21 +00:00
371e7b024a add "reset to default" color option for ColorPicker (#8643)
* add reset to default color option

* Do not show reset button in DOM if resetDefaultValue is undefined

* handle edge case: if invalid hexcode is set for resetDefaultValue

* Do not show the reset button if the color is already set to the default value

* Remove data-testid from Button

---------

Co-authored-by: Praneeth Bhogaraju <praneeth.bhogaraju@ni.com>
Co-authored-by: sean-brydon <55134778+sean-brydon@users.noreply.github.com>
2023-05-05 13:25:18 +01:00
sean-brydon 76807a7e70 Fix switch label hover (#8696) 2023-05-05 12:47:00 +01:00
Hariom BalharaandPeer Richelsen d3f77bf292 Fix: Embed Theme switching when appearance is using System Theme (#8655)
Co-authored-by: Peer Richelsen <peeroke@gmail.com>
2023-05-05 16:54:06 +05:30
Nafees Nazik 2f175eacf5 fix: load date picker on client side (#8690) 2023-05-05 13:04:58 +02:00
Nafees Nazik b45aea3f26 feat: add search for members (#8659)
* feat: add search team members

* fix: add default value

* fix: add placeholder
2023-05-05 10:35:27 +01:00
Jeroen Reumkens c401a58bb1 CAL-1589: Added utm link to powered by in booker. Also added new colors to powered by component, so theyre also used in current booker form now on. (#8670) 2023-05-05 08:36:23 +01:00
05b42c001f feat: Add Zoho Bigin app to appstore (#8158)
* feat: add zoho bigin app to appstore

* Handle appKeys save and read correctly

* Fixes

* Remove env variables and seeding

* Create README for zoho-bigin and link to that in main README

* Remove imageSrc, thats deprecated

* Improved logs

* Remove stray beecepter fetch

* Add Zoho Bigin package.json description

* Load constants from config.json

* Refactor bigin auth tokens management

* Remove try catch

* fix refresh token not getting stored properly

* load api domain dynamically

* Fix reschedule not updating zoho bigin event

---------

Co-authored-by: Peer Richelsen <peeroke@gmail.com>
Co-authored-by: Hariom Balhara <hariombalhara@gmail.com>
2023-05-04 20:19:48 +00:00
Mahesh Bansodeandsean-brydon 20f7a5841e Added validation for duration field in the event types (#8649)
Co-authored-by: sean-brydon <55134778+sean-brydon@users.noreply.github.com>
2023-05-04 12:05:52 +00:00
zomars dbf6bb991f Revert "perf: fix multiple versions of emotion/react loaded warning (#8549)"
This reverts commit 1cea7f9760.
2023-05-04 13:01:16 +01:00
Zeeshan BhatiandEfraín Rochín 75cd5a05b8 Fix Hover Effect in booking page (#8650)
Co-authored-by: Efraín Rochín <roae.85@gmail.com>
2023-05-04 11:58:27 +00:00
Joeandsean-brydon ca6afed27c fix: changed assign to field as typeable input (#8637)
Co-authored-by: sean-brydon <55134778+sean-brydon@users.noreply.github.com>
2023-05-04 11:39:43 +00:00
Jeroen Reumkens 45250f6f3e CAL-1558: Fixed responsiveness of booker for small calendar layout (#8660)
* CAL-1558: Fixed responsiveness of booker for small calendar layout

* Remove commented code
2023-05-04 12:32:22 +01:00
Jeroen Reumkens bd5af9e821 Fix/prevent duplicate avatars (#8664)
* Prevent duplicate avatars in new booker by also checking on profile url.

* Don't filter out profile without profile url

* Use webapp_url for avatars since that's what is used in the rest of the platform, that way the unique filter on avatar works
2023-05-04 11:07:37 +00:00
Jeroen Reumkens 4267c9063b CAL-1556: Alignment of current day dot in datepicker. (#8663) 2023-05-04 11:53:50 +01:00
Crowdin Bot 2b49d96e4a New Crowdin translations by Github Action 2023-05-03 18:37:57 +00:00
127c96b46c Update README.md (#8632)
* Update README.md

* Update README.md

---------

Co-authored-by: Hariom Balhara <hariombalhara@gmail.com>
Co-authored-by: Keith Williams <keithwillcode@gmail.com>
2023-05-03 15:36:55 -03:00
Hariom Balhara 3595ba9824 Fix tests (#8640) 2023-05-03 12:30:26 -03:00
Keith Williams 56acfa38f1 v2.8.12
release.yml / release (push) Canceled after 0s
2023-05-03 10:12:34 -03:00
Syed Ali Shahbaz e78fb22451 [URGENT] Hotfix: re-adds the password and username set check in signup (#8638)
* Check for existing password and username to ensure it isn't an invite

* added check with verified to allow SAML linking

* wrong verified check lol

* updated comment

* unintended
2023-05-03 10:10:28 -03:00
Babis DigosandKeith Williams 99f736b317 fix: Use correct values on append DayRange (#8597)
Co-authored-by: Keith Williams <keithwillcode@gmail.com>
2023-05-02 19:43:32 -03:00
ee9f80ae3b Fix form inputs height to 36px (#8541)
* fix form inputs height to 36px

* fix: remove h-9 from preset

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

* fix input addOns container height

* replace minHeight class with height in input addOn

---------

Signed-off-by: Udit Takkar <udit.07814802719@cse.mait.ac.in>
Co-authored-by: Udit Takkar <udit.07814802719@cse.mait.ac.in>
Co-authored-by: sean-brydon <55134778+sean-brydon@users.noreply.github.com>
Co-authored-by: Keith Williams <keithwillcode@gmail.com>
2023-05-02 21:49:17 +00:00
a3c283da5e Updated the CSS classes for the user name and profile (#8571)
Co-authored-by: sean-brydon <55134778+sean-brydon@users.noreply.github.com>
Co-authored-by: Keith Williams <keithwillcode@gmail.com>
2023-05-02 18:20:01 -03:00
Zoheb Ahmed 0ef678b2cf Booking page bug fixed (#8614) 2023-05-02 18:10:47 -03:00
4f466fd95d [CAL-1095] Embed modal (floating pop up button) - UI/layout/spacing issues (#8217)
* [CAL-1095] Embed modal (floating pop up button) - UI/layout/spacing issues

* requested changes

---------

Co-authored-by: gitstart-calcom <gitstart@users.noreply.github.com>
Co-authored-by: Peer Richelsen <peeroke@gmail.com>
Co-authored-by: Keith Williams <keithwillcode@gmail.com>
2023-05-02 15:57:01 -03:00
Keith Williams 5672a721d9 v2.8.11
release.yml / release (push) Canceled after 0s
2023-05-02 15:21:58 -03:00
Mohd Afzal KhanandKeith Williams 5ad45900ea fix the auto-focus issue in teams setting page (#8577)
Co-authored-by: Keith Williams <keithwillcode@gmail.com>
2023-05-02 15:20:03 -03:00
Hariom Balhara ada88a2f7e Fix: Show smsReminderNumber on booking success page (#8596) 2023-05-02 16:58:39 +00:00
Srijan MukherjeeandAlex van Andel 9ba90e18de resolves #3565 (#8581)
Co-authored-by: Alex van Andel <me@alexvanandel.com>
2023-05-02 16:56:29 +00:00
Carina WollendorferandCarinaWolli a88eb0fdc5 Allow booking date overrides outside of working hours (#8538)
* allow booking on date overrides outside of working hours

* remove comment

---------

Co-authored-by: CarinaWolli <wollencarina@gmail.com>
2023-05-02 11:38:56 -03:00
4b4c1200cd Add HistoryPlugin to the Editor UI component (#8603)
* Add HistoryPlugin to the Editor UI component

* Fix ESLint errors

---------

Co-authored-by: Praneeth Bhogaraju <praneeth.bhogaraju@ni.com>
Co-authored-by: Keith Williams <keithwillcode@gmail.com>
2023-05-02 11:29:52 -03:00
Nafees NazikandUdit Takkar 1cea7f9760 perf: fix multiple versions of emotion/react loaded warning (#8549)
Co-authored-by: Udit Takkar <53316345+Udit-takkar@users.noreply.github.com>
2023-05-02 18:31:54 +05:30
28dcf69d18 use named imports instead to avoid polluting the global namespace. in… (#8616)
* use named imports instead to avoid polluting the global namespace. in nodemailer

* Update packages/emails/templates/_base-email.ts

Lint fix.

* Revert yarn.lock changes

---------

Co-authored-by: alannnc <alannnc@gmail.com>
Co-authored-by: Alex van Andel <me@alexvanandel.com>
2023-05-02 12:58:47 +00:00
Zeeshan Bhatiandnafees nazik 83d5176ddb Remove redirection after app uninstalltion (#8556)
Co-authored-by: nafees nazik <nafeesnazik21@gmail.com>
2023-05-02 18:14:09 +05:30
Alex van Andel 3815a4c4bf Fixed yarn.lock 2023-05-02 14:14:42 +02:00
Julius MarmingeandAlex van Andel 53748eb380 add an enum generator, stop importing from @prisma/client (#8548)
* add an enum generator and start importing from it

* keep moving imports

* fix remaining

* Header simplified

* Removed generated file from repo

* Updated .gitignore to exclude enums directory

* Add eslint rule to check for @prisma/client Prisma enum import

* Added another enum import + exclude PrismaClient

---------

Co-authored-by: Alex van Andel <me@alexvanandel.com>
2023-05-02 13:44:05 +02:00
hiteshbedre 28af11f90e fix: corrected discord link pattern (#8612) 2023-05-02 15:44:26 +05:30
Peer Richelsen ea676907b2 fixed border of status badge (#8568) 2023-04-30 13:26:09 +05:30
hallidayo 221c8b75bc added alignment on items (#8544) 2023-04-28 16:56:31 +05:30
GitStart-Cal.comandgitstart-calcom 5b9b7ab22d [CAL-1530] Assigned members to managed event types missing preview URL (#8552)
Co-authored-by: gitstart-calcom <gitstart@users.noreply.github.com>
2023-04-27 14:51:20 -03:00
668ea088ef fix: password not updatable after an api error (#8514)
* fix: error clearance

* changes

---------

Co-authored-by: Peer Richelsen <peeroke@gmail.com>
Co-authored-by: Udit Takkar <53316345+Udit-takkar@users.noreply.github.com>
2023-04-27 11:43:23 +00:00
Nafees NazikandKeith Williams 8a6c420268 perf: prevent refetching i18n on route change (#8535)
* fix: prevent refetching i18n on route change

* remove additional properties

---------

Co-authored-by: Keith Williams <keithwillcode@gmail.com>
2023-04-27 10:55:26 +00:00
Crowdin Bot d2f8a5c076 New Crowdin translations by Github Action 2023-04-27 08:08:34 +00:00
Abdurrahman RajabandPeer Richelsen 9c0f7bbfc7 Chore: fix RTL style in Color picker, Return arrow, Two factor page (#8317)
* chore: UI arrow left add RTL.

* chore: fix appearence page RTL

* chore: add margins two-factor RTL

* chore: update due to review

---------

Co-authored-by: Peer Richelsen <peeroke@gmail.com>
2023-04-27 08:07:32 +00:00
Joe 8297824051 fix: edit mode set to true by default (#8468) 2023-04-26 22:06:04 +05:30
Joe Au-YeungandHariom Balhara 7ff5b66f46 Bookings with no-show fee to set proper location & prevent broken payments from blocking payment page (#8508)
* Better error logging on Stripe payment service

* Update booking

* If missing payment, load rest of bookings

* Address feedback

* Move requires confirmation threshold to webhook

* Use requiresConfirmation

* Revert unnecessary prettier changes

---------

Co-authored-by: Hariom Balhara <hariombalhara@gmail.com>
2023-04-26 10:12:14 -04:00
Kirat 55570ed4bf Fixed discord validation (#8536) 2023-04-26 13:20:18 +00:00
Hariom Balhara 51695ee79d chore/AppStore: Remove deprecated imageSrc and make the paths relative in logo (#8479)
* Remove depreated imageSrc and make the paths relative in logo

* Do logo replacement at a single place

* Make logo relative at other places

* Fix campfire page not working in dev environment
2023-04-26 12:03:34 +01:00
Crowdin Bot 543466f1b9 New Crowdin translations by Github Action 2023-04-26 08:30:45 +00:00
Peer Richelsen 4abf2d67d9 removed devcontainer (#8521) 2023-04-26 10:29:54 +02:00
1eeb91a793 perf: lazy load tRPC routes (#8167)
* experiment: cold start perf

* fix: update failing test

* chore: add database indexes

* chore: use json protocol and add query batching back

* Update [status].tsx

* Update [trpc].ts

* Delete getSlimSession.ts

* Update createContext.ts

* remove trpc caller

* correctly import Prisma

* lazy ethRouter

* replace crypto with md5

* import fixes

* public event endpoint refactor

* Update yarn.lock

* Update yarn.lock

* Using yarn.lock from main

---------

Co-authored-by: Omar López <zomars@me.com>
Co-authored-by: Peer Richelsen <peeroke@gmail.com>
Co-authored-by: Efraín Rochín <roae.85@gmail.com>
Co-authored-by: Keith Williams <keithwillcode@gmail.com>
2023-04-25 19:39:47 -03:00
Nafees Nazik a4725920ff fix: font not loaded in cal video (#8517) 2023-04-25 20:59:39 +02:00
Richard Poelderl 4cc7766f88 add noindex tags for apps setup pages (#8518) 2023-04-25 20:59:15 +02:00
Crowdin Bot 0c78715e9a New Crowdin translations by Github Action 2023-04-25 14:30:39 +00:00
Crowdin Bot 671d9b4903 New Crowdin translations by Github Action 2023-04-25 14:29:36 +00:00
Jeroen ReumkensandPeer Richelsen 524cefcbad UI Improvements for new booker (#8483)
CAL-1578: No layout shift when switching months (because of timeslots disappearing again)
CAL-1576: Font weight tweaks
Bigger sidebar on fullscreen booker layouts
CAL-1573: Slightly smaller padding around booker sections
CAL-1563: Prevent timezone select from resizing when typing in it
CAL-1561: Spacing improvements timeslots + button height
CAL-1560: Improve resize animation when changing from time slot picker to form
CAL-1549: Added overflow scroll to event description, removed icon from event description so we have more space, and added sexy scrollbars

Co-authored-by: Peer Richelsen <peeroke@gmail.com>
2023-04-25 14:28:32 +00:00
Crowdin Bot 72f72d86b2 New Crowdin translations by Github Action 2023-04-25 14:08:18 +00:00
Crowdin Bot c5c29322d3 New Crowdin translations by Github Action 2023-04-25 14:07:30 +00:00
Crowdin Bot 863b04e9c1 New Crowdin translations by Github Action 2023-04-25 14:06:34 +00:00
Crowdin Bot c2833f1b44 New Crowdin translations by Github Action 2023-04-25 14:05:43 +00:00
Hariom Balhara 25df264823 Remove reviews/rating/trending/verified props (#8482) 2023-04-25 16:04:40 +02:00
Crowdin Bot e870312ebe New Crowdin translations by Github Action 2023-04-25 14:04:23 +00:00
Crowdin Bot 5371bff6ff New Crowdin translations by Github Action 2023-04-25 14:03:32 +00:00
Jeroen Reumkens c791344c8b Switch back to small calendar layout when switching from mobile to desktop view. Also fixed rerender bug triggerd by ToggleGroup constantly updating because it got a new instance for the onValueChange function. (#8515) 2023-04-25 15:02:34 +01:00
Crowdin Bot 5e149d9f5f New Crowdin translations by Github Action 2023-04-25 12:22:07 +00:00
Alex van Andel 3e53aa13eb v2.8.10
release.yml / release (push) Canceled after 0s
2023-04-25 14:16:42 +02:00
317f961bc8 Feat/weekly booking view (#8484)
* Wip on booker atom

* Wip on booker atom

* Added correct icon imports

* Fixed build

* Responsive improvements

* Removed package lock

* Responsive tweaks

* Animation improvements and cleanup

* Animation improvements and event meta layout improvements.

* Tweaked margins.

* Added more event meta blocks

* Layout tweaks

* Converted booker layout to css grid and implemented multiple layout options

* cleanup

* Fixed build

* Fixed build

* Added temporary api route to enable/disable new booker

* Added sticky behavior

* Reverted yarn.lock and reinstalled new packages to see if this fixes build on vercel.

* Ensure divider lines always have 100% height.

* Improved animation config + initial load

* Ensure to pass eventid to getschedule, otherwise custom availability schedule wont work and wont return any availability

* Fixed divider line heights in booker

* Fixed timezone select positioning

* Added ability to view multiple days of timeslots

* Added icons to booker toggle

* Always show timeslots in timeslots view, also if no date is selected yet. In that case we show upcoming 5 days.

* Fixed timeslots in small calendar view

* Show selected day in calendar

* Fixed booker timeslots view

* Wip in making booking form work

* Moved most of the booker atom stuff to features, since it belongs there. Atom should be a rather small wrapper.

* Added create event functionality to booker form.

* Added guests toggle to booker form and styled input addons in dark mode.

* Added dynamic weekstart to booker

* Added seats limit feature to timeslots.

* Removed todo

* Added correct event avatars

* Added correct event name and icons

* Added correct translation for minutes text in multi duration

* Add rescheduling functionality to new booker.

* Added selected booking time to booking meta in sidebar.

* Abstracted away timeformat to custom hook

* Added correct key props to all components in booker.

* Fix build

* Create some new custom hooks to have a lot less repitition in code.

* Moved bookerform component inside booker directory since it is tied to it.

* Added error messages to booker form, plus fixed bug in recurring events.

* Added some comments <3

* Fixed todos in booker form.

* Added loading state for timeslot selector, and added prefetching of next month, in case of multi day view showing 2 months at the same time.

* Fixed import paths

* Added away view

* Validate uniqueness of event attendees.

* Tweaked comment

* #5798 added correct date format and style for selected date in booker.

* UI improvements

* Enable possibility to add booking values via query params.

* Added functionality to update query params when user selects date/duration etc in booker

* First steps in adding e2e test.

* Fixes after merge with main, and added new form builder.

* Implemented new form types and validation to booker, confirming new form builder. Validation still throwing wrong error keys though.

* Added search to timezone dropdown

* Added e2e test for booker (copy of current booker tests, only enabling cookie), plus fixed reschedule view.

* Updated yarn.lock

* Added new booker for team pages.

* Fixed input addon (hover) styles.

* Added dynamic booking.

* Hide timeformat  select for multi day view for now.

* Cleanup and ui tweaks

* removed log

* Mobile improvements

* Cleanup

* Small design tweaks after talking to ciaran.

* Text color and weight tweaks in booker

* Added rainbow gates to new booker.

* Added in default values which fixes form vallidation (???).

* Added empty defaults for name and email

* Added metadata

* Reset yarn.lock

* Fixed booker zod validation after change in main.

* Icon tweak

* Fixed timezone select styles after new classnames have been merged.

* Updated seat availability styles.

* Update yarn.lock

* Added explanation for alchemy key to .env.example

* Added tooltip to booker month/week/multiday toggle

* Fixed timezoneselect styles in booker after select updates.

* Updates bookingfields component by taking changes from current booker component

* Removed remaining booker todos

* Fix bookeventform

* Fix for recurring event meta

* Type fixes

* Typefixes

* Team event fixes

* Avoid hydration errors by only rendering date picker client side. Remove web3 gates since we dont offer them anymore. Prevent timeslot select from staying open when switching to a different month.

* Don't show calendar on mobile booker during booking.

* Always align booker buttons to bottom

* Don't show backend messages in error, rather show a helpful text like the current booker does as well.

* Do invisible next rewrite based on cookie from next.config.js (#7949)

* Do invisible next rewrite based on cookie from next.config.js

* Name embed link instead of bookerPath

* Rewrites only dynamic user pages

---------

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

* Don't allow change of timezone when bookerform is visible

* Don't add duration to query param if the event is not a multi duration event.

* Update next.config.js

* Added correct timezone formatting to event meta when timeslot is selected.

* removed .env variable that isn't needed anymore.

* Update Gates.tsx

* Type fixes

* Allows to run all tests with the new booker

* Fixed timezone select styles after merge.

* Don't throw error when event doesn't have hosts, rather return no users, which will result in no availability in UI.

* Make booker errors of severity info instead of warning.

* Ensure team avatars are shown, as well as filter on uniqueness of avatars.

* Added all booked today message to timeslots.

* Added cal.com logo to booker.

* Fixed fragment classname error, minor mobile animation tweaks plus make all booked today text smaller for multi day layout.

* Improved timezone select styles, and updated arguments of getbooking function after updates in main.

* Prevent infinite loop in rewriting new booker.

* Prevent infinite loop in rewriting new booker.

* Moved new-booker pages to their own directory to prevent regexes confusing next and thus nut running getserversideprops after rewrite. Also adding clearing of old date in booker store, that could stick around when user immediately navigates back to the same page after booking.

* Fixed cal logo color in darkmode for new booker.

* Implemented new color tokens and theme variables. Also small design tweaks after merge with main.

* Minor style tweaks

* Show multiple locations in tooltip on booker #8222

* Radio button style tweaks

* Fixed build

* Updated calendar imports to new lucide names

* Removed resetting of selected times logic, because otherwise url params wouldnt be taken into account which is actually what we want. So old values sticking around when navigating back is actually the desired behavior.

* Updated tests to instead of always run the new booker in tests, have a utility to run both the new and old booker for specified tests.

* Added comment and eslint disable for if statement in booker test.

* Update packages/features/bookings/components/event-meta/Details.tsx

Co-authored-by: sean-brydon <55134778+sean-brydon@users.noreply.github.com>

* Fix badge types

* Lazy loaded timezone select to save 85kb in bundle size.

* Upgraded framer to latest. Als moved framer and react sticky deps to features instead of atoms.

* Added new pagewrapper logic

* Simplified rescheduling ssr fetches, this now also supports multi seat rescheduling.

* Unset selected time when user is rescheduling directly after a new booking, otherwise it would show the form instead of new time selection.

* Updated form builder logic as per form builder in current booker.

* Updated form builder prefill logic as per logic in current booker.

* Updated getbooking function to fetch correct details when a reschedule uid is used

* Fixed booking questions test by NOT waiting for /book page because the new booker doesnt have this.

* Added former meeting time to reschedule view.

* Fixed types

* Undo playwright config update by mistake.

* Fixed event types test by only waiting for /book page in old booker

* Set new booker cookie to one year in the future instead of 2050

* added reset mockdate to test

* Temporary disabled test to see if this solves the out of memory error.

* Deleted test to see if that fixes the memory error

* Large View Header

* BookFormModal

* Modal

* Fix modal

* Select first day when switching months in booker

* SetSelected Date on large layouts

* Fix re-renders

* Fix yarn.lock

* Set selected date when switching layout

* Add empty state

* Lint

* sticky button on modal

* paramater layout & empty state

* fix: 7040 fix - team profile description (#8469)

* New Crowdin translations by Github Action

* Not center

* Fix positionion

* Removed unused dependnecy in effect

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

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

* Fix padding overflow

---------

Co-authored-by: Jeroen Reumkens <hello@jeroenreumkens.nl>
Co-authored-by: zomars <zomars@me.com>
Co-authored-by: Alex van Andel <me@alexvanandel.com>
Co-authored-by: Peer Richelsen <peeroke@gmail.com>
Co-authored-by: hallidayo <22655069+Hallidayo@users.noreply.github.com>
Co-authored-by: Crowdin Bot <support+bot@crowdin.com>
2023-04-25 13:01:45 +01:00
b0c57a5c38 add australia country code to noAlphanumericSenderIdSupport (#8510)
Co-authored-by: CarinaWolli <wollencarina@gmail.com>
Co-authored-by: Alex van Andel <me@alexvanandel.com>
2023-04-25 10:18:44 +00:00
Crowdin Bot 39c16bebd5 New Crowdin translations by Github Action 2023-04-25 09:55:06 +00:00
Alex van Andel b3a5f4a6c0 Fix yarn.lock file 2023-04-25 11:54:03 +02:00
Crowdin Bot 379785196d New Crowdin translations by Github Action 2023-04-25 06:41:22 +00:00
hallidayo 04f8de238f fix: 7040 fix - team profile description (#8469) 2023-04-25 12:10:35 +05:30
Joe 0af2be9d8f Fix: settings moved to userdropdown (#8409) 2023-04-24 23:51:17 +02:00
Crowdin Bot 98d31157cb New Crowdin translations by Github Action 2023-04-24 21:38:14 +00:00
Joe f99d518a06 fix: checkbox and text alignment (#8503) 2023-04-24 23:37:16 +02:00
Crowdin Bot 62770ecc49 New Crowdin translations by Github Action 2023-04-24 18:54:34 +00:00
Crowdin Bot be05ec66ce New Crowdin translations by Github Action 2023-04-24 18:53:52 +00:00
Crowdin Bot 8defc351be New Crowdin translations by Github Action 2023-04-24 18:52:54 +00:00
Crowdin Bot ab112d92ea New Crowdin translations by Github Action 2023-04-24 18:51:55 +00:00
Crowdin Bot cf1b124dc1 New Crowdin translations by Github Action 2023-04-24 18:51:07 +00:00
Crowdin Bot 38158ee043 New Crowdin translations by Github Action 2023-04-24 18:50:10 +00:00
Crowdin Bot 8d214cd8ac New Crowdin translations by Github Action 2023-04-24 18:49:15 +00:00
Crowdin Bot 01ed11ae33 New Crowdin translations by Github Action 2023-04-24 18:48:27 +00:00
Crowdin Bot 5c7756ce6b New Crowdin translations by Github Action 2023-04-24 18:47:38 +00:00
Crowdin Bot a8c5227536 New Crowdin translations by Github Action 2023-04-24 18:46:51 +00:00
Crowdin Bot f3730daf05 New Crowdin translations by Github Action 2023-04-24 18:46:08 +00:00
Crowdin Bot 47d5d800b0 New Crowdin translations by Github Action 2023-04-24 18:45:18 +00:00
Peer Richelsen f6d00a41fb removing more leading-none (#8464) 2023-04-24 18:44:30 +00:00
Crowdin Bot 692f2778e4 New Crowdin translations by Github Action 2023-04-24 17:22:12 +00:00
81d8628a87 remove application_fee_amount (#8496)
* Clean up linting

* Type fix

---------

Co-authored-by: gitstart-calcom <gitstart@users.noreply.github.com>
Co-authored-by: GitStart-Cal.com <121884634+gitstart-calcom@users.noreply.github.com>
Co-authored-by: Joe Au-Yeung <j.auyeung419@gmail.com>
Co-authored-by: Joe Au-Yeung <65426560+joeauyeung@users.noreply.github.com>
2023-04-24 17:21:24 +00:00
Crowdin Bot 07fbc4cbd3 New Crowdin translations by Github Action 2023-04-24 16:38:52 +00:00
Joe 8cb9a96c3a fix: text color when hover (#8497) 2023-04-24 16:37:53 +00:00
Crowdin Bot 73b1c1dfb7 New Crowdin translations by Github Action 2023-04-24 14:55:33 +00:00
Regina LiuandHariom Balhara 224a8864a6 Add Meta Pixel app (#8476)
* Add Meta Pixel app

* Remove app-store seedinfg for app

* Simplify code

* Apply suggestions from code review

* Fix yarn.lock

* Apply suggestions from code review

---------

Co-authored-by: Hariom Balhara <hariombalhara@gmail.com>
2023-04-24 16:54:42 +02:00
6d02ac6729 New Booker Component (preparations for booker atom) (#6792)
* Wip on booker atom

* Wip on booker atom

* Added correct icon imports

* Fixed build

* Responsive improvements

* Removed package lock

* Responsive tweaks

* Animation improvements and cleanup

* Animation improvements and event meta layout improvements.

* Tweaked margins.

* Added more event meta blocks

* Layout tweaks

* Converted booker layout to css grid and implemented multiple layout options

* cleanup

* Fixed build

* Fixed build

* Added temporary api route to enable/disable new booker

* Added sticky behavior

* Reverted yarn.lock and reinstalled new packages to see if this fixes build on vercel.

* Ensure divider lines always have 100% height.

* Improved animation config + initial load

* Ensure to pass eventid to getschedule, otherwise custom availability schedule wont work and wont return any availability

* Fixed divider line heights in booker

* Fixed timezone select positioning

* Added ability to view multiple days of timeslots

* Added icons to booker toggle

* Always show timeslots in timeslots view, also if no date is selected yet. In that case we show upcoming 5 days.

* Fixed timeslots in small calendar view

* Show selected day in calendar

* Fixed booker timeslots view

* Wip in making booking form work

* Moved most of the booker atom stuff to features, since it belongs there. Atom should be a rather small wrapper.

* Added create event functionality to booker form.

* Added guests toggle to booker form and styled input addons in dark mode.

* Added dynamic weekstart to booker

* Added seats limit feature to timeslots.

* Removed todo

* Added correct event avatars

* Added correct event name and icons

* Added correct translation for minutes text in multi duration

* Add rescheduling functionality to new booker.

* Added selected booking time to booking meta in sidebar.

* Abstracted away timeformat to custom hook

* Added correct key props to all components in booker.

* Fix build

* Create some new custom hooks to have a lot less repitition in code.

* Moved bookerform component inside booker directory since it is tied to it.

* Added error messages to booker form, plus fixed bug in recurring events.

* Added some comments <3

* Fixed todos in booker form.

* Added loading state for timeslot selector, and added prefetching of next month, in case of multi day view showing 2 months at the same time.

* Fixed import paths

* Added away view

* Validate uniqueness of event attendees.

* Tweaked comment

* #5798 added correct date format and style for selected date in booker.

* UI improvements

* Enable possibility to add booking values via query params.

* Added functionality to update query params when user selects date/duration etc in booker

* First steps in adding e2e test.

* Fixes after merge with main, and added new form builder.

* Implemented new form types and validation to booker, confirming new form builder. Validation still throwing wrong error keys though.

* Added search to timezone dropdown

* Added e2e test for booker (copy of current booker tests, only enabling cookie), plus fixed reschedule view.

* Updated yarn.lock

* Added new booker for team pages.

* Fixed input addon (hover) styles.

* Added dynamic booking.

* Hide timeformat  select for multi day view for now.

* Cleanup and ui tweaks

* removed log

* Mobile improvements

* Cleanup

* Small design tweaks after talking to ciaran.

* Text color and weight tweaks in booker

* Added rainbow gates to new booker.

* Added in default values which fixes form vallidation (???).

* Added empty defaults for name and email

* Added metadata

* Reset yarn.lock

* Fixed booker zod validation after change in main.

* Icon tweak

* Fixed timezone select styles after new classnames have been merged.

* Updated seat availability styles.

* Update yarn.lock

* Added explanation for alchemy key to .env.example

* Added tooltip to booker month/week/multiday toggle

* Fixed timezoneselect styles in booker after select updates.

* Updates bookingfields component by taking changes from current booker component

* Removed remaining booker todos

* Fix bookeventform

* Fix for recurring event meta

* Type fixes

* Typefixes

* Team event fixes

* Avoid hydration errors by only rendering date picker client side. Remove web3 gates since we dont offer them anymore. Prevent timeslot select from staying open when switching to a different month.

* Don't show calendar on mobile booker during booking.

* Always align booker buttons to bottom

* Don't show backend messages in error, rather show a helpful text like the current booker does as well.

* Do invisible next rewrite based on cookie from next.config.js (#7949)

* Do invisible next rewrite based on cookie from next.config.js

* Name embed link instead of bookerPath

* Rewrites only dynamic user pages

---------

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

* Don't allow change of timezone when bookerform is visible

* Don't add duration to query param if the event is not a multi duration event.

* Update next.config.js

* Added correct timezone formatting to event meta when timeslot is selected.

* removed .env variable that isn't needed anymore.

* Update Gates.tsx

* Type fixes

* Allows to run all tests with the new booker

* Fixed timezone select styles after merge.

* Don't throw error when event doesn't have hosts, rather return no users, which will result in no availability in UI.

* Make booker errors of severity info instead of warning.

* Ensure team avatars are shown, as well as filter on uniqueness of avatars.

* Added all booked today message to timeslots.

* Added cal.com logo to booker.

* Fixed fragment classname error, minor mobile animation tweaks plus make all booked today text smaller for multi day layout.

* Improved timezone select styles, and updated arguments of getbooking function after updates in main.

* Prevent infinite loop in rewriting new booker.

* Prevent infinite loop in rewriting new booker.

* Moved new-booker pages to their own directory to prevent regexes confusing next and thus nut running getserversideprops after rewrite. Also adding clearing of old date in booker store, that could stick around when user immediately navigates back to the same page after booking.

* Fixed cal logo color in darkmode for new booker.

* Implemented new color tokens and theme variables. Also small design tweaks after merge with main.

* Minor style tweaks

* Show multiple locations in tooltip on booker #8222

* Radio button style tweaks

* Fixed build

* Updated calendar imports to new lucide names

* Removed resetting of selected times logic, because otherwise url params wouldnt be taken into account which is actually what we want. So old values sticking around when navigating back is actually the desired behavior.

* Updated tests to instead of always run the new booker in tests, have a utility to run both the new and old booker for specified tests.

* Added comment and eslint disable for if statement in booker test.

* Update packages/features/bookings/components/event-meta/Details.tsx

Co-authored-by: sean-brydon <55134778+sean-brydon@users.noreply.github.com>

* Fix badge types

* Lazy loaded timezone select to save 85kb in bundle size.

* Upgraded framer to latest. Als moved framer and react sticky deps to features instead of atoms.

* Added new pagewrapper logic

* Simplified rescheduling ssr fetches, this now also supports multi seat rescheduling.

* Unset selected time when user is rescheduling directly after a new booking, otherwise it would show the form instead of new time selection.

* Updated form builder logic as per form builder in current booker.

* Updated form builder prefill logic as per logic in current booker.

* Updated getbooking function to fetch correct details when a reschedule uid is used

* Fixed booking questions test by NOT waiting for /book page because the new booker doesnt have this.

* Added former meeting time to reschedule view.

* Fixed types

* Undo playwright config update by mistake.

* Fixed event types test by only waiting for /book page in old booker

* Set new booker cookie to one year in the future instead of 2050

* added reset mockdate to test

* Temporary disabled test to see if this solves the out of memory error.

* Deleted test to see if that fixes the memory error

* Select first day when switching months in booker

---------

Co-authored-by: zomars <zomars@me.com>
Co-authored-by: Alex van Andel <me@alexvanandel.com>
Co-authored-by: sean-brydon <55134778+sean-brydon@users.noreply.github.com>
Co-authored-by: Sean Brydon <sean@cal.com>
Co-authored-by: Peer Richelsen <peeroke@gmail.com>
2023-04-24 16:32:30 +02:00
Crowdin Bot f838e8bd53 New Crowdin translations by Github Action 2023-04-24 14:13:48 +00:00
Hariom Balhara 5dac6896d2 Routing-Forms/External Redirect URL improvement (#8487) 2023-04-24 19:42:50 +05:30
Crowdin Bot 496cb265d1 New Crowdin translations by Github Action 2023-04-24 14:08:30 +00:00
sean-brydon c037a62a9d Sad to see it go (#8230) 2023-04-24 19:37:29 +05:30
Crowdin Bot 88d17165ec New Crowdin translations by Github Action 2023-04-22 19:57:56 +00:00
929 changed files with 26335 additions and 12601 deletions
+8
View File
@@ -0,0 +1,8 @@
# Changesets
Hello and welcome! This folder has been automatically generated by `@changesets/cli`, a build tool that works
with multi-package repos, or single-package repos to help you version and publish your code. You can
find the full documentation for it [in our repository](https://github.com/changesets/changesets)
We have a quick list of common questions to get you started engaging with this project in
[our documentation](https://github.com/changesets/changesets/blob/main/docs/common-questions.md)
+11
View File
@@ -0,0 +1,11 @@
{
"$schema": "https://unpkg.com/@changesets/config@2.3.0/schema.json",
"changelog": "@changesets/cli/changelog",
"commit": false,
"fixed": [],
"linked": [],
"access": "public",
"baseBranch": "main",
"updateInternalDependencies": "patch",
"ignore": []
}
-42
View File
@@ -1,42 +0,0 @@
// For format details, see https://aka.ms/devcontainer.json. For config options, see the
// README at: https://github.com/devcontainers/templates/tree/main/src/docker-outside-of-docker
{
"name": "Docker outside of Docker",
// Or use a Dockerfile or Docker Compose file. More info: https://containers.dev/guide/dockerfile
"image": "mcr.microsoft.com/devcontainers/base:bullseye",
"features": {
"ghcr.io/devcontainers/features/docker-from-docker:1": {
"version": "latest",
"enableNonRootDocker": "true",
"moby": "true"
},
"ghcr.io/devcontainers/features/node:1": {},
"ghcr.io/devcontainers-contrib/features/npm-package:1": {},
"ghcr.io/devcontainers-contrib/features/jest:2": {},
"ghcr.io/devcontainers-contrib/features/prisma:2": {},
"ghcr.io/guiyomh/features/vim:0": {}
},
// Use this environment variable if you need to bind mount your local source code into a new container.
"remoteEnv": {
"LOCAL_WORKSPACE_FOLDER": "${localWorkspaceFolder}"
},
"hostRequirements": {
"cpus": 4,
"memory": "8gb"
},
// Use 'postCreateCommand' to run commands after the container is created.
"postCreateCommand": "./deploy/install.sh"
// Use 'forwardPorts' to make a list of ports inside the container available locally.
// "forwardPorts": [],
// Configure tool-specific properties.
// "customizations": {},
// Uncomment to connect as root instead. More info: https://aka.ms/dev-containers-non-root.
// "remoteUser": "root"
}
+2 -1
View File
@@ -16,11 +16,12 @@
# - WEB3
# - SALESFORCE
# - ZOHOCRM
# - ZOHO_BIGIN
# - APP STORE **********************************************************************************************
# ⚠️ ⚠️ ⚠️ THESE WILL BE MIGRATED TO THE DATABASE TO PREVENT AWS's 4KB ENV QUOTA ⚠️ ⚠️ ⚠️
# - DAILY.CO VIDEO
# Enables Cal Video. to get your key
# Enables Cal Video. to get your key
# 1. Visit our [Daily.co Partnership Form](https://go.cal.com/daily) and enter your information
# 2. From within your dashboard, go to the [developers](https://dashboard.daily.co/developers) tab.
# @see https://github.com/calcom/cal.com#obtaining-daily-api-credentials
+9 -5
View File
@@ -138,12 +138,16 @@ API_KEY_PREFIX=cal_
EMAIL_FROM='notifications@yourselfhostedcal.com'
# Configure SMTP settings (@see https://nodemailer.com/smtp/).
# Configuration to receive emails locally (mailhog)
EMAIL_SERVER_HOST='localhost'
EMAIL_SERVER_PORT=1025
# Note: The below configuration for Office 365 has been verified to work.
EMAIL_SERVER_HOST='smtp.office365.com'
EMAIL_SERVER_PORT=587
EMAIL_SERVER_USER='<office365_emailAddress>'
# EMAIL_SERVER_HOST='smtp.office365.com'
# EMAIL_SERVER_PORT=587
# EMAIL_SERVER_USER='<office365_emailAddress>'
# Keep in mind that if you have 2FA enabled, you will need to provision an App Password.
EMAIL_SERVER_PASSWORD='<office365_password>'
# EMAIL_SERVER_PASSWORD='<office365_password>'
# The following configuration for Gmail has been verified to work.
# EMAIL_SERVER_HOST='smtp.gmail.com'
@@ -178,4 +182,4 @@ CSP_POLICY=
# Vercel Edge Config
EDGE_CONFIG=
NEXT_PUBLIC_MINUTES_TO_BOOK=5 # Minutes
NEXT_PUBLIC_MINUTES_TO_BOOK=5 # Minutes
+1
View File
@@ -7,6 +7,7 @@ on:
paths-ignore:
- "**.md"
- ".github/CODEOWNERS"
merge_group:
workflow_dispatch:
concurrency:
@@ -1,7 +1,6 @@
const https = require("https");
async function applyLabelFromLinkedIssueToPR(pr, token) {
// Get the labels from issues linked to the PR
const query = `
query GetLinkedIssues($owner: String!, $repo: String!, $prNumber: Int!) {
@@ -38,7 +37,7 @@ async function applyLabelFromLinkedIssueToPR(pr, token) {
headers: {
"Content-Type": "application/json",
"Content-Length": graphqlData.length,
"Authorization": "Bearer " + token,
Authorization: "Bearer " + token,
"User-Agent": "Node.js",
},
};
@@ -52,14 +51,7 @@ async function applyLabelFromLinkedIssueToPR(pr, token) {
responseBody += chunk;
});
response.on("end", () => {
resolve(
JSON.parse(responseBody)
?.data
?.repository
?.pullRequest
?.closingIssuesReferences
?.nodes
);
resolve(JSON.parse(responseBody)?.data?.repository?.pullRequest?.closingIssuesReferences?.nodes);
});
});
@@ -96,7 +88,7 @@ async function applyLabelFromLinkedIssueToPR(pr, token) {
headers: {
"Content-Type": "application/json",
"Content-Length": labelsData.length,
"Authorization": "Bearer " + token,
Authorization: "Bearer " + token,
"User-Agent": "Node.js",
},
};
@@ -126,11 +118,9 @@ async function applyLabelFromLinkedIssueToPR(pr, token) {
console.log(`Error labelling PR: ${labelResult.message}`);
continue;
}
console.log(
`Applied labels: ${labels.join(", ")} to PR #${
pr.number
} from linked issue #${issue.number}`
`Applied labels: ${labels.join(", ")} to PR #${pr.number} from linked issue #${issue.number}`
);
}
}
-28
View File
@@ -1,28 +0,0 @@
name: TODO to Issue
on:
push:
branches:
- main
workflow_dispatch:
inputs:
MANUAL_COMMIT_REF:
description: "The SHA of the commit to get the diff for"
required: true
MANUAL_BASE_REF:
description: "By default, the commit entered above is compared to the one directly before it; to go back further, enter an earlier SHA here"
required: false
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
jobs:
todos:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: "Add TODOs to issues"
uses: "alstr/todo-to-issue-action@v4"
env:
MANUAL_COMMIT_REF: ${{ inputs.MANUAL_COMMIT_REF }}
MANUAL_BASE_REF: ${{ inputs.MANUAL_BASE_REF }}
with:
IDENTIFIERS: '[{"name": "TODO", "labels": ["🙋🏻‍♂️help wanted"]}, {"name": "FIXME", "labels": ["🐛 bug"]}]'
+2 -1
View File
@@ -65,8 +65,9 @@ tsconfig.tsbuildinfo
# turbo
.turbo
# Prisma-Zod
# Prisma generated files
packages/prisma/zod/*.ts
packages/prisma/enums
# Builds
dist
+43
View File
@@ -0,0 +1,43 @@
tasks:
- init: |
yarn &&
cp .env.example .env &&
next_auth_secret=$(openssl rand -base64 32) &&
calendso_encryption_key=$(openssl rand -base64 24) &&
sed -i -e "s|^NEXTAUTH_SECRET=.*|NEXTAUTH_SECRET=$next_auth_secret|" \
-e "s|^CALENDSO_ENCRYPTION_KEY=.*|CALENDSO_ENCRYPTION_KEY=$calendso_encryption_key|" .env
command: yarn dx
ports:
- port: 3000
visibility: public
onOpen: open-preview
- port: 5420
visibility: private
onOpen: ignore
- port: 1025
visibility: private
onOpen: ignore
- port: 8025
visibility: private
onOpen: ignore
github:
prebuilds:
master: true
pullRequests: true
pullRequestsFromForks: true
addCheck: true
addComment: true
addBadge: true
vscode:
extensions:
- DavidAnson.vscode-markdownlint
- yzhang.markdown-all-in-one
- esbenp.prettier-vscode
- dbaeumer.vscode-eslint
- bradlc.vscode-tailwindcss
- ban.spellright
- stripe.vscode-stripe
- Prisma.prisma
+1
View File
@@ -14,4 +14,5 @@ public
.DS_Store
.eslintignore
packages/prisma/zod
packages/prisma/enums
apps/web/public/embed
+1 -1
View File
@@ -6,6 +6,6 @@
},
"typescript.preferences.importModuleSpecifier": "non-relative",
"spellright.language": ["en"],
"spellright.documentTypes": ["markdown", "typescript"],
"spellright.documentTypes": ["markdown", "typescript", "typescriptreact"],
"tailwindCSS.experimental.classRegex": [["cva\\(([^)]*)\\)", "[\"'`]([^\"'`]*).*?[\"'`]"]]
}
File diff suppressed because one or more lines are too long
+2
View File
@@ -3,5 +3,7 @@ nodeLinker: node-modules
plugins:
- path: .yarn/plugins/@yarnpkg/plugin-interactive-tools.cjs
spec: "@yarnpkg/plugin-interactive-tools"
- path: .yarn/plugins/@yarnpkg/plugin-workspace-tools.cjs
spec: "@yarnpkg/plugin-workspace-tools"
yarnPath: .yarn/releases/yarn-3.4.1.cjs
+6 -1
View File
@@ -86,7 +86,12 @@ To develop locally:
yarn
```
5. Start developing and watch for code changes:
5. Set up your `.env` file:
- Use `openssl rand -base64 32` to generate a key and add it under `NEXTAUTH_SECRET` in the `.env` file.
- Use `openssl rand -base64 24` to generate a key and add it under `CALENDSO_ENCRYPTION_KEY` in the `.env` file.
6. Start developing and watch for code changes:
```sh
yarn dev
+1 -1
View File
@@ -2,7 +2,7 @@ Copyright (c) 2020-present Cal.com, Inc.
Portions of this software are licensed as follows:
* All content that resides under https://github.com/calcom/cal.com/tree/main/packages/features/ee directory of this repository (Enterprise Edition) is licensed under the license defined in "ee/LICENSE".
* All content that resides under https://github.com/calcom/cal.com/tree/main/packages/features/ee directory of this repository (Commercial License) is licensed under the license defined in "ee/LICENSE".
* All third party components incorporated into the Cal.com Software are licensed under the original license provided by the owner of the applicable component.
* Content outside of the above mentioned directories or restrictions above is available under the "AGPLv3" license as defined below.
+78 -59
View File
@@ -24,7 +24,7 @@
<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://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://status.cal.com"><img height="20px" src="https://betteruptime.com/status-badges/v1/monitor/a9kf.svg" alt="Uptime"></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=34507672"><img src="https://img.shields.io/badge/Hacker%20News-%231-%23FF6600" alt="Hacker News"></a>
@@ -38,13 +38,13 @@
<a href="https://github.com/calcom/cal.com/issues?q=is:issue+is:open+label:%22%F0%9F%99%8B%F0%9F%8F%BB%E2%80%8D%E2%99%82%EF%B8%8Fhelp+wanted%22"><img src="https://img.shields.io/badge/Help%20Wanted-Contribute-blue"></a>
<a href="https://cal.com/figma"><img src="https://img.shields.io/badge/Figma-Design%20System-blueviolet"></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>
<a href="https://contributor-covenant.org/version/1/4/code-of-conduct/ "><img src="https://img.shields.io/badge/Contributor%20Covenant-1.4-purple" /></a>
<a href="https://console.algora.io/org/cal/bounties?status=open"><img src="https://img.shields.io/endpoint?url=https%3A%2F%2Fconsole.algora.io%2Fapi%2Fshields%2Fcal%2Fbounties%3Fstatus%3Dopen" /></a>
</p>
<!-- ABOUT THE PROJECT -->
## About The Project
## About the Project
<img width="100%" alt="booking-screen" src="https://user-images.githubusercontent.com/8019099/176390354-f1bc7069-0341-437a-9bb8-eb41092b4016.gif">
@@ -53,13 +53,13 @@
The open source Calendly alternative. You are in charge
of your own data, workflow and appearance.
Calendly and other scheduling tools are awesome. It made our lives massively easier. We're using it for business meetings, seminars, yoga classes and even calls with our families. However, most tools are very limited in terms of control and customisations.
Calendly and other scheduling tools are awesome. It made our lives massively easier. We're using it for business meetings, seminars, yoga classes and even calls with our families. However, most tools are very limited in terms of control and customizations.
That's where Cal.com comes in. Self-hosted or hosted by us. White-label by design. API-driven and ready to be deployed on your own domain. Full control of your events and data.
## Recognition
#### Hacker News
#### [Hacker News](https://news.ycombinator.com/from?site=cal.com)
<a href="https://news.ycombinator.com/item?id=34507672">
<img
@@ -77,22 +77,22 @@ That's where Cal.com comes in. Self-hosted or hosted by us. White-label by desig
/>
</a>
#### [Product Hunt](https://www.producthunt.com/posts/calendso?utm_source=badge-top-post-badge&utm_medium=badge&utm_souce=badge-calendso)
#### [Product Hunt](https://producthunt.com/products/cal-com?utm_source=badge-top-post-badge&utm_medium=badge)
<a href="https://www.producthunt.com/posts/calendso?utm_source=badge-top-post-badge&utm_medium=badge&utm_souce=badge-calendso" target="_blank"><img src="https://api.producthunt.com/widgets/embed-image/v1/top-post-badge.svg?post_id=291910&theme=light&period=monthly" alt="Cal.com - The open source Calendly alternative | Product Hunt" style="width: 250px; height: 54px;" width="250" height="54" /></a> <a href="https://www.producthunt.com/posts/calendso?utm_source=badge-featured&utm_medium=badge&utm_souce=badge-calendso" target="_blank"><img src="https://api.producthunt.com/widgets/embed-image/v1/featured.svg?post_id=291910&theme=light" alt="Cal.com - The open source Calendly alternative | Product Hunt" style="width: 250px; height: 54px;" width="250" height="54" /></a> <a href="https://www.producthunt.com/stories/how-this-open-source-calendly-alternative-rocketed-to-product-of-the-day" target="_blank"><img src="https://cal.com/maker-grant.svg" alt="Cal.com - The open source Calendly alternative | Product Hunt" style="width: 250px; height: 54px;" width="250" height="54" /></a>
<a href="https://producthunt.com/posts/calendso?utm_source=badge-top-post-badge&utm_medium=badge&utm_souce=badge-calendso" target="_blank"><img src="https://api.producthunt.com/widgets/embed-image/v1/top-post-badge.svg?post_id=291910&theme=light&period=monthly" alt="Cal.com - The open source Calendly alternative | Product Hunt" style="width: 250px; height: 54px;" width="250" height="54" /></a> <a href="https://producthunt.com/posts/calendso?utm_source=badge-featured&utm_medium=badge&utm_souce=badge-calendso" target="_blank"><img src="https://api.producthunt.com/widgets/embed-image/v1/featured.svg?post_id=291910&theme=light" alt="Cal.com - The open source Calendly alternative | Product Hunt" style="width: 250px; height: 54px;" width="250" height="54" /></a> <a href="https://producthunt.com/stories/how-this-open-source-calendly-alternative-rocketed-to-product-of-the-day" target="_blank"><img src="https://cal.com/maker-grant.svg" alt="Cal.com - The open source Calendly alternative | Product Hunt" style="width: 250px; height: 54px;" width="250" height="54" /></a>
### Built With
- [Next.js](https://nextjs.org/?ref=cal.com)
- [tRPC](https://trpc.io/?ref=cal.com)
- [React](https://reactjs.org/?ref=cal.com)
- [Tailwind](https://tailwindcss.com/?ref=cal.com)
- [Prisma](https://prisma.io/?ref=cal.com)
- [React.js](https://reactjs.org/?ref=cal.com)
- [Tailwind CSS](https://tailwindcss.com/?ref=cal.com)
- [Prisma.io](https://prisma.io/?ref=cal.com)
- [Daily.co](https://go.cal.com/daily)
## Stay Up-to-Date
Cal officially launched as v.1.0 on 15th of September, however a lot of new features are coming. Watch **releases** of this repository to be notified for future updates:
Cal.com officially launched as v.1.0 on 15th of September, however a lot of new features are coming. Watch **releases** of this repository to be notified for future updates:
![cal-star-github](https://user-images.githubusercontent.com/8019099/154853944-a9e3c999-3da3-4048-b149-b4f73893c6fb.gif)
@@ -104,7 +104,7 @@ To get a local copy up and running, please follow these simple steps.
### Prerequisites
Here is what you need to be able to run Cal.
Here is what you need to be able to run Cal.com.
- Node.js (Version: >=15.x <17)
- PostgreSQL
@@ -121,6 +121,9 @@ Here is what you need to be able to run Cal.
```sh
git clone https://github.com/calcom/cal.com.git
```
> If you are on windows, run the following command on `gitbash` with admin privileges: <br>
```git clone -c core.symlinks=true https://github.com/calcom/cal.com.git``` <br>
See [docs](https://cal.com/docs/how-to-guides/how-to-troubleshoot-symbolic-link-issues-on-windows#enable-symbolic-links) for more details.
1. Go to the project folder
@@ -134,10 +137,10 @@ Here is what you need to be able to run Cal.
yarn
```
1. Set up your .env file
1. Set up your `.env` file
- Duplicate `.env.example` to `.env`
- Use `openssl rand -base64 32` to generate a key and add it under `NEXTAUTH_SECRET` in the .env file.
- Use `openssl rand -base64 24` to generate a key and add it under `CALENDSO_ENCRYPTION_KEY` in the .env file.
- Use `openssl rand -base64 32` to generate a key and add it under `NEXTAUTH_SECRET` in the `.env` file.
- Use `openssl rand -base64 24` to generate a key and add it under `CALENDSO_ENCRYPTION_KEY` in the `.env` file.
#### Quick start with `yarn dx`
@@ -150,53 +153,63 @@ yarn dx
#### Development tip
> Add `NEXT_PUBLIC_DEBUG=1` anywhere in your `.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' >> .env
```
#### Gitpod Setup
1. Click the button below to open this project in Gitpod.
2. This will open a fully configured workspace in your browser with all the necessary dependencies already installed.
[![Open in Gitpod](https://gitpod.io/button/open-in-gitpod.svg)](https://gitpod.io/#https://github.com/calcom/cal.com)
#### 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 `.env` file. Replace `<user>`, `<pass>`, `<db-host>`, and `<db-port>` with their applicable values
```
DATABASE_URL='postgresql://<user>:<pass>@<db-host>:<db-port>'
```
<details>
<summary>If you don't know how to configure the DATABASE_URL, then follow the steps here to create a quick DB using Heroku</summary>
<summary>If you don't know how to configure the DATABASE_URL, then follow the steps here to create a quick local DB</summary>
1. Create a free account with [Heroku](https://www.heroku.com/).
1. [Download](https://www.postgresql.org/download/) and install postgres in your local (if you don't have it already).
2. Create a new app.
<img width="306" alt="Create an App" src="https://user-images.githubusercontent.com/16905768/115322780-b3d58c00-a17e-11eb-8a52-b758fb0ea942.png">
2. Create your own local db by executing `createDB <DB name>`
3. In your new app, go to `Overview` and next to `Installed add-ons`, click `Configure Add-ons`. We need this to set up our database.
![image](https://user-images.githubusercontent.com/16905768/115323232-a53ba480-a17f-11eb-98db-58e2f8c52426.png)
3. Now open your psql shell with the DB you created: `psql -h localhost -U postgres -d <DB name>`
4. Once you clicked on `Configure Add-ons`, click on `Find more add-ons` and search for `postgres`. One of the options will be `Heroku Postgres` - click on that option.
![image](https://user-images.githubusercontent.com/16905768/115323126-5beb5500-a17f-11eb-8030-7380310807a9.png)
4. Inside the psql shell execute `\conninfo`. And you will get the following info.
![image](https://user-images.githubusercontent.com/39329182/236612291-51d87f69-6dc1-4a23-bf4d-1ca1754e0a35.png)
5. Once the pop-up appears, click `Submit Order Form` - plan name should be `Hobby Dev - Free`.
<img width="512" alt="Submit Order Form" src="https://user-images.githubusercontent.com/16905768/115323265-b4baed80-a17f-11eb-99f0-d67f019aa6df.png">
5. Now extract all the info and add it to your DATABASE_URL. The url would look something like this
`postgresql://postgres:postgres@localhost:5432/Your-DB-Name`.
6. Once you completed the above steps, click on your newly created `Heroku Postgres` and go to its `Settings`.
![image](https://user-images.githubusercontent.com/16905768/115323367-e92ea980-a17f-11eb-9ff4-dec95f2ec349.png)
7. In `Settings`, copy your URI to your Cal.com .env file and replace the `postgresql://<user>:<pass>@<db-host>:<db-port>` with it.
![image](https://user-images.githubusercontent.com/16905768/115323556-4591c900-a180-11eb-9808-2f55d2aa3995.png)
![image](https://user-images.githubusercontent.com/16905768/115323697-7a9e1b80-a180-11eb-9f08-a742b1037f90.png)
8. To view your DB, once you add new data in Prisma, you can use [Heroku Data Explorer](https://heroku-data-explorer.herokuapp.com/).
</details>
1. Set a 32 character random string in your .env file for the `CALENDSO_ENCRYPTION_KEY` (You can use a command like `openssl rand -base64 24` to generate one).
If you don't want to create a local DB. Then you can also consider using services like railway.app or render.
- [Setup postgres DB with railway.app](https://arctype.com/postgres/setup/railway-postgres)
- [Setup postgres DB with render](https://render.com/docs/databases)
1. Copy and paste your `DATABASE_URL` from `.env` to `.env.appStore`.
1. Set a 32 character random string in your `.env` file for the `CALENDSO_ENCRYPTION_KEY` (You can use a command like `openssl rand -base64 24` to generate one).
1. Set up the database using the Prisma schema (found in `packages/prisma/schema.prisma`)
```sh
yarn workspace @calcom/prisma db-deploy
```
1. Run [mailhog](https://github.com/mailhog/MailHog) to view emails sent during development
```sh
docker pull mailhog/mailhog
docker run -d -p 8025:8025 -p 1025:1025 mailhog/mailhog
```
1. Run (in development mode)
@@ -206,7 +219,7 @@ echo 'NEXT_PUBLIC_DEBUG=1' >> .env
#### Setting up your first user
1. Open [Prisma Studio](https://www.prisma.io/studio) to look at or modify the database content:
1. Open [Prisma Studio](https://prisma.io/studio) to look at or modify the database content:
```sh
yarn db-studio
@@ -251,7 +264,7 @@ yarn playwright show-report test-results/reports/playwright-html-report
yarn workspace @calcom/prisma db-migrate
```
(this can clear your development database in some cases)
(This can clear your development database in some cases)
In a production environment, run:
@@ -285,7 +298,7 @@ yarn playwright show-report test-results/reports/playwright-html-report
### Docker
The Docker configuration for Cal is an effort powered by people within the community.
The Docker configuration for Cal.com is an effort powered by people within the community.
If you want to contribute to the Docker repository, [reply here](https://github.com/calcom/docker/discussions/32).
@@ -298,14 +311,14 @@ Cal.com, Inc. does not provide official support for Docker, but we will accept f
### Heroku
<a href="https://heroku.com/deploy?template=https://github.com/calcom/cal.com">
<img width="185px" height="auto" src="https://www.herokucdn.com/deploy/button.svg" alt="Deploy">
<img width="185px" height="auto" src="https://herokucdn.com/deploy/button.svg" alt="Deploy">
</a>
### Railway
[![Deploy on Railway](https://railway.app/button.svg)](https://railway.app/new/template/cal)
You can deploy Cal on [Railway](https://railway.app/) using the button above. The team at Railway also have a [detailed blog post](https://blog.railway.app/p/calendso) on deploying Cal on their platform.
You can deploy Cal.com on [Railway](https://railway.app) using the button above. The team at Railway also have a [detailed blog post](https://blog.railway.app/p/calendso) on deploying Cal.com on their platform.
### Vercel
@@ -386,7 +399,7 @@ Don't code but still want to contribute? Join our [slack](https://cal.com/slack)
8. Select Web Application as the Application Type.
9. Under Authorized redirect URI's, select Add URI and then add the URI `<Cal.com URL>/api/integrations/googlecalendar/callback` and `<Cal.com URL>/api/auth/callback/google` replacing Cal.com URL with the URI at which your application runs.
10. The key will be created and you will be redirected back to the Credentials page. Select the newly generated client ID under OAuth 2.0 Client IDs.
11. Select Download JSON. Copy the contents of this file and paste the entire JSON string in the .env file as the value for GOOGLE_API_CREDENTIALS key.
11. Select Download JSON. Copy the contents of this file and paste the entire JSON string in the `.env` file as the value for `GOOGLE_API_CREDENTIALS` key.
#### _Adding google calendar to Cal.com App Store_
@@ -423,7 +436,7 @@ following
5. Choose "User-managed app" as the app type.
6. De-select the option to publish the app on the Zoom App Marketplace.
7. Click "Create".
8. Now copy the Client ID and Client Secret to your .env file into the `ZOOM_CLIENT_ID` and `ZOOM_CLIENT_SECRET` fields.
8. Now copy the Client ID and Client Secret to your `.env` file into the `ZOOM_CLIENT_ID` and `ZOOM_CLIENT_SECRET` fields.
9. Set the Redirect URL for OAuth `<Cal.com URL>/api/integrations/zoomvideo/callback` replacing Cal.com URL with the URI at which your application runs.
10. Also add the redirect URL given above as a allow list URL and enable "Subdomain check". Make sure, it says "saved" below the form.
11. You don't need to provide basic information about your app. Instead click at "Scopes" and then at "+ Add Scopes". On the left, click the category "Meeting" and check the scope `meeting:write`.
@@ -435,8 +448,8 @@ following
1. Visit our [Daily.co Partnership Form](https://go.cal.com/daily) and enter your information
2. From within your dashboard, go to the [developers](https://dashboard.daily.co/developers) tab.
3. Copy your API key.
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.
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://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
@@ -445,12 +458,16 @@ following
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.
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/hubspot/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 Webex Client ID and Secret
[See Webex Readme](./packages/app-store/webex/)
### Obtaining ZohoCRM Client ID and Secret
1. Open [Zoho API Console](https://api-console.zoho.com/) and sign into your account, or create a new one.
@@ -458,31 +475,33 @@ following
3. Click "ADD CLIENT" button top right and select "Server-based Applications".
4. Fill in any information you want in the "Client Details" tab
5. Go to tab "Client Secret" tab.
6. Now copy the Client ID and Client Secret to your .env file into the `ZOHOCRM_CLIENT_ID` and `ZOHOCRM_CLIENT_SECRET` fields.
6. Now copy the Client ID and Client Secret to your `.env` file into the `ZOHOCRM_CLIENT_ID` and `ZOHOCRM_CLIENT_SECRET` fields.
7. Set the Redirect URL for OAuth `<Cal.com URL>/api/integrations/zohocrm/callback` replacing Cal.com URL with the URI at which your application runs.
8. In the "Settings" section check the "Multi-DC" option if you wish to use the same OAuth credentials for all data centers.
9. Click the "Save"/ "UPDATE" button at the bottom footer.
10. You're good to go. Now you can easily add your ZohoCRM integration in the Cal.com settings.
### Obtaining Zoho Bigin Client ID and Secret
[Follow these steps](./packages/app-store/zoho-bigin/)
## Workflows
### Setting up SendGrid for Email reminders
1. Create a SendGrid account (https://signup.sendgrid.com/)
2. Go to Settings -> API keys and create an API key
3. Copy API key to your .env file into the SENDGRID_API_KEY field
3. Copy API key to your `.env` file into the `SENDGRID_API_KEY` field
4. Go to Settings -> Sender Authentication and verify a single sender
5. Copy the verified E-Mail to your .env file into the SENDGRID_EMAIL field
6. Add your custom sender name to the .env file into the NEXT_PUBLIC_SENDGRID_SENDER_NAME field (fallback is Cal.com)
5. Copy the verified E-Mail to your `.env` file into the `SENDGRID_EMAIL` field
6. Add your custom sender name to the `.env` file into the `NEXT_PUBLIC_SENDGRID_SENDER_NAME` field (fallback is Cal.com)
### Setting up Twilio for SMS reminders
1. Create a Twilio account (https://www.twilio.com/try-twilio)
1. Create a Twilio account (https://twilio.com/try-twilio)
2. Click ‘Get a Twilio phone number’
3. Copy Account SID to your .env file into the TWILIO_SID field
4. Copy Auth Token to your .env file into the TWILIO_TOKEN field
5. Copy your Twilio phone number to your .env file into the TWILIO_PHONE_NUMBER field
6. Add your own sender id to the .env file into the NEXT_PUBLIC_SENDER_ID field (fallback is Cal)
3. Copy Account SID to your `.env` file into the `TWILIO_SID` field
4. Copy Auth Token to your `.env` file into the `TWILIO_TOKEN` field
5. Copy your Twilio phone number to your `.env` file into the `TWILIO_PHONE_NUMBER` field
6. Add your own sender id to the `.env` file into the `NEXT_PUBLIC_SENDER_ID` field (fallback is Cal.com)
7. Create a messaging service (Develop -> Messaging -> Services)
8. Choose any name for the messaging service
9. Click 'Add Senders'
@@ -490,15 +509,15 @@ following
11. Add the listed phone number
12. Leave all other fields as they are
13. Complete setup and click ‘View my new Messaging Service’
14. Copy Messaging Service SID to your .env file into the TWILIO_MESSAGING_SID field
14. Copy Messaging Service SID to your `.env` file into the `TWILIO_MESSAGING_SID` field
15. Create a verify service
16. Copy Verify Service SID to your .env file into the TWILIO_VERIFY_SID field
16. Copy Verify Service SID to your `.env` file into the `TWILIO_VERIFY_SID` field
<!-- LICENSE -->
## License
Distributed under the AGPLv3 License. See `LICENSE` for more information.
Distributed under the [AGPLv3 License](https://github.com/calcom/cal.com/blob/main/LICENSE). See `LICENSE` for more information.
<!-- ACKNOWLEDGEMENTS -->
+1
View File
@@ -1,6 +1,7 @@
{
"name": "@calcom/docs",
"version": "1.0.0",
"private": true,
"description": "",
"main": "index.js",
"scripts": {
+2
View File
@@ -4,6 +4,7 @@ module.exports = {
stories: [
"../intro.stories.mdx",
"../../../packages/ui/components/**/*.stories.mdx",
"../../../packages/atoms/**/*.stories.mdx",
"../../../packages/features/**/*.stories.mdx",
"../../../packages/ui/components/**/*.stories.@(js|jsx|ts|tsx)",
],
@@ -70,4 +71,5 @@ module.exports = {
return config;
},
typescript: { reactDocgen: "react-docgen" },
};
+10
View File
@@ -0,0 +1,10 @@
# @calcom/web
## 2.7.16
### Patch Changes
- Updated dependencies
- @calcom/embed-snippet@1.0.7
- @calcom/embed-react@1.0.12
- @calcom/embed-core@1.1.5
+264 -273
View File
@@ -1,5 +1,6 @@
import { Collapsible, CollapsibleContent } from "@radix-ui/react-collapsible";
import classNames from "classnames";
import type { TFunction } from "next-i18next";
import type { NextRouter } from "next/router";
import { useRouter } from "next/router";
import type { MutableRefObject, RefObject } from "react";
@@ -21,11 +22,10 @@ import {
TextArea,
TextField,
ColorPicker,
Select,
} from "@calcom/ui";
import { Code, Trello, Sun, ArrowLeft } from "@calcom/ui/components/icon";
import Select from "@components/ui/form/Select";
type EmbedType = "inline" | "floating-popup" | "element-click";
type EmbedFramework = "react" | "HTML";
@@ -305,190 +305,189 @@ const getEmbedTypeSpecificString = ({
return "";
};
const embeds: {
illustration: React.ReactElement;
title: string;
subtitle: string;
type: EmbedType;
}[] = [
{
title: "Inline Embed",
subtitle: "Loads your event type directly inline with your other website content.",
type: "inline",
illustration: (
<svg
width="100%"
height="100%"
className="rounded-md"
viewBox="0 0 308 265"
fill="none"
xmlns="http://www.w3.org/2000/svg">
<path
d="M0 1.99999C0 0.895423 0.895431 0 2 0H306C307.105 0 308 0.895431 308 2V263C308 264.105 307.105 265 306 265H2C0.895431 265 0 264.105 0 263V1.99999Z"
fill="white"
/>
<rect x="24" width="260" height="38.5" rx="6" fill="#F3F4F6" />
<rect x="24.5" y="51" width="139" height="163" rx="1.5" fill="#F8F8F8" />
<rect opacity="0.8" x="48" y="74.5" width="80" height="8" rx="6" fill="#F3F4F6" />
<rect x="48" y="86.5" width="48" height="4" rx="6" fill="#F3F4F6" />
<rect x="49" y="99.5" width="6" height="6" rx="1" fill="#C6C6C6" />
<rect x="61" y="99.5" width="6" height="6" rx="1" fill="#3E3E3E" />
<rect x="73" y="99.5" width="6" height="6" rx="1" fill="#C6C6C6" />
<rect x="85" y="99.5" width="6" height="6" rx="1" fill="#C6C6C6" />
<rect x="97" y="99.5" width="6" height="6" rx="1" fill="#C6C6C6" />
<rect x="109" y="99.5" width="6" height="6" rx="1" fill="#C6C6C6" />
<rect x="121" y="99.5" width="6" height="6" rx="1" fill="#C6C6C6" />
<rect x="133" y="99.5" width="6" height="6" rx="1" fill="#C6C6C6" />
<rect x="85" y="113.5" width="6" height="6" rx="1" fill="#C6C6C6" />
<rect x="97" y="113.5" width="6" height="6" rx="1" fill="#C6C6C6" />
<rect x="109" y="113.5" width="6" height="6" rx="1" fill="#C6C6C6" />
<rect x="121" y="113.5" width="6" height="6" rx="1" fill="#C6C6C6" />
<rect x="133" y="113.5" width="6" height="6" rx="1" fill="#C6C6C6" />
<rect x="49" y="125.5" width="6" height="6" rx="1" fill="#C6C6C6" />
<rect x="61" y="125.5" width="6" height="6" rx="1" fill="#3E3E3E" />
<path
d="M61 124.5H67V122.5H61V124.5ZM68 125.5V131.5H70V125.5H68ZM67 132.5H61V134.5H67V132.5ZM60 131.5V125.5H58V131.5H60ZM61 132.5C60.4477 132.5 60 132.052 60 131.5H58C58 133.157 59.3431 134.5 61 134.5V132.5ZM68 131.5C68 132.052 67.5523 132.5 67 132.5V134.5C68.6569 134.5 70 133.157 70 131.5H68ZM67 124.5C67.5523 124.5 68 124.948 68 125.5H70C70 123.843 68.6569 122.5 67 122.5V124.5ZM61 122.5C59.3431 122.5 58 123.843 58 125.5H60C60 124.948 60.4477 124.5 61 124.5V122.5Z"
fill="#3E3E3E"
/>
<rect x="73" y="125.5" width="6" height="6" rx="1" fill="#C6C6C6" />
<rect x="85" y="125.5" width="6" height="6" rx="1" fill="#C6C6C6" />
<rect x="97" y="125.5" width="6" height="6" rx="1" fill="#C6C6C6" />
<rect x="109" y="125.5" width="6" height="6" rx="1" fill="#C6C6C6" />
<rect x="121" y="125.5" width="6" height="6" rx="1" fill="#C6C6C6" />
<rect x="133" y="125.5" width="6" height="6" rx="1" fill="#C6C6C6" />
<rect x="49" y="137.5" width="6" height="6" rx="1" fill="#C6C6C6" />
<rect x="61" y="137.5" width="6" height="6" rx="1" fill="#C6C6C6" />
<rect x="73" y="137.5" width="6" height="6" rx="1" fill="#C6C6C6" />
<rect x="85" y="137.5" width="6" height="6" rx="1" fill="#C6C6C6" />
<rect x="97" y="137.5" width="6" height="6" rx="1" fill="#3E3E3E" />
<rect x="109" y="137.5" width="6" height="6" rx="1" fill="#3E3E3E" />
<rect x="121" y="137.5" width="6" height="6" rx="1" fill="#C6C6C6" />
<rect x="133" y="137.5" width="6" height="6" rx="1" fill="#C6C6C6" />
<rect x="49" y="149.5" width="6" height="6" rx="1" fill="#C6C6C6" />
<rect x="61" y="149.5" width="6" height="6" rx="1" fill="#C6C6C6" />
<rect x="73" y="149.5" width="6" height="6" rx="1" fill="#C6C6C6" />
<rect x="85" y="149.5" width="6" height="6" rx="1" fill="#C6C6C6" />
<rect x="97" y="149.5" width="6" height="6" rx="1" fill="#3E3E3E" />
<rect x="109" y="149.5" width="6" height="6" rx="1" fill="#3E3E3E" />
<rect x="121" y="149.5" width="6" height="6" rx="1" fill="#C6C6C6" />
<rect x="133" y="149.5" width="6" height="6" rx="1" fill="#C6C6C6" />
<rect x="49" y="161.5" width="6" height="6" rx="1" fill="#C6C6C6" />
<rect x="61" y="161.5" width="6" height="6" rx="1" fill="#C6C6C6" />
<rect x="73" y="161.5" width="6" height="6" rx="1" fill="#C6C6C6" />
<rect x="85" y="161.5" width="6" height="6" rx="1" fill="#C6C6C6" />
<rect x="97" y="161.5" width="6" height="6" rx="1" fill="#3E3E3E" />
<rect x="109" y="161.5" width="6" height="6" rx="1" fill="#C6C6C6" />
<rect x="24.5" y="51" width="139" height="163" rx="6" stroke="#292929" />
<rect x="176" y="50.5" width="108" height="164" rx="6" fill="#F3F4F6" />
<rect x="24" y="226.5" width="260" height="38.5" rx="6" fill="#F3F4F6" />
</svg>
),
},
{
title: "Floating pop-up button",
subtitle: "Adds a floating button on your site that launches Cal in a dialog.",
type: "floating-popup",
illustration: (
<svg
width="100%"
height="100%"
className="rounded-md"
viewBox="0 0 308 265"
fill="none"
xmlns="http://www.w3.org/2000/svg">
<path
d="M0 1.99999C0 0.895423 0.895431 0 2 0H306C307.105 0 308 0.895431 308 2V263C308 264.105 307.105 265 306 265H2C0.895431 265 0 264.105 0 263V1.99999Z"
fill="white"
/>
<rect x="24" width="260" height="38.5" rx="6" fill="#F3F4F6" />
<rect x="24" y="50.5" width="120" height="76" rx="6" fill="#F3F4F6" />
<rect x="24" y="138.5" width="120" height="76" rx="6" fill="#F3F4F6" />
<rect x="156" y="50.5" width="128" height="164" rx="6" fill="#F3F4F6" />
<rect x="24" y="226.5" width="260" height="38.5" rx="6" fill="#F3F4F6" />
<rect x="226" y="223.5" width="66" height="26" rx="6" fill="#292929" />
<rect x="242" y="235.5" width="34" height="2" rx="1" fill="white" />
</svg>
),
},
{
title: "Pop up via element click",
subtitle: "Open your Cal dialog when someone clicks an element.",
type: "element-click",
illustration: (
<svg
width="100%"
height="100%"
className="rounded-md"
viewBox="0 0 308 265"
fill="none"
xmlns="http://www.w3.org/2000/svg">
<path
d="M0 1.99999C0 0.895423 0.895431 0 2 0H306C307.105 0 308 0.895431 308 2V263C308 264.105 307.105 265 306 265H2C0.895431 265 0 264.105 0 263V1.99999Z"
fill="white"
/>
<rect x="24" y="0.50293" width="260" height="24" rx="6" fill="#F3F4F6" />
<rect x="24" y="35" width="259" height="192" rx="5.5" fill="#F9FAFB" />
<g filter="url(#filter0_i_3223_14162)">
<rect opacity="0.8" x="40" y="99" width="24" height="24" rx="2" fill="#E5E7EB" />
<rect x="40" y="127" width="48" height="8" rx="1" fill="#E5E7EB" />
<rect x="40" y="139" width="82" height="8" rx="1" fill="#E5E7EB" />
<rect x="40" y="151" width="34" height="4" rx="1" fill="#E5E7EB" />
<rect x="40" y="159" width="34" height="4" rx="1" fill="#E5E7EB" />
</g>
<rect x="152" y="48" width="2" height="169" rx="2" fill="#E5E7EB" />
const embeds = (t: TFunction) =>
(() => {
return [
{
title: t("inline_embed"),
subtitle: t("load_inline_content"),
type: "inline",
illustration: (
<svg
width="100%"
height="100%"
className="rounded-md"
viewBox="0 0 308 265"
fill="none"
xmlns="http://www.w3.org/2000/svg">
<path
d="M0 1.99999C0 0.895423 0.895431 0 2 0H306C307.105 0 308 0.895431 308 2V263C308 264.105 307.105 265 306 265H2C0.895431 265 0 264.105 0 263V1.99999Z"
fill="white"
/>
<rect x="24" width="260" height="38.5" rx="6" fill="#F3F4F6" />
<rect x="24.5" y="51" width="139" height="163" rx="1.5" fill="#F8F8F8" />
<rect opacity="0.8" x="48" y="74.5" width="80" height="8" rx="6" fill="#F3F4F6" />
<rect x="48" y="86.5" width="48" height="4" rx="6" fill="#F3F4F6" />
<rect x="49" y="99.5" width="6" height="6" rx="1" fill="#C6C6C6" />
<rect x="61" y="99.5" width="6" height="6" rx="1" fill="#3E3E3E" />
<rect x="73" y="99.5" width="6" height="6" rx="1" fill="#C6C6C6" />
<rect x="85" y="99.5" width="6" height="6" rx="1" fill="#C6C6C6" />
<rect x="97" y="99.5" width="6" height="6" rx="1" fill="#C6C6C6" />
<rect x="109" y="99.5" width="6" height="6" rx="1" fill="#C6C6C6" />
<rect x="121" y="99.5" width="6" height="6" rx="1" fill="#C6C6C6" />
<rect x="133" y="99.5" width="6" height="6" rx="1" fill="#C6C6C6" />
<rect x="85" y="113.5" width="6" height="6" rx="1" fill="#C6C6C6" />
<rect x="97" y="113.5" width="6" height="6" rx="1" fill="#C6C6C6" />
<rect x="109" y="113.5" width="6" height="6" rx="1" fill="#C6C6C6" />
<rect x="121" y="113.5" width="6" height="6" rx="1" fill="#C6C6C6" />
<rect x="133" y="113.5" width="6" height="6" rx="1" fill="#C6C6C6" />
<rect x="49" y="125.5" width="6" height="6" rx="1" fill="#C6C6C6" />
<rect x="61" y="125.5" width="6" height="6" rx="1" fill="#3E3E3E" />
<path
d="M61 124.5H67V122.5H61V124.5ZM68 125.5V131.5H70V125.5H68ZM67 132.5H61V134.5H67V132.5ZM60 131.5V125.5H58V131.5H60ZM61 132.5C60.4477 132.5 60 132.052 60 131.5H58C58 133.157 59.3431 134.5 61 134.5V132.5ZM68 131.5C68 132.052 67.5523 132.5 67 132.5V134.5C68.6569 134.5 70 133.157 70 131.5H68ZM67 124.5C67.5523 124.5 68 124.948 68 125.5H70C70 123.843 68.6569 122.5 67 122.5V124.5ZM61 122.5C59.3431 122.5 58 123.843 58 125.5H60C60 124.948 60.4477 124.5 61 124.5V122.5Z"
fill="#3E3E3E"
/>
<rect x="73" y="125.5" width="6" height="6" rx="1" fill="#C6C6C6" />
<rect x="85" y="125.5" width="6" height="6" rx="1" fill="#C6C6C6" />
<rect x="97" y="125.5" width="6" height="6" rx="1" fill="#C6C6C6" />
<rect x="109" y="125.5" width="6" height="6" rx="1" fill="#C6C6C6" />
<rect x="121" y="125.5" width="6" height="6" rx="1" fill="#C6C6C6" />
<rect x="133" y="125.5" width="6" height="6" rx="1" fill="#C6C6C6" />
<rect x="49" y="137.5" width="6" height="6" rx="1" fill="#C6C6C6" />
<rect x="61" y="137.5" width="6" height="6" rx="1" fill="#C6C6C6" />
<rect x="73" y="137.5" width="6" height="6" rx="1" fill="#C6C6C6" />
<rect x="85" y="137.5" width="6" height="6" rx="1" fill="#C6C6C6" />
<rect x="97" y="137.5" width="6" height="6" rx="1" fill="#3E3E3E" />
<rect x="109" y="137.5" width="6" height="6" rx="1" fill="#3E3E3E" />
<rect x="121" y="137.5" width="6" height="6" rx="1" fill="#C6C6C6" />
<rect x="133" y="137.5" width="6" height="6" rx="1" fill="#C6C6C6" />
<rect x="49" y="149.5" width="6" height="6" rx="1" fill="#C6C6C6" />
<rect x="61" y="149.5" width="6" height="6" rx="1" fill="#C6C6C6" />
<rect x="73" y="149.5" width="6" height="6" rx="1" fill="#C6C6C6" />
<rect x="85" y="149.5" width="6" height="6" rx="1" fill="#C6C6C6" />
<rect x="97" y="149.5" width="6" height="6" rx="1" fill="#3E3E3E" />
<rect x="109" y="149.5" width="6" height="6" rx="1" fill="#3E3E3E" />
<rect x="121" y="149.5" width="6" height="6" rx="1" fill="#C6C6C6" />
<rect x="133" y="149.5" width="6" height="6" rx="1" fill="#C6C6C6" />
<rect x="49" y="161.5" width="6" height="6" rx="1" fill="#C6C6C6" />
<rect x="61" y="161.5" width="6" height="6" rx="1" fill="#C6C6C6" />
<rect x="73" y="161.5" width="6" height="6" rx="1" fill="#C6C6C6" />
<rect x="85" y="161.5" width="6" height="6" rx="1" fill="#C6C6C6" />
<rect x="97" y="161.5" width="6" height="6" rx="1" fill="#3E3E3E" />
<rect x="109" y="161.5" width="6" height="6" rx="1" fill="#C6C6C6" />
<rect x="24.5" y="51" width="139" height="163" rx="6" stroke="#292929" />
<rect x="176" y="50.5" width="108" height="164" rx="6" fill="#F3F4F6" />
<rect x="24" y="226.5" width="260" height="38.5" rx="6" fill="#F3F4F6" />
</svg>
),
},
{
title: t("floating_pop_up_button"),
subtitle: t("floating_button_trigger_modal"),
type: "floating-popup",
illustration: (
<svg
width="100%"
height="100%"
className="rounded-md"
viewBox="0 0 308 265"
fill="none"
xmlns="http://www.w3.org/2000/svg">
<path
d="M0 1.99999C0 0.895423 0.895431 0 2 0H306C307.105 0 308 0.895431 308 2V263C308 264.105 307.105 265 306 265H2C0.895431 265 0 264.105 0 263V1.99999Z"
fill="white"
/>
<rect x="24" width="260" height="38.5" rx="6" fill="#F3F4F6" />
<rect x="24" y="50.5" width="120" height="76" rx="6" fill="#F3F4F6" />
<rect x="24" y="138.5" width="120" height="76" rx="6" fill="#F3F4F6" />
<rect x="156" y="50.5" width="128" height="164" rx="6" fill="#F3F4F6" />
<rect x="24" y="226.5" width="260" height="38.5" rx="6" fill="#F3F4F6" />
<rect x="226" y="223.5" width="66" height="26" rx="6" fill="#292929" />
<rect x="242" y="235.5" width="34" height="2" rx="1" fill="white" />
</svg>
),
},
{
title: t("pop_up_element_click"),
subtitle: t("open_dialog_with_element_click"),
type: "element-click",
illustration: (
<svg
width="100%"
height="100%"
className="rounded-md"
viewBox="0 0 308 265"
fill="none"
xmlns="http://www.w3.org/2000/svg">
<path
d="M0 1.99999C0 0.895423 0.895431 0 2 0H306C307.105 0 308 0.895431 308 2V263C308 264.105 307.105 265 306 265H2C0.895431 265 0 264.105 0 263V1.99999Z"
fill="white"
/>
<rect x="24" y="0.50293" width="260" height="24" rx="6" fill="#F3F4F6" />
<rect x="24" y="35" width="259" height="192" rx="5.5" fill="#F9FAFB" />
<g filter="url(#filter0_i_3223_14162)">
<rect opacity="0.8" x="40" y="99" width="24" height="24" rx="2" fill="#E5E7EB" />
<rect x="40" y="127" width="48" height="8" rx="1" fill="#E5E7EB" />
<rect x="40" y="139" width="82" height="8" rx="1" fill="#E5E7EB" />
<rect x="40" y="151" width="34" height="4" rx="1" fill="#E5E7EB" />
<rect x="40" y="159" width="34" height="4" rx="1" fill="#E5E7EB" />
</g>
<rect x="152" y="48" width="2" height="169" rx="2" fill="#E5E7EB" />
<rect opacity="0.8" x="176" y="84" width="80" height="8" rx="2" fill="#E5E7EB" />
<rect x="176" y="96" width="48" height="4" rx="1" fill="#E5E7EB" />
<rect x="177" y="109" width="6" height="6" rx="1" fill="#E5E7EB" />
<rect x="189" y="109" width="6" height="6" rx="1" fill="#0D121D" />
<rect x="201" y="109" width="6" height="6" rx="1" fill="#E5E7EB" />
<rect x="213" y="109" width="6" height="6" rx="1" fill="#E5E7EB" />
<rect x="225" y="109" width="6" height="6" rx="1" fill="#E5E7EB" />
<rect x="237" y="109" width="6" height="6" rx="1" fill="#E5E7EB" />
<rect x="249" y="109" width="6" height="6" rx="1" fill="#E5E7EB" />
<rect x="261" y="109" width="6" height="6" rx="1" fill="#E5E7EB" />
<rect x="213" y="123" width="6" height="6" rx="1" fill="#E5E7EB" />
<rect x="225" y="123" width="6" height="6" rx="1" fill="#E5E7EB" />
<rect x="237" y="123" width="6" height="6" rx="1" fill="#E5E7EB" />
<rect x="249" y="123" width="6" height="6" rx="1" fill="#E5E7EB" />
<rect x="261" y="123" width="6" height="6" rx="1" fill="#E5E7EB" />
<rect x="177" y="135" width="6" height="6" rx="1" fill="#E5E7EB" />
<rect x="189" y="135" width="6" height="6" rx="1" fill="#0D121D" />
<rect x="187.3" y="133.4" width="9" height="9" rx="1.5" stroke="#0D121D" />
<rect x="201" y="135" width="6" height="6" rx="1" fill="#E5E7EB" />
<rect x="213" y="135" width="6" height="6" rx="1" fill="#E5E7EB" />
<rect x="225" y="135" width="6" height="6" rx="1" fill="#E5E7EB" />
<rect x="237" y="135" width="6" height="6" rx="1" fill="#E5E7EB" />
<rect x="249" y="135" width="6" height="6" rx="1" fill="#E5E7EB" />
<rect x="261" y="135" width="6" height="6" rx="1" fill="#E5E7EB" />
<rect x="177" y="147" width="6" height="6" rx="1" fill="#E5E7EB" />
<rect x="189" y="147" width="6" height="6" rx="1" fill="#E5E7EB" />
<rect x="201" y="147" width="6" height="6" rx="1" fill="#E5E7EB" />
<rect x="213" y="147" width="6" height="6" rx="1" fill="#E5E7EB" />
<rect x="225" y="147" width="6" height="6" rx="1" fill="#0D121D" />
<rect x="237" y="147" width="6" height="6" rx="1" fill="#0D121D" />
<rect x="249" y="147" width="6" height="6" rx="1" fill="#E5E7EB" />
<rect x="261" y="147" width="6" height="6" rx="1" fill="#E5E7EB" />
<rect x="177" y="159" width="6" height="6" rx="1" fill="#E5E7EB" />
<rect x="189" y="159" width="6" height="6" rx="1" fill="#E5E7EB" />
<rect x="201" y="159" width="6" height="6" rx="1" fill="#E5E7EB" />
<rect x="213" y="159" width="6" height="6" rx="1" fill="#E5E7EB" />
<rect x="225" y="159" width="6" height="6" rx="1" fill="#0D121D" />
<rect x="237" y="159" width="6" height="6" rx="1" fill="#0D121D" />
<rect x="249" y="159" width="6" height="6" rx="1" fill="#E5E7EB" />
<rect x="261" y="159" width="6" height="6" rx="1" fill="#E5E7EB" />
<rect x="177" y="171" width="6" height="6" rx="1" fill="#E5E7EB" />
<rect x="189" y="171" width="6" height="6" rx="1" fill="#E5E7EB" />
<rect x="201" y="171" width="6" height="6" rx="1" fill="#E5E7EB" />
<rect x="213" y="171" width="6" height="6" rx="1" fill="#E5E7EB" />
<rect x="225" y="171" width="6" height="6" rx="1" fill="#0D121D" />
<rect x="237" y="171" width="6" height="6" rx="1" fill="#E5E7EB" />
<rect x="24" y="35" width="259" height="192" rx="5.5" stroke="#101010" />
<rect x="24" y="241.503" width="260" height="24" rx="6" fill="#F3F4F6" />
</svg>
),
},
];
})();
<rect opacity="0.8" x="176" y="84" width="80" height="8" rx="2" fill="#E5E7EB" />
<rect x="176" y="96" width="48" height="4" rx="1" fill="#E5E7EB" />
<rect x="177" y="109" width="6" height="6" rx="1" fill="#E5E7EB" />
<rect x="189" y="109" width="6" height="6" rx="1" fill="#0D121D" />
<rect x="201" y="109" width="6" height="6" rx="1" fill="#E5E7EB" />
<rect x="213" y="109" width="6" height="6" rx="1" fill="#E5E7EB" />
<rect x="225" y="109" width="6" height="6" rx="1" fill="#E5E7EB" />
<rect x="237" y="109" width="6" height="6" rx="1" fill="#E5E7EB" />
<rect x="249" y="109" width="6" height="6" rx="1" fill="#E5E7EB" />
<rect x="261" y="109" width="6" height="6" rx="1" fill="#E5E7EB" />
<rect x="213" y="123" width="6" height="6" rx="1" fill="#E5E7EB" />
<rect x="225" y="123" width="6" height="6" rx="1" fill="#E5E7EB" />
<rect x="237" y="123" width="6" height="6" rx="1" fill="#E5E7EB" />
<rect x="249" y="123" width="6" height="6" rx="1" fill="#E5E7EB" />
<rect x="261" y="123" width="6" height="6" rx="1" fill="#E5E7EB" />
<rect x="177" y="135" width="6" height="6" rx="1" fill="#E5E7EB" />
<rect x="189" y="135" width="6" height="6" rx="1" fill="#0D121D" />
<rect x="187.3" y="133.4" width="9" height="9" rx="1.5" stroke="#0D121D" />
<rect x="201" y="135" width="6" height="6" rx="1" fill="#E5E7EB" />
<rect x="213" y="135" width="6" height="6" rx="1" fill="#E5E7EB" />
<rect x="225" y="135" width="6" height="6" rx="1" fill="#E5E7EB" />
<rect x="237" y="135" width="6" height="6" rx="1" fill="#E5E7EB" />
<rect x="249" y="135" width="6" height="6" rx="1" fill="#E5E7EB" />
<rect x="261" y="135" width="6" height="6" rx="1" fill="#E5E7EB" />
<rect x="177" y="147" width="6" height="6" rx="1" fill="#E5E7EB" />
<rect x="189" y="147" width="6" height="6" rx="1" fill="#E5E7EB" />
<rect x="201" y="147" width="6" height="6" rx="1" fill="#E5E7EB" />
<rect x="213" y="147" width="6" height="6" rx="1" fill="#E5E7EB" />
<rect x="225" y="147" width="6" height="6" rx="1" fill="#0D121D" />
<rect x="237" y="147" width="6" height="6" rx="1" fill="#0D121D" />
<rect x="249" y="147" width="6" height="6" rx="1" fill="#E5E7EB" />
<rect x="261" y="147" width="6" height="6" rx="1" fill="#E5E7EB" />
<rect x="177" y="159" width="6" height="6" rx="1" fill="#E5E7EB" />
<rect x="189" y="159" width="6" height="6" rx="1" fill="#E5E7EB" />
<rect x="201" y="159" width="6" height="6" rx="1" fill="#E5E7EB" />
<rect x="213" y="159" width="6" height="6" rx="1" fill="#E5E7EB" />
<rect x="225" y="159" width="6" height="6" rx="1" fill="#0D121D" />
<rect x="237" y="159" width="6" height="6" rx="1" fill="#0D121D" />
<rect x="249" y="159" width="6" height="6" rx="1" fill="#E5E7EB" />
<rect x="261" y="159" width="6" height="6" rx="1" fill="#E5E7EB" />
<rect x="177" y="171" width="6" height="6" rx="1" fill="#E5E7EB" />
<rect x="189" y="171" width="6" height="6" rx="1" fill="#E5E7EB" />
<rect x="201" y="171" width="6" height="6" rx="1" fill="#E5E7EB" />
<rect x="213" y="171" width="6" height="6" rx="1" fill="#E5E7EB" />
<rect x="225" y="171" width="6" height="6" rx="1" fill="#0D121D" />
<rect x="237" y="171" width="6" height="6" rx="1" fill="#E5E7EB" />
<rect x="24" y="35" width="259" height="192" rx="5.5" stroke="#101010" />
<rect x="24" y="241.503" width="260" height="24" rx="6" fill="#F3F4F6" />
</svg>
),
},
];
const tabs = [
{
name: "HTML",
@@ -534,11 +533,7 @@ ${getEmbedTypeSpecificString({ embedFramework: "HTML", embedType, calLink, previ
<!-- Cal ${embedType} embed code ends -->`
}
/>
<p className="text-subtle hidden text-sm">
{t(
"Need help? See our guides for embedding Cal on Wix, Squarespace, or WordPress, check our common questions, or explore advanced embed options."
)}
</p>
<p className="text-subtle hidden text-sm">{t("need_help_embedding")}</p>
</>
);
}),
@@ -622,7 +617,7 @@ Cal("init", {origin:"${WEBAPP_URL}"});
const ThemeSelectControl = ({ children, ...props }: ControlProps<{ value: Theme; label: string }, false>) => {
return (
<components.Control {...props}>
<Sun className="text-subtle ml-2 h-4 w-4" />
<Sun className="text-subtle mr-2 h-4 w-4" />
{children}
</components.Control>
);
@@ -642,7 +637,7 @@ const ChooseEmbedTypesDialogContent = () => {
</div>
</div>
<div className="items-start space-y-2 md:flex md:space-y-0">
{embeds.map((embed, index) => (
{embeds(t).map((embed, index) => (
<button
className="hover:bg-subtle bg-muted w-full rounded-md border border-transparent p-6 text-left hover:rounded-md ltr:mr-4 ltr:last:mr-0 rtl:ml-4 rtl:last:ml-0 lg:w-1/3"
key={index}
@@ -692,7 +687,7 @@ const EmbedTypeCodeAndPreviewDialogContent = ({
});
const refOfEmbedCodesRefs = useRef(embedCodeRefs);
const embed = embeds.find((embed) => embed.type === embedType);
const embed = embeds(t).find((embed) => embed.type === embedType);
const [isEmbedCustomizationOpen, setIsEmbedCustomizationOpen] = useState(true);
const [isBookingCustomizationOpen, setIsBookingCustomizationOpen] = useState(true);
@@ -806,11 +801,11 @@ const EmbedTypeCodeAndPreviewDialogContent = ({
const FloatingPopupPositionOptions = [
{
value: "bottom-right",
label: "Bottom Right",
label: "Bottom right",
},
{
value: "bottom-left",
label: "Bottom Left",
label: "Bottom left",
},
];
@@ -834,7 +829,7 @@ const EmbedTypeCodeAndPreviewDialogContent = ({
</button>
{embed.title}
</h3>
<h4 className="text-emphasis mb-6 text-sm font-normal">{embed.subtitle}</h4>
<h4 className="text-subtle mb-6 text-sm font-normal">{embed.subtitle}</h4>
<div className="flex flex-col">
<div className={classNames("font-medium", embedType === "element-click" ? "hidden" : "")}>
<Collapsible
@@ -844,7 +839,7 @@ const EmbedTypeCodeAndPreviewDialogContent = ({
<div className={classNames(embedType === "inline" ? "block" : "hidden")}>
{/*TODO: Add Auto/Fixed toggle from Figma */}
<div className="text-default mb-[9px] text-sm">Window sizing</div>
<div className="justify-left flex items-center !font-normal">
<div className="justify-left mb-6 flex items-center !font-normal ">
<div className="mr-[9px]">
<TextField
labelProps={{ className: "hidden" }}
@@ -892,10 +887,10 @@ const EmbedTypeCodeAndPreviewDialogContent = ({
</div>
<div
className={classNames(
"mt-4 items-center justify-between",
"items-center justify-between",
embedType === "floating-popup" ? "text-emphasis" : "hidden"
)}>
<div className="mb-2 text-sm">Button Text</div>
<div className="mb-2 text-sm">Button text</div>
{/* Default Values should come from preview iframe */}
<TextField
labelProps={{ className: "hidden" }}
@@ -910,7 +905,7 @@ const EmbedTypeCodeAndPreviewDialogContent = ({
};
});
}}
defaultValue="Book my Cal"
defaultValue={t("book_my_cal")}
required
/>
</div>
@@ -935,14 +930,14 @@ const EmbedTypeCodeAndPreviewDialogContent = ({
});
}}
/>
<div className="text-default text-sm">Display Calendar Icon Button</div>
<div className="text-default my-2 text-sm">Display calendar icon</div>
</div>
<div
className={classNames(
"mt-4 items-center justify-between",
embedType === "floating-popup" ? "text-emphasis" : "hidden"
)}>
<div className="mb-2">Position of Button</div>
<div className="mb-2">Position of button</div>
<Select
onChange={(position) => {
setPreviewState((previewState) => {
@@ -959,54 +954,50 @@ const EmbedTypeCodeAndPreviewDialogContent = ({
options={FloatingPopupPositionOptions}
/>
</div>
<div
className={classNames(
"mt-4",
embedType === "floating-popup" ? "text-emphasis" : "hidden"
)}>
<div>Button Color</div>
<div className="w-full">
<ColorPicker
popoverAlign="start"
container={dialogContentRef?.current ?? undefined}
defaultValue="#000000"
onChange={(color) => {
setPreviewState((previewState) => {
return {
...previewState,
floatingPopup: {
...previewState.floatingPopup,
buttonColor: color,
},
};
});
}}
/>
<div className="mt-3 flex flex-col xl:flex-row xl:justify-between">
<div className={classNames("mt-4", embedType === "floating-popup" ? "" : "hidden")}>
<div className="whitespace-nowrap">Button color</div>
<div className="mt-2 w-40 xl:mt-0 xl:w-full">
<ColorPicker
className="w-[130px]"
popoverAlign="start"
container={dialogContentRef?.current ?? undefined}
defaultValue="#000000"
onChange={(color) => {
setPreviewState((previewState) => {
return {
...previewState,
floatingPopup: {
...previewState.floatingPopup,
buttonColor: color,
},
};
});
}}
/>
</div>
</div>
</div>
<div
className={classNames(
"mt-4",
embedType === "floating-popup" ? "text-emphasis" : "hidden"
)}>
<div>Text Color</div>
<div className="w-full">
<ColorPicker
popoverAlign="start"
container={dialogContentRef?.current ?? undefined}
defaultValue="#000000"
onChange={(color) => {
setPreviewState((previewState) => {
return {
...previewState,
floatingPopup: {
...previewState.floatingPopup,
buttonTextColor: color,
},
};
});
}}
/>
<div className={classNames("mt-4", embedType === "floating-popup" ? "" : "hidden")}>
<div className="whitespace-nowrap">Text color</div>
<div className="mt-2 mb-6 w-40 xl:mt-0 xl:w-full">
<ColorPicker
className="w-[130px]"
popoverAlign="start"
container={dialogContentRef?.current ?? undefined}
defaultValue="#000000"
onChange={(color) => {
setPreviewState((previewState) => {
return {
...previewState,
floatingPopup: {
...previewState.floatingPopup,
buttonTextColor: color,
},
};
});
}}
/>
</div>
</div>
</div>
</CollapsibleContent>
@@ -1017,7 +1008,30 @@ const EmbedTypeCodeAndPreviewDialogContent = ({
open={isBookingCustomizationOpen}
onOpenChange={() => setIsBookingCustomizationOpen((val) => !val)}>
<CollapsibleContent>
<div className="mt-6 text-sm">
<div className="text-sm">
<Label className="mb-6">
<div className="mb-2">Theme</div>
<Select
className="w-full"
defaultValue={ThemeOptions[0]}
components={{
Control: ThemeSelectControl,
IndicatorSeparator: () => null,
}}
onChange={(option) => {
if (!option) {
return;
}
setPreviewState((previewState) => {
return {
...previewState,
theme: option.value,
};
});
}}
options={ThemeOptions}
/>
</Label>
<div className="mb-6 flex items-center justify-start space-x-2 rtl:space-x-reverse">
<Switch
checked={previewState.hideEventTypeDetails}
@@ -1056,29 +1070,6 @@ const EmbedTypeCodeAndPreviewDialogContent = ({
</div>
</Label>
))}
<Label>
<div className="mb-2">Theme</div>
<Select
className="w-full"
defaultValue={ThemeOptions[0]}
components={{
Control: ThemeSelectControl,
IndicatorSeparator: () => null,
}}
onChange={(option) => {
if (!option) {
return;
}
setPreviewState((previewState) => {
return {
...previewState,
theme: option.value,
};
});
}}
options={ThemeOptions}
/>
</Label>
</div>
</CollapsibleContent>
</Collapsible>
+8 -4
View File
@@ -1,5 +1,4 @@
import Link from "next/link";
import { useRouter } from "next/router";
import type { IframeHTMLAttributes } from "react";
import React, { useState } from "react";
@@ -37,13 +36,13 @@ const Component = ({
tos,
privacy,
isProOnly,
teamsPlanRequired,
descriptionItems,
isTemplate,
dependencies,
}: Parameters<typeof App>[0]) => {
const { t, i18n } = useLocale();
const hasDescriptionItems = descriptionItems && descriptionItems.length > 0;
const router = useRouter();
const mutation = useAddAppMutation(null, {
onSuccess: (data) => {
@@ -154,6 +153,7 @@ const Component = ({
type={type}
isProOnly={isProOnly}
disableInstall={disableInstall}
teamsPlanRequired={teamsPlanRequired}
render={({ useDefaultComponent, ...props }) => {
if (useDefaultComponent) {
props = {
@@ -186,7 +186,7 @@ const Component = ({
label={t("disconnect")}
credentialId={existingCredentials[0]}
onSuccess={() => {
router.replace("/apps/installed");
appCredentials.refetch();
}}
/>
) : (
@@ -194,6 +194,7 @@ const Component = ({
type={type}
isProOnly={isProOnly}
disableInstall={disableInstall}
teamsPlanRequired={teamsPlanRequired}
render={({ useDefaultComponent, ...props }) => {
if (useDefaultComponent) {
props = {
@@ -243,7 +244,9 @@ const Component = ({
</div>
<h4 className="text-emphasis mt-8 font-semibold ">{t("pricing")}</h4>
<span className="text-default">
{price === 0 ? (
{teamsPlanRequired ? (
t("teams_plan_required")
) : price === 0 ? (
t("free_to_use_apps")
) : (
<>
@@ -360,6 +363,7 @@ export default function App(props: {
privacy?: string;
licenseRequired: AppType["licenseRequired"];
isProOnly: AppType["isProOnly"];
teamsPlanRequired: AppType["teamsPlanRequired"];
descriptionItems?: Array<string | { iframe: IframeHTMLAttributes<HTMLIFrameElement> }>;
isTemplate?: boolean;
disableInstall?: boolean;
@@ -1,9 +1,9 @@
import { useMutation } from "@tanstack/react-query";
import Link from "next/link";
import { Fragment } from "react";
import { InstallAppButton } from "@calcom/app-store/components";
import DisconnectIntegration from "@calcom/features/apps/components/DisconnectIntegration";
import { CalendarSwitch } from "@calcom/features/calendars/CalendarSwitch";
import DestinationCalendarSelector from "@calcom/features/calendars/DestinationCalendarSelector";
import { useLocale } from "@calcom/lib/hooks/useLocale";
import { trpc } from "@calcom/trpc/react";
@@ -12,12 +12,10 @@ import {
Button,
EmptyScreen,
List,
showToast,
AppSkeletonLoader as SkeletonLoader,
Switch,
ShellSubHeading,
} from "@calcom/ui";
import { ArrowLeft, Calendar, Plus } from "@calcom/ui/components/icon";
import { Calendar, Plus } from "@calcom/ui/components/icon";
import { QueryCell } from "@lib/QueryCell";
@@ -31,83 +29,6 @@ type Props = {
destinationCalendarId?: string;
};
function CalendarSwitch(props: {
type: string;
externalId: string;
title: string;
defaultSelected: boolean;
destination?: boolean;
}) {
const { t } = useLocale();
const utils = trpc.useContext();
const mutation = useMutation<
unknown,
unknown,
{
isOn: boolean;
}
>(
async ({ isOn }) => {
const body = {
integration: props.type,
externalId: props.externalId,
};
if (isOn) {
const res = await fetch("/api/availability/calendar", {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify(body),
});
if (!res.ok) {
throw new Error("Something went wrong");
}
} else {
const res = await fetch("/api/availability/calendar", {
method: "DELETE",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify(body),
});
if (!res.ok) {
throw new Error("Something went wrong");
}
}
},
{
async onSettled() {
await utils.viewer.integrations.invalidate();
},
onError() {
showToast(`Something went wrong when toggling "${props.title}""`, "error");
},
}
);
return (
<div className="flex flex-col py-1 sm:flex-row">
<Switch
key={props.externalId}
name="enabled"
label={props.title}
defaultChecked={props.defaultSelected}
onCheckedChange={(isOn: boolean) => {
mutation.mutate({ isOn });
}}
/>
{!!props.destination && (
<span className="bg-subtle text-default ml-8 inline-flex items-center gap-1 rounded-md px-2 py-1 text-sm font-normal sm:ml-4">
<ArrowLeft className="h-4 w-4" />
{t("adding_events_to")}
</span>
)}
</div>
);
}
function CalendarList(props: Props) {
const { t } = useLocale();
const query = trpc.viewer.integrations.useQuery({ variant: "calendar", onlyInstalled: false });
@@ -185,14 +106,15 @@ function ConnectedCalendarsList(props: Props) {
{!fromOnboarding && (
<>
<p className="text-subtle px-5 pt-4 text-sm">{t("toggle_calendars_conflict")}</p>
<ul className="space-y-2 px-5 py-4">
<ul className="space-y-4 px-5 py-4">
{item.calendars.map((cal) => (
<CalendarSwitch
key={cal.externalId}
externalId={cal.externalId}
title={cal.name || "Nameless calendar"}
name={cal.name || "Nameless calendar"}
type={item.integration.type}
defaultSelected={cal.isSelected}
isChecked={cal.isSelected}
destination={cal.externalId === props.destinationCalendarId}
/>
))}
@@ -18,9 +18,9 @@ export default function AppsLayout({ children, actions, emptyStore, ...rest }: A
const { t } = useLocale();
const session = useSession();
const router = useRouter();
const isAdmin = session.data?.user.role === "ADMIN";
if (session.status === "loading") return <></>;
return (
<Shell {...rest} actions={actions?.("block")} hideHeadingOnMobile>
<div className="flex flex-col xl:flex-row">
@@ -29,8 +29,8 @@ export default function AppsLayout({ children, actions, emptyStore, ...rest }: A
<EmptyScreen
Icon={AlertCircle}
headline={t("no_apps")}
description={session.data?.user.role === "ADMIN" ? "You can enable apps in the settings" : ""}
buttonText={session.data?.user.role === "ADMIN" ? t("apps_settings") : ""}
description={isAdmin ? "You can enable apps in the settings" : ""}
buttonText={isAdmin ? t("apps_settings") : ""}
buttonOnClick={() => router.push("/settings/admin/apps/calendar")}
/>
) : (
@@ -1,4 +1,3 @@
import { UserPermissionRole } from "@prisma/client";
import { useSession } from "next-auth/react";
import { useRouter } from "next/router";
import type { ComponentProps } from "react";
@@ -6,6 +5,7 @@ import React, { useEffect } from "react";
import SettingsLayout from "@calcom/features/settings/layouts/SettingsLayout";
import type Shell from "@calcom/features/shell/Shell";
import { UserPermissionRole } from "@calcom/prisma/enums";
import { ErrorBoundary } from "@calcom/ui";
export default function AdminLayout({
@@ -47,7 +47,7 @@ export function AvailableEventLocations({ locations }: { locations: Props["event
src={eventLocationType.iconUrl}
className={classNames(
"ml-[2px] h-4 w-4 opacity-70 ltr:mr-[10px] rtl:ml-[10px] dark:opacity-100 ",
!eventLocationType.iconUrl?.includes("api") ? "dark:invert-[.65]" : ""
!eventLocationType.iconUrl?.startsWith("/app-store") ? "dark:invert-[.65]" : ""
)}
alt={`${eventLocationType.label} icon`}
/>
@@ -11,7 +11,7 @@ import useMediaQuery from "@calcom/lib/hooks/useMediaQuery";
import { TimeFormat } from "@calcom/lib/timeFormat";
import { nameOfDay } from "@calcom/lib/weekday";
import { trpc } from "@calcom/trpc/react";
import type { Slot } from "@calcom/trpc/server/routers/viewer/slots";
import type { Slot } from "@calcom/trpc/server/routers/viewer/slots/types";
import { SkeletonContainer, SkeletonText, ToggleGroup } from "@calcom/ui";
import classNames from "@lib/classNames";
@@ -72,6 +72,7 @@ const AvailableTimes: FC<AvailableTimesProps> = ({
slotUtcStartDate: slot.time,
eventTypeId,
slotUtcEndDate: dayjs(slot.time).utc().add(duration, "minutes").format(),
bookingUid: slot.bookingUid,
});
};
@@ -1,10 +1,10 @@
import { SchedulingType } from "@prisma/client";
import type { FC, ReactNode } from "react";
import { useEffect } from "react";
import dayjs from "@calcom/dayjs";
import classNames from "@calcom/lib/classNames";
import { useLocale } from "@calcom/lib/hooks/useLocale";
import { SchedulingType } from "@calcom/prisma/enums";
import { Badge } from "@calcom/ui";
import { CheckSquare, Clock } from "@calcom/ui/components/icon";
+16 -12
View File
@@ -1,4 +1,3 @@
import { BookingStatus } from "@prisma/client";
import { useRouter } from "next/router";
import { useState } from "react";
@@ -13,6 +12,7 @@ import { formatTime } from "@calcom/lib/date-fns";
import getPaymentAppData from "@calcom/lib/getPaymentAppData";
import { useLocale } from "@calcom/lib/hooks/useLocale";
import { getEveryFreqFor } from "@calcom/lib/recurringStrings";
import { BookingStatus } from "@calcom/prisma/enums";
import type { RouterInputs, RouterOutputs } from "@calcom/trpc/react";
import { trpc } from "@calcom/trpc/react";
import type { ActionType } from "@calcom/ui";
@@ -29,7 +29,7 @@ import {
TableActions,
TextAreaField,
} from "@calcom/ui";
import { Check, Clock, MapPin, RefreshCcw, Send, Slash, X, CreditCard } from "@calcom/ui/components/icon";
import { Check, Clock, MapPin, RefreshCcw, Send, Ban, X, CreditCard } from "@calcom/ui/components/icon";
import useMeQuery from "@lib/hooks/useMeQuery";
@@ -119,7 +119,7 @@ function BookingListItem(booking: BookingItemProps) {
onClick: () => {
setRejectionDialogIsOpen(true);
},
icon: Slash,
icon: Ban,
disabled: mutation.isLoading,
},
// For bookings with payment, only confirm if the booking is paid for
@@ -280,13 +280,13 @@ function BookingListItem(booking: BookingItemProps) {
isOpenDialog={isOpenSetLocationDialog}
setShowLocationModal={setIsOpenLocationDialog}
/>
{booking.paid && (
{booking.paid && booking.payment[0] && (
<ChargeCardDialog
isOpenDialog={chargeCardDialogIsOpen}
setIsOpenDialog={setChargeCardDialogIsOpen}
bookingId={booking.id}
paymentAmount={booking?.payment[0].amount}
paymentCurrency={booking?.payment[0].currency}
paymentAmount={booking.payment[0].amount}
paymentCurrency={booking.payment[0].currency}
/>
)}
{showRecordingsButtons && (
@@ -354,11 +354,15 @@ function BookingListItem(booking: BookingItemProps) {
{booking.eventType.team.name}
</Badge>
)}
{booking.paid && (
{booking.paid && !booking.payment[0] ? (
<Badge className="ltr:mr-2 rtl:ml-2" variant="orange">
{t("error_collecting_card")}
</Badge>
) : booking.paid ? (
<Badge className="ltr:mr-2 rtl:ml-2" variant="green">
{booking.payment[0].paymentOption === "HOLD" ? t("card_held") : t("paid")}
</Badge>
)}
) : null}
{recurringDates !== undefined && (
<div className="text-muted mt-2 text-sm">
<RecurringBookingsTooltip booking={booking} recurringDates={recurringDates} />
@@ -458,7 +462,7 @@ function BookingListItem(booking: BookingItemProps) {
<RequestSentMessage />
</div>
)}
{booking.status === "ACCEPTED" && booking.paid && booking?.payment[0]?.paymentOption === "HOLD" && (
{booking.status === "ACCEPTED" && booking.paid && booking.payment[0]?.paymentOption === "HOLD" && (
<div className="ml-2">
<TableActions actions={chargeCardActions} />
</div>
@@ -483,12 +487,12 @@ const RecurringBookingsTooltip = ({ booking, recurringDates }: RecurringBookings
i18n: { language },
} = useLocale();
const now = new Date();
const recurringCount = recurringDates.filter((date) => {
const recurringCount = recurringDates.filter((recurringDate) => {
return (
date >= now &&
recurringDate >= now &&
!booking.recurringInfo?.bookings[BookingStatus.CANCELLED]
.map((date) => date.toDateString())
.includes(date.toDateString())
.includes(recurringDate.toDateString())
);
}).length;
@@ -17,7 +17,7 @@ export function TimezoneDropdown({
return (
<>
<div className="dark:focus-within:bg-darkgray-200 dark:bg-darkgray-100 dark:hover:bg-darkgray-200 !mt-3 flex w-full max-w-[20rem] items-center rounded-[4px] px-1 text-sm font-medium focus-within:bg-gray-200 hover:bg-gray-100 lg:max-w-[12rem] [&_p]:focus-within:text-gray-900 dark:[&_p]:focus-within:text-white [&_svg]:focus-within:text-gray-900 dark:[&_svg]:focus-within:text-white">
<div className="dark:focus-within:bg-darkgray-200 dark:hover:bg-darkgray-200 !mt-3 flex w-full max-w-[20rem] items-center rounded-[4px] px-1 text-sm font-medium focus-within:bg-gray-200 hover:bg-gray-100 lg:max-w-[12rem] [&_p]:focus-within:text-gray-900 dark:[&_p]:focus-within:text-white [&_svg]:focus-within:text-gray-900 dark:[&_svg]:focus-within:text-white">
<Globe className="dark:text-darkgray-600 flex h-4 w-4 text-gray-600 ltr:mr-2 rtl:ml-2" />
<TimeOptions onSelectTimeZone={handleSelectTimeZone} />
</div>
@@ -21,6 +21,7 @@ import {
useIsBackgroundTransparent,
useIsEmbed,
} from "@calcom/embed-core/embed-iframe";
import { createBooking, createRecurringBooking } from "@calcom/features/bookings/lib";
import {
getBookingFieldsWithSystemFields,
SystemField,
@@ -38,6 +39,7 @@ import { useLocale } from "@calcom/lib/hooks/useLocale";
import useTheme from "@calcom/lib/hooks/useTheme";
import { useTypedQuery } from "@calcom/lib/hooks/useTypedQuery";
import { HttpError } from "@calcom/lib/http-error";
import { parseDate, parseRecurringDates } from "@calcom/lib/parse-dates";
import { getEveryFreqFor } from "@calcom/lib/recurringStrings";
import { telemetryEventTypes, useTelemetry } from "@calcom/lib/telemetry";
import { TimeFormat } from "@calcom/lib/timeFormat";
@@ -47,9 +49,6 @@ import { AlertTriangle, Calendar, RefreshCw, User } from "@calcom/ui/components/
import { timeZone } from "@lib/clock";
import useRouterQuery from "@lib/hooks/useRouterQuery";
import createBooking from "@lib/mutations/bookings/create-booking";
import createRecurringBooking from "@lib/mutations/bookings/create-recurring-booking";
import { parseRecurringDates, parseDate } from "@lib/parseDate";
import type { Gate, GateState } from "@components/Gates";
import Gates from "@components/Gates";
@@ -231,12 +230,14 @@ const BookingPage = ({
}),
{}
);
const reserveSlot = () => {
if (queryDuration) {
reserveSlotMutation.mutate({
eventTypeId: eventType.id,
slotUtcStartDate: dayjs(queryDate).utc().format(),
slotUtcEndDate: dayjs(queryDate).utc().add(parseInt(queryDuration), "minutes").format(),
bookingUid: currentSlotBooking?.uid,
});
}
};
@@ -433,7 +434,6 @@ const BookingPage = ({
// Calculate the booking date(s)
let recurringStrings: string[] = [],
recurringDates: Date[] = [];
if (eventType.recurringEvent?.freq && recurringEventCount !== null) {
[recurringStrings, recurringDates] = parseRecurringDates(
{
@@ -443,7 +443,7 @@ const BookingPage = ({
recurringCount: parseInt(recurringEventCount.toString()),
selectedTimeFormat: timeFormat,
},
i18n
i18n.language
);
}
@@ -552,11 +552,11 @@ const BookingPage = ({
)}>
<div className="sm:flex">
{showEventTypeDetails && (
<div className="sm:border-subtle text-default flex flex-col px-6 pt-6 pb-0 sm:w-1/2 sm:border-r sm:pb-6">
<div className="sm:border-subtle text-default flex flex-col px-6 pt-6 pb-0 sm:w-1/2 sm:border-r sm:pb-6">
<BookingDescription isBookingPage profile={profile} eventType={eventType}>
<BookingDescriptionPayment eventType={eventType} t={t} i18n={i18n} />
{!rescheduleUid && eventType.recurringEvent?.freq && recurringEventCount && (
<div className="dark:text-inverted text-default items-start text-sm font-medium">
<div className="text-default items-start text-sm font-medium">
<RefreshCw className="ml-[2px] inline-block h-4 w-4 ltr:mr-[10px] rtl:ml-[10px]" />
<p className="-ml-2 inline-block items-center px-2">
{getEveryFreqFor({
@@ -572,7 +572,7 @@ const BookingPage = ({
<div className="text-sm font-medium">
{isClientTimezoneAvailable &&
(rescheduleUid || !eventType.recurringEvent?.freq) &&
`${parseDate(date, i18n, timeFormat)}`}
`${parseDate(date, i18n.language, { selectedTimeFormat: timeFormat })}`}
{isClientTimezoneAvailable &&
!rescheduleUid &&
eventType.recurringEvent?.freq &&
@@ -602,7 +602,9 @@ const BookingPage = ({
<Calendar className="ml-[2px] -mt-1 inline-block h-4 w-4 ltr:mr-[10px] rtl:ml-[10px]" />
{isClientTimezoneAvailable &&
typeof booking.startTime === "string" &&
parseDate(dayjs(booking.startTime), i18n, timeFormat)}
parseDate(dayjs(booking.startTime), i18n.language, {
selectedTimeFormat: timeFormat,
})}
</p>
</div>
)}
+1 -1
View File
@@ -1,6 +1,6 @@
import React from "react";
import { HttpError } from "@lib/core/http/error";
import { HttpError } from "@calcom/lib/http-error";
type Props = {
statusCode?: number | null;
@@ -11,6 +11,10 @@ import { getEventName } from "@calcom/core/event";
import getLocationsOptionsForSelect from "@calcom/features/bookings/lib/getLocationOptionsForSelect";
import DestinationCalendarSelector from "@calcom/features/calendars/DestinationCalendarSelector";
import useLockedFieldsManager from "@calcom/features/ee/managed-event-types/hooks/useLockedFieldsManager";
import {
allowDisablingAttendeeConfirmationEmails,
allowDisablingHostConfirmationEmails,
} from "@calcom/features/ee/workflows/lib/allowDisablingStandardEmails";
import { FormBuilder } from "@calcom/features/form-builder/FormBuilder";
import { classNames } from "@calcom/lib";
import { APP_NAME, CAL_URL } from "@calcom/lib/constants";
@@ -43,6 +47,8 @@ export const EventAdvancedTab = ({ eventType, team }: Pick<EventTypeSetupProps,
const bookingFields: Prisma.JsonObject = {};
const workflows = eventType.workflows.map((workflowOnEventType) => workflowOnEventType.workflow);
eventType.bookingFields.forEach(({ name }) => {
bookingFields[name] = name + " input";
});
@@ -316,7 +322,6 @@ export const EventAdvancedTab = ({ eventType, team }: Pick<EventTypeSetupProps,
disabled={seatsLocked.disabled}
defaultValue={value || 2}
min={1}
className="w-24"
addOnSuffix={<>{t("seats")}</>}
onChange={(e) => {
onChange(Math.abs(Number(e.target.value)));
@@ -338,7 +343,51 @@ export const EventAdvancedTab = ({ eventType, team }: Pick<EventTypeSetupProps,
</>
)}
/>
{allowDisablingAttendeeConfirmationEmails(workflows) && (
<>
<hr className="border-subtle" />
<Controller
name="metadata.disableStandardEmails.confirmation.attendee"
control={formMethods.control}
render={({ field: { value, onChange } }) => (
<>
<SettingsToggle
title={t("disable_attendees_confirmation_emails")}
description={t("disable_attendees_confirmation_emails_description")}
checked={value || false}
onCheckedChange={(e) => {
formMethods.setValue("metadata.disableStandardEmails.confirmation.attendee", e);
onChange(e);
}}
/>
</>
)}
/>
</>
)}
{allowDisablingHostConfirmationEmails(workflows) && (
<>
<hr className="border-subtle" />
<Controller
name="metadata.disableStandardEmails.confirmation.host"
control={formMethods.control}
defaultValue={!!eventType.seatsPerTimeSlot}
render={({ field: { value, onChange } }) => (
<>
<SettingsToggle
title={t("disable_host_confirmation_emails")}
description={t("disable_host_confirmation_emails_description")}
checked={value || false}
onCheckedChange={(e) => {
formMethods.setValue("metadata.disableStandardEmails.confirmation.host", e);
onChange(e);
}}
/>
</>
)}
/>
</>
)}
{showEventNameTip && (
<CustomEventTypeModal
close={closeEventNameTip}
@@ -1,4 +1,3 @@
import { SchedulingType } from "@prisma/client";
import type { EventTypeSetup, FormValues } from "pages/event-types/[type]";
import { useState } from "react";
import { Controller, useFormContext } from "react-hook-form";
@@ -10,6 +9,7 @@ import useLockedFieldsManager from "@calcom/features/ee/managed-event-types/hook
import classNames from "@calcom/lib/classNames";
import { useLocale } from "@calcom/lib/hooks/useLocale";
import { weekdayNames } from "@calcom/lib/weekday";
import { SchedulingType } from "@calcom/prisma/enums";
import { trpc } from "@calcom/trpc/react";
import useMeQuery from "@calcom/trpc/react/hooks/useMeQuery";
import { Badge, Button, Select, SettingsToggle, SkeletonText } from "@calcom/ui";
@@ -119,7 +119,7 @@ const EventTypeScheduleDetails = ({
{format(dayRange.startTime, timeFormat === 12)}
</span>
<span className="ms-4">-</span>
<div className="ml-6">{format(dayRange.endTime, timeFormat === 12)}</div>
<div className="ml-6 sm:w-28">{format(dayRange.endTime, timeFormat === 12)}</div>
</div>
))}
</div>
@@ -154,12 +154,11 @@ const EventTypeScheduleDetails = ({
const EventTypeSchedule = ({ eventType }: { eventType: EventTypeSetup }) => {
const { t } = useLocale();
const { shouldLockIndicator, shouldLockDisableProps, isManagedEventType, isChildrenManagedEventType } =
useLockedFieldsManager(
eventType,
t("locked_fields_admin_description"),
t("locked_fields_member_description")
);
const { shouldLockIndicator, isManagedEventType, isChildrenManagedEventType } = useLockedFieldsManager(
eventType,
t("locked_fields_admin_description"),
t("locked_fields_member_description")
);
const { watch } = useFormContext<FormValues>();
const watchSchedule = watch("schedule");
const formMethods = useFormContext<FormValues>();
@@ -205,6 +204,8 @@ const EventTypeSchedule = ({ eventType }: { eventType: EventTypeSetup }) => {
const value = options.find((option) =>
scheduleId
? option.value === scheduleId
: isManagedEventType
? option.value === 0
: option.value === schedules.find((schedule) => schedule.isDefault)?.id
);
@@ -13,7 +13,7 @@ import type { DurationType } from "@calcom/lib/convertToNewDurationType";
import convertToNewDurationType from "@calcom/lib/convertToNewDurationType";
import findDurationType from "@calcom/lib/findDurationType";
import { useLocale } from "@calcom/lib/hooks/useLocale";
import type { PeriodType } from "@calcom/prisma/client";
import type { PeriodType } from "@calcom/prisma/enums";
import type { IntervalLimit } from "@calcom/types/Calendar";
import { Button, DateRangePicker, InputField, Label, Select, SettingsToggle, TextField } from "@calcom/ui";
import { Plus, Trash } from "@calcom/ui/components/icon";
@@ -108,7 +108,7 @@ const MinimumBookingNoticeInput = React.forwardRef<
});
export const EventLimitsTab = ({ eventType }: Pick<EventTypeSetupProps, "eventType">) => {
const { t } = useLocale();
const { t, i18n } = useLocale();
const formMethods = useFormContext<FormValues>();
const PERIOD_TYPES = [
@@ -149,12 +149,25 @@ export const EventLimitsTab = ({ eventType }: Pick<EventTypeSetupProps, "eventTy
const bookingLimitsLocked = shouldLockDisableProps("bookingLimits");
const durationLimitsLocked = shouldLockDisableProps("durationLimits");
const periodTypeLocked = shouldLockDisableProps("periodType");
const offsetStartLockedProps = shouldLockDisableProps("offsetStart");
const optionsPeriod = [
{ value: 1, label: t("calendar_days") },
{ value: 0, label: t("business_days") },
];
// offsetStart toggle is client-side only, opened by default if offsetStart is set
const offsetStartValue = useWatch({
control: formMethods.control,
name: "offsetStart",
});
const [offsetToggle, setOffsetToggle] = useState(() => offsetStartValue > 0);
// Preview how the offset will affect start times
const offsetOriginalTime = new Date();
offsetOriginalTime.setHours(9, 0, 0, 0);
const offsetAdjustedTime = new Date(offsetOriginalTime.getTime() + offsetStartValue * 60 * 1000);
return (
<div className="space-y-8">
<div className="space-y-4 lg:space-y-8">
@@ -432,6 +445,32 @@ export const EventLimitsTab = ({ eventType }: Pick<EventTypeSetupProps, "eventTy
</SettingsToggle>
)}
/>
<hr className="border-subtle" />
<SettingsToggle
title={t("offset_toggle")}
description={t("offset_toggle_description")}
{...offsetStartLockedProps}
checked={offsetToggle}
onCheckedChange={(active) => {
setOffsetToggle(active);
if (!active) {
formMethods.setValue("offsetStart", 0);
}
}}>
<TextField
required
type="number"
{...offsetStartLockedProps}
label={t("offset_start")}
defaultValue={eventType.offsetStart}
{...formMethods.register("offsetStart")}
addOnSuffix={<>{t("minutes")}</>}
hint={t("offset_start_description", {
originalTime: offsetOriginalTime.toLocaleTimeString(i18n.language, { timeStyle: "short" }),
adjustedTime: offsetAdjustedTime.toLocaleTimeString(i18n.language, { timeStyle: "short" }),
})}
/>
</SettingsToggle>
</div>
);
};
@@ -276,7 +276,7 @@ export const EventSetupTab = (
return (
<li
key={`${location.type}${index}`}
className="border-default text-default mb-2 rounded-md border py-1.5 px-2 hover:cursor-pointer">
className="border-default text-default mb-2 h-9 rounded-md border py-1.5 px-2 hover:cursor-pointer">
<div className="flex items-center justify-between">
<div className="flex items-center">
<img
@@ -285,7 +285,7 @@ export const EventSetupTab = (
"h-4 w-4",
// invert all the icons except app icons
eventLocationType.iconUrl &&
!eventLocationType.iconUrl.startsWith("/api") &&
!eventLocationType.iconUrl.startsWith("/app-store") &&
"dark:invert"
)}
alt={`${eventLocationType.label} logo`}
@@ -390,7 +390,12 @@ export const EventSetupTab = (
addOnLeading={
<>
{CAL_URL?.replace(/^(https?:|)\/\//, "")}/
{team ? "team/" + team.slug : eventType.users[0].username}/
{!isManagedEventType
? team
? "team/" + team.slug
: eventType.users[0].username
: t("username_placeholder")}
/
</>
}
{...formMethods.register("slug", {
@@ -466,6 +471,7 @@ export const EventSetupTab = (
defaultValue={eventType.length ?? 15}
{...formMethods.register("length")}
addOnSuffix={<>{t("minutes")}</>}
min={1}
/>
)}
{!lengthLockedProps.disabled && (
@@ -1,4 +1,3 @@
import { SchedulingType } from "@prisma/client";
import type { EventTypeSetupProps, FormValues } from "pages/event-types/[type]";
import { useEffect, useRef } from "react";
import type { ComponentProps } from "react";
@@ -10,6 +9,7 @@ import CheckedTeamSelect from "@calcom/features/eventtypes/components/CheckedTea
import ChildrenEventTypeSelect from "@calcom/features/eventtypes/components/ChildrenEventTypeSelect";
import { WEBAPP_URL } from "@calcom/lib/constants";
import { useLocale } from "@calcom/lib/hooks/useLocale";
import { SchedulingType } from "@calcom/prisma/enums";
import { Label, Select } from "@calcom/ui";
interface IUserToValue {
@@ -170,7 +170,7 @@ export const EventTeamWebhooksTab = ({
</Dialog>
{/* Edit webhook dialog */}
<Dialog open={editModalOpen} onOpenChange={(isOpen) => !isOpen && setEditModalOpen(false)}>
<DialogContent title={t("edit_webhook")}>
<DialogContent enableOverflow title={t("edit_webhook")}>
<WebhookForm
webhook={webhookToEdit}
apps={installedApps?.items.map((app) => app.slug)}
@@ -1,4 +1,3 @@
import { SchedulingType } from "@prisma/client";
import { Webhook as TbWebhook } from "lucide-react";
import type { TFunction } from "next-i18next";
import { Trans } from "next-i18next";
@@ -13,6 +12,7 @@ import { classNames } from "@calcom/lib";
import { CAL_URL } from "@calcom/lib/constants";
import { useLocale } from "@calcom/lib/hooks/useLocale";
import { HttpError } from "@calcom/lib/http-error";
import { SchedulingType } from "@calcom/prisma/enums";
import { trpc, TRPCClientError } from "@calcom/trpc/react";
import {
Button,
@@ -170,7 +170,7 @@ function EventTypeSingleLayout({
// Define tab navigation here
const EventTypeTabs = useMemo(() => {
let navigation = getNavigation({
const navigation = getNavigation({
t,
eventType,
enabledAppsNumber,
@@ -210,7 +210,7 @@ function EventTypeSingleLayout({
}
if (isManagedEventType || isChildrenManagedEventType) {
// Removing apps and workflows for manageg event types by admins v1
navigation = navigation.slice(0, -2);
navigation.splice(-2, 1);
} else {
navigation.push({
name: "webhooks",
@@ -238,7 +238,7 @@ function EventTypeSingleLayout({
<div className="flex items-center justify-end">
{!eventType.metadata.managedEventConfig && (
<>
<div className="sm:hover:bg-subtle hidden items-center rounded-md px-2 lg:flex">
<div className="sm:hover:bg-muted hidden items-center rounded-md px-2 lg:flex">
<Skeleton
as={Label}
htmlFor="hiddenSwitch"
@@ -3,15 +3,16 @@ import { useLocale } from "@calcom/lib/hooks/useLocale";
import type { App } from "@calcom/types/App";
import { Button } from "@calcom/ui";
interface ICalendarItem {
interface IAppConnectionItem {
title: string;
description?: string;
logo: string;
type: App["type"];
installed?: boolean;
}
const CalendarItem = (props: ICalendarItem) => {
const { title, logo, type } = props;
const AppConnectionItem = (props: IAppConnectionItem) => {
const { title, logo, type, installed } = props;
const { t } = useLocale();
return (
<div className="flex flex-row items-center justify-between p-5">
@@ -25,13 +26,14 @@ const CalendarItem = (props: ICalendarItem) => {
<Button
{...buttonProps}
color="secondary"
disabled={installed}
type="button"
onClick={(event) => {
// Save cookie key to return url step
document.cookie = `return-to=${window.location.href};path=/;max-age=3600;SameSite=Lax`;
buttonProps && buttonProps.onClick && buttonProps?.onClick(event);
}}>
{t("connect")}
{installed ? t("installed") : t("connect")}
</Button>
)}
/>
@@ -39,4 +41,4 @@ const CalendarItem = (props: ICalendarItem) => {
);
};
export { CalendarItem };
export { AppConnectionItem };
@@ -1,4 +1,4 @@
import { CalendarSwitch } from "./CalendarSwitch";
import { CalendarSwitch } from "@calcom/features/calendars/CalendarSwitch";
interface IConnectedCalendarItem {
name: string;
@@ -0,0 +1,17 @@
import { SkeletonAvatar, SkeletonText, SkeletonButton } from "@calcom/ui";
export function StepConnectionLoader() {
return (
<ul className="bg-default divide-subtle border-subtle divide-y rounded-md border p-0 dark:bg-black">
{Array.from({ length: 4 }).map((_item, index) => {
return (
<li className="flex w-full flex-row justify-center border-b-0 py-6" key={index}>
<SkeletonAvatar className="mx-6 h-8 w-8 px-4" />
<SkeletonText className="ml-1 mr-4 mt-3 h-5 w-full" />
<SkeletonButton className="mr-6 h-8 w-20 rounded-md p-5" />
</li>
);
})}
</ul>
);
}
@@ -1,13 +1,13 @@
import { ArrowRightIcon } from "@heroicons/react/solid";
import classNames from "@calcom/lib/classNames";
import { useLocale } from "@calcom/lib/hooks/useLocale";
import { trpc } from "@calcom/trpc/react";
import { SkeletonAvatar, SkeletonText, SkeletonButton, List } from "@calcom/ui";
import { List } from "@calcom/ui";
import { ArrowRight } from "@calcom/ui/components/icon";
import { CalendarItem } from "../components/CalendarItem";
import { AppConnectionItem } from "../components/AppConnectionItem";
import { ConnectedCalendarItem } from "../components/ConnectedCalendarItem";
import { CreateEventsOnCalendarSelect } from "../components/CreateEventsOnCalendarSelect";
import { StepConnectionLoader } from "../components/StepConnectionLoader";
interface IConnectCalendarsProps {
nextStep: () => void;
@@ -33,7 +33,7 @@ const ConnectedCalendars = (props: IConnectCalendarsProps) => {
firstCalendar.integration.title &&
firstCalendar.integration.logo && (
<>
<List className="bg-default border-subtle rounded-md border p-0 dark:bg-black">
<List className="bg-default border-subtle rounded-md border p-0 dark:bg-black ">
<ConnectedCalendarItem
key={firstCalendar.integration.title}
name={firstCalendar.integration.title}
@@ -60,7 +60,7 @@ const ConnectedCalendars = (props: IConnectCalendarsProps) => {
queryIntegrations.data.items.map((item) => (
<li key={item.title}>
{item.title && item.logo && (
<CalendarItem
<AppConnectionItem
type={item.type}
title={item.title}
description={item.description}
@@ -72,19 +72,8 @@ const ConnectedCalendars = (props: IConnectCalendarsProps) => {
</List>
)}
{queryIntegrations.isLoading && (
<ul className="bg-default divide-subtle border-subtle divide-y rounded-md border p-0 dark:bg-black">
{[0, 0, 0, 0].map((_item, index) => {
return (
<li className="flex w-full flex-row justify-center border-b-0 py-6" key={index}>
<SkeletonAvatar className="mx-6 h-8 w-8 px-4" />
<SkeletonText className="ml-1 mr-4 mt-3 h-5 w-full" />
<SkeletonButton className="mr-6 h-8 w-20 rounded-md p-5" />
</li>
);
})}
</ul>
)}
{queryIntegrations.isLoading && <StepConnectionLoader />}
<button
type="button"
data-testid="save-calendar-button"
@@ -95,7 +84,7 @@ const ConnectedCalendars = (props: IConnectCalendarsProps) => {
onClick={() => nextStep()}
disabled={disabledNextButton}>
{firstCalendar ? `${t("continue")}` : `${t("next_step_text")}`}
<ArrowRightIcon className="ml-2 h-4 w-4 self-center" aria-hidden="true" />
<ArrowRight className="ml-2 h-4 w-4 self-center" aria-hidden="true" />
</button>
</>
);
@@ -0,0 +1,67 @@
import classNames from "@calcom/lib/classNames";
import { useLocale } from "@calcom/lib/hooks/useLocale";
import { trpc } from "@calcom/trpc/react";
import { List } from "@calcom/ui";
import { ArrowRight } from "@calcom/ui/components/icon";
import { AppConnectionItem } from "../components/AppConnectionItem";
import { StepConnectionLoader } from "../components/StepConnectionLoader";
interface ConnectedAppStepProps {
nextStep: () => void;
}
const ConnectedVideoStep = (props: ConnectedAppStepProps) => {
const { nextStep } = props;
const { data: queryConnectedVideoApps, isLoading } = trpc.viewer.integrations.useQuery({
variant: "conferencing",
onlyInstalled: false,
});
const { t } = useLocale();
const hasAnyInstalledVideoApps = queryConnectedVideoApps?.items.some(
(item) => item.credentialIds.length > 0
);
return (
<>
{!isLoading && (
<List className="bg-default border-subtle divide-subtle scroll-bar mx-1 max-h-[45vh] divide-y !overflow-y-scroll rounded-md border p-0 sm:mx-0">
{queryConnectedVideoApps?.items &&
queryConnectedVideoApps?.items.map((item) => {
if (item.slug === "daily-video") return null; // we dont want to show daily here as it is installed by default
return (
<li key={item.name}>
{item.name && item.logo && (
<AppConnectionItem
type={item.type}
title={item.name}
description={item.description}
logo={item.logo}
installed={item.credentialIds.length > 0}
/>
)}
</li>
);
})}
</List>
)}
{isLoading && <StepConnectionLoader />}
<button
type="button"
data-testid="save-video-button"
className={classNames(
"text-inverted mt-8 flex w-full flex-row justify-center rounded-md border border-black bg-black p-2 text-center text-sm",
!hasAnyInstalledVideoApps ? "cursor-not-allowed opacity-20" : ""
)}
disabled={!hasAnyInstalledVideoApps}
onClick={() => nextStep()}>
{t("next_step_text")}
<ArrowRight className="ml-2 h-4 w-4 self-center" aria-hidden="true" />
</button>
</>
);
};
export { ConnectedVideoStep };
@@ -1,4 +1,3 @@
import { ArrowRightIcon } from "@heroicons/react/solid";
import { useRouter } from "next/router";
import { useForm } from "react-hook-form";
@@ -9,6 +8,7 @@ import type { TRPCClientErrorLike } from "@calcom/trpc/react";
import { trpc } from "@calcom/trpc/react";
import type { AppRouter } from "@calcom/trpc/server/routers/_app";
import { Button, Form } from "@calcom/ui";
import { ArrowRight } from "@calcom/ui/components/icon";
interface ISetupAvailabilityProps {
nextStep: () => void;
@@ -81,7 +81,7 @@ const SetupAvailability = (props: ISetupAvailabilityProps) => {
type="submit"
className="mt-2 w-full justify-center p-2 text-sm sm:mt-8"
disabled={availabilityForm.formState.isSubmitting}>
{t("next_step_text")} <ArrowRightIcon className="ml-2 h-4 w-4 self-center" />
{t("next_step_text")} <ArrowRight className="ml-2 h-4 w-4 self-center" />
</Button>
</div>
</Form>
@@ -1,4 +1,3 @@
import { ArrowRightIcon } from "@heroicons/react/solid";
import { useRouter } from "next/router";
import type { FormEvent } from "react";
import { useRef, useState } from "react";
@@ -11,6 +10,7 @@ import turndown from "@calcom/lib/turndownService";
import { trpc } from "@calcom/trpc/react";
import { Button, Editor, ImageUploader, Label, showToast } from "@calcom/ui";
import { Avatar } from "@calcom/ui";
import { ArrowRight } from "@calcom/ui/components/icon";
import type { IOnboardingPageProps } from "../../../pages/getting-started/[[...step]]";
@@ -159,7 +159,7 @@ const UserProfile = (props: IUserProfileProps) => {
type="submit"
className="text-inverted mt-8 flex w-full flex-row justify-center rounded-md border border-black bg-black p-2 text-center text-sm">
{t("finish")}
<ArrowRightIcon className="ml-2 h-4 w-4 self-center" aria-hidden="true" />
<ArrowRight className="ml-2 h-4 w-4 self-center" aria-hidden="true" />
</Button>
</form>
);
@@ -1,4 +1,3 @@
import { ArrowRightIcon } from "@heroicons/react/outline";
import { zodResolver } from "@hookform/resolvers/zod";
import { useEffect, useState } from "react";
import { useForm } from "react-hook-form";
@@ -10,6 +9,7 @@ import { useLocale } from "@calcom/lib/hooks/useLocale";
import { telemetryEventTypes, useTelemetry } from "@calcom/lib/telemetry";
import { trpc } from "@calcom/trpc/react";
import { Button, TimezoneSelect } from "@calcom/ui";
import { ArrowRight } from "@calcom/ui/components/icon";
import { UsernameAvailabilityField } from "@components/ui/UsernameAvailability";
@@ -116,7 +116,7 @@ const UserSettings = (props: IUserSettingsProps) => {
className="mt-8 flex w-full flex-row justify-center"
disabled={mutation.isLoading}>
{t("next_step_text")}
<ArrowRightIcon className="ml-2 h-4 w-4 self-center" aria-hidden="true" />
<ArrowRight className="ml-2 h-4 w-4 self-center" aria-hidden="true" />
</Button>
</form>
);
@@ -1,85 +0,0 @@
import { useMutation } from "@tanstack/react-query";
import { useLocale } from "@calcom/lib/hooks/useLocale";
import { trpc } from "@calcom/trpc/react";
import { Badge, showToast, Switch } from "@calcom/ui";
import { ArrowLeft } from "@calcom/ui/components/icon";
export function CalendarSwitch(props: {
type: string;
externalId: string;
title: string;
defaultSelected: boolean;
isSelected: boolean;
}) {
const { t } = useLocale();
const utils = trpc.useContext();
const mutation = useMutation<
unknown,
unknown,
{
isOn: boolean;
}
>(
async ({ isOn }) => {
const body = {
integration: props.type,
externalId: props.externalId,
};
if (isOn) {
const res = await fetch("/api/availability/calendar", {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify(body),
});
if (!res.ok) {
throw new Error("Something went wrong");
}
} else {
const res = await fetch("/api/availability/calendar", {
method: "DELETE",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify(body),
});
if (!res.ok) {
throw new Error("Something went wrong");
}
}
},
{
async onSettled() {
await utils.viewer.integrations.invalidate();
},
onError() {
showToast(`Something went wrong when toggling "${props.title}""`, "error");
},
}
);
return (
<div className="flex space-x-2 py-1 rtl:space-x-reverse">
<Switch
key={props.externalId}
name="enabled"
label={props.title}
defaultChecked={props.isSelected}
onCheckedChange={(isOn: boolean) => {
mutation.mutate({ isOn });
}}
/>
{props.defaultSelected && (
<Badge variant="gray">
<div className="flex items-center">
<ArrowLeft className="text-default mr-1 h-4 w-4" /> {t("adding_events_to")}
</div>
</Badge>
)}
</div>
);
}
+1 -1
View File
@@ -31,7 +31,7 @@ const Member = ({ member, teamName }: { member: MemberType; teamName: string | n
{!isBioEmpty ? (
<>
<div
className=" text-subtle text-sm [&_a]:text-blue-500 [&_a]:underline [&_a]:hover:text-blue-600"
className=" text-subtle break-words text-sm [&_a]:text-blue-500 [&_a]:underline [&_a]:hover:text-blue-600"
dangerouslySetInnerHTML={{ __html: md.render(member.bio || "") }}
/>
</>
@@ -1,4 +1,3 @@
import { StarIcon as StarIconSolid } from "@heroicons/react/solid";
import classNames from "classnames";
import { debounce, noop } from "lodash";
import { useRouter } from "next/router";
@@ -15,6 +14,7 @@ import type { RouterOutputs } from "@calcom/trpc/react";
import { trpc } from "@calcom/trpc/react";
import type { AppRouter } from "@calcom/trpc/server/routers/_app";
import { Button, Dialog, DialogClose, DialogContent, Input, Label } from "@calcom/ui";
import { Star as StarSolid } from "@calcom/ui/components/icon";
import { Check, Edit2, ExternalLink } from "@calcom/ui/components/icon";
export enum UsernameChangeStatusEnum {
@@ -230,12 +230,16 @@ const PremiumTextfield = (props: ICustomUsernameProps) => {
<div className="absolute top-0 right-2 flex flex-row">
<span
className={classNames(
"mx-2 py-1",
isInputUsernamePremium ? "text-orange-400" : "",
"mx-2 py-2",
isInputUsernamePremium ? "text-transparent" : "",
usernameIsAvailable ? "" : ""
)}>
{isInputUsernamePremium ? <StarIconSolid className="mt-[2px] h-4 w-4" /> : <></>}
{!isInputUsernamePremium && usernameIsAvailable ? <Check className="mt-2 h-4 w-4" /> : <></>}
{isInputUsernamePremium ? <StarSolid className="mt-[2px] h-4 w-4 fill-orange-400" /> : <></>}
{!isInputUsernamePremium && usernameIsAvailable ? (
<Check className="mt-[2px] h-4 w-4" />
) : (
<></>
)}
</span>
</div>
</div>
@@ -25,7 +25,7 @@ const OptionWithIcon = ({ icon, label }: { icon?: string; label: string }) => {
src={icon}
alt="cover"
// invert all the icons except app icons
className={cx("h-3.5 w-3.5", icon && !icon.startsWith("/api") && "dark:invert")}
className={cx("h-3.5 w-3.5", icon && !icon.startsWith("/app-store") && "dark:invert")}
/>
)}
<span className={classNames("text-sm font-medium")}>{label}</span>
+108 -47
View File
@@ -19,12 +19,17 @@ import { MetaProvider } from "@calcom/ui";
import usePublicPage from "@lib/hooks/usePublicPage";
import type { WithNonceProps } from "@lib/withNonce";
import { useViewerI18n } from "@components/I18nLanguageHandler";
const I18nextAdapter = appWithTranslation<NextJsAppProps<SSRConfig> & { children: React.ReactNode }>(
({ children }) => <>{children}</>
);
// Workaround for https://github.com/vercel/next.js/issues/8592
export type AppProps = Omit<NextAppProps<WithNonceProps & Record<string, unknown>>, "Component"> & {
export type AppProps = Omit<
NextAppProps<WithNonceProps & { themeBasis?: string } & Record<string, unknown>>,
"Component"
> & {
Component: NextAppProps["Component"] & {
requiresLicense?: boolean;
isThemeSupported?: boolean;
@@ -46,9 +51,7 @@ const CustomI18nextProvider = (props: AppPropsWithChildren) => {
* i18n should never be clubbed with other queries, so that it's caching can be managed independently.
* We intend to not cache i18n query
**/
const { i18n, locale } = trpc.viewer.public.i18n.useQuery(undefined, {
trpc: { context: { skipBatch: true } },
}).data ?? {
const { i18n, locale } = useViewerI18n().data ?? {
locale: "en",
};
@@ -72,58 +75,21 @@ const enum ThemeSupport {
Booking = "userConfigured",
}
const CalcomThemeProvider = (
props: PropsWithChildren<
WithNonceProps & {
isBookingPage?: boolean | ((arg: { router: NextRouter }) => boolean);
isThemeSupported?: boolean;
}
>
) => {
// We now support the inverse of how we handled it in the past. Setting this to false will disable theme.
// undefined or true means we use system theme
type CalcomThemeProps = PropsWithChildren<
Pick<AppProps["pageProps"], "nonce" | "themeBasis"> &
Pick<AppProps["Component"], "isBookingPage" | "isThemeSupported">
>;
const CalcomThemeProvider = (props: CalcomThemeProps) => {
const router = useRouter();
const isBookingPage = (() => {
if (typeof props.isBookingPage === "function") {
return props.isBookingPage({ router: router });
}
return props.isBookingPage;
})();
const themeSupport = isBookingPage
? ThemeSupport.Booking
: // if isThemeSupported is explicitly false, we don't use theme there
props.isThemeSupported === false
? ThemeSupport.None
: ThemeSupport.App;
const forcedTheme = themeSupport === ThemeSupport.None ? "light" : undefined;
// Use namespace of embed to ensure same namespaced embed are displayed with same theme. This allows different embeds on the same website to be themed differently
// One such example is our Embeds Demo and Testing page at http://localhost:3100
// Having `getEmbedNamespace` defined on window before react initializes the app, ensures that embedNamespace is available on the first mount and can be used as part of storageKey
const embedNamespace = typeof window !== "undefined" ? window.getEmbedNamespace() : null;
const isEmbedMode = typeof embedNamespace === "string";
const storageKey = isEmbedMode
? `embed-theme-${embedNamespace}`
: themeSupport === ThemeSupport.App
? "app-theme"
: themeSupport === ThemeSupport.Booking
? "booking-theme"
: undefined;
return (
<ThemeProvider
nonce={props.nonce}
enableColorScheme={false}
enableSystem={themeSupport !== ThemeSupport.None}
forcedTheme={forcedTheme}
storageKey={storageKey}
// next-themes doesn't listen to changes on storageKey. So we need to force a re-render when storageKey changes
// This is how login to dashboard soft navigation changes theme from light to dark
key={storageKey}
attribute="class">
<ThemeProvider {...getThemeProviderProps({ props, isEmbedMode, embedNamespace, router })}>
{/* Embed Mode can be detected reliably only on client side here as there can be static generated pages as well which can't determine if it's embed mode at backend */}
{/* color-scheme makes background:transparent not work in iframe which is required by embed. */}
{typeof window !== "undefined" && !isEmbedMode && (
@@ -140,6 +106,100 @@ const CalcomThemeProvider = (
);
};
/**
* The most important job for this fn is to generate correct storageKey for theme persistenc.
* `storageKey` is important because that key is listened for changes(using [`storage`](https://developer.mozilla.org/en-US/docs/Web/API/Window/storage_event) event) and any pages opened will change it's theme based on that(as part of next-themes implementation).
* Choosing the right storageKey avoids theme flickering caused by another page using different theme
* So, we handle all the cases here namely,
* - Both Booking Pages, /free/30min and /pro/30min but configured with different themes but being operated together.
* - Embeds using different namespace. They can be completely themed different on the same page.
* - Embeds using the same namespace but showing different cal.com links with different themes
* - Embeds using the same namespace and showing same cal.com links with different themes(Different theme is possible for same cal.com link in case of embed because of theme config available in embed)
* - App has different theme then Booking Pages.
*
* All the above cases have one thing in common, which is the origin and thus localStorage is shared and thus `storageKey` is critical to avoid theme flickering.
*
* Some things to note:
* - There is a side effect of so many factors in `storageKey` that many localStorage keys will be created if a user goes through all these scenarios(e.g like booking a lot of different users)
* - Some might recommend disabling localStorage persistence but that doesn't give good UX as then we would default to light theme always for a few seconds before switching to dark theme(if that's the user's preference).
* - We can't disable [`storage`](https://developer.mozilla.org/en-US/docs/Web/API/Window/storage_event) event handling as well because changing theme in one tab won't change the theme without refresh in other tabs. That's again a bad UX
* - Theme flickering becomes infinitely ongoing in case of embeds because of the browser's delay in processing `storage` event within iframes. Consider two embeds simulatenously opened with pages A and B. Note the timeline and keep in mind that it happened
* because 'setItem(A)' and 'Receives storageEvent(A)' allowed executing setItem(B) in b/w because of the delay.
* - t1 -> setItem(A) & Fires storageEvent(A) - On Page A) - Current State(A)
* - t2 -> setItem(B) & Fires storageEvent(B) - On Page B) - Current State(B)
* - t3 -> Receives storageEvent(A) & thus setItem(A) & thus fires storageEvent(A) (On Page B) - Current State(A)
* - t4 -> Receives storageEvent(B) & thus setItem(B) & thus fires storageEvent(B) (On Page A) - Current State(B)
* - ... and so on ...
*/
function getThemeProviderProps({
props,
isEmbedMode,
embedNamespace,
router,
}: {
props: Omit<CalcomThemeProps, "children">;
isEmbedMode: boolean;
embedNamespace: string | null;
router: NextRouter;
}) {
const isBookingPage = (() => {
if (typeof props.isBookingPage === "function") {
return props.isBookingPage({ router: router });
}
return props.isBookingPage;
})();
const themeSupport = isBookingPage
? ThemeSupport.Booking
: // if isThemeSupported is explicitly false, we don't use theme there
props.isThemeSupported === false
? ThemeSupport.None
: ThemeSupport.App;
const isBookingPageThemSupportRequired = themeSupport === ThemeSupport.Booking;
const themeBasis = props.themeBasis;
if ((isBookingPageThemSupportRequired || isEmbedMode) && !themeBasis) {
console.warn(
"`themeBasis` is required for booking page theme support. Not providing it will cause theme flicker."
);
}
const appearanceIdSuffix = themeBasis ? ":" + themeBasis : "";
const forcedTheme = themeSupport === ThemeSupport.None ? "light" : undefined;
let embedExplicitlySetThemeSuffix = "";
if (typeof window !== "undefined") {
const embedTheme = window.getEmbedTheme();
if (embedTheme) {
embedExplicitlySetThemeSuffix = ":" + embedTheme;
}
}
const storageKey = isEmbedMode
? // Same Namespace, Same Organizer but different themes would still work seamless and not cause theme flicker
// Even though it's recommended to use different namespaces when you want to theme differently on the same page but if the embeds are on different pages, the problem can still arise
`embed-theme-${embedNamespace}${appearanceIdSuffix}${embedExplicitlySetThemeSuffix}`
: themeSupport === ThemeSupport.App
? "app-theme"
: isBookingPageThemSupportRequired
? `booking-theme${appearanceIdSuffix}`
: undefined;
return {
storageKey,
forcedTheme,
themeSupport,
nonce: props.nonce,
enableColorScheme: false,
enableSystem: themeSupport !== ThemeSupport.None,
// next-themes doesn't listen to changes on storageKey. So we need to force a re-render when storageKey changes
// This is how login to dashboard soft navigation changes theme from light to dark
key: storageKey,
attribute: "class",
};
}
function FeatureFlagsProvider({ children }: { children: React.ReactNode }) {
const flags = useFlags();
return <FeatureProvider value={flags}>{children}</FeatureProvider>;
@@ -157,6 +217,7 @@ const AppProviders = (props: AppPropsWithChildren) => {
<TooltipProvider>
{/* color-scheme makes background:transparent not work which is required by embed. We need to ensure next-theme adds color-scheme to `body` instead of `html`(https://github.com/pacocoursey/next-themes/blob/main/src/index.tsx#L74). Once that's done we can enable color-scheme support */}
<CalcomThemeProvider
themeBasis={props.pageProps.themeBasis}
nonce={props.pageProps.nonce}
isThemeSupported={props.Component.isThemeSupported}
isBookingPage={props.Component.isBookingPage}>
@@ -1,13 +0,0 @@
import type { BookingCreateBody } from "@calcom/prisma/zod-utils";
import * as fetch from "@lib/core/http/fetch-wrapper";
import type { BookingResponse } from "@lib/types/booking";
type BookingCreateBodyForMutation = Omit<BookingCreateBody, "location">;
const createBooking = async (data: BookingCreateBodyForMutation) => {
const response = await fetch.post<BookingCreateBodyForMutation, BookingResponse>("/api/book/event", data);
return response;
};
export default createBooking;
+23 -6
View File
@@ -1,6 +1,7 @@
require("dotenv").config({ path: "../../.env" });
const CopyWebpackPlugin = require("copy-webpack-plugin");
const os = require("os");
const glob = require("glob");
const { withAxiom } = require("next-axiom");
const { i18n } = require("./next-i18next.config");
@@ -66,6 +67,18 @@ if (process.env.ANALYZE === "true") {
}
plugins.push(withAxiom);
/** Needed to rewrite public booking page, gets all static pages but [user] */
const pages = glob
.sync("pages/**/[^_]*.{tsx,js,ts}", { cwd: __dirname })
.map((filename) =>
filename
.substr(6)
.replace(/(\.tsx|\.js|\.ts)/, "")
.replace(/\/.*/, "")
)
.filter((v, i, self) => self.indexOf(v) === i && !v.startsWith("[user]"));
/** @type {import("next").NextConfig} */
const nextConfig = {
i18n,
@@ -98,12 +111,6 @@ const nextConfig = {
transform: "lucide-react/dist/esm/icons/{{ kebabCase member }}",
preventFullImport: true,
},
"@heroicons/react/solid": {
transform: "@heroicons/react/solid/esm/{{ member }}",
},
"@heroicons/react/outline": {
transform: "@heroicons/react/outline/esm/{{ member }}",
},
"@calcom/features/insights/components": {
transform: "@calcom/features/insights/components/{{member}}",
skipDefaultConversion: true,
@@ -198,6 +205,16 @@ const nextConfig = {
source: "/embed/embed.js",
destination: process.env.NEXT_PUBLIC_EMBED_LIB_URL?,
}, */
{
source: `/:user((?!${pages.join("|")}).*)/:type`,
destination: "/new-booker/:user/:type",
has: [{ type: "cookie", key: "new-booker-enabled" }],
},
{
source: "/team/:slug/:type",
destination: "/new-booker/team/:slug/:type",
has: [{ type: "cookie", key: "new-booker-enabled" }],
},
];
},
async headers() {
+3 -4
View File
@@ -1,6 +1,6 @@
{
"name": "@calcom/web",
"version": "2.8.9",
"version": "2.9.2",
"private": true,
"scripts": {
"analyze": "ANALYZE=true next build",
@@ -41,7 +41,6 @@
"@daily-co/daily-js": "^0.37.0",
"@formkit/auto-animate": "^1.0.0-beta.5",
"@glidejs/glide": "^3.5.2",
"@heroicons/react": "^1.0.6",
"@hookform/error-message": "^2.0.0",
"@hookform/resolvers": "^2.9.7",
"@next-auth/prisma-adapter": "^1.0.4",
@@ -115,12 +114,11 @@
"react-select": "^5.7.0",
"react-timezone-select": "^1.4.0",
"react-use-intercom": "1.5.1",
"remark": "^14.0.2",
"remove-markdown": "^0.5.0",
"rrule": "^2.7.1",
"sanitize-html": "^2.10.0",
"schema-dts": "^1.1.0",
"short-uuid": "^4.2.0",
"strip-markdown": "^5.0.0",
"stripe": "^9.16.0",
"superjson": "1.9.1",
"tailwindcss-radix": "^2.6.0",
@@ -153,6 +151,7 @@
"@types/qrcode": "^1.4.3",
"@types/react": "18.0.26",
"@types/react-phone-number-input": "^3.0.14",
"@types/remove-markdown": "^0.3.1",
"@types/sanitize-html": "^2.9.0",
"@types/stripe": "^8.0.417",
"@types/uuid": "8.3.1",
+22 -9
View File
@@ -1,4 +1,3 @@
import { BadgeCheckIcon } from "@heroicons/react/solid";
import classNames from "classnames";
import type { GetServerSidePropsContext } from "next";
import Link from "next/link";
@@ -23,11 +22,12 @@ import defaultEvents, {
import { useLocale } from "@calcom/lib/hooks/useLocale";
import useTheme from "@calcom/lib/hooks/useTheme";
import { markdownToSafeHTML } from "@calcom/lib/markdownToSafeHTML";
import { stripMarkdown } from "@calcom/lib/stripMarkdown";
import prisma from "@calcom/prisma";
import { baseEventTypeSelect } from "@calcom/prisma/selects";
import { EventTypeMetaDataSchema } from "@calcom/prisma/zod-utils";
import { Avatar, AvatarGroup, HeadSeo } from "@calcom/ui";
import { ArrowRight } from "@calcom/ui/components/icon";
import { Verified, ArrowRight } from "@calcom/ui/components/icon";
import type { inferSSRProps } from "@lib/types/inferSSRProps";
import type { EmbedProps } from "@lib/withEmbedSsr";
@@ -37,7 +37,16 @@ import PageWrapper from "@components/PageWrapper";
import { ssrInit } from "@server/lib/ssr";
export default function User(props: inferSSRProps<typeof getServerSideProps> & EmbedProps) {
const { users, profile, eventTypes, isDynamicGroup, dynamicNames, dynamicUsernames, isSingleUser } = props;
const {
users,
profile,
eventTypes,
isDynamicGroup,
dynamicNames,
dynamicUsernames,
isSingleUser,
markdownStrippedBio,
} = props;
const [user] = users; //To be used when we only have a single user, not dynamic group
useTheme(user.theme);
const { t } = useLocale();
@@ -107,11 +116,9 @@ export default function User(props: inferSSRProps<typeof getServerSideProps> & E
<>
<HeadSeo
title={isDynamicGroup ? dynamicNames.join(", ") : nameOrUsername}
description={
isDynamicGroup ? `Book events with ${dynamicUsernames.join(", ")}` : (user.bio as string) || ""
}
description={isDynamicGroup ? `Book events with ${dynamicUsernames.join(", ")}` : markdownStrippedBio}
meeting={{
title: isDynamicGroup ? "" : `${user.bio}`,
title: isDynamicGroup ? "" : markdownStrippedBio,
profile: { name: `${profile.name}`, image: null },
users: isDynamicGroup
? dynamicUsernames.map((username, index) => ({ username, name: dynamicNames[index] }))
@@ -131,12 +138,14 @@ export default function User(props: inferSSRProps<typeof getServerSideProps> & E
<Avatar imageSrc={user.avatar} size="xl" alt={nameOrUsername} />
<h1 className="font-cal text-emphasis mb-1 text-3xl">
{nameOrUsername}
{user.verified && <BadgeCheckIcon className=" mx-1 -mt-1 inline h-6 w-6 text-blue-500" />}
{user.verified && (
<Verified className=" mx-1 -mt-1 inline h-6 w-6 fill-blue-500 text-white dark:text-black" />
)}
</h1>
{!isBioEmpty && (
<>
<div
className=" text-subtle text-sm [&_a]:text-blue-500 [&_a]:underline [&_a]:hover:text-blue-600"
className=" text-subtle break-words text-sm [&_a]:text-blue-500 [&_a]:underline [&_a]:hover:text-blue-600"
dangerouslySetInnerHTML={{ __html: props.safeBio }}
/>
</>
@@ -342,11 +351,14 @@ export const getServerSideProps = async (context: GetServerSidePropsContext) =>
const safeBio = markdownToSafeHTML(user.bio) || "";
const markdownStrippedBio = stripMarkdown(user?.bio || "");
return {
props: {
users,
safeBio,
profile,
// Dynamic group has no theme preference right now. It uses system theme.
themeBasis: isDynamicGroup ? null : user.username,
user: {
emailMd5: crypto.createHash("md5").update(user.email).digest("hex"),
},
@@ -361,6 +373,7 @@ export const getServerSideProps = async (context: GetServerSidePropsContext) =>
dynamicNames,
dynamicUsernames,
isSingleUser,
markdownStrippedBio,
},
};
};
+4
View File
@@ -177,6 +177,8 @@ async function getUserPageProps(context: GetStaticPropsContext) {
slug: `${user.username}/${eventType.slug}`,
image: `${WEBAPP_URL}/${user.username}/avatar.png`,
},
// Dynamic group has no theme preference right now. It uses system theme.
themeBasis: user.username,
away: user?.away,
isDynamic: false,
trpcState: ssg.dehydrate(),
@@ -307,6 +309,8 @@ async function getDynamicGroupPageProps(context: GetStaticPropsContext) {
props: {
eventType: eventTypeObject,
profile,
// Dynamic group has no theme preference right now. It uses system theme.
themeBasis: null,
isDynamic: true,
away: false,
trpcState: ssg.dehydrate(),
+4 -2
View File
@@ -5,6 +5,8 @@ import type { LocationObject } from "@calcom/app-store/locations";
import { privacyFilteredLocations } from "@calcom/app-store/locations";
import { getAppFromSlug } from "@calcom/app-store/utils";
import dayjs from "@calcom/dayjs";
import getBooking from "@calcom/features/bookings/lib/get-booking";
import type { GetBookingType } from "@calcom/features/bookings/lib/get-booking";
import { getBookingFieldsWithSystemFields } from "@calcom/features/bookings/lib/getBookingFields";
import { parseRecurringEvent } from "@calcom/lib";
import {
@@ -13,8 +15,6 @@ import {
getGroupName,
getUsernameList,
} from "@calcom/lib/defaultEvents";
import getBooking from "@calcom/lib/getBooking";
import type { GetBookingType } from "@calcom/lib/getBooking";
import { useLocale } from "@calcom/lib/hooks/useLocale";
import { markdownToSafeHTML } from "@calcom/lib/markdownToSafeHTML";
import prisma, { bookEventTypeSelect } from "@calcom/prisma";
@@ -293,6 +293,8 @@ export async function getServerSideProps(context: GetServerSidePropsContext) {
props: {
away: user.away,
profile,
// Dynamic group has no theme preference right now. It uses system theme.
themeBasis: isDynamicGroupBooking ? null : user.username,
eventType: eventTypeObject,
booking,
currentSlotBooking: currentSlotBooking,
+3 -1
View File
@@ -23,6 +23,7 @@ class MyDocument extends Document<Props> {
// If x-csp not set by gSSP, then it's initialPropsOnly
setHeader(ctx, "x-csp", "initialPropsOnly");
}
const asPath = ctx.asPath || "";
// Use a dummy URL as default so that URL parsing works for relative URLs as well. We care about searchParams and pathname only
const parsedUrl = new URL(asPath, "https://dummyurl");
@@ -45,7 +46,8 @@ class MyDocument extends Document<Props> {
<link rel="manifest" href="/site.webmanifest" />
<link rel="mask-icon" href="/safari-pinned-tab.svg" color="#000000" />
<meta name="msapplication-TileColor" content="#ff0000" />
<meta name="theme-color" content="var(--cal-bg)" />
<meta name="theme-color" media="(prefers-color-scheme: light)" content="#f9fafb" />
<meta name="theme-color" media="(prefers-color-scheme: dark)" content="#1C1C1C" />
</Head>
<body
+1 -2
View File
@@ -8,10 +8,9 @@ import NextError from "next/error";
import React from "react";
import { getErrorFromUnknown } from "@calcom/lib/errors";
import { HttpError } from "@calcom/lib/http-error";
import logger from "@calcom/lib/logger";
import { HttpError } from "@lib/core/http/error";
import { ErrorPage } from "@components/error/error-page";
// Adds HttpException to the list of possible error types.
+1 -1
View File
@@ -1,4 +1,3 @@
import { IdentityProvider } from "@prisma/client";
import type { NextApiRequest, NextApiResponse } from "next";
import { ErrorCode } from "@calcom/features/auth/lib/ErrorCode";
@@ -6,6 +5,7 @@ import { getServerSession } from "@calcom/features/auth/lib/getServerSession";
import { hashPassword } from "@calcom/features/auth/lib/hashPassword";
import { verifyPassword } from "@calcom/features/auth/lib/verifyPassword";
import prisma from "@calcom/prisma";
import { IdentityProvider } from "@calcom/prisma/enums";
export default async function handler(req: NextApiRequest, res: NextApiResponse) {
const session = await getServerSession({ req, res });
+1 -2
View File
@@ -1,8 +1,7 @@
import type { NextApiRequest, NextApiResponse } from "next";
import jackson from "@calcom/features/ee/sso/lib/jackson";
import { HttpError } from "@lib/core/http/error";
import { HttpError } from "@calcom/lib/http-error";
// This is the callback endpoint for the OIDC provider
// A team must set this endpoint in the OIDC provider's configuration
+1 -2
View File
@@ -2,8 +2,7 @@ import type { OAuthReq } from "@boxyhq/saml-jackson";
import type { NextApiRequest, NextApiResponse } from "next";
import jackson from "@calcom/features/ee/sso/lib/jackson";
import type { HttpError } from "@lib/core/http/error";
import type { HttpError } from "@calcom/lib/http-error";
export default async function handler(req: NextApiRequest, res: NextApiResponse) {
const { oauthController } = await jackson();
+1 -1
View File
@@ -1,4 +1,3 @@
import { IdentityProvider } from "@prisma/client";
import type { NextApiRequest } from "next";
import z from "zod";
@@ -8,6 +7,7 @@ import { HttpError } from "@calcom/lib/http-error";
import { defaultHandler, defaultResponder } from "@calcom/lib/server";
import slugify from "@calcom/lib/slugify";
import prisma from "@calcom/prisma";
import { IdentityProvider } from "@calcom/prisma/enums";
const querySchema = z.object({
username: z
+15 -4
View File
@@ -1,10 +1,10 @@
import { IdentityProvider } from "@prisma/client";
import type { NextApiRequest, NextApiResponse } from "next";
import { hashPassword } from "@calcom/features/auth/lib/hashPassword";
import slugify from "@calcom/lib/slugify";
import { closeComUpsertTeamUser } from "@calcom/lib/sync/SyncServiceManager";
import prisma from "@calcom/prisma";
import { IdentityProvider } from "@calcom/prisma/enums";
export default async function handler(req: NextApiRequest, res: NextApiResponse) {
if (req.method !== "POST") {
@@ -36,14 +36,25 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse)
return;
}
// There is actually an existingUser if username matches
// OR if email matches and both username and password are set
// There is an existingUser if the username matches
// OR if the email matches AND either the email is verified
// or both username and password are set
const existingUser = await prisma.user.findFirst({
where: {
OR: [
{ username },
{
AND: [{ email: userEmail }],
AND: [
{ email: userEmail },
{
OR: [
{ emailVerified: { not: null } },
{
AND: [{ password: { not: null } }, { username: { not: null } }],
},
],
},
],
},
],
},
@@ -1,4 +1,3 @@
import { IdentityProvider } from "@prisma/client";
import type { NextApiRequest, NextApiResponse } from "next";
import { authenticator } from "otplib";
import qrcode from "qrcode";
@@ -8,6 +7,7 @@ import { getServerSession } from "@calcom/features/auth/lib/getServerSession";
import { verifyPassword } from "@calcom/features/auth/lib/verifyPassword";
import { symmetricEncrypt } from "@calcom/lib/crypto";
import prisma from "@calcom/prisma";
import { IdentityProvider } from "@calcom/prisma/enums";
export default async function handler(req: NextApiRequest, res: NextApiResponse) {
if (req.method !== "POST") {
+1 -1
View File
@@ -1,4 +1,3 @@
import { BookingStatus, ReminderType } from "@prisma/client";
import type { NextApiRequest, NextApiResponse } from "next";
import dayjs from "@calcom/dayjs";
@@ -7,6 +6,7 @@ import { getCalEventResponses } from "@calcom/features/bookings/lib/getCalEventR
import { isPrismaObjOrUndefined, parseRecurringEvent } from "@calcom/lib";
import { getTranslation } from "@calcom/lib/server/i18n";
import prisma, { bookingMinimalSelect } from "@calcom/prisma";
import { BookingStatus, ReminderType } from "@calcom/prisma/enums";
import type { CalendarEvent } from "@calcom/types/Calendar";
export default async function handler(req: NextApiRequest, res: NextApiResponse) {
+1 -2
View File
@@ -4,12 +4,11 @@ import type { Session } from "next-auth";
import getInstalledAppPath from "@calcom/app-store/_utils/getInstalledAppPath";
import { getServerSession } from "@calcom/features/auth/lib/getServerSession";
import { deriveAppDictKeyFromType } from "@calcom/lib/deriveAppDictKeyFromType";
import { HttpError } from "@calcom/lib/http-error";
import { revalidateCalendarCache } from "@calcom/lib/server/revalidateCalendarCache";
import prisma from "@calcom/prisma";
import type { AppDeclarativeHandler, AppHandler } from "@calcom/types/AppHandler";
import { HttpError } from "@lib/core/http/error";
const defaultIntegrationAddHandler = async ({
slug,
supportsMultipleInstalls,
+4 -18
View File
@@ -1,4 +1,3 @@
import { UserPermissionRole } from "@prisma/client";
import type { NextApiRequest, NextApiResponse } from "next";
import { z } from "zod";
@@ -7,7 +6,7 @@ import { defaultResponder } from "@calcom/lib/server";
import prisma from "@calcom/prisma";
import { TRPCError } from "@calcom/trpc/server";
import { createContext } from "@calcom/trpc/server/createContext";
import { viewerRouter } from "@calcom/trpc/server/routers/viewer";
import { viewerRouter } from "@calcom/trpc/server/routers/viewer/_router";
enum DirectAction {
ACCEPT = "accept",
@@ -27,31 +26,18 @@ const decryptedSchema = z.object({
async function handler(req: NextApiRequest, res: NextApiResponse<Response>) {
const { action, token, reason } = querySchema.parse(req.query);
const { bookingUid, userId } = decryptedSchema.parse(
const { bookingUid } = decryptedSchema.parse(
JSON.parse(symmetricDecrypt(decodeURIComponent(token), process.env.CALENDSO_ENCRYPTION_KEY || ""))
);
/** We shape the session as required by tRPC router */
async function sessionGetter() {
return {
user: {
id: userId,
username: "" /* Not used in this context */,
role: UserPermissionRole.USER,
},
hasValidLicense: true,
expires: "" /* Not used in this context */,
};
}
const booking = await prisma.booking.findUniqueOrThrow({
where: { uid: bookingUid },
});
try {
/** @see https://trpc.io/docs/server-side-calls */
const ctx = await createContext({ req, res }, sessionGetter);
const caller = viewerRouter.createCaller(ctx);
const ctx = await createContext({ req, res });
const caller = viewerRouter.createCaller({ ...ctx, req, res });
await caller.bookings.confirm({
bookingId: booking.id,
recurringEventId: booking.recurringEventId || undefined,
+26
View File
@@ -0,0 +1,26 @@
import type { NextApiRequest, NextApiResponse } from "next";
import { z } from "zod";
import { defaultResponder } from "@calcom/lib/server";
const newBookerSchema = z.object({
status: z.enum(["enable", "disable"]),
});
/**
* Very basic temporary api route to enable/disable new booker access.
*/
async function handler(req: NextApiRequest, res: NextApiResponse) {
const { status } = newBookerSchema.parse(req.query);
if (status === "enable") {
const expires = new Date();
expires.setFullYear(expires.getFullYear() + 1);
res.setHeader("Set-Cookie", `new-booker-enabled=true; path=/; expires=${expires.toUTCString()}`);
} else {
res.setHeader("Set-Cookie", "new-booker-enabled=; path=/; expires=Thu, 01 Jan 1970 00:00:00 GMT");
}
res.send({ status: 200, body: `Done – ${status}` });
}
export default defaultResponder(handler);
+62 -21
View File
@@ -1,3 +1,4 @@
import type { WebhookTriggerEvents } from "@prisma/client";
import type { NextApiRequest, NextApiResponse } from "next";
import { z } from "zod";
@@ -5,6 +6,8 @@ import { DailyLocationType } from "@calcom/app-store/locations";
import { getDownloadLinkOfCalVideoByRecordingId } from "@calcom/core/videoClient";
import { sendDailyVideoRecordingEmails } from "@calcom/emails";
import { getServerSession } from "@calcom/features/auth/lib/getServerSession";
import getWebhooks from "@calcom/features/webhooks/lib/getWebhooks";
import sendPayload from "@calcom/features/webhooks/lib/sendPayload";
import { IS_SELF_HOSTED } from "@calcom/lib/constants";
import { defaultHandler } from "@calcom/lib/server";
import { getTranslation } from "@calcom/lib/server/i18n";
@@ -20,6 +23,38 @@ const downloadLinkSchema = z.object({
download_link: z.string(),
});
const triggerWebhook = async ({
evt,
downloadLink,
booking,
}: {
evt: CalendarEvent;
downloadLink: string;
booking: {
userId: number | undefined;
eventTypeId: number | null;
};
}) => {
const eventTrigger: WebhookTriggerEvents = "RECORDING_READY";
// Send Webhook call if hooked to BOOKING.RECORDING_READY
const subscriberOptions = {
userId: booking.userId ?? 0,
eventTypeId: booking.eventTypeId ?? 0,
triggerEvent: eventTrigger,
};
const webhooks = await getWebhooks(subscriberOptions);
const promises = webhooks.map((webhook) =>
sendPayload(webhook.secret, eventTrigger, new Date().toISOString(), webhook, {
...evt,
downloadLink,
}).catch((e) => {
console.error(`Error executing webhook for event: ${eventTrigger}, URL: ${webhook.subscriberUrl}`, e);
})
);
await Promise.all(promises);
};
async function handler(req: NextApiRequest, res: NextApiResponse) {
if (!process.env.SENDGRID_API_KEY || !process.env.SENDGRID_EMAIL) {
return res.status(405).json({ message: "No SendGrid API key or email" });
@@ -51,6 +86,7 @@ async function handler(req: NextApiRequest, res: NextApiResponse) {
uid: true,
location: true,
isRecorded: true,
eventTypeId: true,
user: {
select: {
id: true,
@@ -105,31 +141,36 @@ async function handler(req: NextApiRequest, res: NextApiResponse) {
},
});
const response = await getDownloadLinkOfCalVideoByRecordingId(recordingId);
const downloadLinkResponse = downloadLinkSchema.parse(response);
const downloadLink = downloadLinkResponse.download_link;
const evt: CalendarEvent = {
type: booking.title,
title: booking.title,
description: booking.description || undefined,
startTime: booking.startTime.toISOString(),
endTime: booking.endTime.toISOString(),
organizer: {
email: booking.user?.email || "Email-less",
name: booking.user?.name || "Nameless",
timeZone: booking.user?.timeZone || "Europe/London",
language: { translate: t, locale: booking?.user?.locale ?? "en" },
},
attendees: attendeesList,
uid: booking.uid,
};
await triggerWebhook({
evt,
downloadLink,
booking: { userId: booking?.user?.id, eventTypeId: booking.eventTypeId },
});
const isSendingEmailsAllowed = IS_SELF_HOSTED || session?.user?.belongsToActiveTeam;
// send emails to all attendees only when user has team plan
if (isSendingEmailsAllowed) {
const response = await getDownloadLinkOfCalVideoByRecordingId(recordingId);
const downloadLinkResponse = downloadLinkSchema.parse(response);
const downloadLink = downloadLinkResponse.download_link;
const evt: CalendarEvent = {
type: booking.title,
title: booking.title,
description: booking.description || undefined,
startTime: booking.startTime.toISOString(),
endTime: booking.endTime.toISOString(),
organizer: {
email: booking.user?.email || "Email-less",
name: booking.user?.name || "Nameless",
timeZone: booking.user?.timeZone || "Europe/London",
language: { translate: t, locale: booking?.user?.locale ?? "en" },
},
attendees: attendeesList,
uid: booking.uid,
};
await sendDailyVideoRecordingEmails(evt, downloadLink);
return res.status(200).json({ message: "Success" });
}
+1 -4
View File
@@ -4,7 +4,6 @@ import type { SatoriOptions } from "satori";
import { z } from "zod";
import { Meeting, App, Generic } from "@calcom/lib/OgImages";
import { md } from "@calcom/lib/markdownIt";
const calFont = fetch(new URL("../../../../public/fonts/cal.ttf", import.meta.url)).then((res) =>
res.arrayBuffer()
@@ -75,12 +74,10 @@ export default async function handler(req: NextApiRequest) {
imageType,
});
const title_ = md.render(title).replace(/(<([^>]+)>)/gi, "");
const img = new ImageResponse(
(
<Meeting
title={title_}
title={title}
profile={{ name: meetingProfileName, image: meetingImage }}
users={names.map((name, index) => ({ name, username: usernames[index] }))}
/>
-83
View File
@@ -1,83 +0,0 @@
/**
* This file contains tRPC's HTTP response handler
*/
import { z } from "zod";
import { getServerSession } from "@calcom/features/auth/lib/getServerSession";
import * as trpcNext from "@calcom/trpc/server/adapters/next";
import { createContext as createTrpcContext } from "@calcom/trpc/server/createContext";
import { appRouter } from "@calcom/trpc/server/routers/_app";
export default trpcNext.createNextApiHandler({
router: appRouter,
/**
* @link https://trpc.io/docs/context
*/
createContext: ({ req, res }) => {
const sessionGetter = () => getServerSession({ req, res });
return createTrpcContext({ req, res }, sessionGetter);
},
/**
* @link https://trpc.io/docs/error-handling
*/
onError({ error }) {
if (error.code === "INTERNAL_SERVER_ERROR") {
// send to bug reporting
console.error("Something went wrong", error);
}
},
/**
* Enable query batching
*/
batching: {
enabled: true,
},
/**
* @link https://trpc.io/docs/caching#api-response-caching
*/
responseMeta({ ctx, paths, type, errors }) {
// Some helpers relevant to this function only
const ONE_DAY_IN_SECONDS = 60 * 60 * 24;
// assuming you have all your public routes with the keyword `public` in them
const allPublic = paths && paths.every((path) => path.startsWith("viewer.public."));
// checking that no procedures errored
const allOk = errors.length === 0;
// checking we're doing a query request
const isQuery = type === "query";
const noHeaders = {};
// We cannot set headers on SSG queries
if (!ctx?.res) return noHeaders;
const defaultHeaders: Record<"headers", Record<string, string>> = {
headers: {},
};
const timezone = z.string().safeParse(ctx.req?.headers["x-vercel-ip-timezone"]);
if (timezone.success) defaultHeaders.headers["x-cal-timezone"] = timezone.data;
// We need all these conditions to be true to set cache headers
if (!(allPublic && allOk && isQuery)) return defaultHeaders;
// No cache by default
defaultHeaders.headers["cache-control"] = `no-cache`;
// Our cache can change depending on our current paths value. Since paths is an array,
// we want to create a map that can match potential paths with their desired cache value
const cacheRules = {
"viewer.public.session": `no-cache`,
"viewer.public.i18n": `no-cache`,
// Revalidation time here should be 1 second, per https://github.com/calcom/cal.com/pull/6823#issuecomment-1423215321
"viewer.public.slots.getSchedule": `no-cache`, // FIXME
"viewer.public.cityTimezones": `max-age=${ONE_DAY_IN_SECONDS}, stale-while-revalidate`,
} as const;
// Find which element above is an exact match for this group of paths
const matchedPath = paths.find((v) => v in cacheRules) as keyof typeof cacheRules;
if (matchedPath) defaultHeaders.headers["cache-control"] = cacheRules[matchedPath];
return defaultHeaders;
},
});
@@ -0,0 +1,4 @@
import { createNextApiHandler } from "@calcom/trpc/server/createNextApiHandler";
import { apiKeysRouter } from "@calcom/trpc/server/routers/viewer/apiKeys/_router";
export default createNextApiHandler(apiKeysRouter);
@@ -0,0 +1,4 @@
import appRoutingForms from "@calcom/app-store/routing-forms/trpc-router";
import { createNextApiHandler } from "@calcom/trpc/server/createNextApiHandler";
export default createNextApiHandler(appRoutingForms);
+4
View File
@@ -0,0 +1,4 @@
import { createNextApiHandler } from "@calcom/trpc/server/createNextApiHandler";
import { appsRouter } from "@calcom/trpc/server/routers/viewer/apps/_router";
export default createNextApiHandler(appsRouter);
@@ -0,0 +1,4 @@
import { createNextApiHandler } from "@calcom/trpc/server/createNextApiHandler";
import { appsRouter } from "@calcom/trpc/server/routers/viewer/apps/_router";
export default createNextApiHandler(appsRouter);
+4
View File
@@ -0,0 +1,4 @@
import { createNextApiHandler } from "@calcom/trpc/server/createNextApiHandler";
import { authRouter } from "@calcom/trpc/server/routers/viewer/auth/_router";
export default createNextApiHandler(authRouter);
@@ -0,0 +1,4 @@
import { createNextApiHandler } from "@calcom/trpc/server/createNextApiHandler";
import { availabilityRouter } from "@calcom/trpc/server/routers/viewer/availability/_router";
export default createNextApiHandler(availabilityRouter);
@@ -0,0 +1,4 @@
import { createNextApiHandler } from "@calcom/trpc/server/createNextApiHandler";
import { bookingsRouter } from "@calcom/trpc/server/routers/viewer/bookings/_router";
export default createNextApiHandler(bookingsRouter);
@@ -0,0 +1,4 @@
import { createNextApiHandler } from "@calcom/trpc/server/createNextApiHandler";
import { deploymentSetupRouter } from "@calcom/trpc/server/routers/viewer/deploymentSetup/_router";
export default createNextApiHandler(deploymentSetupRouter);
+4
View File
@@ -0,0 +1,4 @@
import ethRouter from "@calcom/app-store/rainbow/trpc/router";
import { createNextApiHandler } from "@calcom/trpc/server/createNextApiHandler";
export default createNextApiHandler(ethRouter);
@@ -0,0 +1,4 @@
import { createNextApiHandler } from "@calcom/trpc/server/createNextApiHandler";
import { eventTypesRouter } from "@calcom/trpc/server/routers/viewer/eventTypes/_router";
export default createNextApiHandler(eventTypesRouter);
@@ -0,0 +1,4 @@
import { featureFlagRouter } from "@calcom/features/flags/server/router";
import { createNextApiHandler } from "@calcom/trpc/server/createNextApiHandler";
export default createNextApiHandler(featureFlagRouter);
@@ -0,0 +1,4 @@
import { insightsRouter } from "@calcom/features/insights/server/trpc-router";
import { createNextApiHandler } from "@calcom/trpc/server/createNextApiHandler";
export default createNextApiHandler(insightsRouter);
@@ -0,0 +1,4 @@
import { createNextApiHandler } from "@calcom/trpc/server/createNextApiHandler";
import { paymentsRouter } from "@calcom/trpc/server/routers/viewer/payments/_router";
export default createNextApiHandler(paymentsRouter);
+4
View File
@@ -0,0 +1,4 @@
import { createNextApiHandler } from "@calcom/trpc/server/createNextApiHandler";
import { publicViewerRouter } from "@calcom/trpc/server/routers/publicViewer/_router";
export default createNextApiHandler(publicViewerRouter, true);
+4
View File
@@ -0,0 +1,4 @@
import { createNextApiHandler } from "@calcom/trpc/server/createNextApiHandler";
import { ssoRouter } from "@calcom/trpc/server/routers/viewer/sso/_router";
export default createNextApiHandler(ssoRouter);
+4
View File
@@ -0,0 +1,4 @@
import { createNextApiHandler } from "@calcom/trpc/server/createNextApiHandler";
import { slotsRouter } from "@calcom/trpc/server/routers/viewer/slots/_router";
export default createNextApiHandler(slotsRouter);
+4
View File
@@ -0,0 +1,4 @@
import { createNextApiHandler } from "@calcom/trpc/server/createNextApiHandler";
import { viewerTeamsRouter } from "@calcom/trpc/server/routers/viewer/teams/_router";
export default createNextApiHandler(viewerTeamsRouter);
+4
View File
@@ -0,0 +1,4 @@
import { userAdminRouter } from "@calcom/features/ee/users/server/trpc-router";
import { createNextApiHandler } from "@calcom/trpc/server/createNextApiHandler";
export default createNextApiHandler(userAdminRouter);
+4
View File
@@ -0,0 +1,4 @@
import { createNextApiHandler } from "@calcom/trpc/server/createNextApiHandler";
import { loggedInViewerRouter } from "@calcom/trpc/server/routers/loggedInViewer/_router";
export default createNextApiHandler(loggedInViewerRouter);
@@ -0,0 +1,4 @@
import { createNextApiHandler } from "@calcom/trpc/server/createNextApiHandler";
import { webhookRouter } from "@calcom/trpc/server/routers/viewer/webhook/_router";
export default createNextApiHandler(webhookRouter);
@@ -0,0 +1,4 @@
import { createNextApiHandler } from "@calcom/trpc/server/createNextApiHandler";
import { workflowsRouter } from "@calcom/trpc/server/routers/viewer/workflows/_router";
export default createNextApiHandler(workflowsRouter);
+52 -13
View File
@@ -2,10 +2,12 @@ import fs from "fs";
import matter from "gray-matter";
import MarkdownIt from "markdown-it";
import type { GetStaticPaths, GetStaticPropsContext } from "next";
import Link from "next/link";
import path from "path";
import { z } from "zod";
import { getAppWithMetadata } from "@calcom/app-store/_appRegistry";
import { getAppAssetFullPath } from "@calcom/app-store/getAppAssetFullPath";
import prisma from "@calcom/prisma";
import type { inferSSRProps } from "@lib/types/inferSSRProps";
@@ -32,7 +34,26 @@ const sourceSchema = z.object({
}),
});
function SingleAppPage({ data, source }: inferSSRProps<typeof getStaticProps>) {
function SingleAppPage(props: inferSSRProps<typeof getStaticProps>) {
// If it's not production environment, it would be a better idea to inform that the App is disabled.
if (props.isAppDisabled) {
if (process.env.NODE_ENV !== "production") {
// TODO: Improve disabled App UI. This is just a placeholder.
return (
<div className="p-2">
This App seems to be disabled. If you are an admin, you can enable this app from{" "}
<Link href="/settings/admin/apps" className="cursor-pointer text-blue-500 underline">
here
</Link>
</div>
);
}
// Disabled App should give 404 any ways in production.
return null;
}
const { source, data } = props;
return (
<App
name={data.name}
@@ -51,6 +72,7 @@ function SingleAppPage({ data, source }: inferSSRProps<typeof getStaticProps>) {
website={data.url}
email={data.email}
licenseRequired={data.licenseRequired}
teamsPlanRequired={data.teamsPlanRequired}
isProOnly={data.isProOnly}
descriptionItems={source.data?.items as string[] | undefined}
isTemplate={data.isTemplate}
@@ -79,46 +101,63 @@ export const getStaticPaths: GetStaticPaths<{ slug: string }> = async () => {
export const getStaticProps = async (ctx: GetStaticPropsContext) => {
if (typeof ctx.params?.slug !== "string") return { notFound: true };
const app = await prisma.app.findUnique({
const appMeta = await getAppWithMetadata({
slug: ctx.params?.slug,
});
const appFromDb = await prisma.app.findUnique({
where: { slug: ctx.params.slug.toLowerCase() },
});
if (!app) return { notFound: true };
const isAppAvailableInFileSystem = appMeta;
const isAppDisabled = isAppAvailableInFileSystem && (!appFromDb || !appFromDb.enabled);
const singleApp = await getAppWithMetadata(app);
if (process.env.NODE_ENV !== "production" && isAppDisabled) {
return {
props: {
isAppDisabled: true as const,
data: {
...appMeta,
},
},
};
}
if (!singleApp) return { notFound: true };
if (!appFromDb || !appMeta || isAppDisabled) return { notFound: true };
const isTemplate = singleApp.isTemplate;
const appDirname = path.join(isTemplate ? "templates" : "", app.dirName);
const isTemplate = appMeta.isTemplate;
const appDirname = path.join(isTemplate ? "templates" : "", appFromDb.dirName);
const README_PATH = path.join(process.cwd(), "..", "..", `packages/app-store/${appDirname}/DESCRIPTION.md`);
const postFilePath = path.join(README_PATH);
let source = "";
try {
source = fs.readFileSync(postFilePath).toString();
source = source.replace(/{DESCRIPTION}/g, singleApp.description);
source = source.replace(/{DESCRIPTION}/g, appMeta.description);
} catch (error) {
/* If the app doesn't have a README we fallback to the package description */
console.log(`No DESCRIPTION.md provided for: ${appDirname}`);
source = singleApp.description;
source = appMeta.description;
}
const result = matter(source);
const { content, data } = sourceSchema.parse({ content: result.content, data: result.data });
if (data.items) {
data.items = data.items.map((item) => {
if (typeof item === "string" && !item.includes("/api/app-store")) {
// Make relative paths absolute
return `/api/app-store/${appDirname}/${item}`;
if (typeof item === "string") {
return getAppAssetFullPath(item, {
dirName: appMeta.dirName,
isTemplate: appMeta.isTemplate,
});
}
return item;
});
}
return {
props: {
isAppDisabled: false as const,
source: { content, data },
data: singleApp,
data: appMeta,
},
};
};
+8 -1
View File
@@ -4,6 +4,7 @@ import { useRouter } from "next/router";
import { AppSetupPage } from "@calcom/app-store/_pages/setup";
import { getStaticProps } from "@calcom/app-store/_pages/setup/_getStaticProps";
import { HeadSeo } from "@calcom/ui";
import PageWrapper from "@components/PageWrapper";
@@ -25,7 +26,13 @@ export default function SetupInformation(props: InferGetStaticPropsType<typeof g
});
}
return <AppSetupPage slug={slug} {...props} />;
return (
<>
{/* So that the set up page does not get indexed by search engines */}
<HeadSeo nextSeoProps={{ noindex: true, nofollow: true }} title={`${slug} | Cal.com`} description="" />
<AppSetupPage slug={slug} {...props} />
</>
);
}
SetupInformation.PageWrapper = PageWrapper;
@@ -1,4 +1,3 @@
import { AppCategories } from "@prisma/client";
import type { GetStaticPropsContext, InferGetStaticPropsType } from "next";
import Link from "next/link";
import { useRouter } from "next/router";
@@ -7,6 +6,7 @@ import { getAppRegistry } from "@calcom/app-store/_appRegistry";
import Shell from "@calcom/features/shell/Shell";
import { useLocale } from "@calcom/lib/hooks/useLocale";
import prisma from "@calcom/prisma";
import { AppCategories } from "@calcom/prisma/enums";
import { AppCard, SkeletonText } from "@calcom/ui";
import PageWrapper from "@components/PageWrapper";
+2 -2
View File
@@ -6,7 +6,7 @@ import { getAppRegistry, getAppRegistryWithCredentials } from "@calcom/app-store
import { getServerSession } from "@calcom/features/auth/lib/getServerSession";
import { classNames } from "@calcom/lib";
import { useLocale } from "@calcom/lib/hooks/useLocale";
import type { AppCategories } from "@calcom/prisma/client";
import type { AppCategories } from "@calcom/prisma/enums";
import type { inferSSRProps } from "@calcom/types/inferSSRProps";
import type { HorizontalTabItemProps } from "@calcom/ui";
import { AllApps, AppStoreCategories, HorizontalTabs, TextField, PopularAppsSlider } from "@calcom/ui";
@@ -40,7 +40,7 @@ function AppsSearch({
className="bg-subtle !border-muted !pl-0 focus:!ring-offset-0"
addOnLeading={<Search className="text-subtle h-4 w-4" />}
addOnClassname="!border-muted"
containerClassName={classNames("focus:!ring-offset-0", className)}
containerClassName={classNames("focus:!ring-offset-0 m-1", className)}
type="search"
autoComplete="false"
onChange={onChange}
+1 -1
View File
@@ -172,7 +172,7 @@ export default function Login({
className="mb-0"
{...register("password")}
/>
<div className="absolute -top-1.5 ltr:right-0 rtl:left-0">
<div className="absolute -top-[2px] ltr:right-0 rtl:left-0">
<Link
href="/auth/forgot-password"
tabIndex={-1}
+7 -5
View File
@@ -1,4 +1,3 @@
import { UserPermissionRole } from "@prisma/client";
import type { GetServerSidePropsContext } from "next";
import { useRouter } from "next/router";
import { useState } from "react";
@@ -8,6 +7,7 @@ import { getServerSession } from "@calcom/features/auth/lib/getServerSession";
import { getDeploymentKey } from "@calcom/features/ee/deployment/lib/getDeploymentKey";
import { useLocale } from "@calcom/lib/hooks/useLocale";
import prisma from "@calcom/prisma";
import { UserPermissionRole } from "@calcom/prisma/enums";
import type { inferSSRProps } from "@calcom/types/inferSSRProps";
import { Meta, WizardForm } from "@calcom/ui";
@@ -157,10 +157,13 @@ export const getServerSideProps = async (context: GetServerSidePropsContext) =>
};
}
let deploymentKey = await getDeploymentKey(prisma);
const deploymentKey = await prisma.deployment.findUnique({
where: { id: 1 },
select: { licenseKey: true },
});
// Check existant CALCOM_LICENSE_KEY env var and acccount for it
if (!!process.env.CALCOM_LICENSE_KEY && !deploymentKey) {
if (!!process.env.CALCOM_LICENSE_KEY && !deploymentKey?.licenseKey) {
await prisma.deployment.upsert({
where: { id: 1 },
update: {
@@ -172,10 +175,9 @@ export const getServerSideProps = async (context: GetServerSidePropsContext) =>
agreedLicenseAt: new Date(),
},
});
deploymentKey = await getDeploymentKey(prisma);
}
const isFreeLicense = deploymentKey === "";
const isFreeLicense = (await getDeploymentKey(prisma)) === "";
return {
props: {

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