Compare commits

..
66 Commits
Author SHA1 Message Date
Alex van Andel 4a914c2dfb chore: Release v4.5.3 (#16728)
release.yml / release (push) Canceled after 0s
2024-09-20 16:27:25 +01:00
Joe Au-Yeung 62d579d03d Default to connected Salesforce account as owner (#16747) 2024-09-20 15:27:05 +00:00
Morgan 74bed31edc chore: improve api-v2 rate limiting (#16746) 2024-09-20 15:15:48 +00:00
Alex van Andel 97f213f260 revert: be7d45afe2 (#16742) 2024-09-20 15:01:49 +00:00
Carina WollendorferandCarinaWolli b84cdc0d45 fix: bookings ilmits errror (#16739)
* use booker timezone

* add test

---------

Co-authored-by: CarinaWolli <wollencarina@gmail.com>
2024-09-20 13:35:12 +00:00
Syed Ali Shahbaz 8cb5a7080b feat: Add EXPAND accepting "team" in API V1 Bookings (#16736)
* add expand

* add expand to /[id]/_get

* add test

* fix test import

* --

* --

* fix test

* fix test

* revert unintentional commit
2024-09-20 11:46:26 +00:00
Lauris Skraucis 11f0d48d0b feat: onBeforeUpdate AvailabilitySettings prop (#16737) 2024-09-20 11:42:10 +00:00
Syed Ali Shahbaz c4a1382982 chore: add granular logging to the logger (#16734)
* Update README.md

* Update README.md

* Update README.md

* Update README.md

* Update turbo.json

* Update trpc-provider.tsx

* Update logger.ts

* update prisma index

* Update trpc.ts

* Update trpc-provider.tsx

* Update trpc.ts

* Update .env.example

* Update logger.ts
2024-09-20 09:06:37 +00:00
Calcom BotandReplexica e0922c5ee0 feat: update translations (#16726)
release.yml / release (push) Canceled after 0s
Co-authored-by: Replexica <support@replexica.com>
2024-09-19 16:58:47 +00:00
Benny JooandJoe Au-Yeung f8dc7a115a chore: App Router - remove references to /pages for remaining pages in /auth, /insights, /d, signup and add missing default /future page (#16589)
* remove references to /pages for sso, setup, signin pages in /auth

* remove references to pages for insights

* remove references to pages for d

* remove references to pages for signup

* add page for /future index page

* fix routing-forms

* fix

* add missing defaults

* use getServerSessionForAppDir instead

* fix apps/[slug]/[...pages]

* fix metadata in apps/slug/pages

* refactor

* refactor

* remove duplicate code for PageProps

* remove references to pages for /reschedule

* fix

* fix routing forms

* type fix

* fix routing forms again

* revert changes for app/slug/pages

* revert

* revert changes in yarn lock

---------

Co-authored-by: Joe Au-Yeung <65426560+joeauyeung@users.noreply.github.com>
2024-09-19 15:06:51 +00:00
sean-brydonandPeer Richelsen a60aa1bf6c add create license key to admin tab if IS_CALCOM (#16721)
Co-authored-by: Peer Richelsen <peeroke@gmail.com>
2024-09-19 13:09:14 +00:00
Hariom Balhara bc203d7439 Release latest embed (#16713) 2024-09-19 11:02:17 +00:00
Udit Takkar d82847035f fix: type error on booking cancelled page (#16716) 2024-09-19 10:13:16 +00:00
Hariom Balhara 6d133c26f8 Narrow argument type to the specific event being listened to (#16714) 2024-09-19 09:42:32 +00:00
Benny Joo 3ae53a4b6e chore: App router - Fix errors in settings pages & add remaining pages (#16648)
* fix settings/admin/page

* remove references to pages for settings/teams

* remove double layouts

* move pages that do not need layout out of (settings) group

* fix

* fix

* fix

* fix

* add sso page and fix layouts
2024-09-19 09:59:32 +01:00
Lauris Skraucis 63339d8c01 fix: connect apple calendar atom nested <button>'s (#16715) 2024-09-19 08:49:21 +00:00
Lauris SkraucisandMorgan 44410c87f0 docs: v2 schedules and event-types swagger (#16608)
* docs: schedules

* docs: wip event-types

* docs:event-types

* docs:event-types

* Delete yarn.lock

* Revert "Delete yarn.lock"

This reverts commit bb3eb23508c0fa2e216ba7bcb97756215f889daa.

---------

Co-authored-by: Morgan <33722304+ThyMinimalDev@users.noreply.github.com>
2024-09-19 10:00:17 +03:00
Omar López c016241004 chore: removes unnecessary prisma env warnings (#16708)
* chore: removes unnecessary prisma env warnings

* Revert lockfile

Signed-off-by: zomars <zomars@me.com>

* Update yarn lock

Signed-off-by: zomars <zomars@me.com>

---------

Signed-off-by: zomars <zomars@me.com>
2024-09-19 07:32:23 +05:30
Benny Joo 019ef6de2a chore: App router migration - (/bookings, /booking) Move getServerSideProps/getStaticProps to /lib (#16458)
* booking: Move getServerSideProps to /lib

* remove duplicate

* bookings: Move getStaticProps to /lib

* fix type check

* replace setHeader with a server action call in withEmbedSSR

* Add env variables for booking
2024-09-18 19:09:57 -04:00
Omar López a2b064b269 feat: per user and team feature flags (#16040) 2024-09-18 21:27:47 +00:00
abb4fd307f refactor: event setup tab web wrapper (#16672)
* chore: EventTypeWebWrapper base pr

* fixup! chore: EventTypeWebWrapper base pr

* fixup! Merge branch 'main' into morgan/cal-4183-eventtypeatom-web-wrapper-base

* wip

* fix: error

* Event type atom wrapper handles app dir

* fixup! Merge branch 'main' into morgan/cal-4183-eventtypeatom-web-wrapper-base

* fixup! fixup! Merge branch 'main' into morgan/cal-4183-eventtypeatom-web-wrapper-base

* remove console log

* refactor: event-type-atom (setup tab)

* review comments

* update: better naming

* fixup! review comments

* revert: defaultMenuIsOpen --will create a separate PR

---------

Co-authored-by: Morgan Vernay <morgan@cal.com>
Co-authored-by: Morgan <33722304+ThyMinimalDev@users.noreply.github.com>
2024-09-18 20:14:23 +03:00
Peer Richelsen a9ebb0d160 feat: Retell AI (#16706)
* added retell ai to app store

* added retell ai
2024-09-18 17:08:01 +00:00
sean-brydon 1058c0e171 fix(eslint): Adds eslint-ignore-patterns to eslint config (#16701) 2024-09-18 15:17:52 +00:00
Anik Dhabal Babu 021e5f3833 fix: fixed more flaky e2e tests (round 2) (#16660)
* fix: fixed more flaky e2e tests (round 2)

* update

* fix and update

* update
2024-09-18 23:25:44 +09:00
Lauris Skraucis 5b5a42e72d refactor: v2 and atoms booking fields (#16685)
* refactor: define inputs and outputs by separating default and custom fields

* refactor: event type api <-> internal transformers

* refactor: v2 use refactored libraries to transform input and output booking fields

* refactor: dont allow custom slugs with default reserved slugs

* refactor: input service store only specific default system fields

* refactor: atoms display only specific default system fields

* refactor: delete unused system field constants

* fix: tests

* fix: old event types

* fix: imports

* fix: import

* chore: release libraries and use v2 with them

* fix: unit tests

* refactor: push email in case of missing phone

* refactor: satisfies check for event-type locations
2024-09-18 13:59:31 +02:00
MorganandSomay Chauhan 2b43d9a716 chore: EventTypeWebWrapper base pr (#16550)
* chore: EventTypeWebWrapper base pr

* fixup! chore: EventTypeWebWrapper base pr

* fixup! Merge branch 'main' into morgan/cal-4183-eventtypeatom-web-wrapper-base

* wip

* fix: error

* Event type atom wrapper handles app dir

* fixup! Merge branch 'main' into morgan/cal-4183-eventtypeatom-web-wrapper-base

* fixup! fixup! Merge branch 'main' into morgan/cal-4183-eventtypeatom-web-wrapper-base

* remove console log

* review comments

* fixup! review comments

* fixup! Merge branch 'main' into morgan/cal-4183-eventtypeatom-web-wrapper-base

---------

Co-authored-by: Somay Chauhan <somaychauhan98@gmail.com>
2024-09-18 12:26:04 +03:00
Omar López 3a5325f2a8 fix: new user detection for dub analytics (#16695) 2024-09-17 19:19:25 -07:00
Calcom BotandReplexica 5ad73607f0 feat: update translations (#16693)
Co-authored-by: Replexica <support@replexica.com>
2024-09-17 23:21:10 +00:00
Carina Wollendorfer 5067f0dd16 fix: dates in ooo booking redirect email (#16692) 2024-09-17 22:28:40 +00:00
Keith Williams a53e697baa chore: v4.5.1 (#16690)
release.yml / release (push) Canceled after 0s
2024-09-18 04:05:16 +09:00
sean-brydon e7415fe6e2 feat: update vitest version v0.34 to V2.11 (#16676)
* update version

* fix button to match new spec

* migrate tests to objectContaining

* fix tests

* update RTL

* yarn.lock update

* bump fetch mock to latest vitest version

* update deep mock to use vitest 2.0

* fix mock prisma type cast

* meet base test fn singature for V2

* remove console.log from next test
2024-09-17 19:09:55 +01:00
sean-brydonandJoe Au-Yeung 562309d24b fix: add optimistic UI for deleting member on org user table (#16662)
* add optimistic UI for deleting member

* Update packages/features/users/components/UserTable/DeleteMemberModal.tsx

* Remove previous Value

* Update packages/features/users/components/UserTable/DeleteMemberModal.tsx

* Update packages/features/users/components/UserTable/DeleteMemberModal.tsx

* fix onError

---------

Co-authored-by: Joe Au-Yeung <65426560+joeauyeung@users.noreply.github.com>
2024-09-17 10:19:45 +00:00
Lauris Skraucis 3900c55204 fix: make connect calendar atoms client side (#16677)
* fix: make connect calendar atoms client side

* delete unrelated file
2024-09-17 10:16:12 +00:00
Morgan b3be9a93e0 chore: expose metadata on platform booker atom (#16673) 2024-09-17 10:12:30 +00:00
d27ccd6f44 feat: org team app install (#15704)
* feat: remove dropdown from app-store and redirect to new-app-install-flow

* removed extra code

* fix: account select loading issue

* removed getPaymentCredential (unused)

* fix: only redirect after the app has been added to all the event-types

* remove overflowIndicatorStyles

* refactor getUserAdminTeams

* send teamId instead of id

* seperate locations component

* for conferencing apps skip select account page

* refactor InstallAppButtonChild

* installing conferencing apps shows locations dropdown in configure step

* send location data to the handler

* send location data to the handler
* add the newly installed to the locations dropdown (prefillLocation)

* fix: type errors

* fix: handle es-lint errors

* fix: app is added again on submit

* only add app if not already added

* fix: type erros

* filter out managed events for now

* fix: show installed count badge

* remove 2 toast message

* feat: added tests for conferencing apps

* fix: loading indicator

* Update apps/web/pages/apps/installation/[[...step]].tsx

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

* Update apps/web/pages/apps/installation/[[...step]].tsx

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

* move `getUserAdminTeams` to `UserRepository`

* fix: zoom and jelly not redirecting to the new app install flow

* fix: typo

* add `installableOnTeams` prop

* split `configureStepCard` into smaller components

* fix: step count

* fix: show loading indicator until the new page is loaded

* fix: organizer_default_conferencing_app not visible in a team

* Introduce QueryClient to app card tests

* fix: typo

* add installableOnTeams prop

* fix: tests

* seated events shouldn't have multiple locations #15174

* fix: o365 callback

* fix: office365_video not redirecting to event-types step

* Revert "fix: o365 callback"

This reverts commit bba841035ea34f8c31201b64c77221b8d8c3e626.

* add TEAM_SELECT_STEP

* add apps to orgs and their sub-teams initial commit

* undo team select step

* small ui fix

* fix: wrong step numbers

* fix: dont allow app installation without cretendialId

* fix: don't show acme team as it cannot have any events

* refactor useAddAppMutation

* removed console.log

* added comment

* added comment

* move locationOptions from getServerSideProps a trpc query

* fix: failing tests

* Update conferencingApps.e2e.ts

* refactor useAddAppMutation

* refactor useAddAppMutation 2

* fix: test failing

* fix: unit test

* Revert "fix: unit test"

This reverts commit 6d74032211d094478c6d7cf9aedbce696dfb768d.

* fix: failing test

* Increase test timeout for conferencing app tests

* fix: write separate tests for each conferencing app to prevent hitting 6000 ms timeout

* improved tests naming

* fix: correct message and translation key #15657

* fix: write separate tests for each analytics app to prevent hitting 6000 ms timeout

* fix: analytics apps test

* attempt to fix failing tests

* fix typo

* refactor

* update: replace text-gray with text-stuble

- works with light mode too

* update: use userRepository.getUserAdminTeams

* Merge branch 'main' into feat/org-team-app-install-2

* fix: after merge conflict from app router migration

* remove consoles

---------

Co-authored-by: Omar López <zomars@me.com>
Co-authored-by: Joe Au-Yeung <65426560+joeauyeung@users.noreply.github.com>
Co-authored-by: Joe Au-Yeung <j.auyeung419@gmail.com>
Co-authored-by: Udit Takkar <53316345+Udit-takkar@users.noreply.github.com>
2024-09-17 04:40:56 +00:00
Benny Joo f86a5db843 chore: App Router Migration, add metadata to getting-started, extract into /modules and add method to UserRepository (#16449)
* getting-started: extract into /modules

* fix

* fix type-check

* add findByIdWithOptionalSelect to UserRepository

* fix import error

* fix type check

* add metadata

* fix
2024-09-17 02:42:19 +00:00
Steven Tey 4cbf9ec9ab Update dclid → dub_id (#16670) 2024-09-16 22:53:05 +00:00
Benny Joo aa3c91ebd6 chore: App router - add missing metadata for /[user] pages (#16516) 2024-09-16 10:42:00 -04:00
Rajiv Sahal 071c899ea6 fix: overlay calendar view for Booker atom (#16642)
* overlay calendar needs to be false when in month_view

* fixup
2024-09-16 14:39:18 +00:00
sean-brydon 32b2e83564 fix: fix org check on team slider (#16659) 2024-09-16 14:25:10 +00:00
Curious GeorgeandAnik Dhabal Babu 7ff6d6559a Update callback.ts to work with AU location (#16664)
as per https://accounts.zoho.com/oauth/serverinfo, the server location for au is .com.au instead of .au

Co-authored-by: Anik Dhabal Babu <81948346+anikdhabal@users.noreply.github.com>
2024-09-16 12:49:17 +00:00
2572a5cb93 fixes multiselect required check (#16653)
Co-authored-by: Ashutosh Sangwan <ashutoshsangwan@Ashutoshs-MacBook-Pro.local>
Co-authored-by: Anik Dhabal Babu <81948346+anikdhabal@users.noreply.github.com>
2024-09-16 10:31:33 +00:00
Syed Ali Shahbaz 45e0f87e45 fix: add logger to util to debug v1 API slot (#16657)
* Update util.ts

* fix init

* add logger to repository_user
2024-09-16 08:29:58 +00:00
NETRAKAMAL BARUA 6e875fccbe fix: verifyCodeDialog ui (#16655) 2024-09-16 03:32:31 +00:00
Benny Joo 689e17bcf6 fix (#16632) 2024-09-15 20:23:37 -03:00
Keith Williams 584f9c6e93 chore: v4.5.0 (#16650)
release.yml / release (push) Canceled after 0s
2024-09-15 22:30:20 +09:00
Benny Joo 70348c6f64 fix: Add new api-key CTA button is missing in settings/developer/api-keys (#16649)
* Add new api-key button is missing

* fix type check
2024-09-15 22:09:03 +09:00
747591fded refactor: remove networkidle waiters (#16483)
* refactor: remove networkidle waiters

* Update out-of-office.e2e.ts

* Update auth-index.e2e.ts

* WIP

* Update booking-limits.e2e.ts

* fix-conflicts

* fix failed e2e tests

---------

Co-authored-by: Anik Dhabal Babu <81948346+anikdhabal@users.noreply.github.com>
Co-authored-by: unknown <adhabal2002@gmail.com>
2024-09-15 12:25:48 +00:00
Anik Dhabal Babu 9bfd933699 fix: managed eventype is not deleted to the assigned user when team is deleted (#16621) 2024-09-13 23:40:25 +01:00
Rajiv SahalandAnik Dhabal Babu a775e42e85 fix: prevent creating multiple platform orgs (#16629)
* set error messages to know whats wrong

* trying to find if org with same owner already exists

* ensure a user cannot create more than one platform team

---------

Co-authored-by: Anik Dhabal Babu <81948346+anikdhabal@users.noreply.github.com>
2024-09-13 23:37:48 +01:00
Peer Richelsen e3e2bc804a chore: added IS_EUROPE for signup (#16639) 2024-09-13 22:17:24 +00:00
sean-brydon b84099aec0 fix: use correct redirect url for google oauth when using overlay calendar (#16623) 2024-09-13 18:14:33 +00:00
Morgan 073d34f893 chore: rewrite imports of prisma enums to @calcom/prisma/enums (#16633) 2024-09-13 17:45:59 +00:00
Rajiv SahalandPeer Richelsen d72900d164 hide platform tab from navigation when team not setup (#16630)
Co-authored-by: Peer Richelsen <peeroke@gmail.com>
2024-09-13 17:17:44 +00:00
Syed Ali ShahbazandKeith Williams e3b478f5b1 fix: get slot logic for v1 API (#16620)
* fix faulty slug match

* Allow team event slot

* pass it to getSchedule

---------

Co-authored-by: Keith Williams <keithwillcode@gmail.com>
2024-09-13 16:34:03 +00:00
a5191d1e5a chore: App-router-migration(/auth/verify) add missing metadata / page & extract components into /module (#16444)
* create StripeRepository and simplify code

* verify-email-change: extract getServerSideProps

* add verify-email-change to app router

* auth/verify: Add metadata in app router

* auth/verify: extract client component into /modules

* fix type checks for stripe

* fix stripe session handler

* improve getServerSideProps for verify-email-change

* add title to verify-email-change page metadata

* add title to verify page metadata

* refactor

* add safety

* fix

* remove references to pages for verify-email

---------

Co-authored-by: Joe Au-Yeung <65426560+joeauyeung@users.noreply.github.com>
Co-authored-by: Keith Williams <keithwillcode@gmail.com>
2024-09-13 16:13:33 +00:00
Benny Joo ea21cd5826 fix: make admin role unnecessary for future-opt-in API (#16628) 2024-09-13 16:01:30 +00:00
sean-brydon e78c8738fb feat: create loading state for copy referral link from dub.co (#16626)
* create loading state for copy referal

* Update packages/features/shell/Shell.tsx
2024-09-14 00:03:05 +09:00
Calcom BotandReplexica 47314bae83 feat: update translations (#16616)
Co-authored-by: Replexica <support@replexica.com>
2024-09-13 14:37:39 +00:00
fd8afbc418 chore: Add Prisma extension to block deleteMany/updateMany with undefined 'in' (#15721)
* chore: Add Prisma extension to block updateMany with undefined 'in'

* Fix type

* types

* Added check for deleteMany as well

* Improved in check

* type

* Updated check to only check undefined and not isArray

* Renamed the guard

* another rename

* Changed undefined check to use typeof

* Types

* Added check

* Update packages/prisma/extensions/disallow-undefined-in-delete-update-many.ts

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

* Added unit tests

* Added a good case

* Rename

* Rename fix

* Types

* Temporarily disabling the extension for testing

* Added back the extension

* Trying to also log to see if there are swallowed errors

* Update

* removed unused params

* removed console.log

---------

Co-authored-by: Hariom Balhara <hariombalhara@gmail.com>
Co-authored-by: Anik Dhabal Babu <81948346+anikdhabal@users.noreply.github.com>
2024-09-13 22:52:06 +09:00
6e7012757f feat: replace team list view with org list view UI and fix team view user availability (#15344)
* feat: replace team list view with org list view UI and fix team view user availability

* update

* update2

* some changes

* Remove old team availability modal - fix flex direction

* fix

* fix type error

* update

* update

* fix type error

* update

* upfate edit sheet

* final update

* fix flaky e2e

* fix e2e

* typo

* profile update flow

* fix type error and refactor

* small update

* NIT

* update

* chore: fix types

* update

---------

Co-authored-by: sean-brydon <sean@cal.com>
Co-authored-by: Amit Sharma <74371312+Amit91848@users.noreply.github.com>
Co-authored-by: Udit Takkar <53316345+Udit-takkar@users.noreply.github.com>
2024-09-13 19:06:40 +05:30
sean-brydon 933eb0d057 remove teams layout (#16624) 2024-09-13 12:39:42 +00:00
Omar López fcb79888f3 fix: async clipboard support in Safari (#16619) 2024-09-13 09:27:28 +01:00
111e2f30c6 feat: overlay calendar for Booker atom (#16551)
* add prop to see if overlay calendar is enabled

* fix merge conflicts

* overlay calendar enabled prop

* cleanup

* hide toggle group if platform

* remove isPlatform conditional for overlay calendar

* dont display overlay calendar continue modal for platform

* fix images not appearing for platform

* update booker store

* update booker

* update booker

* shifting variables from booker store to useOverlayCalendar store

* update booker platform wrapper

* update booking page view

* revert changes to overlay calendar store

* update typings

* update toggle set value

* update handler to toggle connected calendar

* fixup

* update booker layout

* fixup! Merge branch 'main' into overlay-calendar-for-booker-atom

---------

Co-authored-by: Morgan <33722304+ThyMinimalDev@users.noreply.github.com>
Co-authored-by: Morgan Vernay <morgan@cal.com>
2024-09-13 08:13:20 +00:00
Steven Teyandzomars f2b3e620b4 fix: Show toast after copy referral link + change icon to "gift" (#16618)
Co-authored-by: zomars <zomars@me.com>
2024-09-12 22:06:21 +00:00
Benny Joo d9133cb395 chore: App router migration - Create/Use EventRepository and Extract /team/**/* and /teams/* into /modules from /pages (#16453) 2024-09-12 18:58:08 -03:00
433 changed files with 13726 additions and 11327 deletions
+6
View File
@@ -343,12 +343,14 @@ APP_ROUTER_APPS_SLUG_SETUP_ENABLED=0
APP_ROUTER_APPS_CATEGORIES_ENABLED=0
# whether we redirect to the future/apps/categories/[category] from /apps/categories/[category] or not
APP_ROUTER_APPS_CATEGORIES_CATEGORY_ENABLED=0
APP_ROUTER_BOOKING_ENABLED=0
APP_ROUTER_BOOKINGS_STATUS_ENABLED=0
APP_ROUTER_WORKFLOWS_ENABLED=0
APP_ROUTER_SETTINGS_TEAMS_ENABLED=0
APP_ROUTER_GETTING_STARTED_STEP_ENABLED=0
APP_ROUTER_APPS_ENABLED=0
APP_ROUTER_VIDEO_ENABLED=0
APP_ROUTER_TEAM_ENABLED=0
APP_ROUTER_TEAMS_ENABLED=0
APP_ROUTER_AVAILABILITY_ENABLED=0
APP_ROUTER_AUTH_FORGOT_PASSWORD_ENABLED=0
@@ -392,3 +394,7 @@ VAPID_PRIVATE_KEY=
# Custom privacy policy / terms URLs (for self-hosters: change to your privacy policy / terms URLs)
NEXT_PUBLIC_WEBSITE_PRIVACY_POLICY_URL=
NEXT_PUBLIC_WEBSITE_TERMS_URL=
# NEXT_PUBLIC_LOGGER_LEVEL=3 sets to log info, warn, error and fatal logs.
# [0: silly & upwards, 1: trace & upwards, 2: debug & upwards, 3: info & upwards, 4: warn & upwards, 5: error & fatal, 6: fatal]
NEXT_PUBLIC_LOGGER_LEVEL=
File diff suppressed because one or more lines are too long
+20 -2
View File
@@ -173,11 +173,29 @@ 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_LOGGER_LEVEL={level}` to your .env file to control the logging verbosity for all tRPC queries and mutations.\
Where {level} can be one of the following:
`0` for silly \
`1` for trace \
`2` for debug \
`3` for info \
`4` for warn \
`5` for error \
`6` for fatal
When you set `NEXT_PUBLIC_LOGGER_LEVEL={level}` in your .env file, it enables logging at that level and higher. Here's how it works:
The logger will include all logs that are at the specified level or higher. For example: \
- If you set `NEXT_PUBLIC_LOGGER_LEVEL=2`, it will log from level 2 (debug) upwards, meaning levels 2 (debug), 3 (info), 4 (warn), 5 (error), and (fatal) will be logged. \
- If you set `NEXT_PUBLIC_LOGGER_LEVEL=3`, it will log from level 3 (info) upwards, meaning levels 3 (info), 4 (warn), 5 (error), and 6 (fatal) will be logged, but level 2 (debug) and level 1 (trace) will be ignored. \
```sh
echo 'NEXT_PUBLIC_DEBUG=1' >> .env
echo 'NEXT_PUBLIC_LOGGER_LEVEL=3' >> .env
```
for Logger level to be set at info, for example.
#### Gitpod Setup
+25 -1
View File
@@ -1,6 +1,13 @@
import { z } from "zod";
import { _AttendeeModel, _BookingModel as Booking, _PaymentModel, _UserModel } from "@calcom/prisma/zod";
import {
_AttendeeModel,
_BookingModel as Booking,
_EventTypeModel,
_PaymentModel,
_TeamModel,
_UserModel,
} from "@calcom/prisma/zod";
import { extendedBookingCreateBody, iso8601 } from "@calcom/prisma/zod-utils";
import { schemaQueryUserId } from "./shared/queryUserId";
@@ -46,7 +53,23 @@ export const schemaBookingEditBodyParams = schemaBookingBaseBodyParams
.merge(schemaBookingEditParams)
.omit({ uid: true });
const teamSchema = _TeamModel.pick({
name: true,
slug: true,
});
export const schemaBookingReadPublic = Booking.extend({
eventType: _EventTypeModel
.pick({
title: true,
slug: true,
})
.merge(
z.object({
team: teamSchema.nullish(),
})
)
.nullish(),
attendees: z
.array(
_AttendeeModel.pick({
@@ -87,6 +110,7 @@ export const schemaBookingReadPublic = Booking.extend({
timeZone: true,
attendees: true,
user: true,
eventType: true,
payment: true,
metadata: true,
status: true,
@@ -0,0 +1,12 @@
import { z } from "zod";
const expandEnum = z.enum(["team"]);
export const schemaQuerySingleOrMultipleExpand = z
.union([
expandEnum, // Allow a single value from the enum
z.array(expandEnum).refine((arr) => new Set(arr).size === arr.length, {
message: "Array values must be unique",
}), // Allow an array of enum values, with uniqueness constraint
])
.optional();
+14 -1
View File
@@ -4,6 +4,7 @@ import { defaultResponder } from "@calcom/lib/server";
import prisma from "@calcom/prisma";
import { schemaBookingReadPublic } from "~/lib/validations/booking";
import { schemaQuerySingleOrMultipleExpand } from "~/lib/validations/shared/queryExpandRelations";
import { schemaQueryIdParseInt } from "~/lib/validations/shared/queryIdTransformParseInt";
/**
@@ -89,9 +90,21 @@ import { schemaQueryIdParseInt } from "~/lib/validations/shared/queryIdTransform
export async function getHandler(req: NextApiRequest) {
const { query } = req;
const { id } = schemaQueryIdParseInt.parse(query);
const queryFilterForExpand = schemaQuerySingleOrMultipleExpand.parse(req.query.expand);
const expand = Array.isArray(queryFilterForExpand)
? queryFilterForExpand
: queryFilterForExpand
? [queryFilterForExpand]
: [];
const booking = await prisma.booking.findUnique({
where: { id },
include: { attendees: true, user: true, payment: true },
include: {
attendees: true,
user: true,
payment: true,
eventType: expand.includes("team") ? { include: { team: true } } : false,
},
});
return { booking: schemaBookingReadPublic.parse(booking) };
}
+9
View File
@@ -12,6 +12,7 @@ import {
} from "~/lib/utils/retrieveScopedAccessibleUsers";
import { schemaBookingGetParams, schemaBookingReadPublic } from "~/lib/validations/booking";
import { schemaQuerySingleOrMultipleAttendeeEmails } from "~/lib/validations/shared/queryAttendeeEmail";
import { schemaQuerySingleOrMultipleExpand } from "~/lib/validations/shared/queryExpandRelations";
import { schemaQuerySingleOrMultipleUserIds } from "~/lib/validations/shared/queryUserId";
/**
@@ -216,10 +217,18 @@ export async function handler(req: NextApiRequest) {
args.take = take;
args.skip = skip;
}
const queryFilterForExpand = schemaQuerySingleOrMultipleExpand.parse(req.query.expand);
const expand = Array.isArray(queryFilterForExpand)
? queryFilterForExpand
: queryFilterForExpand
? [queryFilterForExpand]
: [];
args.include = {
attendees: true,
user: true,
payment: true,
eventType: expand.includes("team") ? { include: { team: true } } : false,
};
const queryFilterForAttendeeEmails = schemaQuerySingleOrMultipleAttendeeEmails.parse(req.query);
+3 -2
View File
@@ -27,12 +27,13 @@ async function handler(req: NextApiRequest, res: NextApiResponse) {
isColdStart = false;
}
const { usernameList, ...rest } = req.query;
const { usernameList, isTeamEvent, ...rest } = req.query;
const parsedIsTeamEvent = String(isTeamEvent).toLowerCase() === "true";
let slugs = usernameList;
if (!Array.isArray(usernameList)) {
slugs = usernameList ? [usernameList] : undefined;
}
const input = getScheduleSchema.parse({ usernameList: slugs, ...rest });
const input = getScheduleSchema.parse({ usernameList: slugs, isTeamEvent: parsedIsTeamEvent, ...rest });
const timeZoneSupported = input.timeZone ? isSupportedTimeZone(input.timeZone) : false;
const availableSlots = await getAvailableSlots({ ctx: await createContext({ req, res }), input });
const slotsInProvidedTimeZone = timeZoneSupported
@@ -164,7 +164,6 @@ describe("GET /api/bookings", async () => {
const responseData = await handler(req);
responseData.bookings.forEach((booking) => {
console.log(booking);
expect(new Date(booking.startTime).getTime()).toBeGreaterThanOrEqual(new Date().getTime());
});
});
@@ -188,4 +187,27 @@ describe("GET /api/bookings", async () => {
});
});
});
describe("Expand feature to add relational data in return payload", () => {
it("Returns only team data when expand=team is set", async () => {
const adminUser = await prisma.user.findFirstOrThrow({ where: { email: "owner1-acme@example.com" } });
const { req } = createMocks<CustomNextApiRequest, CustomNextApiResponse>({
method: "GET",
query: {
expand: "team",
},
pagination: DefaultPagination,
});
req.userId = adminUser.id;
req.isOrganizationOwnerOrAdmin = true;
const responseData = await handler(req);
console.log("bookings=>", responseData.bookings);
responseData.bookings.forEach((booking) => {
if (booking.id === 31) expect(booking.eventType?.team?.slug).toBe("team1");
if (booking.id === 19) expect(booking.eventType?.team).toBe(null);
});
});
});
});
+1 -1
View File
@@ -28,7 +28,7 @@
"dependencies": {
"@calcom/platform-constants": "*",
"@calcom/platform-enums": "*",
"@calcom/platform-libraries": "npm:@calcom/platform-libraries@0.0.34",
"@calcom/platform-libraries": "npm:@calcom/platform-libraries@0.0.36",
"@calcom/platform-libraries-0.0.2": "npm:@calcom/platform-libraries@0.0.2",
"@calcom/platform-types": "*",
"@calcom/platform-utils": "*",
+4 -2
View File
@@ -1,4 +1,5 @@
import appConfig from "@/config/app";
import { CustomThrottlerGuard } from "@/lib/throttler-guard";
import { AppLoggerMiddleware } from "@/middleware/app.logger.middleware";
import { RewriterMiddleware } from "@/middleware/app.rewrites.middleware";
import { JsonBodyMiddleware } from "@/middleware/body/json.body.middleware";
@@ -15,7 +16,7 @@ import { BullModule } from "@nestjs/bull";
import { MiddlewareConsumer, Module, NestModule, RequestMethod } from "@nestjs/common";
import { ConfigModule } from "@nestjs/config";
import { APP_GUARD, APP_INTERCEPTOR } from "@nestjs/core";
import { seconds, ThrottlerGuard, ThrottlerModule } from "@nestjs/throttler";
import { seconds, ThrottlerModule } from "@nestjs/throttler";
import { ThrottlerStorageRedisService } from "nestjs-throttler-storage-redis";
import { AppController } from "./app.controller";
@@ -32,6 +33,7 @@ import { AppController } from "./app.controller";
BullModule.forRoot({
redis: `${process.env.REDIS_URL}${process.env.NODE_ENV === "production" ? "?tls=true" : ""}`,
}),
// Rate limiting here is handled by the CustomThrottlerGuard
ThrottlerModule.forRootAsync({
imports: [RedisModule],
inject: [RedisService],
@@ -59,7 +61,7 @@ import { AppController } from "./app.controller";
},
{
provide: APP_GUARD,
useClass: ThrottlerGuard,
useClass: CustomThrottlerGuard,
},
],
})
@@ -36,7 +36,7 @@ import {
InternalServerErrorException,
ParseIntPipe,
} from "@nestjs/common";
import { ApiTags as DocsTags } from "@nestjs/swagger";
import { ApiExcludeController as DocsExcludeController } from "@nestjs/swagger";
import { EVENT_TYPE_READ, EVENT_TYPE_WRITE, SUCCESS_STATUS } from "@calcom/platform-constants";
import { getPublicEvent, getEventTypesByViewer } from "@calcom/platform-libraries-0.0.2";
@@ -47,7 +47,7 @@ import { PrismaClient } from "@calcom/prisma";
version: [VERSION_2024_04_15, VERSION_2024_06_11],
})
@UseGuards(PermissionsGuard)
@DocsTags("Event types")
@DocsExcludeController(true)
export class EventTypesController_2024_04_15 {
constructor(
private readonly eventTypesService: EventTypesService_2024_04_15,
@@ -15,6 +15,7 @@ import {
updateEventType,
EventTypesPublic,
getEventTypesPublic,
systemBeforeFieldEmail,
} from "@calcom/platform-libraries";
import { EventType } from "@calcom/prisma/client";
@@ -127,8 +128,17 @@ export class EventTypesService_2024_04_15 {
async updateEventType(eventTypeId: number, body: UpdateEventTypeInput_2024_04_15, user: UserWithProfile) {
this.checkCanUpdateEventType(user.id, eventTypeId);
const eventTypeUser = await this.getUserToUpdateEvent(user);
const bookingFields = [...(body.bookingFields || [])];
if (
!bookingFields.find((field) => field.type === "email") &&
!bookingFields.find((field) => field.type === "phone")
) {
bookingFields.push(systemBeforeFieldEmail);
}
await updateEventType({
input: { id: eventTypeId, ...body },
input: { id: eventTypeId, ...body, bookingFields },
ctx: {
user: eventTypeUser,
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
@@ -250,7 +250,6 @@ describe("Event types Endpoints", () => {
expect(createdEventType.description).toEqual(body.description);
expect(createdEventType.lengthInMinutes).toEqual(body.lengthInMinutes);
expect(createdEventType.locations).toEqual(body.locations);
expect(createdEventType.bookingFields).toEqual(body.bookingFields);
expect(createdEventType.ownerId).toEqual(user.id);
expect(createdEventType.scheduleId).toEqual(firstSchedule.id);
expect(createdEventType.bookingLimitsCount).toEqual(body.bookingLimitsCount);
@@ -259,6 +258,16 @@ describe("Event types Endpoints", () => {
expect(createdEventType.offsetStart).toEqual(body.offsetStart);
expect(createdEventType.bookingWindow).toEqual(body.bookingWindow);
expect(createdEventType.recurrence).toEqual(body.recurrence);
const responseBookingFields = body.bookingFields || [];
const expectedBookingFields = [
{ isDefault: true, required: true, slug: "name", type: "name" },
{ isDefault: true, required: true, slug: "email", type: "email" },
{ isDefault: true, required: false, slug: "rescheduleReason", type: "textarea" },
...responseBookingFields.map((field) => ({ isDefault: false, ...field })),
];
expect(createdEventType.bookingFields).toEqual(expectedBookingFields);
eventType = responseBody.data;
});
});
@@ -476,6 +485,16 @@ describe("Event types Endpoints", () => {
let legacyEventTypeId1: number;
let legacyEventTypeId2: number;
const expectedReturnSystemFields = [
{ isDefault: true, required: true, slug: "name", type: "name" },
{ isDefault: true, required: true, slug: "email", type: "email" },
{ isDefault: true, type: "radioInput", slug: "location", required: false },
{ isDefault: true, required: true, slug: "title", type: "text" },
{ isDefault: true, required: false, slug: "notes", type: "textarea" },
{ isDefault: true, required: false, slug: "guests", type: "multiemail" },
{ isDefault: true, required: false, slug: "rescheduleReason", type: "textarea" },
];
beforeAll(async () => {
const moduleRef = await withApiAuth(
userEmail,
@@ -545,7 +564,7 @@ describe("Event types Endpoints", () => {
.expect(400);
});
it("should return empty bookingFields if system fields are the only one in database", async () => {
it("should return system bookingFields stored in database", async () => {
const legacyEventTypeInput = {
title: "legacy event type",
description: "legacy event type description",
@@ -638,11 +657,11 @@ describe("Event types Endpoints", () => {
.then(async (response) => {
const responseBody: ApiSuccessResponse<EventTypeOutput_2024_06_14> = response.body;
const fetchedEventType = responseBody.data;
expect(fetchedEventType.bookingFields).toEqual([]);
expect(fetchedEventType.bookingFields).toEqual(expectedReturnSystemFields);
});
});
it("should return user created bookingFields among system fields in the database", async () => {
it("should return user created bookingFields with system fields", async () => {
const userDefinedBookingField = {
name: "team",
type: "textarea",
@@ -755,7 +774,9 @@ describe("Event types Endpoints", () => {
const fetchedEventType = responseBody.data;
expect(fetchedEventType.bookingFields).toEqual([
...expectedReturnSystemFields,
{
isDefault: false,
type: userDefinedBookingField.type,
slug: userDefinedBookingField.name,
label: userDefinedBookingField.label,
@@ -24,7 +24,7 @@ import {
Delete,
Query,
} from "@nestjs/common";
import { ApiTags as DocsTags } from "@nestjs/swagger";
import { ApiHeader, ApiTags as DocsTags } from "@nestjs/swagger";
import { EVENT_TYPE_READ, EVENT_TYPE_WRITE, SUCCESS_STATUS } from "@calcom/platform-constants";
import {
@@ -39,12 +39,23 @@ import {
})
@UseGuards(PermissionsGuard)
@DocsTags("Event types")
@ApiHeader({
name: "cal-api-version",
description: `Must be set to \`2024-06-14\``,
required: true,
})
export class EventTypesController_2024_06_14 {
constructor(private readonly eventTypesService: EventTypesService_2024_06_14) {}
@Post("/")
@Permissions([EVENT_TYPE_WRITE])
@UseGuards(ApiAuthGuard)
@ApiHeader({
name: "Authorization",
description:
"value must be `Bearer <token>` where `<token>` either managed user access token or api key prefixed with cal_",
required: true,
})
async createEventType(
@Body() body: CreateEventTypeInput_2024_06_14,
@GetUser() user: UserWithProfile
@@ -60,6 +71,12 @@ export class EventTypesController_2024_06_14 {
@Get("/:eventTypeId")
@Permissions([EVENT_TYPE_READ])
@UseGuards(ApiAuthGuard)
@ApiHeader({
name: "Authorization",
description:
"value must be `Bearer <token>` where `<token>` either managed user access token or api key prefixed with cal_",
required: true,
})
async getEventTypeById(
@Param("eventTypeId") eventTypeId: string,
@GetUser() user: UserWithProfile
@@ -91,6 +108,12 @@ export class EventTypesController_2024_06_14 {
@Patch("/:eventTypeId")
@Permissions([EVENT_TYPE_WRITE])
@UseGuards(ApiAuthGuard)
@ApiHeader({
name: "Authorization",
description:
"value must be `Bearer <token>` where `<token>` either managed user access token or api key prefixed with cal_",
required: true,
})
@HttpCode(HttpStatus.OK)
async updateEventType(
@Param("eventTypeId") eventTypeId: number,
@@ -108,6 +131,12 @@ export class EventTypesController_2024_06_14 {
@Delete("/:eventTypeId")
@Permissions([EVENT_TYPE_WRITE])
@UseGuards(ApiAuthGuard)
@ApiHeader({
name: "Authorization",
description:
"value must be `Bearer <token>` where `<token>` either managed user access token or api key prefixed with cal_",
required: true,
})
async deleteEventType(
@Param("eventTypeId") eventTypeId: number,
@GetUser("id") userId: number
@@ -6,8 +6,8 @@ import { Injectable } from "@nestjs/common";
import {
getEventTypeById,
transformApiEventTypeBookingFields,
transformApiEventTypeLocations,
transformBookingFieldsApiToInternal,
transformLocationsApiToInternal,
} from "@calcom/platform-libraries";
import { CreateEventTypeInput_2024_06_14 } from "@calcom/platform-types";
import type { PrismaClient } from "@calcom/prisma";
@@ -30,8 +30,8 @@ type InputEventTransformed = Omit<
> & {
length: number;
slug: string;
locations?: ReturnType<typeof transformApiEventTypeLocations>;
bookingFields?: ReturnType<typeof transformApiEventTypeBookingFields>;
locations?: ReturnType<typeof transformLocationsApiToInternal>;
bookingFields?: ReturnType<typeof transformBookingFieldsApiToInternal>;
};
@Injectable()
@@ -1,12 +1,16 @@
import { Injectable } from "@nestjs/common";
import {
transformApiEventTypeBookingFields,
transformApiEventTypeLocations,
transformApiEventTypeIntervalLimits,
transformApiEventTypeFutureBookingLimits,
transformApiEventTypeRecurrence,
transformBookingFieldsApiToInternal,
transformLocationsApiToInternal,
transformIntervalLimitsApiToInternal,
transformFutureBookingLimitsApiToInternal,
transformRecurrenceApiToInternal,
systemBeforeFieldName,
systemBeforeFieldEmail,
systemAfterFieldRescheduleReason,
} from "@calcom/platform-libraries";
import { systemBeforeFieldLocation } from "@calcom/platform-libraries";
import { CreateEventTypeInput_2024_06_14, UpdateEventTypeInput_2024_06_14 } from "@calcom/platform-types";
@Injectable()
@@ -30,11 +34,12 @@ export class InputEventTypesService_2024_06_14 {
...rest
} = inputEventType;
const hasMultipleLocations = (locations || defaultLocations).length > 1;
const eventType = {
...rest,
length: lengthInMinutes,
locations: this.transformInputLocations(locations || defaultLocations),
bookingFields: this.transformInputBookingFields(bookingFields),
bookingFields: this.transformInputBookingFields(bookingFields, hasMultipleLocations),
bookingLimits: bookingLimitsCount ? this.transformInputIntervalLimits(bookingLimitsCount) : undefined,
durationLimits: bookingLimitsDuration
? this.transformInputIntervalLimits(bookingLimitsDuration)
@@ -59,11 +64,15 @@ export class InputEventTypesService_2024_06_14 {
...rest
} = inputEventType;
const hasMultipleLocations = !!(locations && locations?.length > 1);
const eventType = {
...rest,
length: lengthInMinutes,
locations: locations ? this.transformInputLocations(locations) : undefined,
bookingFields: bookingFields ? this.transformInputBookingFields(bookingFields) : undefined,
bookingFields: bookingFields
? this.transformInputBookingFields(bookingFields, hasMultipleLocations)
: undefined,
schedule: scheduleId,
bookingLimits: bookingLimitsCount ? this.transformInputIntervalLimits(bookingLimitsCount) : undefined,
durationLimits: bookingLimitsDuration
@@ -77,23 +86,35 @@ export class InputEventTypesService_2024_06_14 {
}
transformInputLocations(inputLocations: CreateEventTypeInput_2024_06_14["locations"]) {
return transformApiEventTypeLocations(inputLocations);
return transformLocationsApiToInternal(inputLocations);
}
transformInputBookingFields(inputBookingFields: CreateEventTypeInput_2024_06_14["bookingFields"]) {
return transformApiEventTypeBookingFields(inputBookingFields);
transformInputBookingFields(
inputBookingFields: CreateEventTypeInput_2024_06_14["bookingFields"],
hasMultipleLocations: boolean
) {
const defaultFieldsBefore = [systemBeforeFieldName, systemBeforeFieldEmail];
// note(Lauris): if event type has multiple locations then a radio button booking field has to be displayed to allow booker to pick location
if (hasMultipleLocations) {
defaultFieldsBefore.push(systemBeforeFieldLocation);
}
const customFields = transformBookingFieldsApiToInternal(inputBookingFields);
const defaultFieldsAfter = [systemAfterFieldRescheduleReason];
return [...defaultFieldsBefore, ...customFields, ...defaultFieldsAfter];
}
transformInputIntervalLimits(inputBookingFields: CreateEventTypeInput_2024_06_14["bookingLimitsCount"]) {
return transformApiEventTypeIntervalLimits(inputBookingFields);
return transformIntervalLimitsApiToInternal(inputBookingFields);
}
transformInputBookingWindow(inputBookingWindow: CreateEventTypeInput_2024_06_14["bookingWindow"]) {
const res = transformApiEventTypeFutureBookingLimits(inputBookingWindow);
const res = transformFutureBookingLimitsApiToInternal(inputBookingWindow);
return !!res ? res : {};
}
transformInputRecurrignEvent(recurrence: CreateEventTypeInput_2024_06_14["recurrence"]) {
return transformApiEventTypeRecurrence(recurrence);
return transformRecurrenceApiToInternal(recurrence);
}
}
@@ -4,17 +4,17 @@ import type { EventType, User, Schedule } from "@prisma/client";
import {
EventTypeMetaDataSchema,
userMetadata,
getResponseEventTypeLocations,
getResponseEventTypeBookingFields,
transformLocationsInternalToApi,
transformBookingFieldsInternalToApi,
parseRecurringEvent,
TransformedLocationsSchema,
BookingFieldsSchema,
SystemField,
UserField,
CustomField,
parseBookingLimit,
getResponseEventTypeIntervalLimits,
getResponseEventTypeFutureBookingLimits,
getResponseEventTypeRecurrence,
transformIntervalLimitsInternalToApi,
transformFutureBookingLimitsInternalToApi,
transformRecurrenceInternalToApi,
} from "@calcom/platform-libraries";
import { TransformFutureBookingsLimitSchema_2024_06_14 } from "@calcom/platform-types";
@@ -144,19 +144,20 @@ export class OutputEventTypesService_2024_06_14 {
transformLocations(locations: any) {
if (!locations) return [];
return getResponseEventTypeLocations(TransformedLocationsSchema.parse(locations));
return transformLocationsInternalToApi(TransformedLocationsSchema.parse(locations));
}
transformBookingFields(inputBookingFields: (SystemField | UserField)[] | null) {
if (!inputBookingFields) return [];
const userFields = inputBookingFields.filter((field) => field.editable === "user") as UserField[];
return getResponseEventTypeBookingFields(userFields);
transformBookingFields(bookingFields: (SystemField | CustomField)[] | null) {
if (!bookingFields) return [];
return transformBookingFieldsInternalToApi(bookingFields);
}
transformRecurringEvent(recurringEvent: any) {
if (!recurringEvent) return null;
const recurringEventParsed = parseRecurringEvent(recurringEvent);
return getResponseEventTypeRecurrence(recurringEventParsed);
if (!recurringEventParsed) return null;
return transformRecurrenceInternalToApi(recurringEventParsed);
}
transformMetadata(metadata: any) {
@@ -182,10 +183,10 @@ export class OutputEventTypesService_2024_06_14 {
transformIntervalLimits(bookingLimits: any) {
const bookingLimitsParsed = parseBookingLimit(bookingLimits);
return getResponseEventTypeIntervalLimits(bookingLimitsParsed);
return transformIntervalLimitsInternalToApi(bookingLimitsParsed);
}
transformBookingWindow(bookingLimits: TransformFutureBookingsLimitSchema_2024_06_14) {
return getResponseEventTypeFutureBookingLimits(bookingLimits);
return transformFutureBookingLimitsInternalToApi(bookingLimits);
}
}
@@ -23,7 +23,7 @@ import {
Patch,
UseGuards,
} from "@nestjs/common";
import { ApiResponse, ApiTags as DocsTags } from "@nestjs/swagger";
import { ApiResponse, ApiExcludeController as DocsExcludeController } from "@nestjs/swagger";
import { Throttle } from "@nestjs/throttler";
import { SCHEDULE_READ, SCHEDULE_WRITE, SUCCESS_STATUS } from "@calcom/platform-constants";
@@ -36,7 +36,7 @@ import { CreateScheduleInput_2024_04_15 } from "../inputs/create-schedule.input"
version: VERSION_2024_04_15_VALUE,
})
@UseGuards(ApiAuthGuard, PermissionsGuard)
@DocsTags("Schedules")
@DocsExcludeController(true)
export class SchedulesController_2024_04_15 {
constructor(private readonly schedulesService: SchedulesService_2024_04_15) {}
@@ -17,7 +17,7 @@ import {
Patch,
UseGuards,
} from "@nestjs/common";
import { ApiResponse, ApiTags as DocsTags } from "@nestjs/swagger";
import { ApiHeader, ApiOperation, ApiResponse, ApiTags as DocsTags } from "@nestjs/swagger";
import { Throttle } from "@nestjs/throttler";
import { SCHEDULE_READ, SCHEDULE_WRITE, SUCCESS_STATUS } from "@calcom/platform-constants";
@@ -38,11 +38,38 @@ import {
})
@UseGuards(ApiAuthGuard, PermissionsGuard)
@DocsTags("Schedules")
@ApiHeader({
name: "cal-api-version",
description: `Must be set to \`2024-06-11\``,
required: true,
})
@ApiHeader({
name: "Authorization",
description:
"value must be `Bearer <token>` where `<token>` either managed user access token or api key prefixed with cal_",
required: true,
})
export class SchedulesController_2024_06_11 {
constructor(private readonly schedulesService: SchedulesService_2024_06_11) {}
@Post("/")
@Permissions([SCHEDULE_WRITE])
@ApiOperation({
summary: "Create a schedule",
description: `
The point of creating schedules is for event types to be available at specific times.
First goal of schedules is to have a default schedule. If you are platform customer and created managed users, then it is important to note that each managed user should have a default schedule.
1. If you passed \`timeZone\` when creating managed user, then the default schedule from Monday to Friday from 9AM to 5PM will be created with that timezone. Managed user can then change the default schedule via \`AvailabilitySettings\` atom.
2. If you did not, then we assume you want that user has specific schedule right away. You should create default schedule by specifying
\`"isDefault": true\` in the request body. Until the user has a default schedule that user can't be booked or manage his / her schedule via the AvailabilitySettings atom.
Second goal is to create other schedules that event types can point to, so that when that event is booked availability is not checked against the default schedule but against that specific schedule.
After creating a non default schedule you can update event type to point to that schedule via the PATCH \`event-types/{eventTypeId}\` endpoint.
When specifying start time and end time for each day use 24 hour format e.g. 08:00, 15:00 etc.
`,
})
async createSchedule(
@GetUser() user: UserWithProfile,
@Body() bodySchedule: CreateScheduleInput_2024_06_11
@@ -59,7 +86,7 @@ export class SchedulesController_2024_06_11 {
@Permissions([SCHEDULE_READ])
@ApiResponse({
status: 200,
description: "Returns the default schedule",
description: "Returns the default schedule of the authenticated user",
type: GetDefaultScheduleOutput_2024_06_11,
})
async getDefaultSchedule(@GetUser() user: UserWithProfile): Promise<GetScheduleOutput_2024_06_11> {
@@ -88,6 +115,9 @@ export class SchedulesController_2024_06_11 {
@Get("/")
@Permissions([SCHEDULE_READ])
@ApiOperation({
description: "Returns all schedules of the authenticated user",
})
async getSchedules(@GetUser() user: UserWithProfile): Promise<GetSchedulesOutput_2024_06_11> {
const schedules = await this.schedulesService.getUserSchedules(user.id);
+45
View File
@@ -0,0 +1,45 @@
import { isApiKey } from "@/lib/api-key";
import { Injectable, Logger } from "@nestjs/common";
import { ConfigService } from "@nestjs/config";
import { Reflector } from "@nestjs/core";
import { ThrottlerGuard, ThrottlerModuleOptions, ThrottlerStorage } from "@nestjs/throttler";
import { Request } from "express";
import { X_CAL_CLIENT_ID } from "@calcom/platform-constants";
@Injectable()
export class CustomThrottlerGuard extends ThrottlerGuard {
private logger = new Logger("CustomThrottlerGuard");
constructor(
options: ThrottlerModuleOptions,
storageService: ThrottlerStorage,
reflector: Reflector,
private readonly config: ConfigService
) {
super(options, storageService, reflector);
}
protected async getTracker(request: Request): Promise<string> {
const authorizationHeader = request.get("Authorization")?.replace("Bearer ", "");
if (authorizationHeader) {
return isApiKey(authorizationHeader, this.config.get<string>("api.apiKeyPrefix") ?? "cal_")
? `api_key_${authorizationHeader}`
: `access_token_${authorizationHeader}`;
}
const oauthClientId = request.get(X_CAL_CLIENT_ID);
if (oauthClientId) {
return oauthClientId;
}
if (request.ip) {
return request.ip;
}
this.logger.log(`no tracker found: ${request.url}`);
return "unknown";
}
}
@@ -79,7 +79,6 @@ export class OAuthClientUsersController {
`Creating user with data: ${JSON.stringify(body, null, 2)} for OAuth Client with ID ${oAuthClientId}`
);
const client = await this.oauthRepository.getOAuthClient(oAuthClientId);
console.log("asap createUser client", JSON.stringify(client, null, 2));
const isPlatformManaged = true;
const { user, tokens } = await this.oAuthClientUsersService.createOauthClientUser(
@@ -8,4 +8,4 @@ export class CreateOrganizationAttributeOptionInput {
@IsString()
@IsNotEmpty()
readonly slug!: string;
}
}
@@ -3,34 +3,53 @@ import { UpdateOrganizationAttributeInput } from "@/modules/organizations/inputs
import { OrganizationAttributesRepository } from "@/modules/organizations/repositories/attributes/organization-attribute.repository";
import { Injectable } from "@nestjs/common";
@Injectable()
export class OrganizationAttributesService {
constructor(private readonly organizationAttributesRepository: OrganizationAttributesRepository) {}
async createOrganizationAttribute(organizationId: number, data: CreateOrganizationAttributeInput) {
const attribute = await this.organizationAttributesRepository.createOrganizationAttribute(organizationId, data);
const attribute = await this.organizationAttributesRepository.createOrganizationAttribute(
organizationId,
data
);
return attribute;
}
async getOrganizationAttribute(organizationId: number, attributeId: string) {
const attribute = await this.organizationAttributesRepository.getOrganizationAttribute(organizationId, attributeId);
const attribute = await this.organizationAttributesRepository.getOrganizationAttribute(
organizationId,
attributeId
);
return attribute;
}
async getOrganizationAttributes(organizationId: number, skip?: number, take?: number) {
const attributes = await this.organizationAttributesRepository.getOrganizationAttributes(organizationId, skip, take);
const attributes = await this.organizationAttributesRepository.getOrganizationAttributes(
organizationId,
skip,
take
);
return attributes;
}
async updateOrganizationAttribute(organizationId: number, attributeId: string, data: UpdateOrganizationAttributeInput) {
const attribute = await this.organizationAttributesRepository.updateOrganizationAttribute(organizationId, attributeId, data);
return attribute;
}
async deleteOrganizationAttribute(organizationId: number, attributeId: string) {
const attribute = await this.organizationAttributesRepository.deleteOrganizationAttribute(organizationId, attributeId);
async updateOrganizationAttribute(
organizationId: number,
attributeId: string,
data: UpdateOrganizationAttributeInput
) {
const attribute = await this.organizationAttributesRepository.updateOrganizationAttribute(
organizationId,
attributeId,
data
);
return attribute;
}
async deleteOrganizationAttribute(organizationId: number, attributeId: string) {
const attribute = await this.organizationAttributesRepository.deleteOrganizationAttribute(
organizationId,
attributeId
);
return attribute;
}
}
@@ -29,7 +29,11 @@ export class CreateManagedUserInput {
@IsTimeZone()
@IsOptional()
@CapitalizeTimeZone()
@ApiProperty({ example: "America/New_York" })
@ApiProperty({
example: "America/New_York",
description: `Timezone is used to create user's default schedule from Monday to Friday from 9AM to 5PM. If it is not passed then user does not have
a default schedule and it must be created manually via the /schedules endpoint. Until the schedule is created, the user can't access availability atom to set his / her availability nor booked.`,
})
timeZone?: string;
@IsEnum(Locales)
File diff suppressed because it is too large Load Diff
+3
View File
@@ -22,4 +22,7 @@ const env: Partial<Omit<Environment, "NODE_ENV">> = {
process.env = {
...env,
...process.env,
NEXT_PUBLIC_VAPID_PUBLIC_KEY:
"BIds0AQJ96xGBjTSMHTOqLBLutQE7Lu32KKdgSdy7A2cS4mKI2cgb3iGkhDJa5Siy-stezyuPm8qpbhmNxdNHMw",
VAPID_PRIVATE_KEY: "6cJtkASCar5sZWguIAW7OjvyixpBw9p8zL8WDDwk9Jk",
};
+9
View File
@@ -1,5 +1,14 @@
# @calcom/web
## 4.5.2
### Patch Changes
- Updated dependencies
- @calcom/embed-core@1.5.1
- @calcom/embed-react@1.5.1
- @calcom/embed-snippet@1.3.1
## 4.0.8
### Patch Changes
+2
View File
@@ -28,7 +28,9 @@ const ROUTES: [URLPattern, boolean][] = [
["/getting-started/:step", process.env.APP_ROUTER_GETTING_STARTED_STEP_ENABLED === "1"] as const,
["/apps", process.env.APP_ROUTER_APPS_ENABLED === "1"] as const,
["/bookings/:status", process.env.APP_ROUTER_BOOKINGS_STATUS_ENABLED === "1"] as const,
["/booking/:path*", process.env.APP_ROUTER_BOOKING_ENABLED === "1"] as const,
["/video/:path*", process.env.APP_ROUTER_VIDEO_ENABLED === "1"] as const,
["/team", process.env.APP_ROUTER_TEAM_ENABLED === "1"] as const,
["/teams", process.env.APP_ROUTER_TEAMS_ENABLED === "1"] as const,
["/more", process.env.APP_ROUTER_MORE_ENABLED === "1"] as const,
["/maintenance", process.env.APP_ROUTER_MAINTENANCE_ENABLED === "1"] as const,
-4
View File
@@ -14,10 +14,6 @@ export default function withEmbedSsrAppDir<T extends Record<string, any>>(
) {
return async (context: GetServerSidePropsContext): Promise<T> => {
const { embed, layout } = context.query;
const isCOEPEnabled = context.query["flag.coep"] === "true";
if (isCOEPEnabled) {
context.res.setHeader("Cross-Origin-Embedder-Policy", "require-corp");
}
try {
const props = await getData(context);
+1 -1
View File
@@ -55,7 +55,7 @@ export const TrpcProvider: React.FC<{ children: React.ReactNode; dehydratedState
// adds pretty logs to your console in development and logs errors in production
loggerLink({
enabled: (opts) =>
!!process.env.NEXT_PUBLIC_DEBUG || (opts.direction === "down" && opts.result instanceof Error),
(typeof process.env.NEXT_PUBLIC_LOGGER_LEVEL === 'number' && process.env.NEXT_PUBLIC_LOGGER_LEVEL >= 0) || (opts.direction === "down" && opts.result instanceof Error),
}),
splitLink({
// check for context property `skipBatch`
+21 -9
View File
@@ -5,11 +5,10 @@ import { headers } from "next/headers";
import { constructGenericImage } from "@calcom/lib/OgImages";
import { IS_CALCOM, WEBAPP_URL, APP_NAME, SEO_IMG_OGIMG } from "@calcom/lib/constants";
import { truncateOnWord } from "@calcom/lib/text";
//@ts-expect-error no type definitions
import config from "@calcom/web/next-i18next.config";
import { preparePageMetadata } from "@lib/metadata";
const create = async (locale: string, ns: string) => {
const { _nextI18Next } = await serverSideTranslations(locale, [ns], config);
@@ -30,7 +29,8 @@ export const getFixedT = async (locale: string, ns = "common") => {
export const _generateMetadata = async (
getTitle: (t: TFunction<string, undefined>) => string,
getDescription: (t: TFunction<string, undefined>) => string
getDescription: (t: TFunction<string, undefined>) => string,
excludeAppNameFromTitle?: boolean
) => {
const h = headers();
const canonical = h.get("x-pathname") ?? "";
@@ -50,12 +50,24 @@ export const _generateMetadata = async (
description,
});
return preparePageMetadata({
title,
canonical,
image,
const titleSuffix = `| ${APP_NAME}`;
const displayedTitle =
title.includes(titleSuffix) || excludeAppNameFromTitle ? title : `${title} ${titleSuffix}`;
return {
title: title.length === 0 ? APP_NAME : displayedTitle,
description,
siteName: APP_NAME,
alternates: {
canonical,
},
openGraph: {
description: truncateOnWord(description, 158),
url: canonical,
type: "website",
siteName: APP_NAME,
title,
images: [image],
},
metadataBase,
});
};
};
@@ -2,8 +2,11 @@ import { withAppDirSsr } from "app/WithAppDirSsr";
import withEmbedSsrAppDir from "app/WithEmbedSSR";
import { WithLayout } from "app/layoutHOC";
import LegacyPage from "~/users/views/users-type-public-view";
import { getServerSideProps, type PageProps } from "~/users/views/users-type-public-view.getServerSideProps";
import { getServerSideProps } from "@server/lib/[user]/[type]/getServerSideProps";
import LegacyPage, { type PageProps } from "~/users/views/users-type-public-view";
export { generateMetadata } from "../page";
const getData = withAppDirSsr<PageProps>(getServerSideProps);
+18 -17
View File
@@ -4,30 +4,31 @@ import { _generateMetadata } from "app/_utils";
import { WithLayout } from "app/layoutHOC";
import { headers, cookies } from "next/headers";
import { orgDomainConfig } from "@calcom/features/ee/organizations/lib/orgDomains";
import { EventRepository } from "@calcom/lib/server/repository/event";
import { buildLegacyCtx } from "@lib/buildLegacyCtx";
import { getServerSideProps } from "@server/lib/[user]/[type]/getServerSideProps";
import type { PageProps as LegacyPageProps } from "~/users/views/users-type-public-view";
import LegacyPage from "~/users/views/users-type-public-view";
import {
getServerSideProps,
type PageProps as LegacyPageProps,
} from "~/users/views/users-type-public-view.getServerSideProps";
export const generateMetadata = async ({ params, searchParams }: PageProps) => {
const props = await getData(buildLegacyCtx(headers(), cookies(), params, searchParams));
const legacyCtx = buildLegacyCtx(headers(), cookies(), params, searchParams);
const props = await getData(legacyCtx);
const { eventData, booking, user, slug } = props;
const { booking, user: username, slug: eventSlug } = props;
const rescheduleUid = booking?.uid;
const { trpc } = await import("@calcom/trpc");
const { data: event } = trpc.viewer.public.event.useQuery(
{
username: user,
eventSlug: slug,
isTeamEvent: false,
org: eventData.entity.orgSlug ?? null,
fromRedirectOfNonOrgLink: eventData.entity.fromRedirectOfNonOrgLink,
},
{ refetchOnWindowFocus: false }
);
const { currentOrgDomain, isValidOrgDomain } = orgDomainConfig(legacyCtx.req, legacyCtx.params?.orgSlug);
const event = await EventRepository.getPublicEvent({
username,
eventSlug,
isTeamEvent: false,
org: isValidOrgDomain ? currentOrgDomain : null,
fromRedirectOfNonOrgLink: legacyCtx.query.orgRedirection === "true",
});
const profileName = event?.profile?.name ?? "";
const title = event?.title ?? "";
+5 -1
View File
@@ -2,8 +2,12 @@ import { withAppDirSsr } from "app/WithAppDirSsr";
import withEmbedSsrAppDir from "app/WithEmbedSSR";
import { WithLayout } from "app/layoutHOC";
import { getServerSideProps } from "@server/lib/[user]/getServerSideProps";
import type { PageProps as UserPageProps } from "~/users/views/users-public-view";
import LegacyPage from "~/users/views/users-public-view";
import { getServerSideProps, type UserPageProps } from "~/users/views/users-public-view.getServerSideProps";
export { generateMetadata } from "../page";
const getData = withAppDirSsr<UserPageProps>(getServerSideProps);
+4 -2
View File
@@ -8,8 +8,10 @@ import { getLayout } from "@calcom/features/MainLayoutAppDir";
import { buildLegacyCtx } from "@lib/buildLegacyCtx";
import { getServerSideProps } from "@server/lib/[user]/getServerSideProps";
import type { PageProps as LegacyPageProps } from "~/users/views/users-public-view";
import LegacyPage from "~/users/views/users-public-view";
import { getServerSideProps, type UserPageProps } from "~/users/views/users-public-view.getServerSideProps";
export const generateMetadata = async ({ params, searchParams }: PageProps) => {
const props = await getData(buildLegacyCtx(headers(), cookies(), params, searchParams));
@@ -21,5 +23,5 @@ export const generateMetadata = async ({ params, searchParams }: PageProps) => {
);
};
const getData = withAppDirSsr<UserPageProps>(getServerSideProps);
const getData = withAppDirSsr<LegacyPageProps>(getServerSideProps);
export default WithLayout({ getLayout, getData, Page: LegacyPage })<"P">;
@@ -1,9 +1,8 @@
import { withAppDirSsr } from "app/WithAppDirSsr";
import type { SearchParams } from "app/_types";
import type { PageProps } from "app/_types";
import { _generateMetadata } from "app/_utils";
import { WithLayout } from "app/layoutHOC";
import type { GetServerSidePropsResult } from "next";
import type { Params } from "next/dist/shared/lib/router/utils/route-matcher";
import { cookies, headers } from "next/headers";
import { notFound } from "next/navigation";
import z from "zod";
@@ -18,13 +17,7 @@ const paramsSchema = z.object({
pages: z.array(z.string()),
});
export const generateMetadata = async ({
params,
searchParams,
}: {
params: Params;
searchParams: SearchParams;
}) => {
export const generateMetadata = async ({ params, searchParams }: PageProps) => {
const p = paramsSchema.safeParse(params);
if (!p.success) {
@@ -34,7 +27,7 @@ export const generateMetadata = async ({
const legacyContext = buildLegacyCtx(headers(), cookies(), params, searchParams);
const data = await getData(legacyContext);
const form = "form" in data ? (data.form as { name?: string; description?: string }) : null;
const formName = form?.name ?? "Forms";
const formName = form?.name ?? "Routing Forms";
const formDescription = form?.description ?? "";
return await _generateMetadata(
+4 -3
View File
@@ -1,12 +1,13 @@
import Setup from "@pages/auth/setup";
import { withAppDirSsr } from "app/WithAppDirSsr";
import { WithLayout } from "app/layoutHOC";
import type { InferGetServerSidePropsType } from "next";
import { getServerSideProps } from "@server/lib/setup/getServerSideProps";
import Setup from "~/auth/setup-view";
import type { PageProps } from "~/auth/setup-view";
export default WithLayout({
getLayout: null,
Page: Setup,
getData: withAppDirSsr<InferGetServerSidePropsType<typeof getServerSideProps>>(getServerSideProps),
getData: withAppDirSsr<PageProps>(getServerSideProps),
})<"P">;
+5 -4
View File
@@ -1,13 +1,14 @@
import signin from "@pages/auth/signin";
import { withAppDirSsr } from "app/WithAppDirSsr";
import { WithLayout } from "app/layoutHOC";
import type { InferGetServerSidePropsType } from "next";
import { getServerSideProps } from "@server/lib/auth/signin/getServerSideProps";
import SignIn from "~/auth/signin-view";
import type { PageProps } from "~/auth/signin-view";
export default WithLayout({
getLayout: null,
Page: signin,
Page: SignIn,
// @ts-expect-error TODO: fix this
getData: withAppDirSsr<InferGetServerSidePropsType<typeof getServerSideProps>>(getServerSideProps),
getData: withAppDirSsr<PageProps>(getServerSideProps),
})<"P">;
@@ -1,12 +1,13 @@
import Provider from "@pages/auth/sso/[provider]";
import { withAppDirSsr } from "app/WithAppDirSsr";
import { WithLayout } from "app/layoutHOC";
import type { InferGetServerSidePropsType } from "next";
import { getServerSideProps } from "@server/lib/auth/sso/[provider]/getServerSideProps";
import type { SSOProviderPageProps } from "~/auth/sso/provider-view";
import SSOProviderView from "~/auth/sso/provider-view";
export default WithLayout({
getLayout: null,
Page: Provider,
getData: withAppDirSsr<InferGetServerSidePropsType<typeof getServerSideProps>>(getServerSideProps),
Page: SSOProviderView,
getData: withAppDirSsr<SSOProviderPageProps>(getServerSideProps),
})<"P">;
+5 -3
View File
@@ -1,11 +1,13 @@
import DirectSSOLogin from "@pages/auth/sso/direct";
import { withAppDirSsr } from "app/WithAppDirSsr";
import { WithLayout } from "app/layoutHOC";
import { getServerSideProps } from "@server/lib/auth/sso/direct/getServerSideProps";
import type { SSODirectPageProps } from "~/auth/sso/direct-view";
import SSODirectView from "~/auth/sso/direct-view";
export default WithLayout({
getLayout: null,
Page: DirectSSOLogin,
getData: withAppDirSsr(getServerSideProps),
Page: SSODirectView,
getData: withAppDirSsr<SSODirectPageProps>(getServerSideProps),
})<"P">;
@@ -0,0 +1,22 @@
import { withAppDirSsr } from "app/WithAppDirSsr";
import { _generateMetadata } from "app/_utils";
import { WithLayout } from "app/layoutHOC";
import { getServerSideProps } from "@server/lib/auth/verify-email-change/getServerSideProps";
import type { PageProps } from "~/auth/verify-email-change-view";
import VerifyEmailChange from "~/auth/verify-email-change-view";
export const generateMetadata = async () => {
return await _generateMetadata(
() => "Verify email change",
() => ""
);
};
const getData = withAppDirSsr<PageProps>(getServerSideProps);
export default WithLayout({
getLayout: null,
Page: VerifyEmailChange,
getData,
});
@@ -1,11 +1,12 @@
import VerifyEmailPage from "@pages/auth/verify-email";
import { _generateMetadata } from "app/_utils";
import { WithLayout } from "app/layoutHOC";
import VerifyEmailPage from "~/auth/verify-email-view";
export const generateMetadata = async () => {
return await _generateMetadata(
(t) => t("check_your_email"),
(t) => t("check_your_email")
() => "Verify email",
() => ""
);
};
+40 -2
View File
@@ -1,11 +1,49 @@
import VerifyPage from "@pages/auth/verify";
import { withAppDirSsr } from "app/WithAppDirSsr";
import type { PageProps as _PageProps } from "app/_types";
import { _generateMetadata } from "app/_utils";
import { WithLayout } from "app/layoutHOC";
import { z } from "zod";
import { StripeService } from "@calcom/lib/server/service/stripe";
import { getServerSideProps } from "@server/lib/auth/verify/getServerSideProps";
import type { PageProps } from "~/auth/verify-view";
import VerifyPage from "~/auth/verify-view";
const querySchema = z.object({
stripeCustomerId: z.string().optional(),
sessionId: z.string().optional(),
t: z.string().optional(),
});
export const generateMetadata = async ({ params, searchParams }: _PageProps) => {
const p = { ...params, ...searchParams };
const { sessionId, stripeCustomerId } = querySchema.parse(p);
if (!stripeCustomerId && !sessionId) {
return await _generateMetadata(
() => "Verify",
() => ""
);
}
const data = await StripeService.getCheckoutSession({
stripeCustomerId,
checkoutSessionId: sessionId,
});
const { hasPaymentFailed } = data;
return await _generateMetadata(
() =>
hasPaymentFailed ? "Your payment failed" : sessionId ? "Payment successful!" : `Verify your email`,
() => ""
);
};
export default WithLayout({
getLayout: null,
Page: VerifyPage,
getData: withAppDirSsr(getServerSideProps),
getData: withAppDirSsr<PageProps>(getServerSideProps),
})<"P">;
+2 -8
View File
@@ -1,5 +1,5 @@
import { withAppDirSsr } from "app/WithAppDirSsr";
import type { Params, SearchParams } from "app/_types";
import type { PageProps as _PageProps } from "app/_types";
import { _generateMetadata } from "app/_utils";
import { WithLayout } from "app/layoutHOC";
import { cookies, headers } from "next/headers";
@@ -11,13 +11,7 @@ import { buildLegacyCtx } from "@lib/buildLegacyCtx";
import OldPage from "~/bookings/views/bookings-single-view";
import { getServerSideProps, type PageProps } from "~/bookings/views/bookings-single-view.getServerSideProps";
export const generateMetadata = async ({
params,
searchParams,
}: {
params: Params;
searchParams: SearchParams;
}) => {
export const generateMetadata = async ({ params, searchParams }: _PageProps) => {
const { bookingInfo, eventType, recurringBookings } = await getData(
buildLegacyCtx(headers(), cookies(), params, searchParams)
);
@@ -3,8 +3,6 @@ import { _generateMetadata } from "app/_utils";
import { WithLayout } from "app/layoutHOC";
import type { InferGetStaticPropsType } from "next";
import { APP_NAME } from "@calcom/lib/constants";
import { validStatuses } from "~/bookings/lib/validStatuses";
import Page from "~/bookings/views/bookings-listing-view";
import { getStaticProps } from "~/bookings/views/bookings-listing-view.getStaticProps";
@@ -14,8 +12,8 @@ const getData = withAppDirSsg<Y>(getStaticProps);
export const generateMetadata = async () =>
await _generateMetadata(
(t) => `${APP_NAME} | ${t("bookings")}`,
() => ""
() => "Bookings",
() => "Create events to share for people to book on your calendar."
);
export const generateStaticParams = async () => {
+24 -24
View File
@@ -1,35 +1,35 @@
import LegacyPage from "@pages/d/[link]/[slug]";
import { withAppDirSsr } from "app/WithAppDirSsr";
import type { Params, SearchParams } from "app/_types";
import type { PageProps as _PageProps } from "app/_types";
import { _generateMetadata } from "app/_utils";
import { WithLayout } from "app/layoutHOC";
import { cookies, headers } from "next/headers";
import { orgDomainConfig } from "@calcom/features/ee/organizations/lib/orgDomains";
import { EventRepository } from "@calcom/lib/server/repository/event";
import { buildLegacyCtx } from "@lib/buildLegacyCtx";
import { getServerSideProps } from "@lib/d/[link]/[slug]/getServerSideProps";
import { type PageProps } from "@lib/d/[link]/[slug]/getServerSideProps";
export const generateMetadata = async ({
params,
searchParams,
}: {
params: Params;
searchParams: SearchParams;
}) => {
const pageProps = await getData(buildLegacyCtx(headers(), cookies(), params, searchParams));
import Type from "~/d/[link]/d-type-view";
const { entity, booking, user, slug, isTeamEvent } = pageProps;
export const generateMetadata = async ({ params, searchParams }: _PageProps) => {
const legacyCtx = buildLegacyCtx(headers(), cookies(), params, searchParams);
const pageProps = await getData(legacyCtx);
const { booking, user: username, slug: eventSlug, isTeamEvent } = pageProps;
const rescheduleUid = booking?.uid;
const { trpc } = await import("@calcom/trpc");
const { data: event } = trpc.viewer.public.event.useQuery(
{
username: user ?? "",
eventSlug: slug ?? "",
isTeamEvent,
org: entity.orgSlug ?? null,
fromRedirectOfNonOrgLink: entity.fromRedirectOfNonOrgLink,
},
{ refetchOnWindowFocus: false }
);
const { currentOrgDomain, isValidOrgDomain } = orgDomainConfig(legacyCtx.req);
const org = isValidOrgDomain ? currentOrgDomain : null;
const event = await EventRepository.getPublicEvent({
username,
eventSlug,
isTeamEvent,
org,
fromRedirectOfNonOrgLink: legacyCtx.query.orgRedirection === "true",
});
const profileName = event?.profile?.name ?? "";
const title = event?.title ?? "";
return await _generateMetadata(
@@ -38,5 +38,5 @@ export const generateMetadata = async ({
);
};
const getData = withAppDirSsr(getServerSideProps);
export default WithLayout({ getLayout: null, Page: LegacyPage, getData })<"P">;
const getData = withAppDirSsr<PageProps>(getServerSideProps);
export default WithLayout({ getLayout: null, Page: Type, getData })<"P">;
@@ -4,12 +4,12 @@ import { _generateMetadata } from "app/_utils";
import { WithLayout } from "app/layoutHOC";
import { cookies, headers } from "next/headers";
import { EventType } from "@calcom/atoms/monorepo";
import { buildLegacyCtx } from "@lib/buildLegacyCtx";
import { getServerSideProps } from "@lib/event-types/[type]/getServerSideProps";
import type { PageProps as EventTypePageProps } from "@lib/event-types/[type]/getServerSideProps";
import EventTypePageWrapper from "~/event-types/views/event-types-single-view";
export const generateMetadata = async ({ params, searchParams }: PageProps) => {
const legacyCtx = buildLegacyCtx(headers(), cookies(), params, searchParams);
const { eventType } = await getData(legacyCtx);
@@ -21,5 +21,5 @@ export const generateMetadata = async ({ params, searchParams }: PageProps) => {
};
const getData = withAppDirSsr(getServerSideProps);
const Page = (props: EventTypePageProps) => <EventTypePageWrapper {...props} isAppDir={true} />;
const Page = ({ type, ...rest }: EventTypePageProps) => <EventType {...rest} id={type} isAppDir={true} />;
export default WithLayout({ getLayout: null, getData, Page })<"P">;
@@ -1,7 +1,24 @@
import Page from "@pages/getting-started/[[...step]]";
import { withAppDirSsr } from "app/WithAppDirSsr";
import { _generateMetadata } from "app/_utils";
import { WithLayout } from "app/layoutHOC";
import { APP_NAME } from "@calcom/lib/constants";
import { getServerSideProps } from "@lib/getting-started/[[...step]]/getServerSideProps";
export default WithLayout({ getLayout: null, getData: withAppDirSsr(getServerSideProps), Page });
import type { PageProps } from "~/getting-started/[[...step]]/onboarding-view";
import Page from "~/getting-started/[[...step]]/onboarding-view";
export const generateMetadata = async () => {
return await _generateMetadata(
(t) => `${APP_NAME} - ${t("getting_started")}`,
() => "",
true
);
};
export default WithLayout({
getLayout: null,
getData: withAppDirSsr<PageProps>(getServerSideProps),
Page,
});
+5 -4
View File
@@ -1,10 +1,11 @@
import LegacyPage from "@pages/insights/index";
import { withAppDirSsr } from "app/WithAppDirSsr";
import { _generateMetadata } from "app/_utils";
import { WithLayout } from "app/layoutHOC";
import { getServerSideProps } from "@lib/insights/getServerSideProps";
import { type inferSSRProps } from "@lib/types/inferSSRProps";
import type { PageProps } from "~/insights/insights-view";
import InsightsPage from "~/insights/insights-view";
export const generateMetadata = async () =>
await _generateMetadata(
@@ -12,6 +13,6 @@ export const generateMetadata = async () =>
(t) => t("insights_subtitle")
);
const getData = withAppDirSsr<inferSSRProps<typeof getServerSideProps>>(getServerSideProps);
const getData = withAppDirSsr<PageProps>(getServerSideProps);
export default WithLayout({ getLayout: null, getData, Page: LegacyPage });
export default WithLayout({ getLayout: null, getData, Page: InsightsPage });
@@ -1,8 +1,6 @@
import { type PageProps } from "@pages/team/[slug]";
import EmbedPage from "@pages/team/[slug]/embed";
import { withAppDirSsr } from "app/WithAppDirSsr";
import withEmbedSsrAppDir from "app/WithEmbedSSR";
import type { Params, SearchParams } from "app/_types";
import type { PageProps as _PageProps } from "app/_types";
import { _generateMetadata } from "app/_utils";
import { WithLayout } from "app/layoutHOC";
import { cookies, headers } from "next/headers";
@@ -10,15 +8,12 @@ import { cookies, headers } from "next/headers";
import { buildLegacyCtx } from "@lib/buildLegacyCtx";
import { getServerSideProps } from "@lib/team/[slug]/getServerSideProps";
import type { PageProps } from "~/team/team-view";
import TeamPage from "~/team/team-view";
const getData = withAppDirSsr<PageProps>(getServerSideProps);
export const generateMetadata = async ({
params,
searchParams,
}: {
params: Params;
searchParams: SearchParams;
}) => {
export const generateMetadata = async ({ params, searchParams }: _PageProps) => {
const props = await getData(buildLegacyCtx(headers(), cookies(), params, searchParams));
const teamName = props.team.name || "Nameless Team";
@@ -31,7 +26,7 @@ export const generateMetadata = async ({
const getEmbedData = withEmbedSsrAppDir(getData);
export default WithLayout({
Page: EmbedPage,
Page: TeamPage,
getData: getEmbedData,
getLayout: null,
isBookingPage: true,
+5 -9
View File
@@ -1,6 +1,5 @@
import TeamPage, { type PageProps } from "@pages/team/[slug]";
import { withAppDirSsr } from "app/WithAppDirSsr";
import type { Params, SearchParams } from "app/_types";
import type { PageProps as _PageProps } from "app/_types";
import { _generateMetadata } from "app/_utils";
import { WithLayout } from "app/layoutHOC";
import { cookies, headers } from "next/headers";
@@ -8,13 +7,10 @@ import { cookies, headers } from "next/headers";
import { buildLegacyCtx } from "@lib/buildLegacyCtx";
import { getServerSideProps } from "@lib/team/[slug]/getServerSideProps";
export const generateMetadata = async ({
params,
searchParams,
}: {
params: Params;
searchParams: SearchParams;
}) => {
import type { PageProps } from "~/team/team-view";
import TeamPage from "~/team/team-view";
export const generateMetadata = async ({ params, searchParams }: _PageProps) => {
const props = await getData(buildLegacyCtx(headers(), cookies(), params, searchParams));
const teamName = props.team.name || "Nameless Team";
@@ -1,35 +1,31 @@
import TypePage, { type PageProps } from "@pages/team/[slug]/[type]";
import { withAppDirSsr } from "app/WithAppDirSsr";
import type { Params, SearchParams } from "app/_types";
import type { PageProps as _PageProps } from "app/_types";
import { _generateMetadata } from "app/_utils";
import { WithLayout } from "app/layoutHOC";
import { cookies, headers } from "next/headers";
import { orgDomainConfig } from "@calcom/features/ee/organizations/lib/orgDomains";
import { EventRepository } from "@calcom/lib/server/repository/event";
import { buildLegacyCtx } from "@lib/buildLegacyCtx";
import { getServerSideProps } from "@lib/team/[slug]/[type]/getServerSideProps";
export const generateMetadata = async ({
params,
searchParams,
}: {
params: Params;
searchParams: SearchParams;
}) => {
import type { PageProps } from "~/team/type-view";
import TypePage from "~/team/type-view";
export const generateMetadata = async ({ params, searchParams }: _PageProps) => {
const legacyCtx = buildLegacyCtx(headers(), cookies(), params, searchParams);
const props = await getData(legacyCtx);
const { eventData, user, slug, booking } = props;
const entity = eventData.entity;
const { trpc } = await import("@calcom/trpc");
const { data: event } = trpc.viewer.public.event.useQuery(
{
username: user,
eventSlug: slug,
isTeamEvent: false,
org: entity.orgSlug ?? null,
fromRedirectOfNonOrgLink: entity.fromRedirectOfNonOrgLink,
},
{ refetchOnWindowFocus: false }
);
const { user: username, slug: eventSlug, booking } = props;
const { currentOrgDomain, isValidOrgDomain } = orgDomainConfig(legacyCtx.req, legacyCtx.params?.orgSlug);
const event = await EventRepository.getPublicEvent({
username,
eventSlug,
isTeamEvent: true,
org: isValidOrgDomain ? currentOrgDomain : null,
fromRedirectOfNonOrgLink: legacyCtx.query.orgRedirection === "true",
});
const profileName = event?.profile?.name ?? "";
const title = event?.title ?? "";
@@ -1,6 +1,5 @@
import TeamPage, { type PageProps } from "@pages/team/[slug]";
import { withAppDirSsr } from "app/WithAppDirSsr";
import type { Params, SearchParams } from "app/_types";
import type { PageProps as _PageProps } from "app/_types";
import { _generateMetadata } from "app/_utils";
import { WithLayout } from "app/layoutHOC";
import { cookies, headers } from "next/headers";
@@ -8,13 +7,10 @@ import { cookies, headers } from "next/headers";
import { buildLegacyCtx } from "@lib/buildLegacyCtx";
import { getServerSideProps } from "@lib/team/[slug]/getServerSideProps";
export const generateMetadata = async ({
params,
searchParams,
}: {
params: Params;
searchParams: SearchParams;
}) => {
import type { PageProps } from "~/team/team-view";
import TeamPage from "~/team/team-view";
export const generateMetadata = async ({ params, searchParams }: _PageProps) => {
const props = await getData(buildLegacyCtx(headers(), cookies(), params, searchParams));
const teamName = props.team.name || "Nameless Team";
+13
View File
@@ -0,0 +1,13 @@
import { redirect } from "next/navigation";
import { getServerSessionForAppDir } from "@calcom/features/auth/lib/get-server-session-for-app-dir";
const RedirectPage = async () => {
const session = await getServerSessionForAppDir();
if (!session?.user?.id) {
redirect("/auth/login");
}
redirect("/event-types");
};
export default RedirectPage;
@@ -1,14 +1,15 @@
import { getServerSideProps } from "@pages/reschedule/[uid]";
import { withAppDirSsr } from "app/WithAppDirSsr";
import { getServerSideProps as _getServerSideProps } from "@pages/reschedule/[uid]";
import type { PageProps } from "app/_types";
import { cookies, headers } from "next/headers";
import { buildLegacyCtx } from "@lib/buildLegacyCtx";
import withEmbedSsr from "@lib/withEmbedSsr";
const getData = withEmbedSsr(_getServerSideProps);
const Page = async ({ params, searchParams }: PageProps) => {
const legacyCtx = buildLegacyCtx(headers(), cookies(), params, searchParams);
await withAppDirSsr(withEmbedSsr(getServerSideProps))(legacyCtx);
await getData(legacyCtx);
return null;
};
@@ -1,10 +1,10 @@
import { getServerSideProps } from "@pages/reschedule/[uid]";
import { withAppDirSsr } from "app/WithAppDirSsr";
import type { PageProps } from "app/_types";
import { _generateMetadata } from "app/_utils";
import { headers, cookies } from "next/headers";
import { buildLegacyCtx } from "@lib/buildLegacyCtx";
import { getServerSideProps } from "@lib/reschedule/[uid]/getServerSideProps";
export const generateMetadata = async () =>
await _generateMetadata(
@@ -1,12 +1,19 @@
import type { PageProps } from "app/_types";
import { redirect } from "next/navigation";
import z from "zod";
const getPageProps = () => {
return redirect(`/apps/routing-forms/forms`);
};
const Page = () => {
getPageProps();
const paramsSchema = z
.object({
pages: z.array(z.string()),
})
.catch({
pages: [],
});
return null;
const Page = ({ params, searchParams }: PageProps) => {
const { pages } = paramsSchema.parse({ ...params, ...searchParams });
redirect(`/apps/routing-forms/${pages.length ? pages.join("/") : ""}`);
};
export default Page;
+2 -25
View File
@@ -1,30 +1,7 @@
import type { PageProps } from "app/_types";
import { type GetServerSidePropsContext } from "next";
import { cookies, headers } from "next/headers";
import { redirect } from "next/navigation";
import z from "zod";
import { buildLegacyCtx } from "@lib/buildLegacyCtx";
const paramsSchema = z
.object({
pages: z.array(z.string()),
})
.catch({
pages: [],
});
const getPageProps = async (context: GetServerSidePropsContext) => {
const { pages } = paramsSchema.parse(context.params);
return redirect(`/apps/routing-forms/${pages.length ? pages.join("/") : ""}`);
};
const Page = async ({ params, searchParams }: PageProps) => {
const legacyCtx = buildLegacyCtx(headers(), cookies(), params, searchParams);
await getPageProps(legacyCtx);
return null;
const Page = () => {
redirect("/apps/routing-forms/forms");
};
export default Page;
@@ -1,8 +1,4 @@
import LegacyPage from "@pages/settings/admin/index";
import { _generateMetadata } from "app/_utils";
import { WithLayout } from "app/layoutHOC";
import { getLayout } from "@components/auth/layouts/AdminLayoutAppDir";
export const generateMetadata = async () =>
await _generateMetadata(
@@ -10,4 +6,5 @@ export const generateMetadata = async () =>
() => "admin_description"
);
export default WithLayout({ getServerLayout: getLayout, Page: LegacyPage })<"P">;
const Page = () => <h1>Admin index</h1>;
export default Page;
@@ -25,7 +25,7 @@ const Page = async () => {
description={t("create_first_api_key_description", { appName: APP_NAME })}
CTA={<NewApiKeyButton />}
borderInShellHeader={true}>
<ApiKeysView />
<ApiKeysView isAppDir={true} />
</SettingsHeader>
);
};
@@ -1,5 +0,0 @@
import { WithLayout } from "app/layoutHOC";
import { getLayout } from "@calcom/features/settings/appDir/SettingsLayoutAppDir";
export default WithLayout({ getServerLayout: getLayout });
@@ -1,5 +0,0 @@
import { WithLayout } from "app/layoutHOC";
import { getLayout } from "@calcom/features/settings/appDir/SettingsLayoutAppDir";
export default WithLayout({ getServerLayout: getLayout });
@@ -1,11 +1,5 @@
import { _generateMetadata } from "app/_utils";
import BillingPage, { generateMetadata } from "../../billing/page";
import Page from "~/settings/billing/billing-view";
export { generateMetadata };
export const generateMetadata = async () =>
await _generateMetadata(
(t) => t("billing"),
(t) => t("manage_billing_description")
);
export default Page;
export default BillingPage;
@@ -1,5 +0,0 @@
import { WithLayout } from "app/layoutHOC";
import { getLayout } from "@calcom/features/settings/appDir/SettingsLayoutAppDir";
export default WithLayout({ getServerLayout: getLayout });
@@ -1,6 +1,8 @@
import { _generateMetadata } from "app/_utils";
import { _generateMetadata, getFixedT } from "app/_utils";
import Page from "@calcom/features/ee/organizations/pages/settings/general";
import { getServerSessionForAppDir } from "@calcom/features/auth/lib/get-server-session-for-app-dir";
import LegacyPage from "@calcom/features/ee/organizations/pages/settings/general";
import SettingsHeader from "@calcom/features/settings/appDir/SettingsHeader";
export const generateMetadata = async () =>
await _generateMetadata(
@@ -8,4 +10,15 @@ export const generateMetadata = async () =>
(t) => t("general_description")
);
const Page = async () => {
const session = await getServerSessionForAppDir();
const t = await getFixedT(session?.user.locale || "en");
return (
<SettingsHeader title={t("general")} description={t("general_description")} borderInShellHeader={true}>
<LegacyPage isAppDir={true} />
</SettingsHeader>
);
};
export default Page;
@@ -1,5 +0,0 @@
import { WithLayout } from "app/layoutHOC";
import { getLayout } from "@calcom/features/settings/appDir/SettingsLayoutAppDir";
export default WithLayout({ getServerLayout: getLayout });
@@ -1,6 +1,8 @@
import { _generateMetadata } from "app/_utils";
import { _generateMetadata, getFixedT } from "app/_utils";
import Page from "@calcom/features/ee/organizations/pages/settings/members";
import { getServerSessionForAppDir } from "@calcom/features/auth/lib/get-server-session-for-app-dir";
import LegacyPage from "@calcom/features/ee/organizations/pages/settings/members";
import SettingsHeader from "@calcom/features/settings/appDir/SettingsHeader";
export const generateMetadata = async () =>
await _generateMetadata(
@@ -8,4 +10,15 @@ export const generateMetadata = async () =>
(t) => t("organization_description")
);
const Page = async () => {
const session = await getServerSessionForAppDir();
const t = await getFixedT(session?.user.locale || "en");
return (
<SettingsHeader title={t("organization_members")} description={t("organization_description")}>
<LegacyPage isAppDir={true} />
</SettingsHeader>
);
};
export default Page;
@@ -1,5 +0,0 @@
import { WithLayout } from "app/layoutHOC";
import { getLayout } from "@calcom/features/settings/appDir/SettingsLayoutAppDir";
export default WithLayout({ getServerLayout: getLayout });
@@ -1,6 +1,8 @@
import { _generateMetadata } from "app/_utils";
import { _generateMetadata, getFixedT } from "app/_utils";
import Page from "@calcom/features/ee/organizations/pages/settings/profile";
import { getServerSessionForAppDir } from "@calcom/features/auth/lib/get-server-session-for-app-dir";
import LegacyPage from "@calcom/features/ee/organizations/pages/settings/profile";
import SettingsHeader from "@calcom/features/settings/appDir/SettingsHeader";
export const generateMetadata = async () =>
await _generateMetadata(
@@ -8,4 +10,18 @@ export const generateMetadata = async () =>
(t) => t("profile_org_description")
);
const Page = async () => {
const session = await getServerSessionForAppDir();
const t = await getFixedT(session?.user.locale || "en");
return (
<SettingsHeader
title={t("profile")}
description={t("profile_org_description")}
borderInShellHeader={true}>
<LegacyPage isAppDir={true} />
</SettingsHeader>
);
};
export default Page;
@@ -0,0 +1,24 @@
import { _generateMetadata, getFixedT } from "app/_utils";
import { getServerSessionForAppDir } from "@calcom/features/auth/lib/get-server-session-for-app-dir";
import OrgSSOView from "@calcom/features/ee/sso/page/orgs-sso-view";
import SettingsHeader from "@calcom/features/settings/appDir/SettingsHeader";
export const generateMetadata = async () =>
await _generateMetadata(
(t) => t("sso_configuration"),
(t) => t("sso_configuration_description_orgs")
);
const Page = async () => {
const session = await getServerSessionForAppDir();
const t = await getFixedT(session?.user.locale || "en");
return (
<SettingsHeader title={t("profile")} description={t("profile_org_description")}>
<OrgSSOView isAppDir={true} />
</SettingsHeader>
);
};
export default Page;
@@ -1,5 +0,0 @@
import { WithLayout } from "app/layoutHOC";
import { getLayout } from "@calcom/features/settings/appDir/SettingsLayoutAppDir";
export default WithLayout({ getServerLayout: getLayout });
@@ -1,6 +1,8 @@
import { _generateMetadata } from "app/_utils";
import { _generateMetadata, getFixedT } from "app/_utils";
import Page from "@calcom/features/ee/teams/pages/team-appearance-view";
import { getServerSessionForAppDir } from "@calcom/features/auth/lib/get-server-session-for-app-dir";
import LegacyPage from "@calcom/features/ee/teams/pages/team-appearance-view";
import SettingsHeader from "@calcom/features/settings/appDir/SettingsHeader";
export const generateMetadata = async () =>
await _generateMetadata(
@@ -8,4 +10,18 @@ export const generateMetadata = async () =>
(t) => t("appearance_team_description")
);
const Page = async () => {
const session = await getServerSessionForAppDir();
const t = await getFixedT(session?.user.locale || "en");
return (
<SettingsHeader
title={t("booking_appearance")}
description={t("appearance_team_description")}
borderInShellHeader={false}>
<LegacyPage isAppDir={true} />
</SettingsHeader>
);
};
export default Page;
@@ -1,5 +0,0 @@
import { WithLayout } from "app/layoutHOC";
import { getLayout } from "@calcom/features/settings/appDir/SettingsLayoutAppDir";
export default WithLayout({ getServerLayout: getLayout });
@@ -1,6 +1,8 @@
import { _generateMetadata } from "app/_utils";
import { _generateMetadata, getFixedT } from "app/_utils";
import Page from "@calcom/features/ee/organizations/pages/settings/other-team-members-view";
import { getServerSessionForAppDir } from "@calcom/features/auth/lib/get-server-session-for-app-dir";
import LegacyPage from "@calcom/features/ee/organizations/pages/settings/other-team-members-view";
import SettingsHeader from "@calcom/features/settings/appDir/SettingsHeader";
export const generateMetadata = async () =>
await _generateMetadata(
@@ -8,4 +10,16 @@ export const generateMetadata = async () =>
(t) => t("members_team_description")
);
const Page = async () => {
const session = await getServerSessionForAppDir();
const t = await getFixedT(session?.user.locale || "en");
return (
// TODO: Add CTA Button
<SettingsHeader title={t("team_members")} description={t("members_team_description")}>
<LegacyPage isAppDir={true} />
</SettingsHeader>
);
};
export default Page;
@@ -1,5 +0,0 @@
import { WithLayout } from "app/layoutHOC";
import { getLayout } from "@calcom/features/settings/appDir/SettingsLayoutAppDir";
export default WithLayout({ getServerLayout: getLayout });
@@ -1,6 +1,8 @@
import { _generateMetadata } from "app/_utils";
import { _generateMetadata, getFixedT } from "app/_utils";
import Page from "@calcom/features/ee/organizations/pages/settings/other-team-profile-view";
import { getServerSessionForAppDir } from "@calcom/features/auth/lib/get-server-session-for-app-dir";
import LegacyPage from "@calcom/features/ee/organizations/pages/settings/other-team-profile-view";
import SettingsHeader from "@calcom/features/settings/appDir/SettingsHeader";
export const generateMetadata = async () =>
await _generateMetadata(
@@ -8,4 +10,15 @@ export const generateMetadata = async () =>
(t) => t("profile_team_description")
);
const Page = async () => {
const session = await getServerSessionForAppDir();
const t = await getFixedT(session?.user.locale || "en");
return (
<SettingsHeader title={t("profile")} description={t("profile_team_description")}>
<LegacyPage isAppDir={true} />
</SettingsHeader>
);
};
export default Page;
@@ -1,5 +0,0 @@
import { WithLayout } from "app/layoutHOC";
import { getLayout } from "@calcom/features/settings/appDir/SettingsLayoutAppDir";
export default WithLayout({ getServerLayout: getLayout });
@@ -1,11 +0,0 @@
import { _generateMetadata } from "app/_utils";
import Page from "@calcom/features/ee/organizations/pages/settings/other-team-listing-view";
export const generateMetadata = async () =>
await _generateMetadata(
(t) => t("org_admin_other_teams"),
(t) => t("org_admin_other_teams_description")
);
export default Page;
@@ -0,0 +1,24 @@
import { _generateMetadata, getFixedT } from "app/_utils";
import { getServerSessionForAppDir } from "@calcom/features/auth/lib/get-server-session-for-app-dir";
import LegacyPage from "@calcom/features/ee/organizations/pages/settings/other-team-listing-view";
import SettingsHeader from "@calcom/features/settings/appDir/SettingsHeader";
export const generateMetadata = async () =>
await _generateMetadata(
(t) => t("org_admin_other_teams"),
(t) => t("org_admin_other_teams_description")
);
const Page = async () => {
const session = await getServerSessionForAppDir();
const t = await getFixedT(session?.user.locale || "en");
return (
<SettingsHeader title={t("org_admin_other_teams")} description={t("org_admin_other_teams_description")}>
<LegacyPage isAppDir={true} />
</SettingsHeader>
);
};
export default Page;
@@ -1,6 +1,8 @@
import { _generateMetadata } from "app/_utils";
import { _generateMetadata, getFixedT } from "app/_utils";
import Page from "@calcom/features/ee/teams/pages/team-appearance-view";
import { getServerSessionForAppDir } from "@calcom/features/auth/lib/get-server-session-for-app-dir";
import LegacyPage from "@calcom/features/ee/teams/pages/team-appearance-view";
import SettingsHeader from "@calcom/features/settings/appDir/SettingsHeader";
export const generateMetadata = async () =>
await _generateMetadata(
@@ -8,4 +10,18 @@ export const generateMetadata = async () =>
(t) => t("appearance_team_description")
);
const Page = async () => {
const session = await getServerSessionForAppDir();
const t = await getFixedT(session?.user.locale || "en");
return (
<SettingsHeader
title={t("booking_appearance")}
description={t("appearance_team_description")}
borderInShellHeader={false}>
<LegacyPage isAppDir={true} />
</SettingsHeader>
);
};
export default Page;
@@ -1,11 +1,4 @@
import { _generateMetadata } from "app/_utils";
import BillingPage, { generateMetadata } from "../../../billing/page";
import Page from "~/settings/billing/billing-view";
export const generateMetadata = async () =>
await _generateMetadata(
(t) => t("billing"),
(t) => t("team_billing_description")
);
export default Page;
export { generateMetadata };
export default BillingPage;
@@ -1,6 +1,8 @@
import { _generateMetadata } from "app/_utils";
import { _generateMetadata, getFixedT } from "app/_utils";
import Page from "@calcom/features/ee/teams/pages/team-members-view";
import { getServerSessionForAppDir } from "@calcom/features/auth/lib/get-server-session-for-app-dir";
import LegacyPage from "@calcom/features/ee/teams/pages/team-members-view";
import SettingsHeader from "@calcom/features/settings/appDir/SettingsHeader";
export const generateMetadata = async () =>
await _generateMetadata(
@@ -8,4 +10,15 @@ export const generateMetadata = async () =>
(t) => t("members_team_description")
);
const Page = async () => {
const session = await getServerSessionForAppDir();
const t = await getFixedT(session?.user.locale || "en");
return (
<SettingsHeader title={t("team_members")} description={t("members_team_description")}>
<LegacyPage isAppDir={true} />
</SettingsHeader>
);
};
export default Page;
@@ -1,6 +1,8 @@
import { _generateMetadata } from "app/_utils";
import { _generateMetadata, getFixedT } from "app/_utils";
import Page from "@calcom/features/ee/teams/pages/team-profile-view";
import { getServerSessionForAppDir } from "@calcom/features/auth/lib/get-server-session-for-app-dir";
import LegacyPage from "@calcom/features/ee/teams/pages/team-profile-view";
import SettingsHeader from "@calcom/features/settings/appDir/SettingsHeader";
export const generateMetadata = async () =>
await _generateMetadata(
@@ -8,4 +10,18 @@ export const generateMetadata = async () =>
(t) => t("profile_team_description")
);
const Page = async () => {
const session = await getServerSessionForAppDir();
const t = await getFixedT(session?.user.locale || "en");
return (
<SettingsHeader
title={t("profile")}
description={t("profile_team_description")}
borderInShellHeader={true}>
<LegacyPage isAppDir={true} />
</SettingsHeader>
);
};
export default Page;
@@ -1,5 +0,0 @@
import { WithLayout } from "app/layoutHOC";
import { getLayout } from "@calcom/features/settings/appDir/SettingsLayoutAppDir";
export default WithLayout({ getServerLayout: getLayout })<"L">;
@@ -1,11 +0,0 @@
import { _generateMetadata } from "app/_utils";
import Page from "@calcom/features/ee/teams/pages/team-listing-view";
export const generateMetadata = async () =>
await _generateMetadata(
(t) => t("teams"),
(t) => t("create_manage_teams_collaborative")
);
export default Page;
@@ -0,0 +1,24 @@
import { _generateMetadata, getFixedT } from "app/_utils";
import { getServerSessionForAppDir } from "@calcom/features/auth/lib/get-server-session-for-app-dir";
import LegacyPage from "@calcom/features/ee/teams/pages/team-listing-view";
import SettingsHeader from "@calcom/features/settings/appDir/SettingsHeader";
export const generateMetadata = async () =>
await _generateMetadata(
(t) => t("teams"),
(t) => t("create_manage_teams_collaborative")
);
const Page = async () => {
const session = await getServerSessionForAppDir();
const t = await getFixedT(session?.user.locale || "en");
return (
<SettingsHeader title={t("teams")} description={t("create_manage_teams_collaborative")}>
<LegacyPage isAppDir={true} />
</SettingsHeader>
);
};
export default Page;
@@ -1,6 +1,9 @@
import { withAppDirSsr } from "app/WithAppDirSsr";
import { _generateMetadata } from "app/_utils";
import { WithLayout } from "app/layoutHOC";
import { getServerSideProps } from "@calcom/features/ee/organizations/pages/organization";
import LegacyPage, { LayoutWrapper } from "~/settings/organizations/[id]/about-view";
export const generateMetadata = async () =>
@@ -9,7 +12,10 @@ export const generateMetadata = async () =>
(t) => t("about_your_organization_description")
);
const getData = withAppDirSsr(getServerSideProps);
export default WithLayout({
Page: LegacyPage,
getLayout: LayoutWrapper,
getData,
});
@@ -1,6 +1,9 @@
import { withAppDirSsr } from "app/WithAppDirSsr";
import { _generateMetadata } from "app/_utils";
import { WithLayout } from "app/layoutHOC";
import { getServerSideProps } from "@calcom/features/ee/organizations/pages/organization";
import LegacyPage, { LayoutWrapper } from "~/settings/organizations/[id]/add-teams-view";
export const generateMetadata = async () =>
@@ -9,7 +12,10 @@ export const generateMetadata = async () =>
(t) => t("create_your_teams_description")
);
const getData = withAppDirSsr(getServerSideProps);
export default WithLayout({
Page: LegacyPage,
getLayout: LayoutWrapper,
getData,
});
@@ -1,6 +1,9 @@
import { withAppDirSsr } from "app/WithAppDirSsr";
import { _generateMetadata } from "app/_utils";
import { WithLayout } from "app/layoutHOC";
import { getServerSideProps } from "@calcom/features/ee/organizations/pages/organization";
import LegacyPage, { LayoutWrapper } from "~/settings/organizations/[id]/onboard-members-view";
export const generateMetadata = async () =>
@@ -9,7 +12,10 @@ export const generateMetadata = async () =>
(t) => t("invite_organization_admins_description")
);
const getData = withAppDirSsr(getServerSideProps);
export default WithLayout({
Page: LegacyPage,
getLayout: LayoutWrapper,
getData,
});
@@ -1,4 +1,5 @@
import { _generateMetadata } from "app/_utils";
import { WithLayout } from "app/layoutHOC";
import Page from "@calcom/features/ee/organizations/pages/settings/appearance";
@@ -8,4 +9,4 @@ export const generateMetadata = async () =>
(t) => t("appearance_org_description")
);
export default Page;
export default WithLayout({ Page });
@@ -1,11 +1,12 @@
import LegacyPage, { GetLayout } from "@pages/settings/teams/[id]/event-type";
import { _generateMetadata } from "app/_utils";
import { WithLayout } from "app/layoutHOC";
import CreateTeamEventType, { GetLayout } from "~/settings/teams/[id]/event-types-view";
export const generateMetadata = async () =>
await _generateMetadata(
(t) => t("add_new_team_event_type"),
(t) => t("new_event_type_to_book_description")
);
export default WithLayout({ Page: LegacyPage, getLayout: GetLayout })<"P">;
export default WithLayout({ Page: CreateTeamEventType, getLayout: GetLayout })<"P">;
@@ -1,11 +1,12 @@
import LegacyPage, { GetLayout } from "@pages/settings/teams/[id]/onboard-members";
import { _generateMetadata } from "app/_utils";
import { WithLayout } from "app/layoutHOC";
import AddNewTeamMembers, { GetLayout } from "~/settings/teams/[id]/onboard-members-view";
export const generateMetadata = async () =>
await _generateMetadata(
(t) => t("add_team_members"),
(t) => t("add_team_members_description")
);
export default WithLayout({ Page: LegacyPage, getLayout: GetLayout })<"P">;
export default WithLayout({ Page: AddNewTeamMembers, getLayout: GetLayout })<"P">;
@@ -1,11 +1,12 @@
import LegacyPage, { LayoutWrapper } from "@pages/settings/teams/new/index";
import { _generateMetadata } from "app/_utils";
import { WithLayout } from "app/layoutHOC";
import CreateNewTeamView, { LayoutWrapper } from "~/settings/teams/new/create-new-team-view";
export const generateMetadata = async () =>
await _generateMetadata(
(t) => t("create_new_team"),
(t) => t("create_new_team_description")
);
export default WithLayout({ Page: LegacyPage, getLayout: LayoutWrapper })<"P">;
export default WithLayout({ Page: CreateNewTeamView, getLayout: LayoutWrapper })<"P">;
+4 -2
View File
@@ -1,10 +1,12 @@
import LegacyPage, { type SignupProps } from "@pages/signup";
import { withAppDirSsr } from "app/WithAppDirSsr";
import { _generateMetadata } from "app/_utils";
import { WithLayout } from "app/layoutHOC";
import { getServerSideProps } from "@lib/signup/getServerSideProps";
import type { SignupProps } from "~/signup-view";
import Signup from "~/signup-view";
export const generateMetadata = async () =>
await _generateMetadata(
(t) => t("sign_up"),
@@ -14,7 +16,7 @@ export const generateMetadata = async () =>
const getData = withAppDirSsr<SignupProps>(getServerSideProps);
export default WithLayout({
Page: LegacyPage,
Page: Signup,
getLayout: null,
getData,
})<"P">;
@@ -1,10 +1,43 @@
import LegacyPage, { getServerSideProps } from "@pages/team/[slug]/[type]/embed";
import { withAppDirSsr } from "app/WithAppDirSsr";
import withEmbedSsrAppDir from "app/WithEmbedSSR";
import type { PageProps as _PageProps } from "app/_types";
import { _generateMetadata } from "app/_utils";
import { WithLayout } from "app/layoutHOC";
import { cookies, headers } from "next/headers";
const getData = withAppDirSsr(getServerSideProps);
import { orgDomainConfig } from "@calcom/features/ee/organizations/lib/orgDomains";
import { EventRepository } from "@calcom/lib/server/repository/event";
import { buildLegacyCtx } from "@lib/buildLegacyCtx";
import { getServerSideProps } from "@lib/team/[slug]/[type]/getServerSideProps";
import type { PageProps } from "~/team/type-view";
import LegacyPage from "~/team/type-view";
export const generateMetadata = async ({ params, searchParams }: _PageProps) => {
const legacyCtx = buildLegacyCtx(headers(), cookies(), params, searchParams);
const props = await getData(legacyCtx);
const { user: username, slug: eventSlug, booking } = props;
const { currentOrgDomain, isValidOrgDomain } = orgDomainConfig(legacyCtx.req, legacyCtx.params?.orgSlug);
const event = await EventRepository.getPublicEvent({
username,
eventSlug,
isTeamEvent: true,
org: isValidOrgDomain ? currentOrgDomain : null,
fromRedirectOfNonOrgLink: legacyCtx.query.orgRedirection === "true",
});
const profileName = event?.profile?.name ?? "";
const title = event?.title ?? "";
return await _generateMetadata(
(t) => `${booking?.uid && !!booking ? t("reschedule") : ""} ${title} | ${profileName}`,
(t) => `${booking?.uid ? t("reschedule") : ""} ${title}`
);
};
const getData = withAppDirSsr<PageProps>(getServerSideProps);
const getEmbedData = withEmbedSsrAppDir(getData);
// @ts-expect-error Type is missing the following properties from type: entity, duration, booking, away, and 7 more.
export default WithLayout({ getLayout: null, getData: getEmbedData, Page: LegacyPage })<"P">;
+16 -14
View File
@@ -1,28 +1,30 @@
import LegacyPage, { type PageProps as LegacyPageProps, getServerSideProps } from "@pages/team/[slug]/[type]";
import { withAppDirSsr } from "app/WithAppDirSsr";
import type { PageProps } from "app/_types";
import { _generateMetadata } from "app/_utils";
import { WithLayout } from "app/layoutHOC";
import { cookies, headers } from "next/headers";
import { orgDomainConfig } from "@calcom/features/ee/organizations/lib/orgDomains";
import { EventRepository } from "@calcom/lib/server/repository/event";
import { buildLegacyCtx } from "@lib/buildLegacyCtx";
import { getServerSideProps } from "@lib/team/[slug]/[type]/getServerSideProps";
import LegacyPage, { type PageProps as LegacyPageProps } from "~/team/type-view";
export const generateMetadata = async ({ params, searchParams }: PageProps) => {
const legacyCtx = buildLegacyCtx(headers(), cookies(), params, searchParams);
const props = await getData(legacyCtx);
const { eventData, user, slug, booking } = props;
const entity = eventData.entity;
const { trpc } = await import("@calcom/trpc");
const { data: event } = trpc.viewer.public.event.useQuery(
{
username: user,
eventSlug: slug,
isTeamEvent: false,
org: entity.orgSlug ?? null,
fromRedirectOfNonOrgLink: entity.fromRedirectOfNonOrgLink,
},
{ refetchOnWindowFocus: false }
);
const { user: username, slug: eventSlug, booking } = props;
const { currentOrgDomain, isValidOrgDomain } = orgDomainConfig(legacyCtx.req, legacyCtx.params?.orgSlug);
const event = await EventRepository.getPublicEvent({
username,
eventSlug,
isTeamEvent: true,
org: isValidOrgDomain ? currentOrgDomain : null,
fromRedirectOfNonOrgLink: legacyCtx.query.orgRedirection === "true",
});
const profileName = event?.profile?.name ?? "";
const title = event?.title ?? "";
+19 -1
View File
@@ -1,7 +1,25 @@
import LegacyPage, { type PageProps, getServerSideProps } from "@pages/team/[slug]";
import { withAppDirSsr } from "app/WithAppDirSsr";
import withEmbedSsrAppDir from "app/WithEmbedSSR";
import type { PageProps as _PageProps } from "app/_types";
import { _generateMetadata } from "app/_utils";
import { WithLayout } from "app/layoutHOC";
import { cookies, headers } from "next/headers";
import { buildLegacyCtx } from "@lib/buildLegacyCtx";
import { getServerSideProps } from "@lib/team/[slug]/getServerSideProps";
import type { PageProps } from "~/team/team-view";
import LegacyPage from "~/team/team-view";
export const generateMetadata = async ({ params, searchParams }: _PageProps) => {
const props = await getData(buildLegacyCtx(headers(), cookies(), params, searchParams));
const teamName = props.team.name || "Nameless Team";
return await _generateMetadata(
() => teamName,
() => teamName
);
};
const getData = withAppDirSsr<PageProps>(getServerSideProps);
const getEmbedData = withEmbedSsrAppDir(getData);
+7 -5
View File
@@ -1,13 +1,16 @@
import LegacyPage, { getServerSideProps, type PageProps as LegacyPageProps } from "@pages/team/[slug]";
import { withAppDirSsr } from "app/WithAppDirSsr";
import type { PageProps } from "app/_types";
import type { PageProps as _PageProps } from "app/_types";
import { _generateMetadata } from "app/_utils";
import { WithLayout } from "app/layoutHOC";
import { cookies, headers } from "next/headers";
import { buildLegacyCtx } from "@lib/buildLegacyCtx";
import { getServerSideProps } from "@lib/team/[slug]/getServerSideProps";
export const generateMetadata = async ({ params, searchParams }: PageProps) => {
import type { PageProps } from "~/team/team-view";
import LegacyPage from "~/team/team-view";
export const generateMetadata = async ({ params, searchParams }: _PageProps) => {
const props = await getData(buildLegacyCtx(headers(), cookies(), params, searchParams));
const teamName = props.team.name || "Nameless Team";
@@ -17,11 +20,10 @@ export const generateMetadata = async ({ params, searchParams }: PageProps) => {
);
};
const getData = withAppDirSsr<LegacyPageProps>(getServerSideProps);
const getData = withAppDirSsr<PageProps>(getServerSideProps);
export default WithLayout({
Page: LegacyPage,
getData,
getLayout: null,
isBookingPage: true,
})<"P">;
+8 -2
View File
@@ -1,14 +1,20 @@
import Page from "@pages/teams/index";
import { withAppDirSsr } from "app/WithAppDirSsr";
import { _generateMetadata } from "app/_utils";
import { WithLayout } from "app/layoutHOC";
import { getServerSideProps } from "@lib/teams/getServerSideProps";
import type { PageProps } from "~/teams/teams-view";
import Page from "~/teams/teams-view";
export const generateMetadata = async () =>
await _generateMetadata(
(t) => t("teams"),
(t) => t("create_manage_teams_collaborative")
);
export default WithLayout({ getData: withAppDirSsr(getServerSideProps), getLayout: null, Page })<"P">;
export default WithLayout({
getData: withAppDirSsr<PageProps>(getServerSideProps),
getLayout: null,
Page,
})<"P">;

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