Compare commits

..
74 Commits
Author SHA1 Message Date
GitHub Actions 0d2ec20f66 chore: release v5.0.4
Post release / release (push) Canceled after 0s
2025-02-20 22:50:23 +00:00
Benny JooandKeith Williams 01fc501cb9 chore: Block POST requests to all page routes except a whitelist (#19346)
* chore: block POST requests to next.js routes except a whitelist

* update config.matcher

---------

Co-authored-by: Keith Williams <keithwillcode@gmail.com>
2025-02-20 17:19:35 -03:00
Nayan Bagale 1be002c33c fix: Issues with scheduling timezone change without end time (#19103)
* fix: Issues with scheduling timezone change without end time

* test: remove DatePicker component tests

* feat: implement DatePicker component with tests and update button data-testid
2025-02-20 19:19:55 +00:00
Benny Joo 8a4b03833d chore: remove org/team booking routes from middleware (#19349)
* chore: remove user routes from middleware

* chore: remove org and team routes from middleware
2025-02-20 15:30:13 -03:00
Calcom BotandLingo.dev 8714dda047 feat: update translations via @lingodotdev (#19417)
Co-authored-by: Lingo.dev <support@lingo.dev>
2025-02-20 18:18:14 +00:00
5b89123307 fix: fix youtube link and referral url (#19410)
* feat: Add 'Monobot CX' web application into cal.com app-store

* rollback yarn.lock

* fix: youtube link

* fix: change redirect url

* fix: config change redirect url

---------

Co-authored-by: Volodymyr Gusakovskyi <v.gusakovskyi@asferro.com>
Co-authored-by: Anik Dhabal Babu <81948346+anikdhabal@users.noreply.github.com>
2025-02-20 17:48:47 +00:00
Benny Joo 3221379584 chore: remove user routes from middleware (#19345) 2025-02-20 14:39:40 -03:00
Amit SharmaandTushar Bhatt 578f5dc16b feat: implement mintlify AI search into CMD+K (#18749)
Co-authored-by: Tushar Bhatt <95581504+TusharBhatt1@users.noreply.github.com>
2025-02-20 16:07:13 +00:00
amritandTushar Bhatt 3f042a1077 fix: reduce abnormal spacing in calendar invite (#19290)
* fix: reduce abnormal spacing in calendar invite

* add test for CalEventParser's getRichDescription

---------

Co-authored-by: Tushar Bhatt <95581504+TusharBhatt1@users.noreply.github.com>
2025-02-20 21:27:33 +05:30
Anik Dhabal Babu a44e7b2371 fix: multiselect is broken (#19351) 2025-02-20 13:22:34 +00:00
Hariom Balhara b06a94ab57 More dry run fixes (#18865) 2025-02-20 10:21:28 +00:00
Rajiv Sahal ec55454e43 separate phone input for web and platform (#19396) 2025-02-20 10:23:59 +01:00
Hariom Balhara 9ec0217858 chore: Add logs more (#19397) 2025-02-20 10:17:05 +01:00
amrit 66d69f5a06 fix: impersonation button alignment (#19383) 2025-02-20 06:45:45 +00:00
GitHub Actions b7b58c2dc7 chore: release v5.0.3
Post release / release (push) Canceled after 0s
2025-02-19 22:38:11 +00:00
Vachmara de1e19ee6d fix: Intercom app - book an event inside the messenger (#19391) 2025-02-19 21:21:22 +00:00
mintlify[bot] a366cb7c89 Documentation edits made through Mintlify web editor (#19084)
Co-authored-by: mintlify[bot] <109931778+mintlify[bot]@users.noreply.github.com>
2025-02-19 14:33:22 +00:00
yuriisilkov1986andVolodymyr Gusakovskyi dac336894c feat: Add 'Monobot CX' web application into cal.com app-store (#18505)
* feat: Add 'Monobot CX' web application into cal.com app-store

* rollback yarn.lock

---------

Co-authored-by: Volodymyr Gusakovskyi <v.gusakovskyi@asferro.com>
2025-02-19 13:40:07 +00:00
Harshit Singh 373c17a46d fix: Improved EventsLimit page for mobile viewports (#19270)
* Fixed mobile responsiveness UI  bugs

* Minor fix
2025-02-19 18:50:34 +05:30
Peer Richelsen 4c00c1ac2b added millis ai (#19357) 2025-02-19 18:20:47 +05:30
Özer 050a030ff0 fix(ui): prevent text descender cutoff in user dropdown (#19309) 2025-02-19 12:44:21 +00:00
Benny Joo dfb2232a59 chore: deprecate requiresLicense = true (#19374) 2025-02-19 13:33:03 +01:00
Amit SharmaandAnik Dhabal Babu 984ccf7c80 feat: Duration select dropdown multiple durations email embed (#17432)
Co-authored-by: Anik Dhabal Babu <81948346+anikdhabal@users.noreply.github.com>
2025-02-19 12:29:52 +00:00
Hariom Balhara e87168322c fix: Dont crash entire listing if one form has faulty JSON fields (#19368)
* Dont hit members matching endpoint for regular team forms

* fix tests

* Dont crash and instead show the form in readonly mode
2025-02-19 11:05:29 +00:00
Anwar Sadath bf9e9b4ae1 fix: Show loading indicator when delete account API is in progress (#19361) 2025-02-19 10:20:20 +00:00
Peer Richelsen 6d4b05cf1d Update README.md 2025-02-19 10:48:15 +01:00
Peer Richelsen bd1af4027f Update README.md 2025-02-19 10:47:45 +01:00
Peer Richelsen 3872175393 Update LICENSE 2025-02-19 10:27:35 +01:00
Peer Richelsen 5ca063d4e8 Update custom-css.mdx 2025-02-19 10:24:27 +01:00
Peer Richelsen 112aa8201f Update introduction.mdx 2025-02-19 10:22:21 +01:00
Hariom Balhara 17fcc2c213 fix: Test preview - Routing forms crash for regular teams(that are not sub-teams) (#19353) 2025-02-19 08:20:26 +00:00
amritandPeer Richelsen d3f1dc1b32 fix: tanstack getRight error, focus in user impersonation, missing space after input fields, border in my-profile email (#19350)
* fix: shadow after email and before the primary label

* fix: autofill input shadow in impersonation view

* fix: improve spacing and layout in EditUserForm

* fix: error due to getRight

---------

Co-authored-by: Peer Richelsen <peeroke@gmail.com>
2025-02-19 13:23:11 +05:30
Hariom BalharaandhbjORbj 25f3368fa1 fix: Plain Chat loading in embed (#19348)
* PlainChat has to be on dashboard and not on booking pages

* improve useIsBookingPage

---------

Co-authored-by: hbjORbj <sldisek783@gmail.com>
2025-02-19 06:40:32 +00:00
9a271f397b fix: empty hosts array in filterHostsByLeadThreshold (#19343)
* return early if hosts is empty

* feedback

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

---------

Co-authored-by: CarinaWolli <wollencarina@gmail.com>
Co-authored-by: Alex van Andel <me@alexvanandel.com>
2025-02-18 18:19:44 +00:00
GitHub Actions 6847781a7f chore: release v5.0.2
Post release / release (push) Canceled after 0s
2025-02-18 16:07:40 +00:00
amritandPeer Richelsen 2d9a3bd741 fix: EditLocationDialog footer positioning and structure (#19335)
* fix: EditLocationDialog footer positioning and structure

* fix: make RescheduleDialog footer layout and button structure right

* fix: input dialogue glitch now works great

* made tests happy

---------

Co-authored-by: Peer Richelsen <peeroke@gmail.com>
2025-02-18 15:23:40 +00:00
649faf4ff6 fix: Fairness when routing (#18550)
* Partial push of new filters

* Let's always return the passed host array when a filter doesn't need to be applied

* fix: isFixed typing in same round robin host check

* Add main bulk of rewritten logic for routed fairness support

* Remove console.log

* Add getAttributeWithEnabledWeights to AttributeRepository

* Add OOO entry repository

* Use getOrderedListOfLuckyUsers in lead threshold filtering

* Shortfall already includes weight

* test against minShortfall

* first attempt to fix fallbacks

* Added testcase updates

* Partially fix filterHosts test

* Some test updates

* Removed email field from normalization

* fix no available users found error

* fix unit test

* remove fallback from same host reschedule return

* fixes and improvements for findQualifiedHosts

* include fallback logic in handleNewBooking

* use fallback in handleNewBooking

* fix for contact owner in handleNewBooking

* WIP - comment

* pass routingFormResponseId

* fix type error

* pass routingFormResponse

* fixes in treshold logic

* remove reason

* merge qualified and fallback availabilities

* fix type error

* add and fix tests

* clean up test file

* fix filterHostsBySameRoundRobinHost tests

* fix findQualifiedHosts.test.ts

* fix getRoutedUsers.test.ts

* fix tests

* fix isRerouting check

* fix start time for two weeks check

* fix fallback hosts

* fix test

* fallback hosts should also include qualified hosts

* fix type error

* fix typos

* add contact owner to fallbacks

* fix typo

* fix qualifiedRRUsers

* set fixed users when no hosts

* add tets + code clean up

* add test for reschedule with same host

* fix typo

* add more tests for findQualifiedHosts

* remove skip from test

* add comment

* remove unused code

* fix fallback users in loadAndValidateUsers

* improve naming for fallback

* rename missed fallback variable

* fix reschedule with same rr host in handleNewBooking

* fixes for fallback slots

* add more tests + small fixes for contact owner

* fix tests and type errors

* add logs for fallback

* add type:json to logger

* Fix small merge issue

* fix end time if two weeks are cut off

* add more tests for contact owner availability check

* add new logic for two weeks fallback

* fix reschedule same RR host test

---------

Co-authored-by: CarinaWolli <wollencarina@gmail.com>
Co-authored-by: Peer Richelsen <peeroke@gmail.com>
Co-authored-by: Carina Wollendorfer <30310907+CarinaWolli@users.noreply.github.com>
2025-02-18 14:59:48 +00:00
Peer Richelsen 03346f04ed chore: fixed tooltip position for routing form (#19267)
* fixed tooltip position for routing form

* fixed offset
2025-02-18 14:11:09 +00:00
Anik Dhabal BabuandUdit Takkar 99260974f4 fix: Issues with date changes in column view (#19258)
* fix: coulmn view date change

* Update store.ts

---------

Co-authored-by: Udit Takkar <53316345+Udit-takkar@users.noreply.github.com>
2025-02-18 18:46:46 +05:30
Peer Richelsen 4a493c0a0e chore: v3 fixed filters, new profile view (#19312)
* fixed filters with badge

* aligned recurrence in bookings

* removed new badge

* new profile view

* fixed try for free button

* fixed form input
2025-02-18 12:23:30 +00:00
Benny Joo 47435c36ff fix: redirect logic in /settings/admin/apps (#19332) 2025-02-18 11:24:13 +00:00
Benny Joo 599744b31c chore: remove WithLayout from not-found.tsx (#19331) 2025-02-18 11:07:16 +00:00
Amit SharmaandTushar Bhatt d2c4c45137 fix: Can't use unsaved booking question as variable in event name (#18604)
Co-authored-by: Tushar Bhatt <95581504+TusharBhatt1@users.noreply.github.com>
2025-02-18 16:11:40 +05:30
Benny Joo 43ba47a122 perf: Use one PageWrapper instance for all settings pages (#18752)
* add a layoutfile to use-page-wrapper route group

* refactor and move bookings status page to route group

* improve logic in pagesAndRewritePaths

* fix

* add use client directive

* move /403 and /500

* move /auth/error

* move /connect-and-join

* move /enterprise

* move /maintenance

* move /more

* move /upgrade

* chore: remove WithLayout from 8 low-risk single pages (#18745)

* move /403 and /500

* move /auth/error

* move /connect-and-join

* move /enterprise

* move /maintenance

* move /more

* move /upgrade

* move /availability pages

* move /event-types pages

* move /insights pages

* move /apps to use-page-wrapper group

* move /getting-started to use-page-wrapper group

* move /signup to use-page-wrapper group

* move /workflows to use-page-wrapper group

* move /video pages to use-page-wrapper group

* pass dehydratedState in layout

* pass dehydratedState in layout

* move settings/(settings-layout) to use-page-wrapper

* move settings/(admin-layout) to use-page-wrapper

* move remaining settings pages to (use-page-wrapper)

* fix test

* remove unused code

* remove unused files

* fix type check

* remove test tag

* remove page

* RSC should not default export client components
2025-02-18 04:43:25 -05:00
amritandTushar Bhatt 0048b2d92c feat: make first tab active by default (#19315)
* feat: make first tab active by default

* perf: optimize event types tabs rendering with useMemo

---------

Co-authored-by: Tushar Bhatt <95581504+TusharBhatt1@users.noreply.github.com>
2025-02-18 14:42:03 +05:30
amrit 9dc0570d38 fix: timezone input text is now visible in dark mode (#19325) 2025-02-18 05:46:10 +00:00
Anik Dhabal Babu 1fbfca958a fix (#19298) 2025-02-18 11:08:10 +05:30
Joe Au-Yeung 7a6c93795a feat: Create UserCreationService and use in API V1 create user endpoint (#19150)
* Create `createUser` method in `userCreationService`

* Refactor `UserRepository` create method to accept prisma input and remove business logic

* API use `UserCreationService`

* Move slugify to service

* Use hashPassword instead

* Type fixes in `UserCreationService`

* Add `userCreationService` tests

* API accept data object

* Type fixes

* Add user _post test

* Add test for locked user

* Add locked param to log

* Add user repository tests

* Do not return locked status

* Explicitly pass `locked` prop

* Fix tests when locked isn't returned

* Fix tests

* Pass locked prop

* Edit test name

* Use logger

* Fix passing hashed password
2025-02-17 22:30:39 -05:00
GitHub Actions 4481b232cc chore: release v5.0.1
Post release / release (push) Canceled after 0s
2025-02-17 20:02:39 +00:00
Alex van Andel 84b265cd54 refactor: Clean out old code, no longer needed (#19323)
* refactor: Clean out old code, no longer needed

* Removed a sneaky one keen to stay behind
2025-02-17 19:39:20 +00:00
Rajiv Sahal eb86064995 feat: atoms adjustments with ui v3 styles (#19320) 2025-02-17 16:58:47 +02:00
Sanchit TewariandTushar Bhatt 39fdf5a74e feat: prevent automatic query parameters when opening booking page (#18132)
- Resolve the user hindrance where the event's booking page should not have search parameters such as date and month in the initial page load
- Contains changes for the fix of issue #18094 as well as it is needed

Co-authored-by: Tushar Bhatt <95581504+TusharBhatt1@users.noreply.github.com>
2025-02-17 14:41:00 +00:00
Tushar BhattandAnik Dhabal Babu f28c605b50 fix: bulk-update-in-scheduleId-in-detailed-view (#19295)
* fix: bulk-update-in-scheduleId-in-detailed-view

* minor-change

---------

Co-authored-by: Anik Dhabal Babu <81948346+anikdhabal@users.noreply.github.com>
2025-02-17 14:39:27 +00:00
Anik Dhabal Babu 63d26c4fba fix: Can't change availability for managed event type (#19006)
* fix: flaky test organization.spec

* fix
2025-02-17 13:59:39 +00:00
Eunjae Lee 14bba343a4 fix: nested scrolls on /bookings (#19284) 2025-02-17 10:25:42 +01:00
amrit e441f3308f fix: cut off and alignment bug (#19317)
* fix: assignment label cut-off

* fix: add all team members label is vertically aligned
2025-02-17 08:21:26 +00:00
Benny Joo b4aad453cd chore: migrate api for team upgrade to App Router (#19100)
* remove old pages router api

* add new app router api

* fix

* fix redirect

* refactor
2025-02-17 12:07:13 +05:30
Benny JooandHariom Balhara dc7a1c4680 chore: migrate /apps/routing-forms/[...pages] to App Router (#18956)
* wip

* fix

* fix

* refactor

* rename to routingServerSidePropsConfig

* refactor

* refactor

* add routing-link to useIsBookingPage hook

* remove Head component

* fix

* redirect user to apps/routing-forms/forms if user goes to apps/routing-forms

* refactor

* remove log

* remove client component not needed

* clean up code

* remove unneeded metadata

* clean up further

* clean up further 2

* fix type check

* routing-link does not need shell

* Fix title for Routing Form public link and also remove any

* Remove ; in HTML

* Remove unnecessary page reload

---------

Co-authored-by: Hariom Balhara <hariombalhara@gmgmail.com>
2025-02-17 11:15:54 +05:30
Anik Dhabal Babu fd651133c2 fix flake (#19306) 2025-02-16 07:27:34 -03:00
GitHub Actions f0d2a1a051 chore: release v5.0.0
Post release / release (push) Canceled after 0s
2025-02-15 10:26:34 +00:00
Tushar Bhatt 62c7627775 fix: removing-all-members-toggle-for-fh (#19277)
* fix : removing all members toggle for fh

* ux enhancements

* adding placeholder
2025-02-15 10:14:56 +00:00
be53a20429 feat: Use Folders to organize SMS links on Dub (#19248)
* feat: Use Folders to organize SMS links on Dub

* Update yarn.lock

---------

Co-authored-by: sean-brydon <55134778+sean-brydon@users.noreply.github.com>
Co-authored-by: Bailey Pumfleet <bailey@pumfleet.co.uk>
2025-02-15 10:06:28 +00:00
Benny JooandAnik Dhabal Babu 5c6f52f1d4 perf: separate client vs server code from insights layout (#19285)
* add UpgradeTipWrapper

* refactor insights/layout.tsx

---------

Co-authored-by: Anik Dhabal Babu <81948346+anikdhabal@users.noreply.github.com>
2025-02-15 06:43:37 -03:00
Carina WollendorferandCarinaWolli 0e9e3e5012 add ireland country code (#19117)
Co-authored-by: CarinaWolli <wollencarina@gmail.com>
2025-02-15 06:28:44 -03:00
5d709cf63c feat: v3 of UI components (#19136)
* ui playground

* add types to ui

* push avatar ignore ts and eslint errors

* feat: V3 UI avatar  (#18997)

* avatar playground

* add overflow-hidden back for loading indicator

* update lock

* feat: v3/badge  (#18999)

* badge intro

* fix text on small badge

* add dark mode warning

* feat: v3/button (#19014)

* TOC

* wip buttons

* shadows

* secondary

* semantic colours

* minimal buttons

* update disabled states

* checkbox

* dropdown v3

* load icons

* fix design sections

* fix icon gap

* fix

* remove client component from rsc

* use peer as avatar

* gif

* fix button gap - dropdown iocn

* support start icon in dropdowns

* add alert demo + v3 component + darken semantic text

* base inputs and text field

* wip input

* input field addon/suffix

* toast page

* wip select

* match designs for input and select rounded

* fix

* fix select isloading transform

* fix multi icons transition rotation

* fix group heading

* range slider demo + range slider

* range slider popover design

* v3 dialog

* fix slider thumb size

* wrap in suspense for useSearchParam difference in next14+

* base of tabs + horizontal tabs

* fix select sizing to match input 36px

* fix dark mode hover on button

* target domState class for light/dark so we work on portal elements

* fix default bg on popover

* lightmode toasts + eleveation token

* empty screen

* intro to split button concept

* mass colour updates

* intro to themes

* remove i18n from label with name

* bouncy buttons

* feat: small select

* nav item dumb component

* full demo

* settings demo

* fix tabs

* fix mt

* fix dropdown feedback from loom

* alert fixes mentioned in loom

* push font-cal

* move to fumadocs

* fix avatar

* colors table

* add typeography

* icon + spacing guide

* add border radius and shadow tables

* fix colours and border radius

* remove prose undline via fumas fork

* fix icon buttons sizes

* button group component

* fix horizontal tabs

* tab fixes

* switches

* pagination component

* show toasts components raw

* sync with airtable

* add use client

* 10px on input again

* 10px in select also

* fix input height

* fix files merge

* fix loading state for icon buttons

* fix button fab

* Enable addon to now overflow to next line in DS

* use cal font for dialog text

* add avatar square variant

* fix select padding and menu size

* fix type errors

* fix type errors

* add switch small size and fix type errors

* fix ref types on input

* update web styles

* remove addonFilled to fix type errors

* push dialog fixes

* fix checkbox display

* remove prose from alert examples

* remove prose from all our component examples

* badge rounded-lg on lg size

* update colors

* force w/h on icon buttons instead of inheriting

* remove border-focus

* remove border-focus from tailwind config

* update tokens to match new colours

* add new border subtle tokens and add to toasts

* fix lg button padding

* fix and drastically improve rtl rests

* multi select use badges

* use badge design for select pills

* fix avatar alignment

* fix tests and remove redudant ones

* fix tests and remove redudant ones

* update atoms globals css

* extract tokens.css

* extract app.css

* force flex for atoms

* add @calcom/ui/css

* revert ui playground styles abstraction

* fix input focus states

* fix focus states for buttons

* feat: v3/app work (#19233)

* globals.css for app + event types listing search

* few app wide NITS

* fix select foucs within styling

* fix formbuilder switch styles

* fix disabled state of nested inputs

* workflow fixes

* webhook form fixes

* i18n on tabs info

* booking filters + tab

* fix filters spacing

* make first item so we get correct border radius if not default

* round radio group in create event types + make button small

* profile page

* update editor br

* button nits in existing places in the app

* fix timezone select and multilist in guest form

* fix text area on public booking page

* size small event types create

* margin on routing filter

* filters improvments

* routing insights fixes

* fix date filter range

* ooo fixes

* fix teams/members bulk actions

* create team UI

* i18n in useTabs instead of in tab component now

* Add event type setup border to availability

* fix bulk actions on org members table

* onboarding fixes

* fix input types with ref stripe comparision

* i18n fixes for platform

* update globals of atoms

* fix form builder firstname/lastname switch + correct footer useage

* fix select

* Revert "add @calcom/ui/css"

This reverts commit 0dd8f9012907a278cfede4a98f289cb0744c9244.

* revert tokens css

* Revert "extract app.css"

This reverts commit 10b998604816ad3310c24b36a02a638dabc5be24.

* linear nits

* workflow dropdown

* fix page theme heading sizes to match cards

* fix stepper for team creation

* adjust margin to FilterSearchField

* fix ooo icon

* fix booker and dark mode due to darkgray 50

* more dark mode fixes

* add size prop

---------

Co-authored-by: Eunjae Lee <hey@eunjae.dev>
Co-authored-by: Morgan Vernay <morgan@cal.com>

* remove ui-playground

* fix grow missing from merge

* add search icon data-test-id back to search

* fix FormAction style

* fix datatestid for apps and tabs

* change selector for team invitation e2e

* fix use data-testid from item instaed of using names

* rename upper case O

* fix unit tests data-testid

* fix unit tests data-testid

* more data-testid changes

* add data-testid to apps tab

* data-testid to installed appPage

* fix embed tests

* fix filter-popover-trigger

* use text-error and use dataId for locator

* more e2e improvment

* pass in single testId as button is now duplicate

* show field-error instead

* add test to eventtype tabs

* Add css vars to embed too\

* add scrollbar and change dialog overlay colour

* fix type

* use attribute instead of class for tab detection

* await promise

* use new tokens for sprite generation

* add correct testing Ids to e2e instead of button:text

* use testIds for creation of orgs

* Webhook receiver wait for 10 seconds

---------

Co-authored-by: Eunjae Lee <hey@eunjae.dev>
Co-authored-by: Morgan Vernay <morgan@cal.com>
Co-authored-by: Hariom <hariombalhara@gmail.com>
Co-authored-by: Joe Au-Yeung <j.auyeung419@gmail.com>
Co-authored-by: Joe Au-Yeung <65426560+joeauyeung@users.noreply.github.com>
2025-02-14 16:31:21 -05:00
MorganandBailey Pumfleet 0f67faeef3 chore: calendars controller v2 docs (#19291)
Co-authored-by: Bailey Pumfleet <bailey@pumfleet.co.uk>
2025-02-14 17:54:23 +00:00
1ff4f557f6 fix: flaky test (#19294)
Post release / release (push) Canceled after 0s
* fix: flaky test

* fix another test

* update

---------

Co-authored-by: Eunjae Lee <hey@eunjae.dev>
Co-authored-by: unknown <adhabal2002@gmail.com>
2025-02-14 16:25:54 +00:00
GitHub Actions 7e2c0bd29e chore: release v4.9.13 2025-02-14 16:25:10 +00:00
Alex van Andel 5b59cf9d9c revert: Reapply "fix: Multiple rr-hosts combine to create erroneous availabil… (#19263)
* Reapply "fix: Multiple rr-hosts combine to create erroneous availability (#18772)"

This reverts commit 5dbc6d9ca6.

* Only thing left is a diff to show which slots are removed

* Add logging around time slot results

* Setup logging through axiom

* .... forgot

* fix: type errors

* Only log when there are differences

* Updated from old which had a failing test to new logic
2025-02-14 12:34:56 -03:00
Lauris Skraucis d5420eda00 chore: disable v2 booking seats safe parse error logs (#19292) 2025-02-14 10:59:10 +00:00
c17ac67b3f feat: add CSAT to V2 bookings return (#19278)
* init

* test: v2 bookings returns rating

---------

Co-authored-by: supalarry <laurisskraucis@gmail.com>
Co-authored-by: Lauris Skraucis <lauris.skraucis@gmail.com>
2025-02-14 09:47:54 +00:00
VijayandPeer Richelsen b2763a6274 fix: Default people filter in bookings list for admin (#18035)
* default people filter for admin

* chore

* type check

* added test case

* made test concise to reduce flakiness

* add timeout to wait for second get response before counting

* update timeout

---------

Co-authored-by: Peer Richelsen <peeroke@gmail.com>
2025-02-14 10:08:57 +01:00
Morgan 08b6f60407 fix: missing await router controller (#19276) 2025-02-13 21:38:43 +00:00
466b3e4c08 fix: Salesforce - if no contact throw Error (#19271)
* Throw error if no contact is passed to createEvent

* chore: update error message

* chore

---------

Co-authored-by: Udit Takkar <udit222001@gmail.com>
Co-authored-by: Udit Takkar <53316345+Udit-takkar@users.noreply.github.com>
2025-02-13 16:01:46 -05:00
473 changed files with 23760 additions and 15474 deletions
+6
View File
@@ -388,6 +388,12 @@ BLACKLISTED_GUEST_EMAILS=
NEXT_PUBLIC_VAPID_PUBLIC_KEY=
VAPID_PRIVATE_KEY=
# Mintlify chat api
# Power AI chat in for docs
NEXT_PUBLIC_MINTLIFY_CHAT_API_KEY=
NEXT_PUBLIC_CHAT_API_URL=
NEXT_PUBLIC_DOCS_URL=
# 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=
+2
View File
@@ -0,0 +1,2 @@
undecided:
- "@calcom/prisma"
View File
+6
View File
@@ -0,0 +1,6 @@
undecided:
- "@calcom/app-store-cli"
- "@calcom/platform-constants"
- "@calcom/platform-enums"
- "@calcom/platform-types"
- "@calcom/platform-utils"
View File
View File
+8
View File
@@ -0,0 +1,8 @@
undecided:
- calcom-monorepo
- "@calcom/app-store-cli"
- "@calcom/platform-constants"
- "@calcom/platform-enums"
- "@calcom/platform-types"
- "@calcom/platform-utils"
- "@calcom/prisma"
+4 -2
View File
@@ -2,7 +2,7 @@ import type { NextApiRequest } from "next";
import { HttpError } from "@calcom/lib/http-error";
import { defaultResponder } from "@calcom/lib/server";
import prisma from "@calcom/prisma";
import { UserCreationService } from "@calcom/lib/server/service/userCreationService";
import { CreationSource } from "@calcom/prisma/enums";
import { schemaUserCreateBodyParams } from "~/lib/validations/user";
@@ -93,7 +93,9 @@ async function postHandler(req: NextApiRequest) {
// If user is not ADMIN, return unauthorized.
if (!isSystemWideAdmin) throw new HttpError({ statusCode: 401, message: "You are not authorized" });
const data = await schemaUserCreateBodyParams.parseAsync(req.body);
const user = await prisma.user.create({ data: { ...data, creationSource: CreationSource.API_V1 } });
const user = await UserCreationService.createUser({
data: { ...data, creationSource: CreationSource.API_V1 },
});
req.statusCode = 201;
return { user };
}
+134
View File
@@ -0,0 +1,134 @@
import prismock from "../../../../../../tests/libs/__mocks__/prisma";
import type { Request, Response } from "express";
import type { NextApiRequest, NextApiResponse } from "next";
import { createMocks } from "node-mocks-http";
import { describe, test, expect, vi } from "vitest";
import handler from "../../../pages/api/users/_post";
type CustomNextApiRequest = NextApiRequest & Request;
type CustomNextApiResponse = NextApiResponse & Response;
vi.mock("@calcom/lib/server/i18n", () => {
return {
getTranslation: (key: string) => {
return () => key;
},
};
});
vi.stubEnv("CALCOM_LICENSE_KEY", undefined);
describe("POST /api/users", () => {
test("should throw 401 if not system-wide admin", async () => {
const { req, res } = createMocks<CustomNextApiRequest, CustomNextApiResponse>({
method: "POST",
body: {
email: "test@example.com",
username: "test",
},
});
req.isSystemWideAdmin = false;
await handler(req, res);
expect(res.statusCode).toBe(401);
});
test("should throw a 400 if no email is provided", async () => {
const { req, res } = createMocks<CustomNextApiRequest, CustomNextApiResponse>({
method: "POST",
body: {
username: "test",
},
});
req.isSystemWideAdmin = true;
await handler(req, res);
expect(res.statusCode).toBe(400);
});
test("should throw a 400 if no username is provided", async () => {
const { req, res } = createMocks<CustomNextApiRequest, CustomNextApiResponse>({
method: "POST",
body: {
email: "test@example.com",
},
});
req.isSystemWideAdmin = true;
await handler(req, res);
expect(res.statusCode).toBe(400);
});
test("should create user successfully", async () => {
const { req, res } = createMocks<CustomNextApiRequest, CustomNextApiResponse>({
method: "POST",
body: {
email: "test@example.com",
username: "test",
},
prisma: prismock,
});
req.isSystemWideAdmin = true;
await handler(req, res);
expect(res.statusCode).toBe(200);
const userQuery = await prismock.user.findFirst({
where: {
email: "test@example.com",
},
});
expect(userQuery).toEqual(
expect.objectContaining({
email: "test@example.com",
username: "test",
locked: false,
organizationId: null,
})
);
});
test("should auto lock user if email is in watchlist", async () => {
const { req, res } = createMocks<CustomNextApiRequest, CustomNextApiResponse>({
method: "POST",
body: {
email: "test@example.com",
username: "test",
},
prisma: prismock,
});
req.isSystemWideAdmin = true;
await prismock.watchlist.create({
data: {
type: "EMAIL",
value: "test@example.com",
severity: "CRITICAL",
createdById: 1,
},
});
await handler(req, res);
expect(res.statusCode).toBe(200);
const userQuery = await prismock.user.findFirst({
where: {
email: "test@example.com",
},
});
expect(userQuery).toEqual(
expect.objectContaining({
email: "test@example.com",
username: "test",
locked: true,
organizationId: null,
})
);
});
});
+2 -2
View File
@@ -8,13 +8,13 @@ used in production, if you (and any entity that you represent) have agreed to,
and are in compliance with, the Cal.com Subscription Terms available
at https://cal.com/terms, or other agreements governing
the use of the Software, as mutually agreed by you and Cal.com, Inc ("Cal.com"),
and otherwise have a valid Cal.com Enterprise Edition subscription ("Commercial Subscription")
and otherwise have a valid Cal.com Commercial License ("Commercial License")
for the correct number of hosts as defined in the "Commercial Terms ("Hosts"). Subject to the foregoing sentence,
you are free to modify this Software and publish patches to the Software. You agree
that Cal.com and/or its licensors (as applicable) retain all right, title and interest in
and to all such modifications and/or patches, and all such modifications and/or
patches may only be used, copied, modified, displayed, distributed, or otherwise
exploited with a valid Commercial Subscription for the correct number of hosts.
exploited with a valid Commercial License for the correct number of hosts.
Notwithstanding the foregoing, you may copy and modify the Software for development
and testing purposes, without requiring a subscription. You agree that Cal.com and/or
its licensors (as applicable) retain all right, title and interest in and to all such
+5 -5
View File
@@ -4,15 +4,15 @@
<img src="https://user-images.githubusercontent.com/8019099/133430653-24422d2a-3c8d-4052-9ad6-0580597151ee.png" alt="Logo">
</a>
<a href="https://console.cal.com/">Get a License Key</a>
<a href="https://go.cal.com/get-license">Get a License Key</a>
</div>
# Enterprise Edition of API
# Commercial License of API
Welcome to the Enterprise Edition ("/ee") of the Cal.com API.
Welcome to the Commercial License of the Cal.com API.
Our philosophy is simple, all "Singleplayer APIs" are open-source under AGPLv3. All "Multiplayer APIs" are under a commercial license.
The [/ee](https://github.com/calcom/cal.com/tree/main/apps/api/v2/ee) subfolder is the place for all the **Enterprise Edition** features from our [hosted](https://cal.com/pricing) plan and enterprise-grade features for [Enterprise](https://cal.com/enterprise) such as SSO, SAML, OIDC, SCIM, SIEM and much more or [Platform](https://cal.com/platform) plan to build a marketplace.
The [/ee](https://github.com/calcom/cal.com/tree/main/apps/api/v2/ee) subfolder is the place for all the **Commercial License** features from our [hosted](https://cal.com/pricing) plan.
> _❗ WARNING: This repository is copyrighted (unlike our [main repo](https://github.com/calcom/cal.com)). You are not allowed to use this code to host your own version of app.cal.com without obtaining a proper [license](https://console.cal.com/) first❗_
> _❗ WARNING: This repository is copyrighted (unlike our [main repo](https://github.com/calcom/cal.com)). You are not allowed to use this code to host your own version of app.cal.com without obtaining a proper [license](https://go.cal.com/get-license) first❗_
@@ -167,6 +167,7 @@ describe("Bookings Endpoints 2024-08-13", () => {
timeZone: "Europe/Rome",
},
},
rating: 10,
});
app = moduleRef.createNestApplication();
@@ -552,6 +553,30 @@ describe("Bookings Endpoints 2024-08-13", () => {
});
});
it("should should get a booking with rating", async () => {
return request(app.getHttpServer())
.get(`/v2/bookings/${bookingInThePast.uid}`)
.set(CAL_API_VERSION_HEADER, VERSION_2024_08_13)
.expect(200)
.then(async (response) => {
const responseBody: GetBookingOutput_2024_08_13 = response.body;
expect(responseBody.status).toEqual(SUCCESS_STATUS);
expect(responseBody.data).toBeDefined();
expect(responseDataIsBooking(responseBody.data)).toBe(true);
if (responseDataIsBooking(responseBody.data)) {
const data: BookingOutput_2024_08_13 = responseBody.data;
expect(data.id).toEqual(bookingInThePast.id);
expect(data.uid).toEqual(bookingInThePast.uid);
expect(data.rating).toEqual(bookingInThePast.rating);
} else {
throw new Error(
"Invalid response data - expected booking but received array of possibily recurring bookings"
);
}
});
});
it("should should get 1 recurrence of a recurring booking", async () => {
const recurrenceUid = createdRecurringBooking[0].uid;
return request(app.getHttpServer())
@@ -133,6 +133,7 @@ export class OutputBookingsService_2024_08_13 {
absentHost: !!databaseBooking.noShowHost,
createdAt: databaseBooking.createdAt,
updatedAt: databaseBooking.updatedAt,
rating: databaseBooking.rating,
};
const bookingTransformed = plainToClass(BookingOutput_2024_08_13, booking, { strategy: "excludeAll" });
@@ -227,6 +228,7 @@ export class OutputBookingsService_2024_08_13 {
bookingFieldsResponses: databaseBooking.responses,
createdAt: databaseBooking.createdAt,
updatedAt: databaseBooking.updatedAt,
rating: databaseBooking.rating,
};
const bookingTransformed = plainToClass(RecurringBookingOutput_2024_08_13, booking, {
@@ -274,6 +276,7 @@ export class OutputBookingsService_2024_08_13 {
absentHost: !!databaseBooking.noShowHost,
createdAt: databaseBooking.createdAt,
updatedAt: databaseBooking.updatedAt,
rating: databaseBooking.rating,
};
const parsed = plainToClass(GetSeatedBookingOutput_2024_08_13, booking, { strategy: "excludeAll" });
@@ -283,7 +286,8 @@ export class OutputBookingsService_2024_08_13 {
const { responses } = safeParse(
seatedBookingDataSchema,
attendee.bookingSeat?.data,
defaultSeatedBookingData
defaultSeatedBookingData,
false
);
const attendeeData = {
@@ -300,7 +304,8 @@ export class OutputBookingsService_2024_08_13 {
attendeeParsed.metadata = safeParse(
seatedBookingMetadataSchema,
attendee.bookingSeat?.metadata,
defaultSeatedBookingMetadata
defaultSeatedBookingMetadata,
false
);
// note(Lauris): as of now email is not returned for privacy
delete attendeeParsed.bookingFieldsResponses.email;
@@ -380,6 +385,7 @@ export class OutputBookingsService_2024_08_13 {
absentHost: !!databaseBooking.noShowHost,
createdAt: databaseBooking.createdAt,
updatedAt: databaseBooking.updatedAt,
rating: databaseBooking.rating,
};
const parsed = plainToClass(GetRecurringSeatedBookingOutput_2024_08_13, booking, {
@@ -391,7 +397,8 @@ export class OutputBookingsService_2024_08_13 {
const { responses } = safeParse(
seatedBookingDataSchema,
attendee.bookingSeat?.data,
defaultSeatedBookingData
defaultSeatedBookingData,
false
);
const attendeeData = {
@@ -408,7 +415,8 @@ export class OutputBookingsService_2024_08_13 {
attendeeParsed.metadata = safeParse(
seatedBookingMetadataSchema,
attendee.bookingSeat?.metadata,
defaultSeatedBookingMetadata
defaultSeatedBookingMetadata,
false
);
// note(Lauris): as of now email is not returned for privacy
delete attendeeParsed.bookingFieldsResponses.email;
@@ -34,7 +34,7 @@ import {
Post,
Body,
} from "@nestjs/common";
import { ApiOperation, ApiTags as DocsTags } from "@nestjs/swagger";
import { ApiOperation, ApiParam, ApiTags as DocsTags } from "@nestjs/swagger";
import { User } from "@prisma/client";
import { plainToClass } from "class-transformer";
import { Request } from "express";
@@ -123,10 +123,15 @@ export class CalendarsController {
};
}
@ApiParam({
enum: [OFFICE_365_CALENDAR, GOOGLE_CALENDAR],
type: String,
name: "calendar",
})
@UseGuards(ApiAuthGuard)
@Get("/:calendar/connect")
@HttpCode(HttpStatus.OK)
@ApiOperation({ summary: "Get connect URL" })
@ApiOperation({ summary: "Get oAuth connect URL" })
async redirect(
@Req() req: Request,
@Headers("Authorization") authorization: string,
@@ -146,10 +151,15 @@ export class CalendarsController {
}
}
@ApiParam({
enum: [OFFICE_365_CALENDAR, GOOGLE_CALENDAR],
type: String,
name: "calendar",
})
@Get("/:calendar/save")
@HttpCode(HttpStatus.OK)
@Redirect(undefined, 301)
@ApiOperation({ summary: "Save a calendar" })
@ApiOperation({ summary: "Save an oAuth calendar credentials" })
async save(
@Query("state") state: string,
@Query("code") code: string,
@@ -177,6 +187,11 @@ export class CalendarsController {
}
}
@ApiParam({
enum: [APPLE_CALENDAR],
type: String,
name: "calendar",
})
@UseGuards(ApiAuthGuard)
@Post("/:calendar/credentials")
@ApiOperation({ summary: "Sync credentials" })
@@ -198,6 +213,11 @@ export class CalendarsController {
}
}
@ApiParam({
enum: [APPLE_CALENDAR, GOOGLE_CALENDAR, OFFICE_365_CALENDAR],
type: String,
name: "calendar",
})
@Get("/:calendar/check")
@HttpCode(HttpStatus.OK)
@UseGuards(ApiAuthGuard, PermissionsGuard)
@@ -219,6 +239,11 @@ export class CalendarsController {
}
}
@ApiParam({
enum: [APPLE_CALENDAR, GOOGLE_CALENDAR, OFFICE_365_CALENDAR],
type: String,
name: "calendar",
})
@UseGuards(ApiAuthGuard)
@Post("/:calendar/disconnect")
@HttpCode(HttpStatus.OK)
+15 -8
View File
@@ -3,20 +3,27 @@ import { ZodSchema } from "zod";
const logger = new Logger("safeParse");
export function safeParse<T>(schema: ZodSchema<T>, value: unknown, defaultValue: T): T {
export function safeParse<T>(
schema: ZodSchema<T>,
value: unknown,
defaultValue: T,
logError = true
): T {
const result = schema.safeParse(value);
if (result.success) {
return result.data;
} else {
const errorStack = new Error().stack;
logger.error(
`Zod parsing failed.\n` +
`1. Schema: ${schema.description || "UnnamedSchema"}\n` +
`2. Input: ${JSON.stringify(value, null, 2)}\n` +
`3. Zod Error: ${result.error}\n` +
`4. Call Stack: ${errorStack}`
);
if (logError) {
logger.error(
`Zod parsing failed.\n` +
`1. Schema: ${schema.description || "UnnamedSchema"}\n` +
`2. Input: ${JSON.stringify(value, null, 2)}\n` +
`3. Zod Error: ${result.error}\n` +
`4. Call Stack: ${errorStack}`
);
}
return defaultValue;
}
@@ -65,7 +65,11 @@ export class RouterController {
const pathNameParams = routingUrl.pathname.split("/");
const eventTypeSlug = pathNameParams[pathNameParams.length - 1];
const teamId = Number(routingSearchParams.get("cal.teamId"));
const eventTypeData = this.teamsEventTypesRepository.getTeamEventTypeBySlug(teamId, eventTypeSlug, 3);
const eventTypeData = await this.teamsEventTypesRepository.getTeamEventTypeBySlug(
teamId,
eventTypeSlug,
3
);
// get the salesforce record owner email for the email given as a form response.
const {
+48 -4
View File
@@ -4063,7 +4063,7 @@
"/v2/calendars/{calendar}/connect": {
"get": {
"operationId": "CalendarsController_redirect",
"summary": "Get connect URL",
"summary": "Get oAuth connect URL",
"parameters": [
{
"name": "Authorization",
@@ -4078,6 +4078,10 @@
"required": true,
"in": "path",
"schema": {
"enum": [
"office365",
"google"
],
"type": "string"
}
}
@@ -4102,7 +4106,7 @@
"/v2/calendars/{calendar}/save": {
"get": {
"operationId": "CalendarsController_save",
"summary": "Save a calendar",
"summary": "Save an oAuth calendar credentials",
"parameters": [
{
"name": "state",
@@ -4125,6 +4129,10 @@
"required": true,
"in": "path",
"schema": {
"enum": [
"office365",
"google"
],
"type": "string"
}
}
@@ -4149,6 +4157,9 @@
"required": true,
"in": "path",
"schema": {
"enum": [
"apple"
],
"type": "string"
}
}
@@ -4173,6 +4184,11 @@
"required": true,
"in": "path",
"schema": {
"enum": [
"apple",
"google",
"office365"
],
"type": "string"
}
}
@@ -4204,6 +4220,11 @@
"required": true,
"in": "path",
"schema": {
"enum": [
"apple",
"google",
"office365"
],
"type": "string"
}
}
@@ -12698,8 +12719,7 @@
}
},
"required": [
"callId",
"agentId"
"callId"
]
},
"CreatePhoneCallOutput": {
@@ -15376,6 +15396,10 @@
"key": "value"
}
},
"rating": {
"type": "number",
"example": 4
},
"attendees": {
"type": "array",
"items": {
@@ -15524,6 +15548,10 @@
"key": "value"
}
},
"rating": {
"type": "number",
"example": 4
},
"attendees": {
"type": "array",
"items": {
@@ -15775,6 +15803,10 @@
"key": "value"
}
},
"rating": {
"type": "number",
"example": 4
},
"seatUid": {
"type": "string",
"example": "3be561a9-31f1-4b8e-aefc-9d9a085f0dd1"
@@ -15910,6 +15942,10 @@
"key": "value"
}
},
"rating": {
"type": "number",
"example": 4
},
"seatUid": {
"type": "string",
"example": "3be561a9-31f1-4b8e-aefc-9d9a085f0dd1"
@@ -16090,6 +16126,10 @@
"key": "value"
}
},
"rating": {
"type": "number",
"example": 4
},
"attendees": {
"type": "array",
"items": {
@@ -16220,6 +16260,10 @@
"key": "value"
}
},
"rating": {
"type": "number",
"example": 4
},
"attendees": {
"type": "array",
"items": {
+1 -1
View File
@@ -230,7 +230,7 @@
--cal-text-info: hsla(228, 56%, 33%, 1);
--cal-text-success: hsla(133, 34%, 24%, 1);
--cal-text-attention: hsla(16, 62%, 28%, 1);
--cal-text-error: hsla(2, 55%, 30%, 1);
--cal-text-error: hsla(0, 63%, 31%, 1);
/* Brand shinanigans
-> These will be computed for the users theme at runtime.
-41
View File
@@ -1,41 +0,0 @@
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
# dependencies
/node_modules
/.pnp
.pnp.*
.yarn/*
!.yarn/patches
!.yarn/plugins
!.yarn/releases
!.yarn/versions
# testing
/coverage
# next.js
/.next/
/out/
# production
/build
# misc
.DS_Store
*.pem
# debug
npm-debug.log*
yarn-debug.log*
yarn-error.log*
.pnpm-debug.log*
# env files (can opt-in for committing if needed)
.env*
# vercel
.vercel
# typescript
*.tsbuildinfo
next-env.d.ts
-36
View File
@@ -1,36 +0,0 @@
This is a [Next.js](https://nextjs.org) project bootstrapped with [`create-next-app`](https://nextjs.org/docs/app/api-reference/cli/create-next-app).
## Getting Started
First, run the development server:
```bash
npm run dev
# or
yarn dev
# or
pnpm dev
# or
bun dev
```
Open [http://localhost:3000](http://localhost:3000) with your browser to see the result.
You can start editing the page by modifying `app/page.tsx`. The page auto-updates as you edit the file.
This project uses [`next/font`](https://nextjs.org/docs/app/building-your-application/optimizing/fonts) to automatically optimize and load [Geist](https://vercel.com/font), a new font family for Vercel.
## Learn More
To learn more about Next.js, take a look at the following resources:
- [Next.js Documentation](https://nextjs.org/docs) - learn about Next.js features and API.
- [Learn Next.js](https://nextjs.org/learn) - an interactive Next.js tutorial.
You can check out [the Next.js GitHub repository](https://github.com/vercel/next.js) - your feedback and contributions are welcome!
## Deploy on Vercel
The easiest way to deploy your Next.js app is to use the [Vercel Platform](https://vercel.com/new?utm_medium=default-template&filter=next.js&utm_source=create-next-app&utm_campaign=create-next-app-readme) from the creators of Next.js.
Check out our [Next.js deployment documentation](https://nextjs.org/docs/app/building-your-application/deploying) for more details.
Binary file not shown.

Before

Width:  |  Height:  |  Size: 25 KiB

-485
View File
@@ -1,485 +0,0 @@
@tailwind base;
@tailwind components;
@tailwind utilities;
/**
* Add css variables here as well for light mode in addition to tailwind.config to avoid FOUC
*/
:root {
/* background */
--cal-bg-emphasis: hsla(220,13%,91%,1);
--cal-bg: hsla(0,0%,100%,1);
--cal-bg-subtle: hsla(220, 14%, 96%,1);
--cal-bg-muted: hsla(210,20%,98%,1);
--cal-bg-inverted: hsla(0,0%,6%,1);
/* background -> components*/
--cal-bg-info: hsla(218,83%,98%,1);
--cal-bg-success: hsla(134,76%,94%,1);
--cal-bg-attention: hsla(37, 86%, 92%, 1);
--cal-bg-error: hsla(3,66%,93%,1);
--cal-bg-dark-error: hsla(2, 55%, 30%, 1);
/* Borders */
--cal-border-emphasis: hsla(218, 11%, 65%, 1);
--cal-border: hsla(216, 12%, 84%, 1);
--cal-border-subtle: hsla(220, 13%, 91%, 1);
--cal-border-booker: #e5e7eb;
--cal-border-muted: hsla(220, 14%, 96%, 1);
--cal-border-error: hsla(4, 63%, 41%, 1);
--cal-border-focus: hsla(0, 0%, 10%, 1);
/* Content/Text */
--cal-text-emphasis: hsla(217, 19%, 27%, 1);
--cal-text: hsla(217, 19%, 27%, 1);
--cal-text-subtle: hsla(220, 9%, 46%, 1);
--cal-text-muted: hsla(218, 11%, 65%, 1);
--cal-text-inverted: hsla(0, 0%, 100%, 1);
/* Content/Text -> components */
--cal-text-info: hsla(228, 56%, 33%, 1);
--cal-text-success: hsla(133, 34%, 24%, 1);
--cal-text-attention: hsla(16, 62%, 28%, 1);
--cal-text-error: hsla(2, 55%, 30%, 1);
/* Brand shinanigans
-> These will be computed for the users theme at runtime.
*/
--cal-brand: hsla(221, 39%, 11%, 1);
--cal-brand-emphasis: hsla(0, 0%, 6%, 1);
--cal-brand-text: hsla(0, 0%, 100%, 1);
}
.dark {
/* background */
--cal-bg-emphasis: hsla(0, 0%, 25%, 1);
--cal-bg: hsla(0, 0%, 10%, 1);
--cal-bg-subtle: hsla(0, 0%, 18%, 1);
--cal-bg-muted: hsla(0, 0%, 12%, 1);
--cal-bg-inverted: hsla(220, 14%, 96%, 1);
/* background -> components*/
--cal-bg-info: hsla(228, 56%, 33%, 1);
--cal-bg-success: hsla(133, 34%, 24%, 1);
--cal-bg-attention: hsla(16, 62%, 28%, 1);
--cal-bg-error: hsla(2, 55%, 30%, 1);
--cal-bg-dark-error: hsla(2, 55%, 30%, 1);
/* Borders */
--cal-border-emphasis: hsla(0, 0%, 46%, 1);
--cal-border: hsla(0, 0%, 34%, 1);
--cal-border-subtle: hsla(0, 0%, 22%, 1);
--cal-border-booker: hsla(0, 0%, 22%, 1);
--cal-border-muted: hsla(0, 0%, 18%, 1);
--cal-border-error: hsla(4, 63%, 41%, 1);
--cal-border-focus: hsla(0, 0%, 100%, 1);
/* Content/Text */
--cal-text-emphasis: hsla(240, 20%, 99%, 1);
--cal-text: hsla(0, 0%, 84%, 1);
--cal-text-subtle: hsla(0, 0%, 65%, 1);
--cal-text-muted: hsla(0, 0%, 34%, 1);
--cal-text-inverted: hsla(0, 0%, 10%, 1);
/* Content/Text -> components */
--cal-text-info: hsla(218, 83%, 93%, 1);
--cal-text-success: hsla(134, 76%, 94%, 1);
--cal-text-attention: hsla(37, 86%, 92%, 1);
--cal-text-error: hsla(3, 66%, 93%, 1);
/* Brand shenanigans
-> These will be computed for the users theme at runtime.
*/
--cal-brand: hsla(0, 0%, 100%, 1);
--cal-brand-emphasis: hsla(218, 11%, 65%, 1);
--cal-brand-text: hsla(0, 0%, 0%,1);
}
@layer base {
* {
@apply border-default
}
}
::-moz-selection {
color: var(--cal-brand-text);
background: var(--cal-brand);
}
::selection {
color: var(--cal-brand-text);
background: var(--cal-brand);
}
body  {
text-rendering: optimizeLegibility;
-webkit-font-smoothing: antialiased;
}
/*
Desktop App specific CSS
https://docs.todesktop.com/
*/
html.todesktop-platform-win32 .todesktop\:\!bg-transparent{
background: inherit !important;
}
/* disable user selection on buttons, links and images on desktop app */
html.todesktop button,
html.todesktop a,
html.todesktop img,
html.todesktop header {
-webkit-touch-callout: none;
-webkit-user-select: none;
-khtml-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
cursor: default !important;
}
html.todesktop,
html.todesktop div {
cursor: default !important;
}
/* make header draggable on desktop app */
html.todesktop header {
-webkit-app-region: drag;
}
html.todesktop header button,
html.todesktop header a {
-webkit-app-region: no-drag;
}
html.todesktop-platform-darwin body, html.todesktop-platform-darwin aside {
background: transparent !important;
}
html.todesktop-platform-darwin.dark main.bg-default {
background: rgba(0, 0, 0, 0.6) !important;
}
html.todesktop-platform-darwin.light main.bg-default {
background: rgba(255, 255, 255, 0.8) !important;
}
html.todesktop.light {
--cal-bg-emphasis: hsla(0, 0%, 11%, 0.1);
}
html.todesktop.dark {
--cal-bg-emphasis: hsla(220, 2%, 26%, 0.3);
}
/*
Adds Utility to hide scrollbar to tailwind
https://github.com/tailwindlabs/tailwindcss/discussions/2394
https://github.com/tailwindlabs/tailwindcss/pull/5732
*/
@layer utilities {
/* Chrome, Safari and Opera */
.no-scrollbar::-webkit-scrollbar {
display: none;
}
.no-scrollbar {
-ms-overflow-style: none; /* IE and Edge */
scrollbar-width: none; /* Firefox */
}
}
/*
* Override the default tailwindcss-forms styling (default is: 'colors.blue.600')
* @see: https://github.com/tailwindlabs/tailwindcss-forms/issues/14#issuecomment-1005376006
*/
[type="text"]:focus,
[type="email"]:focus,
[type="url"]:focus,
[type="password"]:focus,
[type="number"]:focus,
[type="date"]:focus,
[type="datetime-local"]:focus,
[type="month"]:focus,
[type="search"]:focus,
[type="tel"]:focus,
[type="checkbox"]:focus,
[type="radio"]:focus,
[type="time"]:focus,
[type="week"]:focus,
[multiple]:focus,
textarea:focus,
select:focus {
--tw-ring-color: var(--brand-color);
border-color: var(--brand-color);
}
@layer components {
.scroll-bar {
@apply scrollbar-thin scrollbar-thumb-rounded-md dark:scrollbar-thumb-darkgray-300 scrollbar-thumb-gray-300 scrollbar-track-transparent;
}
}
/* TODO: avoid global specific css */
/* button[role="switch"][data-state="checked"] span {
transform: translateX(16px);
} */
@layer components {
/* slider */
.slider {
@apply relative flex h-4 w-40 select-none items-center;
}
.slider > .slider-track {
@apply relative h-1 flex-grow rounded-md bg-gray-400;
}
.slider .slider-range {
@apply absolute h-full rounded-full bg-gray-700;
}
.slider .slider-thumb {
@apply block h-3 w-3 cursor-pointer rounded-full bg-gray-700 transition-all;
}
.slider .slider-thumb:hover {
@apply bg-gray-600;
}
.slider .slider-thumb:focus {
box-shadow: 0 0 0 4px rgba(0, 0, 0, 0.2);
}
}
/* hide chat bubble on mobile */
@media only screen and (max-width: 768px) {
/* Intercom FAB*/
#launcher {
display: none !important;
}
/* Zendesk FAB*/
div[role="presentation"] > iframe {
display: none !important;
}
/* Helpscout FAB*/
.BeaconFabButtonFrame {
margin-left: -30px;
left: 50%;
bottom: 28px !important;
z-index: 1058 !important;
}
}
/* TODO: implement styling for react-multi-email */
/* !important to override react-dates */
.DateRangePickerInput__withBorder {
border: 0 !important;
}
.DateInput_input {
border: 1px solid #d1d5db !important;
border-radius: 2px !important;
font-size: inherit !important;
font-weight: inherit !important;
color: #000;
padding: 11px ​11px 9px !important;
line-height: 16px !important;
}
.DateInput_input__focused {
border: 2px solid #000 !important;
border-radius: 2px !important;
box-shadow: none !important;
padding: 10px ​10px 9px !important;
}
.DateRangePickerInput_arrow {
padding: 0px 10px;
}
.loader {
display: block;
width: 30px;
height: 30px;
margin: 60px auto;
position: relative;
border-width: 4px;
border-style: solid;
animation: loader 2s infinite ease;
}
.loader-inner {
vertical-align: top;
display: inline-block;
width: 100%;
animation: loader-inner 2s infinite ease-in;
}
.no-ring-inset {
--tw-ring-inset: unset;
}
@keyframes loader {
0% {
transform: rotate(0deg);
}
25% {
transform: rotate(180deg);
}
50% {
transform: rotate(180deg);
}
75% {
transform: rotate(360deg);
}
100% {
transform: rotate(360deg);
}
}
@keyframes loader-inner {
0% {
height: 0%;
}
25% {
height: 0%;
}
50% {
height: 100%;
}
75% {
height: 100%;
}
100% {
height: 0%;
}
}
.text-inverted-important {
color: white !important;
}
@layer utilities {
.transition-max-width {
-webkit-transition-property: max-width;
transition-property: max-width;
}
}
#timeZone input:focus {
box-shadow: none;
}
/* react-date-picker forces a border upon us, cast it away */
.react-date-picker__wrapper {
border: none !important;
}
.react-date-picker__inputGroup__input {
padding-top: 0;
padding-bottom: 0;
}
/* animations */
.slideInBottom {
animation-duration: 0.3s;
animation-fill-mode: both;
animation-name: slideInBottom;
}
@keyframes slideInBottom {
from {
opacity: 0;
transform: translateY(30%);
pointer-events: none;
}
to {
opacity: 1;
pointer-events: auto;
}
}
/* animations */
.slideInTop {
animation-duration: 0.3s;
animation-fill-mode: both;
animation-name: slideInTop;
}
@keyframes slideInTop {
from {
opacity: 0;
transform: translateY(-20%);
pointer-events: none;
}
to {
opacity: 1;
pointer-events: auto;
transform: translateY(0%);
}
}
.fadeIn {
animation-duration: 0.3s;
animation-fill-mode: both;
animation-name: fadeIn;
animation-timing-function: ease-in-out;
}
@keyframes fadeIn {
from {
opacity: 0;
}
to {
opacity: 1;
}
}
/**
* Makes sure h-screen works on mobile Safari. By default h-screen
* does not take into account the height of the address bar, causing
* weird behaviour when scrolling — sometimes the height will be correct
* and sometimes it won't, depending on whether the address bar is
* in 'collapsed' state or not.
* @see: https://benborgers.com/posts/tailwind-h-screen
*/
@supports (-webkit-touch-callout: none) {
.h-screen {
height: -webkit-fill-available;
}
}
::-webkit-search-cancel-button {
-webkit-appearance: none;
}
.react-tel-input .country-list .country:hover,
.react-tel-input .country-list .country.highlight {
@apply !bg-emphasis;
}
.react-tel-input .flag-dropdown .selected-flag,
.react-tel-input .flag-dropdown.open .selected-flag {
@apply !bg-default;
}
.react-tel-input .flag-dropdown {
@apply !border-r-default left-0.5 !border-y-0 !border-l-0;
}
.intercom-lightweight-app {
@apply z-40 !important;
}
-31
View File
@@ -1,31 +0,0 @@
import type { Metadata } from "next";
import { Geist, Geist_Mono } from "next/font/google";
import "./globals.css";
const geistSans = Geist({
variable: "--font-geist-sans",
subsets: ["latin"],
});
const geistMono = Geist_Mono({
variable: "--font-geist-mono",
subsets: ["latin"],
});
export const metadata: Metadata = {
title: "Create Next App",
description: "Generated by create next app",
};
export default function RootLayout({
children,
}: Readonly<{
children: React.ReactNode;
}>) {
return (
<html lang="en">
<body className={`${geistSans.variable} ${geistMono.variable} antialiased`}>{children}</body>
</html>
);
}
-5
View File
@@ -1,5 +0,0 @@
// import AvatarDemo from "./_components/AvatarDemo";
export default function Home() {
return <div className="p-4 font-[family-name:var(--font-geist-sans)]">{/* <AvatarDemo /> */}</div>;
}
-16
View File
@@ -1,16 +0,0 @@
import { dirname } from "path";
import { fileURLToPath } from "url";
import { FlatCompat } from "@eslint/eslintrc";
const __filename = fileURLToPath(import.meta.url);
const __dirname = dirname(__filename);
const compat = new FlatCompat({
baseDirectory: __dirname,
});
const eslintConfig = [
...compat.extends("next/core-web-vitals", "next/typescript"),
];
export default eslintConfig;
-7
View File
@@ -1,7 +0,0 @@
import type { NextConfig } from "next";
const nextConfig: NextConfig = {
/* config options here */
};
export default nextConfig;
-30
View File
@@ -1,30 +0,0 @@
{
"name": "ui-playground",
"version": "0.1.0",
"private": true,
"scripts": {
"dev": "next dev --turbopack --port=1337",
"build": "next build",
"start": "next start",
"lint": "next lint"
},
"dependencies": {
"@calcom/config": "*",
"@calcom/lib": "*",
"@calcom/ui": "*",
"next": "15.1.6",
"react": "^18.0.0",
"react-dom": "^18.0.0"
},
"devDependencies": {
"@eslint/eslintrc": "^3",
"@types/node": "^20",
"@types/react": "^18",
"@types/react-dom": "^18",
"eslint": "^9",
"eslint-config-next": "15.1.6",
"postcss": "^8",
"tailwindcss": "^3.4.1",
"typescript": "^5"
}
}
-8
View File
@@ -1,8 +0,0 @@
/** @type {import('postcss-load-config').Config} */
const config = {
plugins: {
tailwindcss: {},
},
};
export default config;
-8
View File
@@ -1,8 +0,0 @@
import base from "@calcom/config/tailwind-preset";
/** @type {import('tailwindcss').Config} */
module.exports = {
...base,
content: [...base.content],
plugins: [...base.plugins, require("tailwindcss-animate")],
};
-27
View File
@@ -1,27 +0,0 @@
{
"compilerOptions": {
"target": "ES2017",
"lib": ["dom", "dom.iterable", "esnext"],
"allowJs": true,
"skipLibCheck": true,
"strict": true,
"noEmit": true,
"esModuleInterop": true,
"module": "esnext",
"moduleResolution": "bundler",
"resolveJsonModule": true,
"isolatedModules": true,
"jsx": "preserve",
"incremental": true,
"plugins": [
{
"name": "next"
}
],
"paths": {
"@/*": ["./*"]
}
},
"include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"],
"exclude": ["node_modules"]
}
-62
View File
@@ -1,62 +0,0 @@
import { getBucket } from "abTest/utils";
import type { NextMiddleware, NextRequest } from "next/server";
import { NextResponse, URLPattern } from "next/server";
import { FUTURE_ROUTES_ENABLED_COOKIE_NAME, FUTURE_ROUTES_OVERRIDE_COOKIE_NAME } from "@calcom/lib/constants";
const ROUTES: [URLPattern, boolean][] = [
["/apps/:slug/setup", process.env.APP_ROUTER_APPS_SLUG_SETUP_ENABLED === "1"] as const,
["/team", process.env.APP_ROUTER_TEAM_ENABLED === "1"] as const,
].map(([pathname, enabled]) => [
new URLPattern({
pathname,
}),
enabled,
]);
export const abTestMiddlewareFactory =
(next: (req: NextRequest) => Promise<NextResponse<unknown>>): NextMiddleware =>
async (req: NextRequest) => {
const response = await next(req);
const { pathname } = req.nextUrl;
const override = req.cookies.has(FUTURE_ROUTES_OVERRIDE_COOKIE_NAME);
const route = ROUTES.find(([regExp]) => regExp.test(req.url)) ?? null;
const enabled = route !== null ? route[1] || override : false;
if (pathname.includes("future") || !enabled) {
return response;
}
const bucketValue = override ? "future" : req.cookies.get(FUTURE_ROUTES_ENABLED_COOKIE_NAME)?.value;
if (!bucketValue || !["future", "legacy"].includes(bucketValue)) {
// cookie does not exist or it has incorrect value
const bucket = getBucket();
response.cookies.set(FUTURE_ROUTES_ENABLED_COOKIE_NAME, bucket, {
expires: Date.now() + 1000 * 60 * 30,
httpOnly: true,
}); // 30 min in ms
if (bucket === "legacy") {
return response;
}
const url = req.nextUrl.clone();
url.pathname = `future${pathname}/`;
return NextResponse.rewrite(url, response);
}
if (bucketValue === "legacy") {
return response;
}
const url = req.nextUrl.clone();
url.pathname = `future${pathname}/`;
return NextResponse.rewrite(url, response);
};
-9
View File
@@ -1,9 +0,0 @@
import { AB_TEST_BUCKET_PROBABILITY } from "@calcom/lib/constants";
const cryptoRandom = () => {
return crypto.getRandomValues(new Uint8Array(1))[0] / 0xff;
};
export const getBucket = () => {
return cryptoRandom() * 100 < AB_TEST_BUCKET_PROBABILITY ? "future" : "legacy";
};
@@ -5,7 +5,7 @@ import { headers, cookies } from "next/headers";
import { getOrgFullOrigin } from "@calcom/features/ee/organizations/lib/orgDomains";
import { buildLegacyCtx } from "@lib/buildLegacyCtx";
import { buildLegacyCtx, decodeParams } from "@lib/buildLegacyCtx";
import { getServerSideProps } from "@server/lib/[user]/[type]/getServerSideProps";
@@ -31,12 +31,14 @@ export const generateMetadata = async ({ params, searchParams }: PageProps) => {
})),
],
};
const decodedParams = decodeParams(params);
const metadata = await generateMeetingMetadata(
meeting,
(t) => `${rescheduleUid && !!booking ? t("reschedule") : ""} ${title} | ${profileName}`,
(t) => `${rescheduleUid ? t("reschedule") : ""} ${title}`,
isBrandingHidden,
getOrgFullOrigin(eventData?.entity.orgSlug ?? null)
getOrgFullOrigin(eventData?.entity.orgSlug ?? null),
`/${decodedParams.user}/${decodedParams.type}`
);
return {
@@ -5,7 +5,7 @@ import { headers, cookies } from "next/headers";
import { getOrgFullOrigin } from "@calcom/features/ee/organizations/lib/orgDomains";
import { buildLegacyCtx } from "@lib/buildLegacyCtx";
import { buildLegacyCtx, decodeParams } from "@lib/buildLegacyCtx";
import { getServerSideProps } from "@server/lib/[user]/getServerSideProps";
@@ -30,7 +30,8 @@ export const generateMetadata = async ({ params, searchParams }: PageProps) => {
() => profile.name,
() => markdownStrippedBio,
false,
getOrgFullOrigin(entity.orgSlug ?? null)
getOrgFullOrigin(entity.orgSlug ?? null),
`/${decodeParams(params).user}`
);
return {
@@ -32,4 +32,4 @@ const ServerPage = async ({ params, searchParams }: ServerPageProps) => {
return <SetupView {...props} />;
};
export default ServerPage;
export default ServerPage;
@@ -0,0 +1,55 @@
import { withAppDirSsr } from "app/WithAppDirSsr";
import type { PageProps as ServerPageProps } from "app/_types";
import { _generateMetadata } from "app/_utils";
import { cookies, headers } from "next/headers";
import type { routingServerSidePropsConfig } from "@calcom/app-store/routing-forms/pages/app-routing.config";
import LayoutHandler from "@calcom/app-store/routing-forms/pages/layout-handler/[...appPages]";
import Shell from "@calcom/features/shell/Shell";
import { getServerSideProps } from "@lib/apps/routing-forms/[...pages]/getServerSideProps";
import { buildLegacyCtx } from "@lib/buildLegacyCtx";
const normalizePages = (pages: string[] | string | undefined) => {
const normalizedPages = Array.isArray(pages) ? pages : pages?.split("/") ?? [];
return {
mainPage: normalizedPages[0],
subPages: normalizedPages.slice(1),
};
};
export const generateMetadata = async ({ params }: { params: { pages: string[] } }) => {
const { mainPage } = normalizePages(params.pages);
return await _generateMetadata(
// TODO: Need to show the actual form name instead of "Form"
(t) => (mainPage === "routing-link" ? `Form | Cal.com Forms` : `${t("routing_forms")} | Cal.com Forms`),
() => ""
);
};
type GetServerSidePropsResult =
(typeof routingServerSidePropsConfig)[keyof typeof routingServerSidePropsConfig];
const getData = withAppDirSsr<GetServerSidePropsResult>(getServerSideProps);
const ServerPage = async ({ params, searchParams }: ServerPageProps) => {
const context = buildLegacyCtx(headers(), cookies(), params, searchParams);
const props = await getData(context);
const { mainPage, subPages } = normalizePages(params.pages);
const componentProps = {
...props,
pages: subPages,
};
if (mainPage === "routing-link") {
return <LayoutHandler {...componentProps} />;
}
return (
<Shell withoutMain withoutSeo>
<LayoutHandler {...componentProps} />
</Shell>
);
};
export default ServerPage;
@@ -0,0 +1,7 @@
import { redirect } from "next/navigation";
const ServerPage = async () => {
redirect("/apps/routing-forms/forms");
};
export default ServerPage;
@@ -1,5 +1,7 @@
import { _generateMetadata } from "app/_utils";
import LicenseRequired from "@calcom/features/ee/common/components/LicenseRequired";
import LegacyPage from "~/connect-and-join/connect-and-join-view";
export const generateMetadata = async () => {
@@ -9,4 +11,11 @@ export const generateMetadata = async () => {
);
};
export default LegacyPage;
const ServerPage = async () => {
return (
<LicenseRequired>
<LegacyPage />
</LicenseRequired>
);
};
export default ServerPage;
@@ -0,0 +1,53 @@
"use client";
import { useSession } from "next-auth/react";
import { UpgradeTip } from "@calcom/features/tips";
import { WEBAPP_URL } from "@calcom/lib/constants";
import { useLocale } from "@calcom/lib/hooks/useLocale";
import { Icon, Button, ButtonGroup } from "@calcom/ui";
export default function UpgradeTipWrapper({ children }: { children: React.ReactNode }) {
const { t } = useLocale();
const session = useSession();
const features = [
{
icon: <Icon name="users" className="h-5 w-5" />,
title: t("view_bookings_across"),
description: t("view_bookings_across_description"),
},
{
icon: <Icon name="refresh-ccw" className="h-5 w-5" />,
title: t("identify_booking_trends"),
description: t("identify_booking_trends_description"),
},
{
icon: <Icon name="user-plus" className="h-5 w-5" />,
title: t("spot_popular_event_types"),
description: t("spot_popular_event_types_description"),
},
];
return (
<UpgradeTip
plan="team"
title={t("make_informed_decisions")}
description={t("make_informed_decisions_description")}
features={features}
background="/tips/insights"
buttons={
<div className="space-y-2 rtl:space-x-reverse sm:space-x-2">
<ButtonGroup>
<Button color="primary" href={`${WEBAPP_URL}/settings/teams/new`}>
{t("create_team")}
</Button>
<Button color="minimal" href="https://go.cal.com/insights" target="_blank">
{t("learn_more")}
</Button>
</ButtonGroup>
</div>
}>
{!session.data?.user ? null : children}
</UpgradeTip>
);
}
@@ -1,65 +1,15 @@
"use client";
import { useSession } from "next-auth/react";
import { getTranslate } from "app/_utils";
import Shell from "@calcom/features/shell/Shell";
import { UpgradeTip } from "@calcom/features/tips";
import { WEBAPP_URL } from "@calcom/lib/constants";
import { useLocale } from "@calcom/lib/hooks/useLocale";
import { Button, ButtonGroup } from "@calcom/ui";
import { Icon } from "@calcom/ui";
export default function InsightsLayout({ children }: { children: React.ReactNode }) {
const { t } = useLocale();
const session = useSession();
const features = [
{
icon: <Icon name="users" className="h-5 w-5" />,
title: t("view_bookings_across"),
description: t("view_bookings_across_description"),
},
{
icon: <Icon name="refresh-ccw" className="h-5 w-5" />,
title: t("identify_booking_trends"),
description: t("identify_booking_trends_description"),
},
{
icon: <Icon name="user-plus" className="h-5 w-5" />,
title: t("spot_popular_event_types"),
description: t("spot_popular_event_types_description"),
},
];
import UpgradeTipWrapper from "./UpgradeTipWrapper";
export default async function InsightsLayout({ children }: { children: React.ReactNode }) {
const t = await getTranslate();
return (
<div>
<Shell
withoutMain={false}
withoutSeo={true}
heading={t("insights")}
subtitle={t("insights_subtitle")}
title={t("insights")}
description={t("insights_subtitle")}>
<UpgradeTip
plan="team"
title={t("make_informed_decisions")}
description={t("make_informed_decisions_description")}
features={features}
background="/tips/insights"
buttons={
<div className="space-y-2 rtl:space-x-reverse sm:space-x-2">
<ButtonGroup>
<Button color="primary" href={`${WEBAPP_URL}/settings/teams/new`}>
{t("create_team")}
</Button>
<Button color="minimal" href="https://go.cal.com/insights" target="_blank">
{t("learn_more")}
</Button>
</ButtonGroup>
</div>
}>
{!session.data?.user ? null : children}
</UpgradeTip>
<Shell withoutMain={false} withoutSeo={true} heading={t("insights")} subtitle={t("insights_subtitle")}>
<UpgradeTipWrapper>{children}</UpgradeTipWrapper>
</Shell>
</div>
);
@@ -8,7 +8,7 @@ export const generateMetadata = async () =>
);
const Page = () => {
redirect("/[category]");
redirect("/settings/admin/apps/calendar");
};
export default Page;
@@ -6,7 +6,7 @@ import { getServerSession } from "@calcom/features/auth/lib/getServerSession";
import { buildLegacyRequest } from "@lib/buildLegacyCtx";
import SettingsLayoutAppDir from "../(settings-layout)/SettingsLayoutAppDir";
import SettingsLayoutAppDir from "../(settings-layout)/layout";
import type { AdminLayoutProps } from "./AdminLayoutAppDirClient";
const AdminLayoutAppDirClient = dynamic(() => import("./AdminLayoutAppDirClient"), {
@@ -21,5 +21,3 @@ export default async function AdminLayoutAppDir(props: AdminLayoutAppDirProps) {
return await SettingsLayoutAppDir({ children: <AdminLayoutAppDirClient {...props} userRole={userRole} /> });
}
export const getLayout = async (page: React.ReactElement) => await AdminLayoutAppDir({ children: page });
@@ -13,10 +13,11 @@ const SettingsLayoutAppDirClient = dynamic(() => import("./SettingsLayoutAppDirC
ssr: false,
});
type SettingsLayoutAppDir = Omit<SettingsLayoutProps, "currentOrg" | "otherTeams">;
type SettingsLayoutAppDirProps = Omit<SettingsLayoutProps, "currentOrg" | "otherTeams">;
export default async function SettingsLayoutAppDir(props: SettingsLayoutAppDir) {
export default async function SettingsLayoutAppDir(props: SettingsLayoutAppDirProps) {
const session = await getServerSession({ req: buildLegacyRequest(headers(), cookies()) });
const userId = session?.user?.id ?? -1;
const orgId = session?.user?.org?.id ?? -1;
let currentOrg = null;
@@ -35,5 +36,3 @@ export default async function SettingsLayoutAppDir(props: SettingsLayoutAppDir)
return <SettingsLayoutAppDirClient {...props} currentOrg={currentOrg} otherTeams={otherTeams} />;
}
export const getLayout = async (page: React.ReactElement) => await SettingsLayoutAppDir({ children: page });
@@ -18,7 +18,7 @@ const Page = async () => {
<SettingsHeader
title={t("out_of_office")}
description={t("out_of_office_description")}
CTA={<CreateNewOutOfOfficeEntryButton />}>
CTA={<CreateNewOutOfOfficeEntryButton data-testid="add_entry_ooo" />}>
<OutOfOfficeEntriesList />
</SettingsHeader>
);
@@ -0,0 +1,5 @@
import BillingPage, { generateMetadata } from "../../billing/page";
export { generateMetadata };
export default BillingPage;
@@ -0,0 +1,4 @@
import BillingPage, { generateMetadata } from "../../../billing/page";
export { generateMetadata };
export default BillingPage;
@@ -1,9 +1,11 @@
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 type { inferSSRProps } from "@calcom/types/inferSSRProps";
import { buildLegacyCtx } from "@lib/buildLegacyCtx";
import { getServerSideProps } from "@lib/settings/license-key/new/getServerSideProps";
import CreateANewLicenseKeyForm, { LayoutWrapper } from "~/settings/license-key/new/new-view";
@@ -14,8 +16,15 @@ export const generateMetadata = async () =>
(t) => t("organizations_description")
);
export default WithLayout({
Page: CreateANewLicenseKeyForm,
getLayout: LayoutWrapper,
getData: withAppDirSsr<inferSSRProps<typeof getServerSideProps>>(getServerSideProps),
});
const getData = withAppDirSsr<inferSSRProps<typeof getServerSideProps>>(getServerSideProps);
const ServerPage = async ({ params, searchParams }: PageProps) => {
await getData(buildLegacyCtx(headers(), cookies(), params, searchParams));
return (
<LayoutWrapper>
<CreateANewLicenseKeyForm />
</LayoutWrapper>
);
};
export default ServerPage;
@@ -1,9 +1,12 @@
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 { getServerSideProps } from "@calcom/features/ee/organizations/pages/organization";
import { buildLegacyCtx } from "@lib/buildLegacyCtx";
import LegacyPage, { LayoutWrapper } from "~/settings/organizations/[id]/about-view";
export const generateMetadata = async () =>
@@ -14,8 +17,13 @@ export const generateMetadata = async () =>
const getData = withAppDirSsr(getServerSideProps);
export default WithLayout({
Page: LegacyPage,
getLayout: LayoutWrapper,
getData,
});
const ServerPage = async ({ params, searchParams }: PageProps) => {
await getData(buildLegacyCtx(headers(), cookies(), params, searchParams));
return (
<LayoutWrapper>
<LegacyPage />
</LayoutWrapper>
);
};
export default ServerPage;
@@ -1,9 +1,12 @@
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 { getServerSideProps } from "@calcom/features/ee/organizations/pages/organization";
import { buildLegacyCtx } from "@lib/buildLegacyCtx";
import LegacyPage, { LayoutWrapper } from "~/settings/organizations/[id]/add-teams-view";
export const generateMetadata = async () =>
@@ -14,8 +17,13 @@ export const generateMetadata = async () =>
const getData = withAppDirSsr(getServerSideProps);
export default WithLayout({
Page: LegacyPage,
getLayout: LayoutWrapper,
getData,
});
const ServerPage = async ({ params, searchParams }: PageProps) => {
await getData(buildLegacyCtx(headers(), cookies(), params, searchParams));
return (
<LayoutWrapper>
<LegacyPage />
</LayoutWrapper>
);
};
export default ServerPage;
@@ -1,5 +1,4 @@
import { _generateMetadata } from "app/_utils";
import { WithLayout } from "app/layoutHOC";
import MembersPage from "~/members/members-view";
@@ -9,6 +8,8 @@ export const generateMetadata = async () =>
(t) => t("organization_description")
);
export default WithLayout({
Page: MembersPage,
});
const ServerPageWrapper = () => {
return <MembersPage />;
};
export default ServerPageWrapper;
@@ -1,9 +1,12 @@
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 { getServerSideProps } from "@calcom/features/ee/organizations/pages/organization";
import { buildLegacyCtx } from "@lib/buildLegacyCtx";
import LegacyPage, { LayoutWrapper } from "~/settings/organizations/[id]/onboard-members-view";
export const generateMetadata = async () =>
@@ -14,8 +17,13 @@ export const generateMetadata = async () =>
const getData = withAppDirSsr(getServerSideProps);
export default WithLayout({
Page: LegacyPage,
getLayout: LayoutWrapper,
getData,
});
const ServerPage = async ({ params, searchParams }: PageProps) => {
await getData(buildLegacyCtx(headers(), cookies(), params, searchParams));
return (
<LayoutWrapper>
<LegacyPage />
</LayoutWrapper>
);
};
export default ServerPage;
@@ -1,5 +1,4 @@
import { _generateMetadata } from "app/_utils";
import { WithLayout } from "app/layoutHOC";
import Page from "@calcom/features/ee/organizations/pages/settings/appearance";
@@ -9,4 +8,8 @@ export const generateMetadata = async () =>
(t) => t("appearance_org_description")
);
export default WithLayout({ Page });
const ServerPageWrapper = () => {
return <Page />;
};
export default ServerPageWrapper;
@@ -1,11 +1,9 @@
import SettingsLayoutAppDir from "app/(use-page-wrapper)/settings/(settings-layout)/layout";
import { _generateMetadata, getTranslate } from "app/_utils";
import { WithLayout } from "app/layoutHOC";
import LegacyPage from "@calcom/features/ee/organizations/pages/members";
import SettingsHeader from "@calcom/features/settings/appDir/SettingsHeader";
import SettingsLayoutAppDir from "../../(settings-layout)/SettingsLayoutAppDir";
export const generateMetadata = async () =>
await _generateMetadata(
(t) => t("organization_members"),
@@ -15,14 +13,12 @@ export const generateMetadata = async () =>
const Page = async () => {
const t = await getTranslate();
return (
const children = (
<SettingsHeader title={t("organization_members")} description={t("organization_description")}>
<LegacyPage />
</SettingsHeader>
);
return await SettingsLayoutAppDir({ children, containerClassName: "lg:max-w-screen-2xl" });
};
const getLayout = async (page: React.ReactElement) =>
await SettingsLayoutAppDir({ children: page, containerClassName: "lg:max-w-screen-2xl" });
export default WithLayout({ ServerPage: Page, getServerLayout: getLayout })<"P">;
export default Page;

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