Compare commits

...
254 Commits
Author SHA1 Message Date
Alex van Andel dca1d35cb4 v2.6.3
release.yml / release (push) Canceled after 0s
2023-02-21 13:26:11 +00:00
Esaú Morais af970c049a Do not show location when booking has been cancelled (#7244)
* fix(schedule): close on click #7143

* fix(booking): do not show location when booking has been cancelled
2023-02-21 09:25:57 +00:00
Esaú Morais 6fc3840ca3 Remove duplicated border in Calendar category (#7235)
* fix(schedule): close on click #7143

* fix(CalendarListContainer): remove duplicated border #7222

* fix: set right border to all installed apps
2023-02-21 09:19:29 +00:00
Udit TakkarandHariom Balhara c51150350a chore: check IS_SELF_HOSTED in download (#7214)
* chore: check IS_SELF_HOSTED in download

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

* Update apps/web/pages/api/download-cal-video-recording.ts

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

* Update apps/web/pages/api/download-cal-video-recording.ts

* Linting fix

---------

Signed-off-by: Udit Takkar <udit.07814802719@cse.mait.ac.in>
Co-authored-by: Hariom Balhara <hariombalhara@gmail.com>
2023-02-21 09:00:08 +00:00
Alex van Andel 51664bf733 Fixed invalid busy times query logic (#7243)
* Fixed invalid busy times query logic

* Adjusted collective test
2023-02-21 02:45:10 +00:00
Alex van Andel 831506447a Assign userIds to all schedules, including common eventType schedules (#7241) 2023-02-20 23:48:15 +00:00
zomars ee54e670cb FIXME 2023-02-20 14:32:56 -07:00
Carina WollendorferandCarinaWolli 99cd6fe7da add all location links to metadata (#7236)
Co-authored-by: CarinaWolli <wollencarina@gmail.com>
2023-02-20 18:52:07 +00:00
Hariom Balhara 75c7e03efe Upgrade vite (#7197) 2023-02-20 17:50:40 +00:00
Carina WollendorferandCarinaWolli 2ebfcf448c Fixes that workflow reminders of cancelled and rescheduled bookings are still sent (#7232)
* small UI fix

* fix cancelling scheduled emails

* improve comments

* delete reminders for rescheduled bookings

* add migration file

* cancel rescheduled bookings immediately

* remove immediate delete for request reschedule

---------

Co-authored-by: CarinaWolli <wollencarina@gmail.com>
2023-02-20 12:40:08 -05:00
Oscar DominguezandHariom Balhara 235ec0e906 improve typing by removing as html element (#7212)
* refactor(embeds): use generic HTMLIFrameElement instead of 'as HTMLIFrameElement'

* refactor(embeds): improve types for floatingButton logic

* Fix floating button popup not working

---------

Co-authored-by: Hariom Balhara <hariombalhara@gmail.com>
2023-02-20 17:37:03 +00:00
Nafees Nazik ea73870ce9 fix: overflow issue in Custom event name modal (#7224) 2023-02-20 21:46:31 +05:30
Peer Richelsen d1440bb5d2 added pwa: extension for standalone, lots of mobile improvements (#7218) 2023-02-20 15:11:51 +01:00
Hariom Balhara a000030040 Check embed in a better way (#7221) 2023-02-20 11:31:56 +00:00
Joe Au-Yeung 44864a801d Admin apps console - revert back to swtiches (#7219) 2023-02-20 15:38:16 +05:30
Sai Deepesh b9fd0b4c78 chore: add i18n in routing form pages (#7193)
* chore: add i18n in routing form pages

* use existing string

* add strings to en/common.json file

* address comments
2023-02-20 10:07:58 +00:00
Harsh SinghandGuest 0e7276370f Fix: mounting state use theme (#7203)
Co-authored-by: Guest <guest@pop-os.localdomain>
2023-02-20 15:17:33 +05:30
Hariom Balhara 4d2cf28c7e Fix metadata not being retrieved (#7208) 2023-02-20 07:30:23 +05:30
sean-brydon 55ee939cf9 Dont default empty state (#7217) 2023-02-19 20:16:19 +00:00
Udit Takkar 2fe54ded15 fix: use getVideoData function (#7205) 2023-02-19 13:13:36 +05:30
Udit Takkar 8e3fa4be29 Fix/email responsive bug (#6901)
* fix: prevent overflow of url

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

* fix: manage link responsive in emails

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

---------

Signed-off-by: Udit Takkar <udit.07814802719@cse.mait.ac.in>
2023-02-18 22:26:55 +00:00
Hariom Balhara d7b4d5932d Avoid theme not ready causing the select to not render (#7194)
release.yml / release (push) Canceled after 0s
2023-02-18 15:53:14 +00:00
3c7fc85b34 feat(app-store): add facetime app to app-store (#7174)
* feat(app-store): add facetime app to app-store

Add the facetime app to the app-store allowing for facetime web links and facetime app link schemes.

fixes #6965

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

* Remove unneeded files and make app follow the new app rules

* fix(app-store): update facetime app config

Update the regex and placeholder for the facetime app to reflect the decisions to only accept https://facetime.apple.com links. This was decided as it means that all participants can join a meeting even in the event that they don't have an Apple device.

---------

Co-authored-by: Peer Richelsen <peer@cal.com>
Co-authored-by: Hariom Balhara <hariombalhara@gmail.com>
2023-02-18 06:40:07 +00:00
Omar López af018f0e8b Adds CalDav Edge case (#7187)
* Adds CalDav Edge case

* Update packages/lib/CalendarService.ts
2023-02-17 18:34:37 -07:00
Alex van Andel 6573f75a83 Bugfix/customer being prompted to upgrade to teams after purchasing (#6955)
* Move subscriptionId creation to earlier in the flow

* Fail silently when slug is missing

* Set team to created team
2023-02-17 23:45:50 +00:00
Carina WollendorferandCarinaWolli a3b26cd1e7 Removes team paywall for self-hosted (#7185)
Co-authored-by: CarinaWolli <wollencarina@gmail.com>
2023-02-17 23:00:19 +00:00
Nafees NazikandPeer Richelsen 4f99746f68 fix: color picker a11y fixes (#7084)
* refactor: remove swatch component

* feat: use radix ui popover component

* refactor: remove duplicate component

* fix: import color picker from `@calcom/ui`

* fix: type error

* fix: update color picker to match the design

* fix: type

---------

Co-authored-by: Peer Richelsen <peer@cal.com>
2023-02-17 20:27:29 +00:00
Efraín Rochínandzomars fd76bc9cab Reduce booking page bundle size (#7131)
* AvailabilityPage Component loaded dynamically

* update next/bundle-analyzer dependency

* Load dynamically SlotPicker and TimezoneDropDown and make some imports refactoring

* Gates functionality Returned

* Replace crypto with md5 dependency to generate gravatar url

* Refactor: AvailableTimes and SlotPicker

* Update next.config.js

* Update SlotPicker.tsx

* Update getEventTypeAppData.ts

---------

Co-authored-by: zomars <zomars@me.com>
2023-02-17 12:53:31 -07:00
Nafees Nazik 602c813928 fix: remove styled jsx (#7133) 2023-02-17 19:32:29 +00:00
Jeremiah Ajayi 2c54ea90f9 CAL-1053: Invalidate password to avoid once Google auth is used to merge accounts (#7152)
* CAL-1053: Invalidate password to avoid once Google auth is used to merge accounts

* remove log
2023-02-17 18:59:34 +00:00
+17 2698cde311 Gradually increase the getSchedule refetch interval until it reaches 30 seconds (#7104)
* Generate SSG Page used as cache for user's third-party calendars

* remove next-build-id dependency

* yarn.lock from main

* add support to get cached data from multiple months

* Update apps/web/pages/[user]/calendar-cache/[month].tsx

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

* Update apps/web/pages/[user]/calendar-cache/[month].tsx

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

* Update packages/core/CalendarManager.ts

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

* Add api endpoint that revalidates the current month and 3 more ahead

* Revalidate calendar cache when user connect new calendar.

* Revalidate calendar cache when user remove a calendar.

* Revalidate calendar cache when user change de selected calendars-

* Change revalidateCalendarCache function to @calcom/lib/server

* Remove the memory cache from getCachedResults

* refetch availability slots in a 3 seconds interval

* Hotfix: Event Name (#6863) (#6864)

* feat: make key unique (#6861)

* version 2.5.9 (#6868)

* Use Calendar component view=day for drop-in replacement troubleshooter (#6869)

* Use Calendar component view=day for drop-in replacement troubleshooter

* Setting the id to undefined makes the busy time selected

* Updated event title to include title+source

* lots of small changes by me and ciaran (#6871)

* Hotfix: For old Plausible installs enabled in an EventType, give a default value (#6860)

* Add default for trackingId for old plausible installs in event-types

* Fix types

* fix: filter booking in upcoming (#6406)

* fix: filter booking in upcoming

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

* fix: test

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

* fix: wipe-my-cal failing test

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

---------

Signed-off-by: Udit Takkar <udit.07814802719@cse.mait.ac.in>
Co-authored-by: Peer Richelsen <peeroke@gmail.com>
Co-authored-by: Peer Richelsen <peer@cal.com>

* fix workflows when duplicating event types (#6873)

* fix: get location url from metadata (#6774)

* fix: get location url from metadata

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

* fix: replace location

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

* fix: type error

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

* fix: use zod

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

---------

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

* Updates heroku deployment template (#6879)

* Hide button (#6895)

* Fixed some inconsistencies within single event type page (#6887)

* Fixed some inconsistencies within single event type page

* Fix layout shift on AvailabilityTab

* fix(date-overrides): alignment of edit & delete btns (#6892)

* When unchecking the common schedule, schedule should be nulled (#6898)

* theme for storybook

* nit border change (#6899)

* fix: metadata not saved while creating a booking. (#6866)

* feat: add metadata to booking creation

* fix: bug

* Beginning of Strict CSP Compliance (#6841)

* Add CSP Support and enable it initially for Login page

* Update README

* Make sure that CSP is not enabled if CSP_POLICY isnt set

* Add a new value for x-csp header that tells if instance has opted-in to CSP or not

* Add more src to CSP

* Fix typo in header name

* Remove duplicate headers fn

* Add https://eu.ui-avatars.com/api/

* Add CSP_POLICY to env.example

* v2.5.10

* fix: add req.headers (#6921)

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

* add-console-vars (#6929)

* Admin Wizard Choose License (#6574)

* Implementation

* i18n

* More i18n

* extracted i18n, needs api to get most recent price, added hint: update later

* Fixing i18n var

* Fix booking filters not working for admin (#6576)

* fix: react-select overflow issue in some modals. (#6587)

* feat: add a disable overflow prop

* feat: use the disable overflow prop

* Tailwind Merge (#6596)

* Tailwind Merge

* Fix merge classNames

* [CAL-808] /availability/single - UI issue on buttons beside time inputs (#6561)

* [CAL-808] /availability/single - UI issue on buttons beside time inputs

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

* Update packages/features/schedules/components/Schedule.tsx

* create new translation for tooltip

Co-authored-by: gitstart-calcom <gitstart@users.noreply.github.com>
Co-authored-by: Peer Richelsen <peeroke@gmail.com>
Co-authored-by: CarinaWolli <wollencarina@gmail.com>

* Bye bye submodules (#6585)

* WIP

* Uses ssh instead

* Update .gitignore

* Update .gitignore

* Update Makefile

* Update git-setup.sh

* Update git-setup.sh

* Replaced Makefile with bash script

* Update package.json

* fix: show button on empty string (#6601)

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

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

* fix: add delete in dropdown (#6599)

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

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

* Update README.md

* Update README.md

* Changed a neutral- classes to gray (#6603)

* Changed a neutral- classes to gray

* Changed all border-1 to border

* Update package.json

* Test fixes

* Yarn lock fixes

* Fix string equality check in git-setup.sh

* [CAL-811] Avatar icon not redirecting user back to the main page (#6586)

* Remove cursor-pointer, remove old Avatar* files

* Fixed styling for checkedSelect + some cleanup

Co-authored-by: gitstart-calcom <gitstart@users.noreply.github.com>
Co-authored-by: Alex van Andel <me@alexvanandel.com>

* Harsh/add member invite (#6598)

Co-authored-by: Guest <guest@pop-os.localdomain>
Co-authored-by: root <harsh.singh@gocomet.com>

* Regenerated lockfile without upgrade (#6610)

* fix: remove annoying outline when <Button /> clicked (#6537)

* fix: remove annoying outline when <Button /> clicked

* Delete yarn.lock

* remove 1 on 1 icon (#6609)

* removed 1-on-1 badge

* changed user to users for group events

* fix: case-sensitivity in apps path (#6552)

* fix: lowercase slug

* fix: make fallback blocking

* Fix FAB (#6611)

* feat: add LocationSelect component (#6571)

* feat: add LocationSelect component

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

* fix: type error

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

* chore: type error

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

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

* Update booking filters design  (#6543)

* Update booking filters

* Add filter on YOUR bookings

* Fix pending members showing up in list

* Reduce the avatar size to 'sm' for now

* Bugfix/dropdown menu trigger as child remove class names (#6614)

* Fix UsernameTextfield to take right height

* Remove className side-effect

* Incorrect resolution version fixed

* Converted mobile DropdownMenuTrigger styles into Button

* v2.5.3

* fix: use items-center (#6618)

* fix tooltip and modal stacking issues (#6491)

* fix tooltip and modal stacking issues

* use z-index in larger screens and less

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

* Temporary fix (#6626)

* Fix Ga4 tracking (#6630)

* generic <UpgradeScreen> component (#6594)

* first attempt of <UpgradeScreen>

* changes to icons

* reverted changes back to initial state, needs fix: teams not showing

* WIP

* Fix weird reactnode error

* Fix loading text

* added upgradeTip to routing forms

* icon colors

* create and use hook to check if user has team plan

* use useTeamPlan for upgradeTeamsBadge

* replace huge svg with compressed jpeg

* responsive fixes

* Update packages/ui/components/badge/UpgradeTeamsBadge.tsx

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

* Give team plan features to E2E tests

* Allow option to make a user part of team int ests

* Remove flash of paywall for team user

* Add team user for typeform tests as well

Co-authored-by: Peer Richelsen <peer@cal.com>
Co-authored-by: CarinaWolli <wollencarina@gmail.com>
Co-authored-by: Carina Wollendorfer <30310907+CarinaWolli@users.noreply.github.com>
Co-authored-by: Alex van Andel <me@alexvanandel.com>
Co-authored-by: Hariom Balhara <hariombalhara@gmail.com>

* Removing env var to rely on db

* Restoring i18n keys, set loading moved

* Fixing tailwind-preset glob

* Wizard width fix for md+ screens

* Converting licenses options to radix radio

* Applying feedback + other tweaks

* Reverting this, not this PR related

* Unneeded code removal

* Reverting unneeded style change

* Applying feedback

* Removing licenseType

* Upgrades typescript

* Update yarn lock

* Typings

* Hotfix: ping,riverside,whereby and around not showing up in list (#6712)

* Hotfix: ping,riverside,whereby and around not showing up in list (#6712) (#6713)

* Adds deployment settings to DB (#6706)

* WIP

* Adds DeploymentTheme

* Add missing migrations

* Adds client extensions for deployment

* Cleanup

* Delete migration.sql

* Relying on both, env var and new model

* Restoring env example doc for backward compat

* Maximum call stack size exceeded fix?

* Revert upgrade

* Update index.ts

* Delete index.ts

* Not exposing license key, fixed radio behavior

* Covering undefined env var

* Self contained checkLicense

* Feedback

* Moar feedback

* Feedback

* Feedback

* Feedback

* Cleanup

---------

Signed-off-by: Udit Takkar <udit.07814802719@cse.mait.ac.in>
Co-authored-by: Peer Richelsen <peer@cal.com>
Co-authored-by: sean-brydon <55134778+sean-brydon@users.noreply.github.com>
Co-authored-by: Nafees Nazik <84864519+G3root@users.noreply.github.com>
Co-authored-by: GitStart-Cal.com <121884634+gitstart-calcom@users.noreply.github.com>
Co-authored-by: gitstart-calcom <gitstart@users.noreply.github.com>
Co-authored-by: Peer Richelsen <peeroke@gmail.com>
Co-authored-by: CarinaWolli <wollencarina@gmail.com>
Co-authored-by: Omar López <zomars@me.com>
Co-authored-by: Udit Takkar <53316345+Udit-takkar@users.noreply.github.com>
Co-authored-by: Alex van Andel <me@alexvanandel.com>
Co-authored-by: Harsh Singh <51085015+harshsinghatz@users.noreply.github.com>
Co-authored-by: Guest <guest@pop-os.localdomain>
Co-authored-by: root <harsh.singh@gocomet.com>
Co-authored-by: Luis Cadillo <luiscaf3r@gmail.com>
Co-authored-by: Mohammed Cherfaoui <hi@cherfaoui.dev>
Co-authored-by: Hariom Balhara <hariombalhara@gmail.com>
Co-authored-by: Carina Wollendorfer <30310907+CarinaWolli@users.noreply.github.com>

* added two new tips (#6915)

* [CAL-488] Timezone selection has a weird double dropdown (#6851)

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

* fix: color and line height of icon (#6913)

* fix: use destination calendar email (#6886)

* fix: use destination calendar email
to display correct primary email

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

* fix: simplify logic

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

---------

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

* fix: dropdown title in bookings page (#6924)

* fixes the broken max size of members on teams page (#6926)

* fix: display provider name instead of url (#6914)

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

* fix: add sortByLabel (#6797)

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

* Email Variables Bug (#6943)

* Remove _subject translations for zh-CN, needs retranslation

* minor timezone-select improvements (#6944)

* fixed timezone select positioning and hover

* fixed timezone select positioning and hover

* Give trackingId a default value because if user doesnt interact with trackingId input it is not set (#6945)

* Block /auth/:path, nothing else. (#6949)

* Block /auth/:path, nothing else.

* Also add /signup

* fix start icon in button (#6950)

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

* Fixes localisation of {EVENT_DATE} in workflows (#6907)

* translate {EVENT_DATE} variable to correct language

* fix locale for cron schedule reminder emails/sms

* fix type error

* add missing locale to attendees

* fix type error

* code clean up

* revert last commit

* using Intl for date translations

---------

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

* Allow account linking for Google and SAML providers (#6874)

* allow account linking for self-hosted instances, both Google and SAML are verified emails

* allow account linking for Google and SSO if emails match with existing username/password account

* Tweaked find user by email since we now have multiple providers (other than credentials provider)

* feat/payment-service-6438-cal-767 (#6677)

* WIP paymentService

* Changes for payment Service

* Fix for stripe payment flow

* Remove logs/comments

* Refactored refund for stripe app

* Move stripe handlePayment to own lib

* Move stripe delete payments to paymentService

* lint fix

* Change handleRefundError as generic function

* remove log

* remove logs

* remove logs

* Return stripe default export to lib/server

* Fixing types

* Fix types

* Upgrades typescript

* Update yarn lock

* Typings

* Hotfix: ping,riverside,whereby and around not showing up in list (#6712)

* Hotfix: ping,riverside,whereby and around not showing up in list (#6712) (#6713)

* Adds deployment settings to DB (#6706)

* WIP

* Adds DeploymentTheme

* Add missing migrations

* Adds client extensions for deployment

* Cleanup

* Revert "lint fix"

This reverts commit e1a2e4a357e58e6673c47399888ae2e00d1351a6.

* Add validation

* Revert changes removed in force push

* Removing abstract class and just leaving interface implementation

* Fix types for handlePayments

* Fix payment test appStore import

* Fix stripe metadata in event type

* Move migration to separate PR

* Revert "Move migration to separate PR"

This reverts commit 48aa64e0724a522d3cc2fefaaaee5792ee9cd9e6.

* Update packages/prisma/migrations/20230125175109_remove_type_from_payment_and_add_app_relationship/migration.sql

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

---------

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

* Small UI fixes for seats & destination calendars (#6859)

* Do not add former time for events on seats

* Default display destination calendar

* Add seats badge to event type item

* Add string

* Actively watch seats enabled option for requires confirmation

* Only show former time when there is a rescheduleUid

* fix: use typedquery hook in duplicate dialog (#6730)

* fix: use typedquery hook in duplicate dialog

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

* Update packages/features/eventtypes/components/DuplicateDialog.tsx

---------

Signed-off-by: Udit Takkar <udit.07814802719@cse.mait.ac.in>
Co-authored-by: Peer Richelsen <peer@cal.com>
Co-authored-by: Omar López <zomars@me.com>

* Fixing admin wizard step done (#6954)

* Feature/maintenance mode (#6930)

* Implement maintenance mode with Vercel Edge Config

* Error log is spam during development/ added \n in .env.example

* Exclude _next, /api for /maintenance page

* Re-instate previous config

* rtl: begone

* Added note to explain why /auth/login covers the maintenance page.

---------

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

* Update package.json

* I18N Caching (#6823)

* Caching Logic Changes

Enabled this function to change its cache value based on incoming paths value

* Invalidate I18N Cache

Invalidating the I18N cache when a user saves changes to their General settings

* Removes deprecated useLocale location

* Overriding the default getSchedule cache to have a revalidation time of 1 second

* Update apps/web/pages/api/trpc/[trpc].ts

* Updated cache values to match the comment

---------

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

* feat: return `x-vercel-ip-timezone` in headers (#6849)

* feat: add trpc to matcher and pass vercel timezone header

* feat: pass request to context

* feat: return timezone in header

* refactor: split context

* fix: remove tsignore comment

* Update [trpc].ts

---------

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

* log the json url for testing

* use WEBAPP_URL constant instead env.NEXT_PUBLIC_WEBAPP_URL

* remove the commented selectedCalendars var, it is not necessary

* Caching fixes

* Separate selectedDate slots from month slots

* Update [trpc].ts

* Log headers

* Update [trpc].ts

* Update package.json

* Fixes/trpc headers (#7045)

* Cache fixes

* Testing

* SWR breaks embed tests

* Prevent refetching day on month switch

* Skeleton fixes

* gradually increase the refetch interval

* Update AvailabilityPage.tsx

---------

Signed-off-by: Udit Takkar <udit.07814802719@cse.mait.ac.in>
Co-authored-by: zomars <zomars@me.com>
Co-authored-by: Hariom Balhara <hariombalhara@gmail.com>
Co-authored-by: Nafees Nazik <84864519+G3root@users.noreply.github.com>
Co-authored-by: Ben Hybert <53020786+Hybes@users.noreply.github.com>
Co-authored-by: Alex van Andel <me@alexvanandel.com>
Co-authored-by: Peer Richelsen <peeroke@gmail.com>
Co-authored-by: Udit Takkar <53316345+Udit-takkar@users.noreply.github.com>
Co-authored-by: Peer Richelsen <peer@cal.com>
Co-authored-by: Carina Wollendorfer <30310907+CarinaWolli@users.noreply.github.com>
Co-authored-by: Syed Ali Shahbaz <52925846+alishaz-polymath@users.noreply.github.com>
Co-authored-by: sean-brydon <55134778+sean-brydon@users.noreply.github.com>
Co-authored-by: Sai Deepesh <saideepesh000@gmail.com>
Co-authored-by: alannnc <alannnc@gmail.com>
Co-authored-by: Leo Giovanetti <hello@leog.me>
Co-authored-by: GitStart-Cal.com <121884634+gitstart-calcom@users.noreply.github.com>
Co-authored-by: gitstart-calcom <gitstart@users.noreply.github.com>
Co-authored-by: CarinaWolli <wollencarina@gmail.com>
Co-authored-by: Harsh Singh <51085015+harshsinghatz@users.noreply.github.com>
Co-authored-by: Guest <guest@pop-os.localdomain>
Co-authored-by: root <harsh.singh@gocomet.com>
Co-authored-by: Luis Cadillo <luiscaf3r@gmail.com>
Co-authored-by: Mohammed Cherfaoui <hi@cherfaoui.dev>
Co-authored-by: Joe Shajan <joeshajan1551@gmail.com>
Co-authored-by: Deepak Prabhakara <deepak@boxyhq.com>
Co-authored-by: Joe Au-Yeung <65426560+joeauyeung@users.noreply.github.com>
Co-authored-by: Aaron Presley <155617+AaronPresley@users.noreply.github.com>
2023-02-17 11:50:02 -07:00
1433ec6946 feat: use @next/font for font loading (#6346)
Co-authored-by: Peer Richelsen <peeroke@gmail.com>
Co-authored-by: Alex van Andel <me@alexvanandel.com>
2023-02-17 18:53:17 +01:00
Peer RichelsenandCarinaWolli 48e5d18ea1 show upgrade badge and hide /team/null when team unpublished (#7059)
* untested but i think this works

* fix upgrade badge

---------

Co-authored-by: CarinaWolli <wollencarina@gmail.com>
2023-02-17 10:48:13 -07:00
Peer Richelsen 5da76c698e use support email (.env) in password reset mail (#7181)
release.yml / release (push) Canceled after 0s
2023-02-17 16:44:42 +00:00
Christian Emmert 578308a8cb Display timezones in availabilities (#7081) 2023-02-17 16:07:59 +00:00
Lucas Smith 6b3862f96d fix(app): disable edit availability link while fetching (#7144) 2023-02-17 13:27:56 +00:00
Matt Pocock 94f239bc42 Improved typings of window.Cal (#7178) 2023-02-17 13:23:30 +00:00
Matt Pocock 2f2f6006e6 Improved types in ModalBox.ts (#7177) 2023-02-17 13:23:19 +00:00
Matt Pocock f8558e16e8 Removed 'as any' in jackson.ts (#7175) 2023-02-17 13:21:29 +00:00
Carina WollendorferandCarinaWolli 38be2bef9a fix custom workflow template (#7154)
Co-authored-by: CarinaWolli <wollencarina@gmail.com>
2023-02-17 13:21:11 +00:00
Nafees Nazik 485619602f refactor: usetheme hook (#7112)
* refactor: useTheme hook

* feat: add mounted state hook

* feat: add mounted hook

* fix: add comments
2023-02-17 11:18:54 +00:00
sean-brydon ce01537fe6 Fix errors (#7134) 2023-02-17 11:15:42 +00:00
sean-brydon f77e7476d2 Fix tab focus state in New select (#7139)
* Fix tab focus state

* Update packages/ui/components/form/selectimproved/components/Select.tsx

* Remove flex import
2023-02-17 11:15:02 +00:00
Carina WollendorferandCarinaWolli b6016c8f20 fix zapier app settings (#7161)
Co-authored-by: CarinaWolli <wollencarina@gmail.com>
2023-02-17 11:12:20 +00:00
Hariom Balhara a5e5d103a0 Embed: Remove ugly windows scrollbar even on unscrollable content (#7171) 2023-02-17 10:35:39 +00:00
Peer Richelsen fec02979ba hide team member availability button (#7147) 2023-02-17 10:09:49 +00:00
sean-brydon dc200b95cb Add max h to booking filters (#7170) 2023-02-17 11:02:10 +01:00
Peer Richelsen 78a54e5f54 Update CONTRIBUTING.md 2023-02-17 10:59:46 +01:00
sean-brydon 00ebda2fc6 Fix default app in main appstore list (#7141) 2023-02-17 09:11:03 +00:00
Omar López 7c749299bb Enforces explicit type imports (#7158)
* Enforces explicit type imports

* Upgrades typescript-eslint

* Upgrades eslint related dependencies

* Update config

* Sync packages mismatches

* Syncs prettier version

* Linting

* Relocks node version

* Fixes

* Locks @vitejs/plugin-react to 1.3.2

* Linting
2023-02-16 15:39:57 -07:00
Esaú Morais 3df289b557 fix(schedule): close on click #7143 (#7148) 2023-02-16 13:42:41 -07:00
Carina Wollendorfer f4c849b75c fix deleting webhook (#7159) 2023-02-16 21:22:14 +01:00
Aaron Presley 09cc6f07e4 Booking page now displays localized dates, times, and timezones (#7130) 2023-02-16 18:16:22 +01:00
sean-brydon 78656f2116 Layout Story (#7116)
* Flex component + spacing story

* Add Flex Story

* Remove flex component
2023-02-15 19:12:10 +00:00
Nafees Nazikandzomars 1fa5e296af refactor: use dynamic import in booking page (#7101)
Co-authored-by: zomars <zomars@me.com>
2023-02-15 20:08:17 +01:00
alannnc 0f76530c11 fix/premium-username-user-state-overriden (#7099) 2023-02-15 19:40:29 +01:00
Omar López ab6758194b v2.6.0
release.yml / release (push) Canceled after 0s
2023-02-15 11:28:32 -07:00
zomars 5528d60897 Set bundle threshold to 500 bytes 2023-02-15 11:05:12 -07:00
Nafees Nazik bb1c55e07f fix: booking confirmation email missing variables (#7109)
* fix: make the method public

* fix: missing variables
2023-02-15 10:49:44 -07:00
Nafees Nazik c899921591 fix: label (#7119) 2023-02-15 17:19:39 +00:00
sean-brydonandzomars ea34545d72 Handle booking flow for dynamic default events (#7094)
* Handle booking flow for default events

* Cleanup

* Update packages/lib/defaultEvents.ts

* Fix naming conventions

* Fix prettier error

---------

Co-authored-by: zomars <zomars@me.com>
2023-02-15 15:42:49 +00:00
Omar López 9d3540511b Add/eslint plugin unused imports (#7102)
* Re added debug endpoint

* Update me.ts

* Adds eslint-plugin-unused-imports

* Linting
2023-02-14 23:26:29 +00:00
zomars e8cf92361a Fingers crossed 🤞 2023-02-14 15:36:02 -07:00
zomars e8525b963b Update .gitignore 2023-02-14 14:47:58 -07:00
zomars 24dabd0ddc Update nextjs-bundle-analysis.yml 2023-02-14 14:21:12 -07:00
zomars 5203168b2e Re added debug endpoint
Update me.ts
2023-02-14 14:11:09 -07:00
Omar López c3e40f84a9 v2.5.15
release.yml / release (push) Canceled after 0s
2023-02-14 10:08:30 -07:00
Omar López 8e2ece7526 Prevent timeouts when cache fails (#7095)
Return empty cache instead of failing

Keeping console errors
2023-02-14 10:07:58 -07:00
Omar López b6eca6e083 v2.5.14
release.yml / release (push) Canceled after 0s
2023-02-14 09:02:24 -07:00
zomars 4cb264f1f7 Revert "Revert "I18N Caching (#6823)""
This reverts commit e248fda36b.

Re-fixed cache rules
2023-02-14 09:00:28 -07:00
Alex van Andel e248fda36b Revert "I18N Caching (#6823)"
This reverts commit 05c33bd94b.
2023-02-14 13:55:19 +00:00
sean-brydon 1c97e549eb Implement URL validation on default videos links (#7087) 2023-02-14 13:19:45 +00:00
77600f8168 Feat/custom default video (#6971)
* Add queries to fetch metadata and update default

* Add to zod schema

* Change default rules on settings page

* Update query

* Initall override on create event type

* Working default

* Change schema to save locationLink too

* Update default conferncing to include link

* Rename tsx to ts. Fix metadata keys

* WIP on refactoring appstore installed

* Add this to appstore installed apps too

* Display only on conferencing apps

* Add i18n strings

* Change order in dropdown menu so delete is bottom

* Refactor query to not expose all of metadata

* Fix mr type checker

* Possible e2e fix

* Refactor metadata to use ctx

* Refactor back to query cell

* Alias schema

* Adding comment for more info

* Remove constant for clarity

* Update nextjs-bundle-analysis.yml

---------

Co-authored-by: Alex van Andel <me@alexvanandel.com>
Co-authored-by: zomars <zomars@me.com>
2023-02-13 22:55:32 +00:00
Omar López 6cad606ba1 v2.5.13
release.yml / release (push) Canceled after 0s
2023-02-13 15:54:14 -07:00
zomars 7cae7a7bd4 Bundle analyzer fixes 2023-02-13 15:38:44 -07:00
zomars 93f65807e7 Bundle output fixes 2023-02-13 15:13:57 -07:00
Peer Richelsen 0a63820699 fixed border on dark mode (#7079) 2023-02-13 23:02:57 +01:00
zomars 05ad437b27 Update nextjs-bundle-analysis.yml 2023-02-13 15:01:23 -07:00
zomars 26a57a71ae Update nextjs-bundle-analysis.yml 2023-02-13 14:46:04 -07:00
zomars 34a10205a3 Update nextjs-bundle-analysis.yml 2023-02-13 14:44:55 -07:00
Joe Shajan fbf8ff6db7 Public booking page hover fix (#6952)
* fix: hover bg on dark mode

* fix: badge bg color

* fix: bg darkgray 200 on dark mode
2023-02-13 22:02:12 +01:00
Amir FakhrullahandUdit Takkar bef6d18fdf [CAL-1030] fix flickering border issue in menu layout for mobile (#7036)
* fix flickering border issue in menu layout for mobile

* transfer styles changes to the DropdownMenuItem

* remove button border for Remove button

* fix: use dropdownItem

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

---------

Signed-off-by: Udit Takkar <udit.07814802719@cse.mait.ac.in>
Co-authored-by: Udit Takkar <udit.07814802719@cse.mait.ac.in>
2023-02-13 21:57:33 +01:00
zomars 2e96e2ef3f Update nextjs-bundle-analysis.yml 2023-02-13 13:54:27 -07:00
zomars 2ca6769a70 Update nextjs_bundle_analysis.yml 2023-02-13 12:44:37 -07:00
zomars 1eb514dfcf Testing bundle analyzer action 2023-02-13 12:38:54 -07:00
Nafees Nazik d6c004ba22 feat: add stale issues action (#7028) 2023-02-13 12:21:07 -07:00
+17 afb9605f0a Generate SSG Page used as cache for user's third-party calendar (#6775)
* Generate SSG Page used as cache for user's third-party calendars

* remove next-build-id dependency

* yarn.lock from main

* add support to get cached data from multiple months

* Update apps/web/pages/[user]/calendar-cache/[month].tsx

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

* Update apps/web/pages/[user]/calendar-cache/[month].tsx

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

* Update packages/core/CalendarManager.ts

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

* Add api endpoint that revalidates the current month and 3 more ahead

* Revalidate calendar cache when user connect new calendar.

* Revalidate calendar cache when user remove a calendar.

* Revalidate calendar cache when user change de selected calendars-

* Change revalidateCalendarCache function to @calcom/lib/server

* Remove the memory cache from getCachedResults

* refetch availability slots in a 3 seconds interval

* Hotfix: Event Name (#6863) (#6864)

* feat: make key unique (#6861)

* version 2.5.9 (#6868)

* Use Calendar component view=day for drop-in replacement troubleshooter (#6869)

* Use Calendar component view=day for drop-in replacement troubleshooter

* Setting the id to undefined makes the busy time selected

* Updated event title to include title+source

* lots of small changes by me and ciaran (#6871)

* Hotfix: For old Plausible installs enabled in an EventType, give a default value (#6860)

* Add default for trackingId for old plausible installs in event-types

* Fix types

* fix: filter booking in upcoming (#6406)

* fix: filter booking in upcoming

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

* fix: test

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

* fix: wipe-my-cal failing test

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

---------

Signed-off-by: Udit Takkar <udit.07814802719@cse.mait.ac.in>
Co-authored-by: Peer Richelsen <peeroke@gmail.com>
Co-authored-by: Peer Richelsen <peer@cal.com>

* fix workflows when duplicating event types (#6873)

* fix: get location url from metadata (#6774)

* fix: get location url from metadata

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

* fix: replace location

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

* fix: type error

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

* fix: use zod

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

---------

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

* Updates heroku deployment template (#6879)

* Hide button (#6895)

* Fixed some inconsistencies within single event type page (#6887)

* Fixed some inconsistencies within single event type page

* Fix layout shift on AvailabilityTab

* fix(date-overrides): alignment of edit & delete btns (#6892)

* When unchecking the common schedule, schedule should be nulled (#6898)

* theme for storybook

* nit border change (#6899)

* fix: metadata not saved while creating a booking. (#6866)

* feat: add metadata to booking creation

* fix: bug

* Beginning of Strict CSP Compliance (#6841)

* Add CSP Support and enable it initially for Login page

* Update README

* Make sure that CSP is not enabled if CSP_POLICY isnt set

* Add a new value for x-csp header that tells if instance has opted-in to CSP or not

* Add more src to CSP

* Fix typo in header name

* Remove duplicate headers fn

* Add https://eu.ui-avatars.com/api/

* Add CSP_POLICY to env.example

* v2.5.10

* fix: add req.headers (#6921)

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

* add-console-vars (#6929)

* Admin Wizard Choose License (#6574)

* Implementation

* i18n

* More i18n

* extracted i18n, needs api to get most recent price, added hint: update later

* Fixing i18n var

* Fix booking filters not working for admin (#6576)

* fix: react-select overflow issue in some modals. (#6587)

* feat: add a disable overflow prop

* feat: use the disable overflow prop

* Tailwind Merge (#6596)

* Tailwind Merge

* Fix merge classNames

* [CAL-808] /availability/single - UI issue on buttons beside time inputs (#6561)

* [CAL-808] /availability/single - UI issue on buttons beside time inputs

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

* Update packages/features/schedules/components/Schedule.tsx

* create new translation for tooltip

Co-authored-by: gitstart-calcom <gitstart@users.noreply.github.com>
Co-authored-by: Peer Richelsen <peeroke@gmail.com>
Co-authored-by: CarinaWolli <wollencarina@gmail.com>

* Bye bye submodules (#6585)

* WIP

* Uses ssh instead

* Update .gitignore

* Update .gitignore

* Update Makefile

* Update git-setup.sh

* Update git-setup.sh

* Replaced Makefile with bash script

* Update package.json

* fix: show button on empty string (#6601)

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

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

* fix: add delete in dropdown (#6599)

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

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

* Update README.md

* Update README.md

* Changed a neutral- classes to gray (#6603)

* Changed a neutral- classes to gray

* Changed all border-1 to border

* Update package.json

* Test fixes

* Yarn lock fixes

* Fix string equality check in git-setup.sh

* [CAL-811] Avatar icon not redirecting user back to the main page (#6586)

* Remove cursor-pointer, remove old Avatar* files

* Fixed styling for checkedSelect + some cleanup

Co-authored-by: gitstart-calcom <gitstart@users.noreply.github.com>
Co-authored-by: Alex van Andel <me@alexvanandel.com>

* Harsh/add member invite (#6598)

Co-authored-by: Guest <guest@pop-os.localdomain>
Co-authored-by: root <harsh.singh@gocomet.com>

* Regenerated lockfile without upgrade (#6610)

* fix: remove annoying outline when <Button /> clicked (#6537)

* fix: remove annoying outline when <Button /> clicked

* Delete yarn.lock

* remove 1 on 1 icon (#6609)

* removed 1-on-1 badge

* changed user to users for group events

* fix: case-sensitivity in apps path (#6552)

* fix: lowercase slug

* fix: make fallback blocking

* Fix FAB (#6611)

* feat: add LocationSelect component (#6571)

* feat: add LocationSelect component

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

* fix: type error

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

* chore: type error

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

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

* Update booking filters design  (#6543)

* Update booking filters

* Add filter on YOUR bookings

* Fix pending members showing up in list

* Reduce the avatar size to 'sm' for now

* Bugfix/dropdown menu trigger as child remove class names (#6614)

* Fix UsernameTextfield to take right height

* Remove className side-effect

* Incorrect resolution version fixed

* Converted mobile DropdownMenuTrigger styles into Button

* v2.5.3

* fix: use items-center (#6618)

* fix tooltip and modal stacking issues (#6491)

* fix tooltip and modal stacking issues

* use z-index in larger screens and less

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

* Temporary fix (#6626)

* Fix Ga4 tracking (#6630)

* generic <UpgradeScreen> component (#6594)

* first attempt of <UpgradeScreen>

* changes to icons

* reverted changes back to initial state, needs fix: teams not showing

* WIP

* Fix weird reactnode error

* Fix loading text

* added upgradeTip to routing forms

* icon colors

* create and use hook to check if user has team plan

* use useTeamPlan for upgradeTeamsBadge

* replace huge svg with compressed jpeg

* responsive fixes

* Update packages/ui/components/badge/UpgradeTeamsBadge.tsx

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

* Give team plan features to E2E tests

* Allow option to make a user part of team int ests

* Remove flash of paywall for team user

* Add team user for typeform tests as well

Co-authored-by: Peer Richelsen <peer@cal.com>
Co-authored-by: CarinaWolli <wollencarina@gmail.com>
Co-authored-by: Carina Wollendorfer <30310907+CarinaWolli@users.noreply.github.com>
Co-authored-by: Alex van Andel <me@alexvanandel.com>
Co-authored-by: Hariom Balhara <hariombalhara@gmail.com>

* Removing env var to rely on db

* Restoring i18n keys, set loading moved

* Fixing tailwind-preset glob

* Wizard width fix for md+ screens

* Converting licenses options to radix radio

* Applying feedback + other tweaks

* Reverting this, not this PR related

* Unneeded code removal

* Reverting unneeded style change

* Applying feedback

* Removing licenseType

* Upgrades typescript

* Update yarn lock

* Typings

* Hotfix: ping,riverside,whereby and around not showing up in list (#6712)

* Hotfix: ping,riverside,whereby and around not showing up in list (#6712) (#6713)

* Adds deployment settings to DB (#6706)

* WIP

* Adds DeploymentTheme

* Add missing migrations

* Adds client extensions for deployment

* Cleanup

* Delete migration.sql

* Relying on both, env var and new model

* Restoring env example doc for backward compat

* Maximum call stack size exceeded fix?

* Revert upgrade

* Update index.ts

* Delete index.ts

* Not exposing license key, fixed radio behavior

* Covering undefined env var

* Self contained checkLicense

* Feedback

* Moar feedback

* Feedback

* Feedback

* Feedback

* Cleanup

---------

Signed-off-by: Udit Takkar <udit.07814802719@cse.mait.ac.in>
Co-authored-by: Peer Richelsen <peer@cal.com>
Co-authored-by: sean-brydon <55134778+sean-brydon@users.noreply.github.com>
Co-authored-by: Nafees Nazik <84864519+G3root@users.noreply.github.com>
Co-authored-by: GitStart-Cal.com <121884634+gitstart-calcom@users.noreply.github.com>
Co-authored-by: gitstart-calcom <gitstart@users.noreply.github.com>
Co-authored-by: Peer Richelsen <peeroke@gmail.com>
Co-authored-by: CarinaWolli <wollencarina@gmail.com>
Co-authored-by: Omar López <zomars@me.com>
Co-authored-by: Udit Takkar <53316345+Udit-takkar@users.noreply.github.com>
Co-authored-by: Alex van Andel <me@alexvanandel.com>
Co-authored-by: Harsh Singh <51085015+harshsinghatz@users.noreply.github.com>
Co-authored-by: Guest <guest@pop-os.localdomain>
Co-authored-by: root <harsh.singh@gocomet.com>
Co-authored-by: Luis Cadillo <luiscaf3r@gmail.com>
Co-authored-by: Mohammed Cherfaoui <hi@cherfaoui.dev>
Co-authored-by: Hariom Balhara <hariombalhara@gmail.com>
Co-authored-by: Carina Wollendorfer <30310907+CarinaWolli@users.noreply.github.com>

* added two new tips (#6915)

* [CAL-488] Timezone selection has a weird double dropdown (#6851)

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

* fix: color and line height of icon (#6913)

* fix: use destination calendar email (#6886)

* fix: use destination calendar email
to display correct primary email

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

* fix: simplify logic

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

---------

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

* fix: dropdown title in bookings page (#6924)

* fixes the broken max size of members on teams page (#6926)

* fix: display provider name instead of url (#6914)

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

* fix: add sortByLabel (#6797)

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

* Email Variables Bug (#6943)

* Remove _subject translations for zh-CN, needs retranslation

* minor timezone-select improvements (#6944)

* fixed timezone select positioning and hover

* fixed timezone select positioning and hover

* Give trackingId a default value because if user doesnt interact with trackingId input it is not set (#6945)

* Block /auth/:path, nothing else. (#6949)

* Block /auth/:path, nothing else.

* Also add /signup

* fix start icon in button (#6950)

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

* Fixes localisation of {EVENT_DATE} in workflows (#6907)

* translate {EVENT_DATE} variable to correct language

* fix locale for cron schedule reminder emails/sms

* fix type error

* add missing locale to attendees

* fix type error

* code clean up

* revert last commit

* using Intl for date translations

---------

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

* Allow account linking for Google and SAML providers (#6874)

* allow account linking for self-hosted instances, both Google and SAML are verified emails

* allow account linking for Google and SSO if emails match with existing username/password account

* Tweaked find user by email since we now have multiple providers (other than credentials provider)

* feat/payment-service-6438-cal-767 (#6677)

* WIP paymentService

* Changes for payment Service

* Fix for stripe payment flow

* Remove logs/comments

* Refactored refund for stripe app

* Move stripe handlePayment to own lib

* Move stripe delete payments to paymentService

* lint fix

* Change handleRefundError as generic function

* remove log

* remove logs

* remove logs

* Return stripe default export to lib/server

* Fixing types

* Fix types

* Upgrades typescript

* Update yarn lock

* Typings

* Hotfix: ping,riverside,whereby and around not showing up in list (#6712)

* Hotfix: ping,riverside,whereby and around not showing up in list (#6712) (#6713)

* Adds deployment settings to DB (#6706)

* WIP

* Adds DeploymentTheme

* Add missing migrations

* Adds client extensions for deployment

* Cleanup

* Revert "lint fix"

This reverts commit e1a2e4a357e58e6673c47399888ae2e00d1351a6.

* Add validation

* Revert changes removed in force push

* Removing abstract class and just leaving interface implementation

* Fix types for handlePayments

* Fix payment test appStore import

* Fix stripe metadata in event type

* Move migration to separate PR

* Revert "Move migration to separate PR"

This reverts commit 48aa64e0724a522d3cc2fefaaaee5792ee9cd9e6.

* Update packages/prisma/migrations/20230125175109_remove_type_from_payment_and_add_app_relationship/migration.sql

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

---------

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

* Small UI fixes for seats & destination calendars (#6859)

* Do not add former time for events on seats

* Default display destination calendar

* Add seats badge to event type item

* Add string

* Actively watch seats enabled option for requires confirmation

* Only show former time when there is a rescheduleUid

* fix: use typedquery hook in duplicate dialog (#6730)

* fix: use typedquery hook in duplicate dialog

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

* Update packages/features/eventtypes/components/DuplicateDialog.tsx

---------

Signed-off-by: Udit Takkar <udit.07814802719@cse.mait.ac.in>
Co-authored-by: Peer Richelsen <peer@cal.com>
Co-authored-by: Omar López <zomars@me.com>

* Fixing admin wizard step done (#6954)

* Feature/maintenance mode (#6930)

* Implement maintenance mode with Vercel Edge Config

* Error log is spam during development/ added \n in .env.example

* Exclude _next, /api for /maintenance page

* Re-instate previous config

* rtl: begone

* Added note to explain why /auth/login covers the maintenance page.

---------

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

* Update package.json

* I18N Caching (#6823)

* Caching Logic Changes

Enabled this function to change its cache value based on incoming paths value

* Invalidate I18N Cache

Invalidating the I18N cache when a user saves changes to their General settings

* Removes deprecated useLocale location

* Overriding the default getSchedule cache to have a revalidation time of 1 second

* Update apps/web/pages/api/trpc/[trpc].ts

* Updated cache values to match the comment

---------

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

* feat: return `x-vercel-ip-timezone` in headers (#6849)

* feat: add trpc to matcher and pass vercel timezone header

* feat: pass request to context

* feat: return timezone in header

* refactor: split context

* fix: remove tsignore comment

* Update [trpc].ts

---------

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

* log the json url for testing

* use WEBAPP_URL constant instead env.NEXT_PUBLIC_WEBAPP_URL

* remove the commented selectedCalendars var, it is not necessary

* Caching fixes

* Separate selectedDate slots from month slots

* Update [trpc].ts

* Log headers

* Update [trpc].ts

* Update package.json

* Fixes/trpc headers (#7045)

* Cache fixes

* Testing

* SWR breaks embed tests

* Prevent refetching day on month switch

* Skeleton fixes

---------

Signed-off-by: Udit Takkar <udit.07814802719@cse.mait.ac.in>
Co-authored-by: zomars <zomars@me.com>
Co-authored-by: Hariom Balhara <hariombalhara@gmail.com>
Co-authored-by: Nafees Nazik <84864519+G3root@users.noreply.github.com>
Co-authored-by: Ben Hybert <53020786+Hybes@users.noreply.github.com>
Co-authored-by: Alex van Andel <me@alexvanandel.com>
Co-authored-by: Peer Richelsen <peeroke@gmail.com>
Co-authored-by: Udit Takkar <53316345+Udit-takkar@users.noreply.github.com>
Co-authored-by: Peer Richelsen <peer@cal.com>
Co-authored-by: Carina Wollendorfer <30310907+CarinaWolli@users.noreply.github.com>
Co-authored-by: Syed Ali Shahbaz <52925846+alishaz-polymath@users.noreply.github.com>
Co-authored-by: sean-brydon <55134778+sean-brydon@users.noreply.github.com>
Co-authored-by: Sai Deepesh <saideepesh000@gmail.com>
Co-authored-by: alannnc <alannnc@gmail.com>
Co-authored-by: Leo Giovanetti <hello@leog.me>
Co-authored-by: GitStart-Cal.com <121884634+gitstart-calcom@users.noreply.github.com>
Co-authored-by: gitstart-calcom <gitstart@users.noreply.github.com>
Co-authored-by: CarinaWolli <wollencarina@gmail.com>
Co-authored-by: Harsh Singh <51085015+harshsinghatz@users.noreply.github.com>
Co-authored-by: Guest <guest@pop-os.localdomain>
Co-authored-by: root <harsh.singh@gocomet.com>
Co-authored-by: Luis Cadillo <luiscaf3r@gmail.com>
Co-authored-by: Mohammed Cherfaoui <hi@cherfaoui.dev>
Co-authored-by: Joe Shajan <joeshajan1551@gmail.com>
Co-authored-by: Deepak Prabhakara <deepak@boxyhq.com>
Co-authored-by: Joe Au-Yeung <65426560+joeauyeung@users.noreply.github.com>
Co-authored-by: Aaron Presley <155617+AaronPresley@users.noreply.github.com>
2023-02-13 11:42:53 -07:00
Nafees Nazik a2549bd7b6 feat: use week start from owner (#7072) 2023-02-13 16:21:55 +00:00
Joe Shajan c2a8f799ff fix: availability header margin bottom (#7037) 2023-02-13 15:06:27 +00:00
sean-brydon c68ff54e77 Feat/full custom select (#6865)
* Inital Setup - refactors/optimise

* Escape clears focus

* A11y and optimisations

* A11y enter fix

* Sort out flatternt list indexing

* Fix spacing - fix single selected state

* Solves group highlights breaking things

* Fix selecting while filtering list

* Remove styles and rename story

* Hide labels while searching for now

* Remove group item

* move onclick hook to hooks

* Fix typo

* Use check icon on single select

* scroll into view when keyboard navigating

* add comment explaining dropdown close

* Remove tenery and make disabled easier to read

* Typo

* remove log

* Remove destructing of classNames props

* Refactor callbacks + hooks

* Style updates with ciaran

* Final style changes

* center icon

* Add darkmode
2023-02-13 15:14:23 +01:00
darshan 74fe20802d Ability to write placeholder in routing forms (#7054) 2023-02-13 18:43:24 +05:30
Aaron Presley d59cda3286 Collective events are now considered from getBusyTimes booking query (#6911)
* Updated the busyTimes query to include bookings owned OR hosted by the given user

* Updated getSchedule tests to account for the new where condition

* Ignoring typing within a mocked function

* Further type checks, figured out how to run the command locally
2023-02-13 12:46:37 +00:00
Carina WollendorferandCarinaWolli 1cae2b6f3d Fixing issues around workflows (#6991)
Co-authored-by: CarinaWolli <wollencarina@gmail.com>
2023-02-13 12:39:06 +00:00
Richard Poelderl 9d9fa8e575 turn inline logo & shell headers into h3 (#7060) 2023-02-13 12:29:48 +00:00
Nafees Nazik f04c634c48 fix: fixme line in todo action (#6982)
* fix: remove line marked with the comment fixme

* fix: remove push
2023-02-13 12:27:48 +00:00
alannnc c3e7981917 Fix/bookings unintended confirmations on rejection 6975 (#7047)
* Fixed translation message and added paymentStatus to booking page

* Fix booking confirmation with payment

* Remove previous code unnecesary
2023-02-13 12:26:28 +00:00
Shane Maglangit d6594dab0f fix: add null check for userSchedule.availability (#7053) 2023-02-13 11:23:24 +00:00
Carina WollendorferandCarinaWolli 5fcfbb2d90 fix text color (#7056)
Co-authored-by: CarinaWolli <wollencarina@gmail.com>
2023-02-13 11:10:52 +00:00
Peer Richelsen 8a99c3d2a5 Update Tips.tsx 2023-02-12 22:34:07 +01:00
Peer Richelsen 336c2d3643 Update README.md 2023-02-12 22:06:03 +01:00
Peer Richelsen cfe3ef4ab0 Update README.md 2023-02-12 20:43:16 +01:00
Peer Richelsen 4ec8241a86 Update README.md 2023-02-12 20:33:16 +01:00
Peer Richelsen e6313aafac Update README.md 2023-02-12 20:31:32 +01:00
Peer Richelsen f87f030bb5 Update README.md 2023-02-12 20:31:20 +01:00
Amir FakhrullahandPeer Richelsen f87254cdc3 Fix: avatar group buggy with +0 (#7044)
* fix AvatarGroup, refactor a bit

* handle cases where truncated avatars are 2 digits

* use slice, and add comment

* update comment

* Update packages/ui/components/avatar/AvatarGroup.tsx

* fix classname order issue

---------

Co-authored-by: Peer Richelsen <peer@cal.com>
2023-02-11 16:25:36 +00:00
Omar López 1f74837189 Fixes/trpc headers (#7045)
* Cache fixes

* Testing

* SWR breaks embed tests
2023-02-10 14:06:52 -07:00
Omar López c7064906c9 Update package.json (#7043) 2023-02-10 13:50:01 -07:00
Omar López 86c94a3cd5 Upgrades tRPC to 10.10.0 (#6995)
* Upgrades tRPC to 10.10.0

* Type fixes
2023-02-10 13:05:02 -07:00
Joe Au-Yeung 2056ebe186 Only show seats badge if it is greater than 1 (#7041) 2023-02-10 16:38:20 +00:00
Leo Giovanetti 53424ca9ae Fixing using given username (#7033) 2023-02-10 10:23:24 -03:00
Nafees NazikandPeer Richelsen 8197ba18d4 feat: add new Jitsu events (#6980)
Co-authored-by: Peer Richelsen <peer@cal.com>
2023-02-10 09:53:03 +00:00
GitStart-Cal.comandgitstart-calcom d341ea5111 [CAL-812] Button group focus/hover state (#6854)
Co-authored-by: gitstart-calcom <gitstart@users.noreply.github.com>
2023-02-09 21:54:09 +00:00
Omar López 42dcd4a2a9 Revert "Use Calendar component view=day for drop-in replacement troubleshooter (#6869)" (#6985)
This reverts commit f18e80cfcf.
2023-02-09 12:01:43 -07:00
Leo Giovanetti c63225fdbf Fixing finish button not working (#6977) 2023-02-09 18:15:28 +00:00
zomars 41774e4932 Fix flaky test 2023-02-09 10:51:48 -07:00
Omar López af7849f951 v2.5.12
release.yml / release (push) Canceled after 0s
2023-02-09 09:34:51 -07:00
Alex van Andel 5353610d9a Only handle refunds when there are payments, otherwise skip (#6974) 2023-02-09 15:43:28 +00:00
+14 156f3e5de2 fix: admin password hint text (#6906)
* feat: use the trans hook

* fix: hide AdminPasswordBanner

* fix: translation

* fix: style and use validation

* fix: layout

* fix: use trans keys

* fix: replace number with placeholder

* feat: add alert banner

* fix: use the correct password length

* fix: metadata not saved while creating a booking. (#6866)

* feat: add metadata to booking creation

* fix: bug

* Beginning of Strict CSP Compliance (#6841)

* Add CSP Support and enable it initially for Login page

* Update README

* Make sure that CSP is not enabled if CSP_POLICY isnt set

* Add a new value for x-csp header that tells if instance has opted-in to CSP or not

* Add more src to CSP

* Fix typo in header name

* Remove duplicate headers fn

* Add https://eu.ui-avatars.com/api/

* Add CSP_POLICY to env.example

* v2.5.10

* fix: add req.headers (#6921)

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

* add-console-vars (#6929)

* Admin Wizard Choose License (#6574)

* Implementation

* i18n

* More i18n

* extracted i18n, needs api to get most recent price, added hint: update later

* Fixing i18n var

* Fix booking filters not working for admin (#6576)

* fix: react-select overflow issue in some modals. (#6587)

* feat: add a disable overflow prop

* feat: use the disable overflow prop

* Tailwind Merge (#6596)

* Tailwind Merge

* Fix merge classNames

* [CAL-808] /availability/single - UI issue on buttons beside time inputs (#6561)

* [CAL-808] /availability/single - UI issue on buttons beside time inputs

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

* Update packages/features/schedules/components/Schedule.tsx

* create new translation for tooltip

Co-authored-by: gitstart-calcom <gitstart@users.noreply.github.com>
Co-authored-by: Peer Richelsen <peeroke@gmail.com>
Co-authored-by: CarinaWolli <wollencarina@gmail.com>

* Bye bye submodules (#6585)

* WIP

* Uses ssh instead

* Update .gitignore

* Update .gitignore

* Update Makefile

* Update git-setup.sh

* Update git-setup.sh

* Replaced Makefile with bash script

* Update package.json

* fix: show button on empty string (#6601)

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

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

* fix: add delete in dropdown (#6599)

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

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

* Update README.md

* Update README.md

* Changed a neutral- classes to gray (#6603)

* Changed a neutral- classes to gray

* Changed all border-1 to border

* Update package.json

* Test fixes

* Yarn lock fixes

* Fix string equality check in git-setup.sh

* [CAL-811] Avatar icon not redirecting user back to the main page (#6586)

* Remove cursor-pointer, remove old Avatar* files

* Fixed styling for checkedSelect + some cleanup

Co-authored-by: gitstart-calcom <gitstart@users.noreply.github.com>
Co-authored-by: Alex van Andel <me@alexvanandel.com>

* Harsh/add member invite (#6598)

Co-authored-by: Guest <guest@pop-os.localdomain>
Co-authored-by: root <harsh.singh@gocomet.com>

* Regenerated lockfile without upgrade (#6610)

* fix: remove annoying outline when <Button /> clicked (#6537)

* fix: remove annoying outline when <Button /> clicked

* Delete yarn.lock

* remove 1 on 1 icon (#6609)

* removed 1-on-1 badge

* changed user to users for group events

* fix: case-sensitivity in apps path (#6552)

* fix: lowercase slug

* fix: make fallback blocking

* Fix FAB (#6611)

* feat: add LocationSelect component (#6571)

* feat: add LocationSelect component

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

* fix: type error

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

* chore: type error

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

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

* Update booking filters design  (#6543)

* Update booking filters

* Add filter on YOUR bookings

* Fix pending members showing up in list

* Reduce the avatar size to 'sm' for now

* Bugfix/dropdown menu trigger as child remove class names (#6614)

* Fix UsernameTextfield to take right height

* Remove className side-effect

* Incorrect resolution version fixed

* Converted mobile DropdownMenuTrigger styles into Button

* v2.5.3

* fix: use items-center (#6618)

* fix tooltip and modal stacking issues (#6491)

* fix tooltip and modal stacking issues

* use z-index in larger screens and less

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

* Temporary fix (#6626)

* Fix Ga4 tracking (#6630)

* generic <UpgradeScreen> component (#6594)

* first attempt of <UpgradeScreen>

* changes to icons

* reverted changes back to initial state, needs fix: teams not showing

* WIP

* Fix weird reactnode error

* Fix loading text

* added upgradeTip to routing forms

* icon colors

* create and use hook to check if user has team plan

* use useTeamPlan for upgradeTeamsBadge

* replace huge svg with compressed jpeg

* responsive fixes

* Update packages/ui/components/badge/UpgradeTeamsBadge.tsx

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

* Give team plan features to E2E tests

* Allow option to make a user part of team int ests

* Remove flash of paywall for team user

* Add team user for typeform tests as well

Co-authored-by: Peer Richelsen <peer@cal.com>
Co-authored-by: CarinaWolli <wollencarina@gmail.com>
Co-authored-by: Carina Wollendorfer <30310907+CarinaWolli@users.noreply.github.com>
Co-authored-by: Alex van Andel <me@alexvanandel.com>
Co-authored-by: Hariom Balhara <hariombalhara@gmail.com>

* Removing env var to rely on db

* Restoring i18n keys, set loading moved

* Fixing tailwind-preset glob

* Wizard width fix for md+ screens

* Converting licenses options to radix radio

* Applying feedback + other tweaks

* Reverting this, not this PR related

* Unneeded code removal

* Reverting unneeded style change

* Applying feedback

* Removing licenseType

* Upgrades typescript

* Update yarn lock

* Typings

* Hotfix: ping,riverside,whereby and around not showing up in list (#6712)

* Hotfix: ping,riverside,whereby and around not showing up in list (#6712) (#6713)

* Adds deployment settings to DB (#6706)

* WIP

* Adds DeploymentTheme

* Add missing migrations

* Adds client extensions for deployment

* Cleanup

* Delete migration.sql

* Relying on both, env var and new model

* Restoring env example doc for backward compat

* Maximum call stack size exceeded fix?

* Revert upgrade

* Update index.ts

* Delete index.ts

* Not exposing license key, fixed radio behavior

* Covering undefined env var

* Self contained checkLicense

* Feedback

* Moar feedback

* Feedback

* Feedback

* Feedback

* Cleanup

---------

Signed-off-by: Udit Takkar <udit.07814802719@cse.mait.ac.in>
Co-authored-by: Peer Richelsen <peer@cal.com>
Co-authored-by: sean-brydon <55134778+sean-brydon@users.noreply.github.com>
Co-authored-by: Nafees Nazik <84864519+G3root@users.noreply.github.com>
Co-authored-by: GitStart-Cal.com <121884634+gitstart-calcom@users.noreply.github.com>
Co-authored-by: gitstart-calcom <gitstart@users.noreply.github.com>
Co-authored-by: Peer Richelsen <peeroke@gmail.com>
Co-authored-by: CarinaWolli <wollencarina@gmail.com>
Co-authored-by: Omar López <zomars@me.com>
Co-authored-by: Udit Takkar <53316345+Udit-takkar@users.noreply.github.com>
Co-authored-by: Alex van Andel <me@alexvanandel.com>
Co-authored-by: Harsh Singh <51085015+harshsinghatz@users.noreply.github.com>
Co-authored-by: Guest <guest@pop-os.localdomain>
Co-authored-by: root <harsh.singh@gocomet.com>
Co-authored-by: Luis Cadillo <luiscaf3r@gmail.com>
Co-authored-by: Mohammed Cherfaoui <hi@cherfaoui.dev>
Co-authored-by: Hariom Balhara <hariombalhara@gmail.com>
Co-authored-by: Carina Wollendorfer <30310907+CarinaWolli@users.noreply.github.com>

* added two new tips (#6915)

* [CAL-488] Timezone selection has a weird double dropdown (#6851)

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

* fix: color and line height of icon (#6913)

* fix: use destination calendar email (#6886)

* fix: use destination calendar email
to display correct primary email

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

* fix: simplify logic

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

---------

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

* fix: dropdown title in bookings page (#6924)

* fixes the broken max size of members on teams page (#6926)

* fix: display provider name instead of url (#6914)

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

* fix: add sortByLabel (#6797)

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

* Email Variables Bug (#6943)

* Remove _subject translations for zh-CN, needs retranslation

* minor timezone-select improvements (#6944)

* fixed timezone select positioning and hover

* fixed timezone select positioning and hover

* Give trackingId a default value because if user doesnt interact with trackingId input it is not set (#6945)

* Block /auth/:path, nothing else. (#6949)

* Block /auth/:path, nothing else.

* Also add /signup

* fix start icon in button (#6950)

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

* Fixes localisation of {EVENT_DATE} in workflows (#6907)

* translate {EVENT_DATE} variable to correct language

* fix locale for cron schedule reminder emails/sms

* fix type error

* add missing locale to attendees

* fix type error

* code clean up

* revert last commit

* using Intl for date translations

---------

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

* Allow account linking for Google and SAML providers (#6874)

* allow account linking for self-hosted instances, both Google and SAML are verified emails

* allow account linking for Google and SSO if emails match with existing username/password account

* Tweaked find user by email since we now have multiple providers (other than credentials provider)

* feat/payment-service-6438-cal-767 (#6677)

* WIP paymentService

* Changes for payment Service

* Fix for stripe payment flow

* Remove logs/comments

* Refactored refund for stripe app

* Move stripe handlePayment to own lib

* Move stripe delete payments to paymentService

* lint fix

* Change handleRefundError as generic function

* remove log

* remove logs

* remove logs

* Return stripe default export to lib/server

* Fixing types

* Fix types

* Upgrades typescript

* Update yarn lock

* Typings

* Hotfix: ping,riverside,whereby and around not showing up in list (#6712)

* Hotfix: ping,riverside,whereby and around not showing up in list (#6712) (#6713)

* Adds deployment settings to DB (#6706)

* WIP

* Adds DeploymentTheme

* Add missing migrations

* Adds client extensions for deployment

* Cleanup

* Revert "lint fix"

This reverts commit e1a2e4a357e58e6673c47399888ae2e00d1351a6.

* Add validation

* Revert changes removed in force push

* Removing abstract class and just leaving interface implementation

* Fix types for handlePayments

* Fix payment test appStore import

* Fix stripe metadata in event type

* Move migration to separate PR

* Revert "Move migration to separate PR"

This reverts commit 48aa64e0724a522d3cc2fefaaaee5792ee9cd9e6.

* Update packages/prisma/migrations/20230125175109_remove_type_from_payment_and_add_app_relationship/migration.sql

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

---------

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

* Small UI fixes for seats & destination calendars (#6859)

* Do not add former time for events on seats

* Default display destination calendar

* Add seats badge to event type item

* Add string

* Actively watch seats enabled option for requires confirmation

* Only show former time when there is a rescheduleUid

* fix: use typedquery hook in duplicate dialog (#6730)

* fix: use typedquery hook in duplicate dialog

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

* Update packages/features/eventtypes/components/DuplicateDialog.tsx

---------

Signed-off-by: Udit Takkar <udit.07814802719@cse.mait.ac.in>
Co-authored-by: Peer Richelsen <peer@cal.com>
Co-authored-by: Omar López <zomars@me.com>

* Fixing admin wizard step done (#6954)

* Feature/maintenance mode (#6930)

* Implement maintenance mode with Vercel Edge Config

* Error log is spam during development/ added \n in .env.example

* Exclude _next, /api for /maintenance page

* Re-instate previous config

* rtl: begone

* Added note to explain why /auth/login covers the maintenance page.

---------

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

* Update package.json

* I18N Caching (#6823)

* Caching Logic Changes

Enabled this function to change its cache value based on incoming paths value

* Invalidate I18N Cache

Invalidating the I18N cache when a user saves changes to their General settings

* Removes deprecated useLocale location

* Overriding the default getSchedule cache to have a revalidation time of 1 second

* Update apps/web/pages/api/trpc/[trpc].ts

* Updated cache values to match the comment

---------

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

---------

Signed-off-by: Udit Takkar <udit.07814802719@cse.mait.ac.in>
Co-authored-by: Hariom Balhara <hariombalhara@gmail.com>
Co-authored-by: Omar López <zomars@me.com>
Co-authored-by: Udit Takkar <53316345+Udit-takkar@users.noreply.github.com>
Co-authored-by: alannnc <alannnc@gmail.com>
Co-authored-by: Leo Giovanetti <hello@leog.me>
Co-authored-by: Peer Richelsen <peer@cal.com>
Co-authored-by: sean-brydon <55134778+sean-brydon@users.noreply.github.com>
Co-authored-by: GitStart-Cal.com <121884634+gitstart-calcom@users.noreply.github.com>
Co-authored-by: gitstart-calcom <gitstart@users.noreply.github.com>
Co-authored-by: Peer Richelsen <peeroke@gmail.com>
Co-authored-by: CarinaWolli <wollencarina@gmail.com>
Co-authored-by: Alex van Andel <me@alexvanandel.com>
Co-authored-by: Harsh Singh <51085015+harshsinghatz@users.noreply.github.com>
Co-authored-by: Guest <guest@pop-os.localdomain>
Co-authored-by: root <harsh.singh@gocomet.com>
Co-authored-by: Luis Cadillo <luiscaf3r@gmail.com>
Co-authored-by: Mohammed Cherfaoui <hi@cherfaoui.dev>
Co-authored-by: Carina Wollendorfer <30310907+CarinaWolli@users.noreply.github.com>
Co-authored-by: Joe Shajan <joeshajan1551@gmail.com>
Co-authored-by: Ben Hybert <53020786+Hybes@users.noreply.github.com>
Co-authored-by: Deepak Prabhakara <deepak@boxyhq.com>
Co-authored-by: Joe Au-Yeung <65426560+joeauyeung@users.noreply.github.com>
Co-authored-by: Aaron Presley <155617+AaronPresley@users.noreply.github.com>
2023-02-09 02:02:17 +00:00
Omar López 05f51459a6 Add todo to issue action (#6749)
* Create todo-to-issue.yml

* Update todo-to-issue.yml

* Update todo-to-issue.yml

* Update todo-to-issue.yml

* Update todo-to-issue.yml

* test

* Update todo-to-issue.yml
2023-02-08 18:24:01 -07:00
Nafees Nazikandzomars f0db97bbb1 feat: return x-vercel-ip-timezone in headers (#6849)
* feat: add trpc to matcher and pass vercel timezone header

* feat: pass request to context

* feat: return timezone in header

* refactor: split context

* fix: remove tsignore comment

* Update [trpc].ts

---------

Co-authored-by: zomars <zomars@me.com>
2023-02-09 01:12:45 +00:00
Aaron Presleyandzomars 05c33bd94b I18N Caching (#6823)
* Caching Logic Changes

Enabled this function to change its cache value based on incoming paths value

* Invalidate I18N Cache

Invalidating the I18N cache when a user saves changes to their General settings

* Removes deprecated useLocale location

* Overriding the default getSchedule cache to have a revalidation time of 1 second

* Update apps/web/pages/api/trpc/[trpc].ts

* Updated cache values to match the comment

---------

Co-authored-by: zomars <zomars@me.com>
2023-02-08 17:35:43 -07:00
Omar López 7d4cc59cd2 Update package.json
release.yml / release (push) Canceled after 0s
2023-02-08 16:07:19 -07:00
Alex van AndelandOmar López a94465ff04 Feature/maintenance mode (#6930)
* Implement maintenance mode with Vercel Edge Config

* Error log is spam during development/ added \n in .env.example

* Exclude _next, /api for /maintenance page

* Re-instate previous config

* rtl: begone

* Added note to explain why /auth/login covers the maintenance page.

---------

Co-authored-by: Omar López <zomars@me.com>
2023-02-08 21:51:58 +00:00
Leo Giovanetti 4d54ac3ca2 Fixing admin wizard step done (#6954) 2023-02-08 14:36:46 -07:00
15da690270 fix: use typedquery hook in duplicate dialog (#6730)
* fix: use typedquery hook in duplicate dialog

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

* Update packages/features/eventtypes/components/DuplicateDialog.tsx

---------

Signed-off-by: Udit Takkar <udit.07814802719@cse.mait.ac.in>
Co-authored-by: Peer Richelsen <peer@cal.com>
Co-authored-by: Omar López <zomars@me.com>
2023-02-08 21:29:16 +00:00
Joe Au-Yeung 2462e8e597 Small UI fixes for seats & destination calendars (#6859)
* Do not add former time for events on seats

* Default display destination calendar

* Add seats badge to event type item

* Add string

* Actively watch seats enabled option for requires confirmation

* Only show former time when there is a rescheduleUid
2023-02-08 21:13:10 +00:00
2f628a17df feat/payment-service-6438-cal-767 (#6677)
* WIP paymentService

* Changes for payment Service

* Fix for stripe payment flow

* Remove logs/comments

* Refactored refund for stripe app

* Move stripe handlePayment to own lib

* Move stripe delete payments to paymentService

* lint fix

* Change handleRefundError as generic function

* remove log

* remove logs

* remove logs

* Return stripe default export to lib/server

* Fixing types

* Fix types

* Upgrades typescript

* Update yarn lock

* Typings

* Hotfix: ping,riverside,whereby and around not showing up in list (#6712)

* Hotfix: ping,riverside,whereby and around not showing up in list (#6712) (#6713)

* Adds deployment settings to DB (#6706)

* WIP

* Adds DeploymentTheme

* Add missing migrations

* Adds client extensions for deployment

* Cleanup

* Revert "lint fix"

This reverts commit e1a2e4a357e58e6673c47399888ae2e00d1351a6.

* Add validation

* Revert changes removed in force push

* Removing abstract class and just leaving interface implementation

* Fix types for handlePayments

* Fix payment test appStore import

* Fix stripe metadata in event type

* Move migration to separate PR

* Revert "Move migration to separate PR"

This reverts commit 48aa64e0724a522d3cc2fefaaaee5792ee9cd9e6.

* Update packages/prisma/migrations/20230125175109_remove_type_from_payment_and_add_app_relationship/migration.sql

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

---------

Co-authored-by: zomars <zomars@me.com>
Co-authored-by: Hariom Balhara <hariombalhara@gmail.com>
2023-02-08 13:36:22 -07:00
Deepak Prabhakara 1ee3783db3 Allow account linking for Google and SAML providers (#6874)
* allow account linking for self-hosted instances, both Google and SAML are verified emails

* allow account linking for Google and SSO if emails match with existing username/password account

* Tweaked find user by email since we now have multiple providers (other than credentials provider)
2023-02-08 11:39:56 -07:00
Carina WollendorferandCarinaWolli b3d8d7e944 Fixes localisation of {EVENT_DATE} in workflows (#6907)
* translate {EVENT_DATE} variable to correct language

* fix locale for cron schedule reminder emails/sms

* fix type error

* add missing locale to attendees

* fix type error

* code clean up

* revert last commit

* using Intl for date translations

---------

Co-authored-by: CarinaWolli <wollencarina@gmail.com>
2023-02-08 17:06:25 +00:00
Carina WollendorferandCarinaWolli a4b7f1af65 fix start icon in button (#6950)
Co-authored-by: CarinaWolli <wollencarina@gmail.com>
2023-02-08 17:02:08 +00:00
Alex van Andel f7445bf8a1 Block /auth/:path, nothing else. (#6949)
* Block /auth/:path, nothing else.

* Also add /signup
2023-02-08 16:27:18 +00:00
Hariom Balhara 9cad7086d7 Give trackingId a default value because if user doesnt interact with trackingId input it is not set (#6945) 2023-02-08 16:20:13 +00:00
Peer Richelsen 3345ec61ee minor timezone-select improvements (#6944)
* fixed timezone select positioning and hover

* fixed timezone select positioning and hover
2023-02-08 14:34:17 +00:00
Alex van Andel 7797421ce9 Remove _subject translations for zh-CN, needs retranslation 2023-02-08 14:31:29 +00:00
Udit Takkar 075a274207 Email Variables Bug (#6943) 2023-02-08 15:17:45 +01:00
Udit Takkar a46a31040a fix: add sortByLabel (#6797)
Signed-off-by: Udit Takkar <udit.07814802719@cse.mait.ac.in>
2023-02-08 12:48:47 +00:00
Udit Takkar 7a28e1d6f4 fix: display provider name instead of url (#6914)
Signed-off-by: Udit Takkar <udit.07814802719@cse.mait.ac.in>
2023-02-08 12:45:09 +00:00
Ben Hybert 51fd7fdb3e fixes the broken max size of members on teams page (#6926) 2023-02-08 12:44:28 +00:00
Joe Shajan d01963303a fix: dropdown title in bookings page (#6924) 2023-02-08 12:43:45 +00:00
Udit Takkar 6877d0f693 fix: use destination calendar email (#6886)
* fix: use destination calendar email
to display correct primary email

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

* fix: simplify logic

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

---------

Signed-off-by: Udit Takkar <udit.07814802719@cse.mait.ac.in>
2023-02-08 12:19:02 +00:00
Udit Takkar 39040fca9a fix: color and line height of icon (#6913) 2023-02-08 13:14:52 +01:00
GitStart-Cal.comandgitstart-calcom 6fa4befc9b [CAL-488] Timezone selection has a weird double dropdown (#6851)
Co-authored-by: gitstart-calcom <gitstart@users.noreply.github.com>
2023-02-08 12:08:00 +00:00
Peer Richelsen 8c9871c6ce added two new tips (#6915) 2023-02-08 11:21:07 +00:00
+8 a9af2fb255 Admin Wizard Choose License (#6574)
* Implementation

* i18n

* More i18n

* extracted i18n, needs api to get most recent price, added hint: update later

* Fixing i18n var

* Fix booking filters not working for admin (#6576)

* fix: react-select overflow issue in some modals. (#6587)

* feat: add a disable overflow prop

* feat: use the disable overflow prop

* Tailwind Merge (#6596)

* Tailwind Merge

* Fix merge classNames

* [CAL-808] /availability/single - UI issue on buttons beside time inputs (#6561)

* [CAL-808] /availability/single - UI issue on buttons beside time inputs

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

* Update packages/features/schedules/components/Schedule.tsx

* create new translation for tooltip

Co-authored-by: gitstart-calcom <gitstart@users.noreply.github.com>
Co-authored-by: Peer Richelsen <peeroke@gmail.com>
Co-authored-by: CarinaWolli <wollencarina@gmail.com>

* Bye bye submodules (#6585)

* WIP

* Uses ssh instead

* Update .gitignore

* Update .gitignore

* Update Makefile

* Update git-setup.sh

* Update git-setup.sh

* Replaced Makefile with bash script

* Update package.json

* fix: show button on empty string (#6601)

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

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

* fix: add delete in dropdown (#6599)

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

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

* Update README.md

* Update README.md

* Changed a neutral- classes to gray (#6603)

* Changed a neutral- classes to gray

* Changed all border-1 to border

* Update package.json

* Test fixes

* Yarn lock fixes

* Fix string equality check in git-setup.sh

* [CAL-811] Avatar icon not redirecting user back to the main page (#6586)

* Remove cursor-pointer, remove old Avatar* files

* Fixed styling for checkedSelect + some cleanup

Co-authored-by: gitstart-calcom <gitstart@users.noreply.github.com>
Co-authored-by: Alex van Andel <me@alexvanandel.com>

* Harsh/add member invite (#6598)

Co-authored-by: Guest <guest@pop-os.localdomain>
Co-authored-by: root <harsh.singh@gocomet.com>

* Regenerated lockfile without upgrade (#6610)

* fix: remove annoying outline when <Button /> clicked (#6537)

* fix: remove annoying outline when <Button /> clicked

* Delete yarn.lock

* remove 1 on 1 icon (#6609)

* removed 1-on-1 badge

* changed user to users for group events

* fix: case-sensitivity in apps path (#6552)

* fix: lowercase slug

* fix: make fallback blocking

* Fix FAB (#6611)

* feat: add LocationSelect component (#6571)

* feat: add LocationSelect component

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

* fix: type error

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

* chore: type error

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

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

* Update booking filters design  (#6543)

* Update booking filters

* Add filter on YOUR bookings

* Fix pending members showing up in list

* Reduce the avatar size to 'sm' for now

* Bugfix/dropdown menu trigger as child remove class names (#6614)

* Fix UsernameTextfield to take right height

* Remove className side-effect

* Incorrect resolution version fixed

* Converted mobile DropdownMenuTrigger styles into Button

* v2.5.3

* fix: use items-center (#6618)

* fix tooltip and modal stacking issues (#6491)

* fix tooltip and modal stacking issues

* use z-index in larger screens and less

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

* Temporary fix (#6626)

* Fix Ga4 tracking (#6630)

* generic <UpgradeScreen> component (#6594)

* first attempt of <UpgradeScreen>

* changes to icons

* reverted changes back to initial state, needs fix: teams not showing

* WIP

* Fix weird reactnode error

* Fix loading text

* added upgradeTip to routing forms

* icon colors

* create and use hook to check if user has team plan

* use useTeamPlan for upgradeTeamsBadge

* replace huge svg with compressed jpeg

* responsive fixes

* Update packages/ui/components/badge/UpgradeTeamsBadge.tsx

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

* Give team plan features to E2E tests

* Allow option to make a user part of team int ests

* Remove flash of paywall for team user

* Add team user for typeform tests as well

Co-authored-by: Peer Richelsen <peer@cal.com>
Co-authored-by: CarinaWolli <wollencarina@gmail.com>
Co-authored-by: Carina Wollendorfer <30310907+CarinaWolli@users.noreply.github.com>
Co-authored-by: Alex van Andel <me@alexvanandel.com>
Co-authored-by: Hariom Balhara <hariombalhara@gmail.com>

* Removing env var to rely on db

* Restoring i18n keys, set loading moved

* Fixing tailwind-preset glob

* Wizard width fix for md+ screens

* Converting licenses options to radix radio

* Applying feedback + other tweaks

* Reverting this, not this PR related

* Unneeded code removal

* Reverting unneeded style change

* Applying feedback

* Removing licenseType

* Upgrades typescript

* Update yarn lock

* Typings

* Hotfix: ping,riverside,whereby and around not showing up in list (#6712)

* Hotfix: ping,riverside,whereby and around not showing up in list (#6712) (#6713)

* Adds deployment settings to DB (#6706)

* WIP

* Adds DeploymentTheme

* Add missing migrations

* Adds client extensions for deployment

* Cleanup

* Delete migration.sql

* Relying on both, env var and new model

* Restoring env example doc for backward compat

* Maximum call stack size exceeded fix?

* Revert upgrade

* Update index.ts

* Delete index.ts

* Not exposing license key, fixed radio behavior

* Covering undefined env var

* Self contained checkLicense

* Feedback

* Moar feedback

* Feedback

* Feedback

* Feedback

* Cleanup

---------

Signed-off-by: Udit Takkar <udit.07814802719@cse.mait.ac.in>
Co-authored-by: Peer Richelsen <peer@cal.com>
Co-authored-by: sean-brydon <55134778+sean-brydon@users.noreply.github.com>
Co-authored-by: Nafees Nazik <84864519+G3root@users.noreply.github.com>
Co-authored-by: GitStart-Cal.com <121884634+gitstart-calcom@users.noreply.github.com>
Co-authored-by: gitstart-calcom <gitstart@users.noreply.github.com>
Co-authored-by: Peer Richelsen <peeroke@gmail.com>
Co-authored-by: CarinaWolli <wollencarina@gmail.com>
Co-authored-by: Omar López <zomars@me.com>
Co-authored-by: Udit Takkar <53316345+Udit-takkar@users.noreply.github.com>
Co-authored-by: Alex van Andel <me@alexvanandel.com>
Co-authored-by: Harsh Singh <51085015+harshsinghatz@users.noreply.github.com>
Co-authored-by: Guest <guest@pop-os.localdomain>
Co-authored-by: root <harsh.singh@gocomet.com>
Co-authored-by: Luis Cadillo <luiscaf3r@gmail.com>
Co-authored-by: Mohammed Cherfaoui <hi@cherfaoui.dev>
Co-authored-by: Hariom Balhara <hariombalhara@gmail.com>
Co-authored-by: Carina Wollendorfer <30310907+CarinaWolli@users.noreply.github.com>
2023-02-07 17:23:42 -07:00
alannnc 8c150264f4 add-console-vars (#6929) 2023-02-07 15:40:38 -07:00
Udit Takkar cfc3644d51 fix: add req.headers (#6921)
Signed-off-by: Udit Takkar <udit.07814802719@cse.mait.ac.in>
2023-02-07 12:42:47 +00:00
Omar López bdb4a7353b v2.5.10
release.yml / release (push) Canceled after 0s
2023-02-06 16:12:11 -07:00
Hariom Balhara 30c0e6d1d7 Beginning of Strict CSP Compliance (#6841)
* Add CSP Support and enable it initially for Login page

* Update README

* Make sure that CSP is not enabled if CSP_POLICY isnt set

* Add a new value for x-csp header that tells if instance has opted-in to CSP or not

* Add more src to CSP

* Fix typo in header name

* Remove duplicate headers fn

* Add https://eu.ui-avatars.com/api/

* Add CSP_POLICY to env.example
2023-02-06 22:50:08 +00:00
Nafees Nazik 390967990a fix: metadata not saved while creating a booking. (#6866)
* feat: add metadata to booking creation

* fix: bug
2023-02-06 18:05:30 +00:00
Peer Richelsen cc56602474 nit border change (#6899) 2023-02-06 15:59:20 +01:00
Peer Richelsen 43a044d59e theme for storybook 2023-02-06 15:15:26 +01:00
Alex van Andel 5b8ed9c3ef When unchecking the common schedule, schedule should be nulled (#6898) 2023-02-06 15:01:54 +01:00
Sai Deepesh c3d6df2dcf fix(date-overrides): alignment of edit & delete btns (#6892) 2023-02-06 01:31:05 +00:00
Alex van Andel 9d02cb493c Fixed some inconsistencies within single event type page (#6887)
* Fixed some inconsistencies within single event type page

* Fix layout shift on AvailabilityTab
2023-02-06 00:09:27 +01:00
sean-brydon 26ed478e50 Hide button (#6895) 2023-02-05 20:30:51 +00:00
Syed Ali Shahbaz 09e338970d Updates heroku deployment template (#6879) 2023-02-05 14:50:04 +00:00
Udit Takkar f60399ca8b fix: get location url from metadata (#6774)
* fix: get location url from metadata

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

* fix: replace location

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

* fix: type error

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

* fix: use zod

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

---------

Signed-off-by: Udit Takkar <udit.07814802719@cse.mait.ac.in>
2023-02-05 14:43:37 +00:00
Carina Wollendorfer 5cf7e32852 fix workflows when duplicating event types (#6873) 2023-02-04 13:06:37 +01:00
24be8a63f2 fix: filter booking in upcoming (#6406)
* fix: filter booking in upcoming

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

* fix: test

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

* fix: wipe-my-cal failing test

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

---------

Signed-off-by: Udit Takkar <udit.07814802719@cse.mait.ac.in>
Co-authored-by: Peer Richelsen <peeroke@gmail.com>
Co-authored-by: Peer Richelsen <peer@cal.com>
2023-02-03 22:03:35 +00:00
Hariom Balhara 75509c97fd Hotfix: For old Plausible installs enabled in an EventType, give a default value (#6860)
* Add default for trackingId for old plausible installs in event-types

* Fix types
2023-02-03 21:38:06 +00:00
Peer Richelsen 9b26c7aee6 lots of small changes by me and ciaran (#6871) 2023-02-03 16:49:33 +00:00
Alex van Andel f18e80cfcf Use Calendar component view=day for drop-in replacement troubleshooter (#6869)
* Use Calendar component view=day for drop-in replacement troubleshooter

* Setting the id to undefined makes the busy time selected

* Updated event title to include title+source
2023-02-03 16:43:52 +00:00
Ben Hybert 0a4b1ca014 version 2.5.9 (#6868) 2023-02-03 15:36:31 +00:00
Nafees Nazik 9fa6aced33 feat: make key unique (#6861)
release.yml / release (push) Canceled after 0s
2023-02-03 11:20:45 +01:00
Hariom Balhara 9093909075 Hotfix: Event Name (#6863) (#6864) 2023-02-03 11:20:10 +01:00
Aaron Presley 832fce91e0 Left / Right buttons now bottom-aligned and slightly shorter (#6857)
Fixes https://github.com/calcom/cal.com/issues/6589
2023-02-02 20:49:20 +01:00
Peer Richelsen 6da41fce63 fixed availabilty layout 2023-02-02 19:28:46 +01:00
Alex van Andel 3b51cc9aef v2.5.8
release.yml / release (push) Canceled after 0s
2023-02-02 15:54:38 +00:00
Hariom Balhara 50c8959cfa Use trackingId only for trackingDomain as thats the only variable supported (#6856) 2023-02-02 15:13:42 +00:00
Hariom Balhara c96d258f5e Give highest possible value to z-index (#6853) 2023-02-02 15:04:38 +00:00
Alex van Andel 6e45b1c383 Don't override but decorate the built-in encode function (#6850)
* Don't override but decorate the built-in encode function

* Removed jose + synced lockfile
2023-02-02 14:26:00 +00:00
GitStart-Cal.comandgitstart-calcom 551ebe863b [CAL-90] Event Types Single / Allow multiple physical locations (#6692)
Co-authored-by: gitstart-calcom <gitstart@users.noreply.github.com>
2023-02-02 12:42:56 +00:00
Peer Richelsen fa7b94bfe9 Merge branch 'main' of https://github.com/calcom/cal.com 2023-02-02 13:33:49 +01:00
Peer Richelsen 56c5d39cd3 i18n fix 2023-02-02 12:50:28 +01:00
Peer Richelsen 7574fb6f44 i18n fix 2023-02-02 12:49:11 +01:00
Nafees Nazik 901d1f0e01 fix: make cal video default value (#6716) 2023-02-02 12:24:34 +01:00
GitStart-Cal.comandgitstart-calcom 828fcbe1d9 [CAL-713] /availability single - layout issues. Check spacing, margin, alignment with spec'd design (#6724)
Co-authored-by: gitstart-calcom <gitstart@users.noreply.github.com>
2023-02-02 12:21:05 +01:00
Joe Au-Yeung 34db46869e Move e2e to buildjet (#6840) 2023-02-02 08:42:28 +00:00
Nafees Nazik 1f1cab2be1 fix: padding in shell for mobile (#6825)
* fix: padding

* fix: breakpoints in fab

* fix: padding
2023-02-02 09:24:31 +01:00
Alex van Andel 6cf53feaf8 v2.5.7
release.yml / release (push) Canceled after 0s
2023-02-02 01:06:20 +00:00
Leo Giovanetti 376b693d91 Not allowing random duration (#6743) 2023-02-01 22:19:37 +00:00
Alex van Andel 831aa72d23 Invalidate hasTeamPlan when the last team is removed (#6837) 2023-02-01 21:23:34 +00:00
Peer RichelsenandAlex van Andel ef78db7856 /teams improvements (#6831)
Co-authored-by: Alex van Andel <me@alexvanandel.com>
2023-02-01 20:41:47 +00:00
Nafees Nazik 7ee5967075 feat: add theming options to teams (#6807) 2023-02-01 19:27:26 +01:00
Alex van Andel 5b165e6ebf Fixed broken path to fix SB build failure 2023-02-01 16:09:45 +00:00
Joe Shajan 624f52c305 webhook from ui design change (#6803)
* webhook from ui change

* fix: webhook test border & test webhook font style
2023-02-01 14:51:42 +00:00
GitStart-Cal.comandgitstart-calcom df25ae6a3d [CAL-845] Improve the custom event name modal UI/UX (#6660)
Co-authored-by: gitstart-calcom <gitstart@users.noreply.github.com>
2023-02-01 13:10:16 +01:00
Josh Avant 7f65d7f3c3 Removes pay_later_instructions (#6824) 2023-02-01 09:17:11 +01:00
Alex van AndelandHariom Balhara c42674595c Add X-Frame-Options to page headers (#6784)
Co-authored-by: Hariom Balhara <hariombalhara@gmail.com>
2023-02-01 11:28:47 +05:30
Nafees Nazikandalannnc 17eb45b0b6 fix: input component style in routing forms (#6731)
* fix: remove custom className

* removed extra type text

removed extra type text from input

---------

Co-authored-by: alannnc <alannnc@gmail.com>
2023-02-01 01:39:29 +00:00
Peer Richelsen 48d0edeaf4 fixed event-type description 2023-01-31 23:35:05 +01:00
Peer Richelsen ed4b31767f lint 2023-01-31 23:33:20 +01:00
Peer Richelsen cebb10bfe4 re-adding subtitle to Shell 2023-01-31 23:31:04 +01:00
Ben Lam 7a6e7c2f1d Removed unused variables (#6704) (#6750) 2023-01-31 22:29:24 +00:00
Peer Richelsen 0ffed24359 user management moved to console.cal.com (#6799) 2023-01-31 21:59:11 +00:00
Nafees NazikandAlan e121615d36 fix: installed apps and admin apps layout spacing issues. (#6753)
* feat: add highlight props

* feat: add isTemplate prop

* feat: add invalid credintial prop

* feat: add children prop

* feat: render app list card

* fix: add horizontal gap

* fix: installed app layout style

* fix: admin layout

* feat: add isGlobal to returned data

* feat: fix admin tab.

* use common components list and AppListCard

* show isDefault Badge

* hide switch for global apps

* fix: show switch

* fix: remove isglobal

* fix: layout

* refactor: remove unused component and import

* feat: use app list card component

* fix: query param

* fix: prevent unnecessary props passed to the component

* feat: add disabled style

* feat: add disconnect integration modal

* feat: new changes.

* render disconnect integration model only once.

* add dropdown for actions

* feat: changes in admin apps.

* use dropdown for selecting action buttons.

* use modal for editing keys.

* Remove boolean comparison

---------

Co-authored-by: Alan <alannnc@gmail.com>
2023-01-31 22:45:38 +01:00
4f9aa8bd96 Hide attendees from calendar description (#6800)
* Show the organizer timezone when booking on seats

* Only show organizer in event description

* Type fixes

* Update snapshot with new response

---------

Co-authored-by: Alex van Andel <me@alexvanandel.com>
Co-authored-by: Alan <alannnc@gmail.com>
2023-01-31 14:14:19 -07:00
alannncandsean-brydon 64ede37ad6 Fix embed modal leading inputs (#6822)
Co-authored-by: sean-brydon <55134778+sean-brydon@users.noreply.github.com>
2023-01-31 13:58:15 -07:00
36b6c351ec Session Timeout (#6439)
* Implementation

* Unifying UI to password screen

* Tweaks for session in password section

* Update apps/web/pages/settings/security/password.tsx

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

* Update packages/features/kbar/Kbar.tsx

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

* Update packages/features/settings/layouts/SettingsLayout.tsx

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

* Relying on extra db query

* Upgrades typescript

* Update yarn lock

* Typings

* Hotfix: ping,riverside,whereby and around not showing up in list (#6712)

* Hotfix: ping,riverside,whereby and around not showing up in list (#6712) (#6713)

* Adds deployment settings to DB (#6706)

* WIP

* Adds DeploymentTheme

* Add missing migrations

* Adds client extensions for deployment

* Cleanup

* Using same version as other deps

* Reverting prisma changes and fixing things

* Uneeded tx-expect-error

* Fixing default value

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

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

---------

Co-authored-by: Omar López <zomars@me.com>
Co-authored-by: Hariom Balhara <hariombalhara@gmail.com>
Co-authored-by: Carina Wollendorfer <30310907+CarinaWolli@users.noreply.github.com>
2023-01-31 17:44:14 -03:00
GitStart-Cal.comandgitstart-calcom 9ab5a3149c [CAL-807] /event-types/single - Fix the header (#6738)
release.yml / release (push) Canceled after 0s
* [CAL-807] /event-types/single - Fix the header

* [CAL-807] /event-types/single - Fix the header

* [CAL-807] /event-types/single - Fix the header

---------

Co-authored-by: gitstart-calcom <gitstart@users.noreply.github.com>
2023-01-31 20:19:02 +00:00
Nafees NazikandAlan 3b8f436bdf feat: tabs for teams in mobile (#6685)
* fix: padding

* feat: add teams tab component

* fix: add image to type

* fix: current path check

* fix: add avatar prop

* feat: add teams tab for mobile

* fix: padding

* fix: background and padding x

* fix: empty logic

* fix: conditions

* fix: bg

---------

Co-authored-by: Alan <alannnc@gmail.com>
2023-01-31 12:54:40 -07:00
Nafees Nazik 77d45a6ec2 fix: use guest email in create booking link banner (#6694) 2023-01-31 19:47:32 +00:00
Carina WollendorferandCarinaWolli 50c74cf286 change useHasTeamPlan hook to useHasPaidPlan (#6699)
Co-authored-by: CarinaWolli <wollencarina@gmail.com>
2023-01-31 19:10:21 +00:00
Richard Poelderl dcbafced8b update isCalcom for canonicals to handle https://cal.com (#6802)
* update isCalcom for canonicals to handle https://cal.com

* avoid env var

* prettier

* handle window undefined

* handle window undefined during pre-render

* add some logs

* add some logs

* Revert "add some logs"

This reverts commit 9d27de029024e526417bc79e9cee42d7333ac592.
2023-01-31 19:07:50 +00:00
GitStart-Cal.comandgitstart-calcom 4679c80ea0 [CAL-727] [500] on /api/trpc/[trpc] (#6795)
Co-authored-by: gitstart-calcom <gitstart@users.noreply.github.com>
2023-01-31 18:50:06 +00:00
Bram Verstraten 291316ee01 Fix Dutch custom event names (#6806)
Continued from #6375
2023-01-31 18:46:07 +00:00
sean-brydon 208fc2f0e4 Feat - invite user to team flow improvements (#6725) 2023-01-31 18:16:43 +00:00
Joe Au-Yeung 99e71054ff Change lint action to run on BuildJet (#6819) 2023-01-31 19:08:08 +01:00
Nafees Nazik 9d118d4e34 fix: flash of i18n in teams page (#6818) 2023-01-31 19:05:18 +01:00
+6 d1a877e70d Add additional guests (#6419)
* Add additional guests

* WIP

* WIP

* Type fix

* WIP

* Add validation for already invited attendees

* Revert type to email

* remove controlled fields

* disables signups via env variable (#6212)

* disables signups via env variable

* Apply suggestions from code review

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

* Reusable Upgrade component for teams only features (#6473)

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

* i18n udpate

* fix: darkmode in booking/[id] page (#6458)

* fix: text-area style

* fix: border styles

* fix: german translation for reschedule booking email  subject (#6483)

* fix: german translation for reschedule subject

* fix: add a full stop

* fix: app store spacing issues (#6481)

* feat: add equal spacing with gap

* fix: title style

* fix: title style

* fix: remove margin

* fix: remove margin

* fix: sub header spacing and slider button

* fix: category card text

* fix: app store spacing issues

* fix: tab in tablet

* fix: shell

* fix: styling of dropdown component (#6440)

* fix: styling of dropdown component

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

* Apply suggestions from code review

* fix: use dropdown item in all pages

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

* chore: undo

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

Signed-off-by: Udit Takkar <udit.07814802719@cse.mait.ac.in>
Co-authored-by: Peer Richelsen <peeroke@gmail.com>

* readding sidebar tips for everyone, added 3 more features to teams empty screen (#6475)

* readding sidebar tips for everyone

* added 3 more features to teams plan

* responsive fixes

* responsive fixes

* small responsive fix

* CTA alignment fixed

* Minor alignment fixes to Shell for event-types/[type]

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

* fix: wrong i18n  placeholder in many locales (#6496)

* fix: czech translation

* fix: spanish translation

* fix: italian translation

* fix: japanese translation

* fix: korean translation

* fix: dutch translation

* fix: norwegian translation

* fix: polish translation

* fix: portuguese translation

* fix: portuguese translation

* fix: romanian translation

* fix: russian translation

* fix: serbian translation

* fix: swedish translation

* fix: turkish translation

* fix: ukrainian translation

* fix: vietnamese translation

* fix: chinese simplified translation

* fix: chinese traditional translation

* Disable redirect for cancellation page (#6498)

* [CAL-677] /event-type : Event Setup sidebar item doesn't reflect multiple durations (#6390)

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

* Added fallback to hostsFixed too which is used in COLLECTIVE (#6500)

* Don't update the field when changing the select (#6486)

* Don't update the field when changing the select

* Fixing missing label

* Applied the correct y-8 vertical margin

* Changed the description vertical offset from title a bit more

* Add Trash icon on Availability list dropdown

* fix: tablet sidebar profile being too wide and not centered  (#6490)

* feat: updated app list items styling issues inside settings/conferencing

* feat: fixed tablet sidebar width and not centered issue

* fix: removed un-related changes from this pr

* deleted .env

* fix: added the accidentaly deleted .env file

* fix: removed unwanted .env file from the pr

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

* Bring back PublicShell (#6505)

* Add red text to error message

* WIP

* Rearrange guest input

* Fix validate unique guests logic

* Allow guests on reschedule

* Lint fix

* More lint fixes

* Lint fixes

* More lint fixes

* Fix remove guest button margin

---------

Signed-off-by: Udit Takkar <udit.07814802719@cse.mait.ac.in>
Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com>
Co-authored-by: Jeff Loiselle <jeff@loiselles.com>
Co-authored-by: Peer Richelsen <peeroke@gmail.com>
Co-authored-by: Omar López <zomars@me.com>
Co-authored-by: Carina Wollendorfer <30310907+CarinaWolli@users.noreply.github.com>
Co-authored-by: CarinaWolli <wollencarina@gmail.com>
Co-authored-by: Peer Richelsen <peer@cal.com>
Co-authored-by: Nafees Nazik <84864519+G3root@users.noreply.github.com>
Co-authored-by: Udit Takkar <53316345+Udit-takkar@users.noreply.github.com>
Co-authored-by: Alex van Andel <me@alexvanandel.com>
Co-authored-by: Hariom Balhara <hariombalhara@gmail.com>
Co-authored-by: GitStart-Cal.com <121884634+gitstart-calcom@users.noreply.github.com>
Co-authored-by: gitstart-calcom <gitstart@users.noreply.github.com>
Co-authored-by: Ronit Panda <72537293+rtpa25@users.noreply.github.com>
Co-authored-by: Alan <alannnc@gmail.com>
2023-01-31 17:36:38 +00:00
Nafees Nazik 238b509be6 fix: border color in dark teams page (#6817) 2023-01-31 18:21:51 +01:00
Richard Poelderl c7471b404c fix(web): remove noindex & nofollow tags from the App and Shell components (#6816)
Fixes https://github.com/calcom/cal.com/issues/6815
2023-01-31 17:08:59 +00:00
Alex van Andel 4db4df8ace Correct invalid ukraine language code ua -> uk 2023-01-30 21:09:09 +00:00
Udit Takkar a15b8fb92e fix: booking limits saved as undefined (#6720)
* fix: booking limits saved as undefined

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

* fix: add event limit

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

---------

Signed-off-by: Udit Takkar <udit.07814802719@cse.mait.ac.in>
2023-01-30 19:38:22 +01:00
Syed Ali Shahbaz a4bed48eaf Standardize response codes in Login (#6787)
* standardizing login response codes

* playwright fix

* added translation
2023-01-30 18:37:03 +00:00
Peer Richelsen 1be6f192d4 added impersonation tip (#6794) 2023-01-30 16:19:11 +01:00
Richard Poelderl f1c5838aef fix(web): set canonical as https://cal.com in the <HeadSeo/> (#6693)
* fix(web): set canonical as https://cal.com in the <HeadSeo/>

* use `window.document.location?.href` if self hosted

* clean up

* use `isCalcom` from library

* handle trailing slash on homepage again
2023-01-30 13:54:07 +01:00
Peer Richelsen 8e994dcc33 adding ukrainian (#6791) 2023-01-30 13:49:08 +01:00
Peer Richelsen 506bbe3d31 Update README.md 2023-01-30 13:48:02 +01:00
Nafees Nazik 419a84c5a2 fix: location select menu overflowing the container (#6719) 2023-01-30 12:58:37 +01:00
Hariom Balhara 8cf0050d1f Fix: EventType Duplication (#6778) 2023-01-30 12:55:08 +01:00
Sai Deepesh 6c23813192 fix padding of lenght input on add event modal (#6771) 2023-01-30 11:12:53 +00:00
Joe Au-Yeung 875f922597 Disable autocomplete on password field (#6705) 2023-01-30 09:42:52 +00:00
Udit Takkar c8e3f6494a fix: back button and heading size (#6768)
Signed-off-by: Udit Takkar <udit.07814802719@cse.mait.ac.in>
2023-01-29 10:38:31 +01:00
Carina WollendorferandCarinaWolli 333801d2ae Fix shift-enter in bio editor (#6769)
* fix wrong enabled update button at first load

* fix shift-enter error

* small fixes + code clean up

---------

Co-authored-by: CarinaWolli <wollencarina@gmail.com>
2023-01-27 23:14:58 +00:00
Joe Au-Yeung 60f7528cbc On seats, hide attendees if option is selected (#6767)
* On seats, hide attendees if option is selected

* Remove unused line
2023-01-27 12:10:49 -07:00
Peer Richelsen 0faf294367 removed credits from auth container (#6766) 2023-01-27 19:20:39 +01:00
Peer Richelsen 87c178e53b added blue color for links in bio (#6760) 2023-01-27 17:03:04 +01:00
Peer Richelsen 7710b1b718 Update README.md 2023-01-27 15:14:16 +01:00
Peer Richelsen d71c6ccb31 Update README.md 2023-01-27 12:07:12 +01:00
GitStart-Cal.comandgitstart-calcom 33a4117fb5 On duplicating an event type, spacing between arrows and label is wide (Length field) (#6717)
Co-authored-by: gitstart-calcom <gitstart@users.noreply.github.com>
2023-01-27 11:06:29 +01:00
Omar López a90419c40b Adds booking data to SDK success event (#6737) 2023-01-27 11:02:33 +05:30
Omar López 16adf86c8c Upgrades typescript to 4.9.4 (#6747)
* Upgrades typescript to 4.9.4

* Type fixes
2023-01-26 18:50:56 -07:00
Peer Richelsen 3b838c475a replaced edit location dialog subtitle with link to app store (#6746) 2023-01-27 00:33:56 +01:00
Omar López cf33106d8b WIP: SIU: Maximum call stack size exceeded fix? (#6740)
* Maximum call stack size exceeded fix?

# Conflicts:
#	packages/prisma/index.ts

* Prisma client extensions is too much for our TS

* Removed unused Icons

* Type fixes
2023-01-26 17:51:03 -05:00
zomars a63f9ddf61 Adds deployment settings to DB (#6706) 2023-01-26 13:36:15 -07:00
zomars 1cf83068b2 Update yarn.lock 2023-01-26 13:33:59 -07:00
Hariom Balhara 23de92f818 Hotfix: ping,riverside,whereby and around not showing up in list (#6712) 2023-01-26 13:31:13 -07:00
zomars c6fc1f756b Update yarn.lock 2023-01-25 16:56:44 -07:00
zomars 88b7c506f1 Include submodule dependencies in lockfile 2023-01-25 16:56:25 -07:00
zomars 755aae969c Removed pre-install script
devs should opt-in to submodules
2023-01-25 13:39:12 -07:00
Peer Richelsen 2d50d09ce6 added hacker news badge to readme 2023-01-25 13:52:08 +01:00
Peer Richelsen a22397dbb4 Update README.md 2023-01-25 13:44:28 +01:00
Mohammed Cherfaoui d1076982a7 fix: event location link modal (#6387) 2023-01-25 09:49:05 +00:00
Nafees Nazik d77e4f3c4a fix: decode characters if encoded (#6447) 2023-01-25 09:44:48 +00:00
Joe Cohen b1c0ea4c38 Fix duplicate event modal page slug (#6657) 2023-01-25 09:16:50 +00:00
Carina WollendorferandCarinaWolli 425e18f53c enable scroll (#6676)
Co-authored-by: CarinaWolli <wollencarina@gmail.com>
2023-01-25 09:14:20 +00:00
Peer Richelsen 3611807838 Update README.md (#6682) 2023-01-25 09:13:33 +00:00
Udit Takkar 5b1cd9e5ce fix: send email if username is being passed (#6674)
Signed-off-by: Udit Takkar <udit.07814802719@cse.mait.ac.in>

Signed-off-by: Udit Takkar <udit.07814802719@cse.mait.ac.in>
2023-01-25 08:56:20 +00:00
Joe Au-Yeung 00bff598ef Add videoCallData to evt on new attendee (#6673)
* Add videoCallData to evt on new attendee

* Remove console.log
2023-01-25 08:52:58 +00:00
Nafees Nazik 3a8aa26c78 fix: duplicate iframes in cal video (#6662)
* chore: upgrade daily-co

* feat: return only needed data and preload i18n

* fix: useEffect
2023-01-25 08:51:09 +00:00
Carina WollendorferandCarinaWolli 3c761f4451 Fixes issues with workflows that have more than one action (#6670)
* fix untitled workflow name when no action exists

* fix wrong data loaded one first laod when step was added

Co-authored-by: CarinaWolli <wollencarina@gmail.com>
2023-01-25 08:42:57 +00:00
8640eb9f52 Ability to format user and team bio (#6572)
* use texteditor for bio

* remove block types from about editor

* add props to make editor height adjustable

* set isDirty to true when about input is edited

* add editor to getting-started

* fix editor height

* remove required error for onboarding

* add helper function to check if parsed bio has text

* add back commented code

* fix onboarding tests for optional about field

* rename function

* parse team bio for read only members

* code clean up

* fix failing e2e because of missing test id

* fix onboarding e2e test

* add missing parse of user bio

* Update apps/web/components/getting-started/steps-views/UserProfile.tsx

* Update apps/web/pages/settings/my-account/profile.tsx

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

* use css inline style for height instead of tailwind class

* fix height of editor-input

* save bio as markdown in db

* fix empty line when bio is empty

* fix hydration failed error

* Update packages/ui/components/editor/Editor.tsx

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

* remove unused import

Co-authored-by: CarinaWolli <wollencarina@gmail.com>
Co-authored-by: Omar López <zomars@me.com>
Co-authored-by: Peer Richelsen <peeroke@gmail.com>
2023-01-24 18:08:10 -07:00
Kiran K abb5fd36f3 Support OIDC (#6661)
* Support OIDC

* tweak to the Configure button

* fix the type import
2023-01-24 13:02:43 -07:00
707 changed files with 11559 additions and 5154 deletions
+11 -4
View File
@@ -1,20 +1,21 @@
# ********** INDEX **********
#
# - LICENSE
# - LICENSE (DEPRECATED)
# - DATABASE
# - SHARED
# - NEXTAUTH
# - E-MAIL SETTINGS
# - LICENSE *************************************************************************************************
# https://github.com/calendso/calendso/blob/main/LICENSE
# - LICENSE (DEPRECATED) ************************************************************************************
# https://github.com/calcom/cal.com/blob/main/LICENSE
#
# Summary of terms:
# - The codebase has to stay open source, whether it was modified or not
# - You can not repackage or sell the codebase
# - Acquire a commercial license to remove these terms by visiting: cal.com/sales
#
# To enable enterprise-only features, fill your license key in here.
# To enable enterprise-only features, as an admin, go to /auth/setup to select your license and follow
# instructions. This environment variable is deprecated although still supported for backward compatibility.
# @see https://console.cal.com
CALCOM_LICENSE_KEY=
# ***********************************************************************************************************
@@ -157,3 +158,9 @@ NEXT_PUBLIC_COMPANY_NAME="Cal.com, Inc."
# Set this to true in to disable new signups
# NEXT_PUBLIC_DISABLE_SIGNUP=true
NEXT_PUBLIC_DISABLE_SIGNUP=
# Content Security Policy
CSP_POLICY=
# Vercel Edge Config
EDGE_CONFIG=
+22
View File
@@ -0,0 +1,22 @@
name: Cron - mark stale for inactive issues
permissions:
issues: write
on:
# "Scheduled workflows run on the latest commit on the default or base branch."
# — https://docs.github.com/en/actions/learn-github-actions/events-that-trigger-workflows#schedule
schedule:
# Runs every day (see https://crontab.guru)
- cron: "0 0 * * *"
jobs:
stale:
runs-on: ubuntu-latest
steps:
- uses: actions/stale@v7
with:
days-before-stale: 60
include-only-assigned: true
days-before-close: -1
+1 -1
View File
@@ -13,7 +13,7 @@ concurrency:
jobs:
e2e:
timeout-minutes: 20
runs-on: ubuntu-latest
runs-on: buildjet-4vcpu-ubuntu-2204
env:
DATABASE_URL: postgresql://postgres:@localhost:5432/calendso
+1 -1
View File
@@ -11,7 +11,7 @@ concurrency:
cancel-in-progress: true
jobs:
lint:
runs-on: ubuntu-latest
runs-on: buildjet-4vcpu-ubuntu-2204
steps:
- name: Checkout repo
@@ -0,0 +1,153 @@
name: "Next.js Bundle Analysis"
on:
pull_request:
push:
branches:
- main
workflow_dispatch:
concurrency:
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
cancel-in-progress: true
defaults:
run:
# change this if your nextjs app does not live at the root of the repo
working-directory: ./apps/web/
jobs:
analyze:
env:
DATABASE_URL: postgresql://postgres:@localhost:5432/calendso
NEXT_PUBLIC_WEBAPP_URL: http://localhost:3000
NEXT_PUBLIC_WEBSITE_URL: http://localhost:3000
NEXTAUTH_SECRET: secret
GOOGLE_API_CREDENTIALS: ${{ secrets.CI_GOOGLE_API_CREDENTIALS }}
GOOGLE_LOGIN_ENABLED: true
CALENDSO_ENCRYPTION_KEY: ${{ secrets.CI_CALENDSO_ENCRYPTION_KEY }}
DAILY_API_KEY: ${{ secrets.CI_DAILY_API_KEY }}
NEXT_PUBLIC_STRIPE_PUBLIC_KEY: ${{ secrets.CI_NEXT_PUBLIC_STRIPE_PUBLIC_KEY }}
NEXT_PUBLIC_STRIPE_FREE_PLAN_PRICE: ${{ secrets.CI_NEXT_PUBLIC_STRIPE_FREE_PLAN_PRICE }}
NEXT_PUBLIC_STRIPE_PRO_PLAN_PRICE: ${{ secrets.CI_NEXT_PUBLIC_STRIPE_PRO_PLAN_PRICE }}
NEXT_PUBLIC_STRIPE_PREMIUM_PLAN_PRICE: ${{ secrets.CI_NEXT_PUBLIC_STRIPE_PREMIUM_PLAN_PRICE }}
NEXT_PUBLIC_STRIPE_PREMIUM_NEW_PLAN_PRICE: ${{ secrets.NEXT_PUBLIC_STRIPE_PREMIUM_NEW_PLAN_PRICE }}
NEXT_PUBLIC_IS_PREMIUM_NEW_PLAN: 1
STRIPE_PRIVATE_KEY: ${{ secrets.CI_STRIPE_PRIVATE_KEY }}
STRIPE_CLIENT_ID: ${{ secrets.CI_STRIPE_CLIENT_ID }}
STRIPE_WEBHOOK_SECRET: ${{ secrets.CI_STRIPE_WEBHOOK_SECRET }}
STRIPE_PRO_PLAN_PRODUCT_ID: ${{ secrets.CI_STRIPE_PRO_PLAN_PRODUCT_ID }}
STRIPE_PREMIUM_PLAN_PRODUCT_ID: ${{ secrets.CI_STRIPE_PREMIUM_PLAN_PRODUCT_ID }}
STRIPE_FREE_PLAN_PRODUCT_ID: ${{ secrets.CI_STRIPE_FREE_PLAN_PRODUCT_ID }}
PAYMENT_FEE_PERCENTAGE: 0.005
PAYMENT_FEE_FIXED: 10
SAML_DATABASE_URL: postgresql://postgres:@localhost:5432/calendso
SAML_ADMINS: pro@example.com
NEXTAUTH_URL: http://localhost:3000/api/auth
NEXT_PUBLIC_IS_E2E: 1
TURBO_TOKEN: ${{ secrets.TURBO_TOKEN }}
TURBO_TEAM: ${{ secrets.TURBO_TEAM }}
services:
postgres:
image: postgres:12.1
env:
POSTGRES_USER: postgres
POSTGRES_DB: calendso
ports:
- 5432:5432
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Set up node
uses: actions/setup-node@v3
with:
node-version: 16.x
cache: "yarn"
- name: Install dependencies
uses: bahmutov/npm-install@v1
- name: Restore next build
uses: actions/cache@v2
id: restore-build-cache
env:
cache-name: cache-next-build
with:
path: apps/web/.next/cache
# change this if you prefer a more strict cache
key: ${{ runner.os }}-build-${{ env.cache-name }}
- name: Build next.js app
# change this if your site requires a custom build command
run: cd ../.. && yarn db-seed && yarn build
# Here's the first place where next-bundle-analysis' own script is used
# This step pulls the raw bundle stats for the current bundle
- name: Analyze bundle
run: npx -p nextjs-bundle-analysis report
- name: Upload bundle
uses: actions/upload-artifact@v2
with:
name: bundle
path: apps/web/.next/analyze/__bundle_analysis.json
- name: Download base branch bundle stats
uses: dawidd6/action-download-artifact@v2
if: success() && github.event.number
with:
workflow: nextjs-bundle-analysis.yml
branch: ${{ github.event.pull_request.base.ref }}
path: apps/web/.next/analyze/base
# And here's the second place - this runs after we have both the current and
# base branch bundle stats, and will compare them to determine what changed.
# There are two configurable arguments that come from package.json:
#
# - budget: optional, set a budget (bytes) against which size changes are measured
# it's set to 350kb here by default, as informed by the following piece:
# https://infrequently.org/2021/03/the-performance-inequality-gap/
#
# - red-status-percentage: sets the percent size increase where you get a red
# status indicator, defaults to 20%
#
# Either of these arguments can be changed or removed by editing the `nextBundleAnalysis`
# entry in your package.json file.
- name: Compare with base branch bundle
if: success() && github.event.number
run: ls -laR .next/analyze/base && npx -p nextjs-bundle-analysis compare
- name: Get comment body
id: get-comment-body
if: success() && github.event.number
run: |
body=$(cat .next/analyze/__bundle_analysis_comment.txt)
body="${body//'%'/'%25'}"
body="${body//$'\n'/'%0A'}"
body="${body//$'\r'/'%0D'}"
echo ::set-output name=body::$body
- name: Find Comment
uses: peter-evans/find-comment@v1
if: success() && github.event.number
id: fc
with:
issue-number: ${{ github.event.number }}
body-includes: "<!-- __NEXTJS_BUNDLE -->"
- name: Create Comment
uses: peter-evans/create-or-update-comment@v1.4.4
if: success() && github.event.number && steps.fc.outputs.comment-id == 0
with:
issue-number: ${{ github.event.number }}
body: ${{ steps.get-comment-body.outputs.body }}
- name: Update Comment
uses: peter-evans/create-or-update-comment@v1.4.4
if: success() && github.event.number && steps.fc.outputs.comment-id != 0
with:
issue-number: ${{ github.event.number }}
body: ${{ steps.get-comment-body.outputs.body }}
comment-id: ${{ steps.fc.outputs.comment-id }}
edit-mode: replace
+32
View File
@@ -0,0 +1,32 @@
name: TODO to Issue
on:
pull_request_target: # So we can test on forks
branches:
- main
workflow_dispatch:
inputs:
MANUAL_COMMIT_REF:
description: "The SHA of the commit to get the diff for"
required: true
MANUAL_BASE_REF:
description: "By default, the commit entered above is compared to the one directly before it; to go back further, enter an earlier SHA here"
required: false
concurrency:
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
cancel-in-progress: true
jobs:
todos:
runs-on: ubuntu-latest
steps:
- name: Checkout repo
uses: actions/checkout@v3
with:
ref: ${{ github.event.pull_request.head.sha }}
fetch-depth: 2
- name: "Add TODOs to issues"
uses: "alstr/todo-to-issue-action@v4"
env:
MANUAL_COMMIT_REF: ${{ inputs.MANUAL_COMMIT_REF }}
MANUAL_BASE_REF: ${{ inputs.MANUAL_BASE_REF }}
with:
IDENTIFIERS: '[{"name": "TODO", "labels": ["🙋🏻‍♂️help wanted"]}, {"name": "FIXME", "labels": ["🐛 bug"]}]'
+3
View File
@@ -77,6 +77,9 @@ lint-results
#Storybook
apps/storybook/build-storybook.log
# Infisical
.infisical.json
# Snaplet
.snaplet/snapshots
.snaplet/structure.d.ts
+54
View File
@@ -4,6 +4,60 @@ Contributions are what make the open source community such an amazing place to l
- Before jumping into a PR be sure to search [existing PRs](https://github.com/calcom/cal.com/pulls) or [issues](https://github.com/calcom/cal.com/issues) for an open or closed item that relates to your submission.
## Priorities
<table>
<tr>
<td>
Type of Issue
</td>
<td>
Priority
</td>
</tr>
<tr>
<td>
Minor improvements, non-core feature requests
</td>
<td>
<a href="https://github.com/calcom/cal.com/issues?q=is:issue+is:open+sort:updated-desc+label:%22Low+priority%22">
<img src="https://img.shields.io/badge/-Low%20Priority-green">
</a>
</td>
</tr>
<tr>
<td>
Confusing UX (... but working)
</td>
<td>
<a href="https://github.com/calcom/cal.com/issues?q=is:issue+is:open+sort:updated-desc+label:%22Medium+priority%22">
<img src="https://img.shields.io/badge/-Medium%20Priority-yellow">
</a>
</td>
</tr>
<tr>
<td>
Core Features (Booking page, availabilty, timezone calculation)
</td>
<td>
<a href="https://github.com/calcom/cal.com/issues?q=is:issue+is:open+sort:updated-desc+label:%22High+priority%22">
<img src="https://img.shields.io/badge/-High%20Priority-orange">
</a>
</td>
</tr>
<tr>
<td>
Core Bugs (Login, Booking page, Emails are not working)
</td>
<td>
<a href="https://github.com/calcom/cal.com/issues?q=is:issue+is:open+sort:updated-desc+label:Urgent">
<img src="https://img.shields.io/badge/-Urgent-red">
</a>
</td>
</tr>
</table>
## Developing
The development branch is `main`. This is the branch that all pull
+40 -8
View File
File diff suppressed because one or more lines are too long
+7 -4
View File
@@ -6,7 +6,7 @@
"keywords": ["react", "typescript", "node", "nextjs", "prisma", "postgres", "trpc"],
"addons": [
{
"plan": "heroku-postgresql:hobby-dev"
"plan": "heroku-postgresql:mini"
}
],
"env": {
@@ -43,15 +43,18 @@
},
"SENDGRID_API_KEY": {
"description": "Sendgrid api key. Used for email reminders in workflows",
"value": ""
"value": "",
"required": false
},
"SENDGRID_SYNC_API_KEY": {
"description": "Sendgrid internal sync service",
"value": ""
"value": "",
"required": false
},
"SENDGRID_EMAIL": {
"description": "Sendgrid email. Used for email reminders in workflows",
"value": ""
"value": "",
"required": false
},
"EMAIL_FROM": {
"description": "Configures the global From: header whilst sending emails",
-81
View File
@@ -1,81 +0,0 @@
<!-- PROJECT LOGO -->
<div align="right">
<a href="https://github.com/calcom/cal.com">
<img src="https://user-images.githubusercontent.com/8019099/133430653-24422d2a-3c8d-4052-9ad6-0580597151ee.png" alt="Logo">
</a>
<a href="https://cal.com">Website</a>
·
<a href="https://github.com/calcom/cal.com/issues">Community Support</a>
</div>
# Cal.com Documentation
The official product, support and developer documentation, containing information and guides about using the product as well as support for self-hosted installations. This documentation site runs on [Nextra](https://nextra.vercel.app), so you may refer to their documentation should you need information on anything that isn't covered here.
## Prerequisites
- Git
- Node.js & npm
- Yarn
## Installation
Firstly, clone the repository using Git:
```console
git clone https://github.com/calcom/docs.git
```
Now, you can install the dependencies with yarn:
```console
yarn install
```
## Editing
To create, edit and delete documentation pages, you can simply create markdown (.mdx) files in the `pages/` folder. You can edit Markdown with any text editor, but VS Code and WebStorm have side-by-side previews so you can see your formatted content whilst writing markdown.
You will also need to add it as an entry to the `meta.json` file found in whichever directory that the .mdx file is in.
## Local Development
```console
yarn dev
```
This command starts a local development server and opens up a browser window. Most changes are reflected live without having to restart the server.
## Build
```console
yarn build
```
This command generates static content into the `build` directory and can be served using any static content hosting service.
## How to easily contribute
## Existing Page
1. From the documentation's GitHub repository, head to the folder called 'pages' and open it.
2. From here you can view all current pages on the documentation site. Select the page you would like to contribute to.
3. You should now be able to view the page you have selected. Located at the top right of the page will be a pencil icon. Pressing this will bring you up an editor to edit and make changes. You can add formatting using the buttons at the top, which will automatically insert the relevant markdown content needed to style the text.
4. From here make the changes you wish to make.
5. At the bottom of the screen will be a 'Propose Changes' box, fill in all the relevant details such as title and description then press the green 'Propose Changes' button.
6. Your changes have been saved, to submit them for review, located on your screen, press the green 'Create Pull Request' button.
7. Fill in all the relevant details such as title and description and after finalize the submission.
You have now successfully edited and submitted changes to our documentation site.
## Creating a New Page
1. From the documentation's GitHub repository, head to the folder called 'pages' and open it.
2. From here you can view all current pages on the documentation site. At the top of your screen press the 'New file' button.
3. You should now be able to view the page you have created. Remember when renaming the document to put .mdx at the end of the file name.
4. From here make the changes you wish to make. Such as creating a title, sub-title and body text.
5. At the bottom of the screen will be a 'Propose Changes' box, fill in all the relevant details such as title and description then press the green 'Propose Changes' button.
6. Your changes have been saved, to submit them for review, located on your screen, press the greem 'Create Pull Request' button.
7. Fill in all the relevant details such as title and description and after finalize the submission.
You have now successfully created and submitted changes to our documentation site.
+1 -1
View File
@@ -25,6 +25,6 @@
},
"devDependencies": {
"@calcom/config": "*",
"eslint": "^8.22.0"
"eslint": "^8.34.0"
}
}
+1 -1
View File
@@ -1,4 +1,4 @@
import { AppProps } from "next/app";
import type { AppProps } from "next/app";
import "nextra-theme-docs/style.css";
import "./style.css";
+12
View File
@@ -0,0 +1,12 @@
import { create } from "@storybook/theming";
export default create({
base: "light",
colorPrimary: "#111827",
colorSecondary: "#111827",
appContentBg: "#F9FAFC",
brandTitle: "Cal.com UI",
brandUrl: "https://cal.com",
brandImage: "https://cal.com/logo.svg",
brandTarget: "_self",
});
+7
View File
@@ -0,0 +1,7 @@
import { addons } from "@storybook/addons";
import yourTheme from "./YourTheme";
addons.setConfig({
theme: yourTheme,
});
+4 -4
View File
@@ -15,7 +15,7 @@
"@radix-ui/react-dialog": "^1.0.0",
"@radix-ui/react-dropdown-menu": "^1.0.0",
"@radix-ui/react-id": "^1.0.0",
"@radix-ui/react-popover": "^1.0.0",
"@radix-ui/react-popover": "^1.0.2",
"@radix-ui/react-radio-group": "^1.0.0",
"@radix-ui/react-slider": "^1.0.0",
"@radix-ui/react-switch": "^1.0.0",
@@ -36,8 +36,8 @@
"@storybook/manager-webpack5": "^6.5.13",
"@storybook/react": "^6.5.13",
"@storybook/testing-library": "^0.0.13",
"@types/react": "^18.0.17",
"@types/react-dom": "^18.0.6",
"@types/react": "18.0.26",
"@types/react-dom": "18.0.9",
"@vitejs/plugin-react": "^2.1.0",
"autoprefixer": "^10.4.12",
"babel-loader": "^8.2.5",
@@ -49,7 +49,7 @@
"storybook-addon-next": "^1.6.9",
"storybook-react-i18next": "^1.1.2",
"tailwindcss": "^3.2.1",
"typescript": "^4.7.4",
"typescript": "^4.9.4",
"vite": "^2.9.15"
}
}
+6 -1
View File
@@ -2,4 +2,9 @@
@tailwind components;
@tailwind utilities;
@import "../../../packages/ui/styles/shared-globals.css"
@import "../../../packages/ui/styles/shared-globals.css";
:root {
--font-inter: "Inter var";
--font-cal: "Cal Sans";
}
+3 -3
View File
@@ -22,8 +22,8 @@
},
"devDependencies": {
"@types/node": "16.9.1",
"@types/react": "^18.0.17",
"@types/react-dom": "^18.0.6",
"typescript": "^4.7.4"
"@types/react": "18.0.26",
"@types/react-dom": "18.0.9",
"typescript": "^4.9.4"
}
}
+1 -1
View File
@@ -1,5 +1,5 @@
import dynamic from "next/dynamic";
import { SwaggerUI } from "swagger-ui-react";
import type { SwaggerUI } from "swagger-ui-react";
import { SnippedGenerator, requestSnippets } from "@lib/snippets";
@@ -1,6 +1,6 @@
import React from "react";
import Select from "react-select";
import { OptionProps } from "react-select";
import type { OptionProps } from "react-select";
import { InstallAppButton } from "@calcom/app-store/components";
import { useLocale } from "@calcom/lib/hooks/useLocale";
+66 -8
View File
@@ -1,35 +1,93 @@
import { ReactNode } from "react";
import { useRouter } from "next/router";
import type { ReactNode } from "react";
import { useEffect, useRef, useState } from "react";
import { z } from "zod";
import { useLocale } from "@calcom/lib/hooks/useLocale";
import { useTypedQuery } from "@calcom/lib/hooks/useTypedQuery";
import { Badge, ListItemText } from "@calcom/ui";
import { FiAlertCircle } from "@calcom/ui/components/icon";
interface AppListCardProps {
type ShouldHighlight = { slug: string; shouldHighlight: true } | { shouldHighlight?: never; slug?: never };
type AppListCardProps = {
logo?: string;
title: string;
description: string;
actions?: ReactNode;
isDefault?: boolean;
}
isTemplate?: boolean;
invalidCredential?: boolean;
children?: ReactNode;
} & ShouldHighlight;
const schema = z.object({ hl: z.string().optional() });
export default function AppListCard(props: AppListCardProps) {
const { t } = useLocale();
const { logo, title, description, actions, isDefault } = props;
const {
logo,
title,
description,
actions,
isDefault,
slug,
shouldHighlight,
isTemplate,
invalidCredential,
children,
} = props;
const {
data: { hl },
} = useTypedQuery(schema);
const router = useRouter();
const [highlight, setHighlight] = useState(shouldHighlight && hl === slug);
const timeoutRef = useRef<NodeJS.Timeout | null>(null);
useEffect(() => {
if (shouldHighlight && highlight) {
const timer = setTimeout(() => {
setHighlight(false);
const url = new URL(window.location.href);
url.searchParams.delete("hl");
router.replace(url.pathname, undefined, { shallow: true });
}, 3000);
timeoutRef.current = timer;
}
return () => {
if (timeoutRef.current) {
clearTimeout(timeoutRef.current);
timeoutRef.current = null;
}
};
}, []);
return (
<div className="p-4">
<div className="flex items-center gap-x-3">
<div className={`${highlight ? "bg-yellow-100" : ""}`}>
<div className="flex gap-x-3 p-4">
{logo ? <img className="h-10 w-10" src={logo} alt={`${title} logo`} /> : null}
<div className="flex grow flex-col gap-y-1 truncate">
<div className="flex items-center gap-x-2">
<h3 className="truncate text-sm font-semibold text-gray-900">{title}</h3>
{isDefault ? <Badge variant="green">{t("default")}</Badge> : null}
<div className="flex items-center gap-x-2">
{isDefault && <Badge variant="green">{t("default")}</Badge>}
{isTemplate && <Badge variant="red">Template</Badge>}
</div>
</div>
<ListItemText component="p">{description}</ListItemText>
{invalidCredential && (
<div className="flex gap-x-2 pt-2">
<FiAlertCircle className="h-8 w-8 text-red-500 sm:h-4 sm:w-4" />
<ListItemText component="p" className="whitespace-pre-wrap text-red-500">
{t("invalid_credential")}
</ListItemText>
</div>
)}
</div>
{actions}
</div>
{children && <div className="w-full">{children}</div>}
</div>
);
}
@@ -3,7 +3,7 @@ import React, { useEffect, useState } from "react";
import Select from "react-select";
import { useLocale } from "@calcom/lib/hooks/useLocale";
import { DestinationCalendar } from "@calcom/prisma/client";
import type { DestinationCalendar } from "@calcom/prisma/client";
import { trpc } from "@calcom/trpc/react";
interface Props {
+12 -10
View File
@@ -1,8 +1,11 @@
import { Collapsible, CollapsibleContent, CollapsibleTrigger } from "@radix-ui/react-collapsible";
import classNames from "classnames";
import { NextRouter, useRouter } from "next/router";
import { createRef, forwardRef, MutableRefObject, RefObject, useRef, useState } from "react";
import { components, ControlProps } from "react-select";
import type { NextRouter } from "next/router";
import { useRouter } from "next/router";
import type { MutableRefObject, RefObject } from "react";
import { createRef, forwardRef, useRef, useState } from "react";
import type { ControlProps } from "react-select";
import { components } from "react-select";
import { APP_NAME, EMBED_LIB_URL, WEBAPP_URL } from "@calcom/lib/constants";
import { useLocale } from "@calcom/lib/hooks/useLocale";
@@ -12,16 +15,15 @@ import {
DialogClose,
DialogContent,
HorizontalTabs,
InputLeading,
Label,
showToast,
Switch,
TextArea,
TextField,
ColorPicker,
} from "@calcom/ui";
import { FiCode, FiTrello, FiSun, FiArrowLeft, FiChevronRight } from "@calcom/ui/components/icon";
import ColorPicker from "@components/ui/colorpicker";
import Select from "@components/ui/form/Select";
type EmbedType = "inline" | "floating-popup" | "element-click";
@@ -676,7 +678,7 @@ const EmbedTypeCodeAndPreviewDialogContent = ({
return `${router.asPath.split("?")[0]}?${searchParams.toString()}`;
};
const parsedTabs = tabs.map((t) => ({ ...t, href: s(t.href) }));
const embedCodeRefs: Record<typeof tabs[0]["name"], RefObject<HTMLTextAreaElement>> = {};
const embedCodeRefs: Record<(typeof tabs)[0]["name"], RefObject<HTMLTextAreaElement>> = {};
tabs
.filter((tab) => tab.type === "code")
.forEach((codeTab) => {
@@ -720,7 +722,7 @@ const EmbedTypeCodeAndPreviewDialogContent = ({
const calLink = decodeURIComponent(embedUrl);
const addToPalette = (update: typeof previewState["palette"]) => {
const addToPalette = (update: (typeof previewState)["palette"]) => {
setPreviewState((previewState) => {
return {
...previewState,
@@ -863,7 +865,7 @@ const EmbedTypeCodeAndPreviewDialogContent = ({
};
});
}}
addOnLeading={<InputLeading>W</InputLeading>}
addOnLeading={<>W</>}
/>
<span className="p-2">×</span>
<TextField
@@ -883,7 +885,7 @@ const EmbedTypeCodeAndPreviewDialogContent = ({
};
});
}}
addOnLeading={<InputLeading>H</InputLeading>}
addOnLeading={<>H</>}
/>
</div>
</div>
@@ -1061,7 +1063,7 @@ const EmbedTypeCodeAndPreviewDialogContent = ({
defaultValue="#000000"
onChange={(color) => {
addToPalette({
[palette.name as keyof typeof previewState["palette"]]: color,
[palette.name as keyof (typeof previewState)["palette"]]: color,
});
}}
/>
+3 -2
View File
@@ -1,6 +1,7 @@
import dynamic from "next/dynamic";
import { Dispatch, useState, useEffect } from "react";
import { JSONObject } from "superjson/dist/types";
import type { Dispatch } from "react";
import { useState, useEffect } from "react";
import type { JSONObject } from "superjson/dist/types";
export type Gate = undefined | "rainbow"; // Add more like ` | "geolocation" | "payment"`
+5 -3
View File
@@ -1,11 +1,13 @@
import { FormEvent, useCallback, useEffect, useState } from "react";
import type { FormEvent } from "react";
import { useCallback, useEffect, useState } from "react";
import Cropper from "react-easy-crop";
import { useLocale } from "@calcom/lib/hooks/useLocale";
import { Button, Dialog, DialogClose, DialogContent, DialogTrigger } from "@calcom/ui";
import { Area, getCroppedImg } from "@lib/cropImage";
import type { Area } from "@lib/cropImage";
import { getCroppedImg } from "@lib/cropImage";
import { useFileReader } from "@lib/hooks/useFileReader";
import { useLocale } from "@lib/hooks/useLocale";
import Slider from "@components/Slider";
+5 -3
View File
@@ -1,13 +1,15 @@
import { AdminRequired } from "components/ui/AdminRequired";
import noop from "lodash/noop";
import Link, { LinkProps } from "next/link";
import type { LinkProps } from "next/link";
import Link from "next/link";
import { useRouter } from "next/router";
import { FC, Fragment, MouseEventHandler } from "react";
import type { FC, MouseEventHandler } from "react";
import { Fragment } from "react";
import { useLocale } from "@calcom/lib/hooks/useLocale";
import classNames from "@lib/classNames";
import { SVGComponent } from "@lib/types/SVGComponent";
import type { SVGComponent } from "@lib/types/SVGComponent";
export interface NavTabProps {
tabs: {
+2 -1
View File
@@ -1,4 +1,5 @@
import React, { ComponentProps } from "react";
import type { ComponentProps } from "react";
import React from "react";
import Shell from "@calcom/features/shell/Shell";
import { ErrorBoundary } from "@calcom/ui";
@@ -1,4 +1,4 @@
import { OptionProps } from "react-select";
import type { OptionProps } from "react-select";
import { InstallAppButton } from "@calcom/app-store/components";
import { useLocale } from "@calcom/lib/hooks/useLocale";
+3 -7
View File
@@ -11,7 +11,7 @@ import classNames from "@calcom/lib/classNames";
import { APP_NAME, COMPANY_NAME, SUPPORT_MAIL_ADDRESS } from "@calcom/lib/constants";
import { useLocale } from "@calcom/lib/hooks/useLocale";
import { trpc } from "@calcom/trpc/react";
import { App as AppType } from "@calcom/types/App";
import type { App as AppType } from "@calcom/types/App";
import { Button, showToast, SkeletonButton, SkeletonText, HeadSeo, Badge } from "@calcom/ui";
import {
FiBookOpen,
@@ -210,7 +210,7 @@ const Component = ({
</span>
)}
<div className="prose prose-sm mt-8">{body}</div>
<div className="prose-sm prose mt-8">{body}</div>
<h4 className="mt-8 font-semibold text-gray-900 ">{t("pricing")}</h4>
<span>
{price === 0 ? (
@@ -331,15 +331,11 @@ export default function App(props: {
const { t } = useLocale();
return (
<Shell large isPublic heading={t("app_store")} backPath="/apps" withoutSeo>
<Shell smallHeading isPublic heading={t("app_store")} backPath="/apps" withoutSeo>
<HeadSeo
title={props.name}
description={props.description}
app={{ slug: props.logo, name: props.name, description: props.description }}
nextSeoProps={{
nofollow: true,
noindex: true,
}}
/>
{props.licenseRequired ? (
<LicenseRequired>
@@ -21,8 +21,8 @@ import { FiArrowLeft, FiCalendar, FiPlus } from "@calcom/ui/components/icon";
import { QueryCell } from "@lib/QueryCell";
import AppListCard from "@components/AppListCard";
import AdditionalCalendarSelector from "@components/apps/AdditionalCalendarSelector";
import IntegrationListItem from "@components/apps/IntegrationListItem";
import SubHeadingTitleWithConnections from "@components/integrations/SubHeadingTitleWithConnections";
type Props = {
@@ -118,13 +118,13 @@ function CalendarList(props: Props) {
success={({ data }) => (
<List>
{data.items.map((item) => (
<IntegrationListItem
name={item.name}
slug={item.slug}
key={item.title}
title={item.title}
<AppListCard
title={item.name}
key={item.name}
logo={item.logo}
description={item.description}
shouldHighlight
slug={item.slug}
actions={
<InstallAppButton
type={item.type}
@@ -161,16 +161,16 @@ function ConnectedCalendarsList(props: Props) {
}
return (
<List className="flex flex-col gap-6" noBorderTreatment>
<List>
{data.connectedCalendars.map((item) => (
<Fragment key={item.credentialId}>
{item.calendars ? (
<IntegrationListItem
<AppListCard
shouldHighlight
slug={item.integration.slug}
title={item.integration.title}
title={item.integration.name}
logo={item.integration.logo}
description={item.primary?.email ?? item.integration.description}
separate={true}
actions={
<div className="flex w-32 justify-end">
<DisconnectIntegration
@@ -200,7 +200,7 @@ function ConnectedCalendarsList(props: Props) {
</>
)}
</div>
</IntegrationListItem>
</AppListCard>
) : (
<Alert
severity="warning"
@@ -3,7 +3,7 @@ import React, { useEffect, useState } from "react";
import Select from "react-select";
import { useLocale } from "@calcom/lib/hooks/useLocale";
import { DestinationCalendar } from "@calcom/prisma/client";
import type { DestinationCalendar } from "@calcom/prisma/client";
import { trpc } from "@calcom/trpc/react";
interface Props {
@@ -1,81 +0,0 @@
import Link from "next/link";
import { useRouter } from "next/router";
import { ReactNode, useEffect, useState } from "react";
import { useLocale } from "@calcom/lib/hooks/useLocale";
import { Badge, ListItem, ListItemText, ListItemTitle, showToast } from "@calcom/ui";
import { FiAlertCircle } from "@calcom/ui/components/icon";
import classNames from "@lib/classNames";
function IntegrationListItem(props: {
imageSrc?: string;
slug: string;
name?: string;
title?: string;
description: string;
actions?: ReactNode;
children?: ReactNode;
logo: string;
destination?: boolean;
separate?: boolean;
invalidCredential?: boolean;
isTemplate?: boolean;
}): JSX.Element {
const { t } = useLocale();
const router = useRouter();
const { hl } = router.query;
const [highlight, setHighlight] = useState(hl === props.slug);
const title = props.name || props.title;
// The highlight is to show a newly installed app, coming from the app's
// redirection after installation, so we proceed to show the corresponding
// message
if (highlight) {
showToast(t("app_successfully_installed"), "success");
}
useEffect(() => {
const timer = setTimeout(() => setHighlight(false), 3000);
return () => {
clearTimeout(timer);
};
}, []);
return (
<ListItem
expanded={!!props.children}
className={classNames(
props.separate ? "rounded-md" : "first:rounded-t-md last:rounded-b-md",
"my-0 flex-col border transition-colors duration-500",
highlight ? "bg-yellow-100" : ""
)}>
<div className={classNames("flex w-full flex-1 items-center space-x-2 p-4 rtl:space-x-reverse")}>
{props.logo && <img className="h-11 w-11" src={props.logo} alt={title} />}
<div className="flex-grow truncate pl-2">
<ListItemTitle component="h3" className="flex ">
<Link href={"/apps/" + props.slug}>{props.name || title}</Link>
{props.isTemplate && (
<Badge variant="red" className="ml-4">
Template
</Badge>
)}
</ListItemTitle>
<ListItemText component="p">{props.description}</ListItemText>
{/* Alert error that key stopped working. */}
{props.invalidCredential && (
<div className="flex items-center space-x-2 rtl:space-x-reverse">
<FiAlertCircle className="w-8 text-red-500 sm:w-4" />
<ListItemText component="p" className="whitespace-pre-wrap text-red-500">
{t("invalid_credential")}
</ListItemText>
</div>
)}
</div>
<div>{props.actions}</div>
</div>
{props.children && <div className="w-full">{props.children}</div>}
</ListItem>
);
}
export default IntegrationListItem;
@@ -1,6 +1,7 @@
import { useSession } from "next-auth/react";
import { useRouter } from "next/router";
import React, { ComponentProps } from "react";
import type { ComponentProps } from "react";
import React from "react";
import Shell from "@calcom/features/shell/Shell";
import { useLocale } from "@calcom/lib/hooks/useLocale";
@@ -1,7 +1,8 @@
import React, { ComponentProps } from "react";
import type { ComponentProps } from "react";
import React from "react";
import AppCategoryNavigation from "@calcom/app-store/_components/AppCategoryNavigation";
import { InstalledAppVariants } from "@calcom/app-store/utils";
import type { InstalledAppVariants } from "@calcom/app-store/utils";
import Shell from "@calcom/features/shell/Shell";
import { trpc } from "@calcom/trpc/react";
import type { HorizontalTabItemProps, VerticalTabItemProps } from "@calcom/ui";
@@ -44,7 +45,7 @@ export default function InstalledAppsLayout({
children,
...rest
}: { children: React.ReactNode } & ComponentProps<typeof Shell>) {
const variant: typeof InstalledAppVariants[number] = "payment";
const variant: (typeof InstalledAppVariants)[number] = "payment";
const query = trpc.viewer.integrations.useQuery({
variant,
@@ -57,9 +58,7 @@ export default function InstalledAppsLayout({
return (
<Shell {...rest}>
<AppCategoryNavigation
baseURL="/apps/installed"
containerClassname="w-full xl:mx-5 xl:w-4/5 xl:max-w-2xl xl:pr-5">
<AppCategoryNavigation baseURL="/apps/installed" containerClassname="min-w-0 w-full">
{children}
</AppCategoryNavigation>
</Shell>
@@ -1,15 +1,16 @@
import { UserPermissionRole } from "@prisma/client";
import { useSession } from "next-auth/react";
import { useRouter } from "next/router";
import React, { ComponentProps, useEffect } from "react";
import type { ComponentProps } from "react";
import React, { useEffect } from "react";
import SettingsLayout from "@calcom/features/settings/layouts/SettingsLayout";
import Shell from "@calcom/features/shell/Shell";
import type Shell from "@calcom/features/shell/Shell";
import { ErrorBoundary } from "@calcom/ui";
import { UserPermissionRole } from ".prisma/client";
export default function AdminLayout({
children,
...rest
}: { children: React.ReactNode } & ComponentProps<typeof Shell>) {
const session = useSession();
@@ -22,10 +23,11 @@ export default function AdminLayout({
}
}, [session, router]);
const isAppsPage = router.asPath.startsWith("/settings/admin/apps");
return (
<SettingsLayout {...rest}>
<div className="mx-auto flex max-w-4xl flex-row divide-y divide-gray-200">
<div className="flex flex-1 [&>*]:flex-1">
<div className={isAppsPage ? "min-w-0" : "flex flex-1 [&>*]:flex-1"}>
<ErrorBoundary>{children}</ErrorBoundary>
</div>
</div>
@@ -4,21 +4,21 @@ import { useLocale } from "@calcom/lib/hooks/useLocale";
import { Tooltip } from "@calcom/ui";
import { FiLink } from "@calcom/ui/components/icon";
import { Props } from "./pages/AvailabilityPage";
import type { Props } from "./pages/AvailabilityPage";
export function AvailableEventLocations({ locations }: { locations: Props["eventType"]["locations"] }) {
const { t } = useLocale();
return locations.length ? (
<div className="dark:text-darkgray-600 mr-6 flex w-full flex-col space-y-2 break-words text-sm text-gray-600">
{locations.map((location) => {
<div className="dark:text-darkgray-600 mr-6 flex w-full flex-col space-y-4 break-words text-sm text-gray-600">
{locations.map((location, index) => {
const eventLocationType = getEventLocationType(location.type);
if (!eventLocationType) {
// It's possible that the location app got uninstalled
return null;
}
return (
<div key={location.type} className="flex flex-row items-center text-sm font-medium">
<div key={`${location.type}-${index}`} className="flex flex-row items-center text-sm font-medium">
{eventLocationType.iconUrl === "/link.svg" ? (
<FiLink className="dark:text-darkgray-600 ml-[2px] h-4 w-4 opacity-70 ltr:mr-[10px] rtl:ml-[10px] dark:opacity-100 " />
) : (
@@ -26,7 +26,7 @@ export function AvailableEventLocations({ locations }: { locations: Props["event
src={eventLocationType.iconUrl}
className={classNames(
"ml-[2px] h-4 w-4 opacity-70 ltr:mr-[10px] rtl:ml-[10px] dark:opacity-100 ",
!eventLocationType.iconUrl?.includes("api") ? "dark:invert" : ""
!eventLocationType.iconUrl?.includes("api") ? "dark:invert-[.65]" : ""
)}
alt={`${eventLocationType.label} icon`}
/>
+121 -115
View File
@@ -1,8 +1,11 @@
import { useAutoAnimate } from "@formkit/auto-animate/react";
import Link from "next/link";
import { useRouter } from "next/router";
import { FC, useEffect, useState } from "react";
import type { FC } from "react";
import { useEffect, useState } from "react";
import dayjs, { Dayjs } from "@calcom/dayjs";
import type { Dayjs } from "@calcom/dayjs";
import dayjs from "@calcom/dayjs";
import { useLocale } from "@calcom/lib/hooks/useLocale";
import { TimeFormat } from "@calcom/lib/timeFormat";
import { nameOfDay } from "@calcom/lib/weekday";
@@ -37,6 +40,7 @@ const AvailableTimes: FC<AvailableTimesProps> = ({
seatsPerTimeSlot,
ethSignature,
}) => {
const [slotPickerRef] = useAutoAnimate<HTMLDivElement>();
const { t, i18n } = useLocale();
const router = useRouter();
const { rescheduleUid } = router.query;
@@ -47,122 +51,124 @@ const AvailableTimes: FC<AvailableTimesProps> = ({
setBrand(getComputedStyle(document.documentElement).getPropertyValue("--brand-color").trim());
}, []);
if (!date) return null;
return (
<div className="dark:bg-darkgray-100 mt-8 flex h-full w-full flex-col px-4 text-center sm:mt-0 sm:p-5 md:-mb-5 md:min-w-[200px] lg:min-w-[300px]">
<div className="mb-6 flex items-center text-left text-base">
<div className="mr-4">
<span className="text-bookingdarker dark:text-darkgray-800 font-semibold text-gray-900">
{nameOfDay(i18n.language, Number(date.format("d")), "short")}
</span>
<span className="text-bookinglight font-medium">
, {date.toDate().toLocaleString(i18n.language, { month: "short" })} {date.format(" D ")}
</span>
</div>
<div className="ml-auto">
<ToggleGroup
onValueChange={(timeFormat) => onTimeFormatChange(timeFormat === "24")}
defaultValue={timeFormat === TimeFormat.TWELVE_HOUR ? "12" : "24"}
options={[
{ value: "12", label: t("12_hour_short") },
{ value: "24", label: t("24_hour_short") },
]}
/>
</div>
</div>
<div className="flex-grow overflow-y-auto sm:block md:h-[364px]">
{slots.length > 0 &&
slots.map((slot) => {
type BookingURL = {
pathname: string;
query: Record<string, string | number | string[] | undefined>;
};
const bookingUrl: BookingURL = {
pathname: router.pathname.endsWith("/embed") ? "../book" : "book",
query: {
...router.query,
date: dayjs.utc(slot.time).tz(timeZone()).format(),
type: eventTypeId,
slug: eventTypeSlug,
/** Treat as recurring only when a count exist and it's not a rescheduling workflow */
count: recurringCount && !rescheduleUid ? recurringCount : undefined,
...(ethSignature ? { ethSignature } : {}),
},
};
if (rescheduleUid) {
bookingUrl.query.rescheduleUid = rescheduleUid as string;
}
// If event already has an attendee add booking id
if (slot.bookingUid) {
bookingUrl.query.bookingUid = slot.bookingUid;
}
return (
<div data-slot-owner={(slot.userIds || []).join(",")} key={`${dayjs(slot.time).format()}`}>
{/* ^ data-slot-owner is helpful in debugging and used to identify the owners of the slot. Owners are the users which have the timeslot in their schedule. It doesn't consider if a user has that timeslot booked */}
{/* Current there is no way to disable Next.js Links */}
{seatsPerTimeSlot && slot.attendees && slot.attendees >= seatsPerTimeSlot ? (
<div
className={classNames(
"text-primary-500 dark:bg-darkgray-200 dark:text-darkgray-900 mb-2 block rounded-sm border bg-white py-2 font-medium opacity-25 dark:border-transparent ",
brand === "#fff" || brand === "#ffffff" ? "" : ""
)}>
{dayjs(slot.time).tz(timeZone()).format(timeFormat)}
{!!seatsPerTimeSlot && <p className="text-sm">{t("booking_full")}</p>}
</div>
) : (
<Link
href={bookingUrl}
prefetch={false}
className={classNames(
"text-primary-500 hover:border-gray-900 hover:bg-gray-50",
"dark:bg-darkgray-200 dark:hover:bg-darkgray-300 dark:hover:border-darkmodebrand dark:text-darkgray-800 mb-2 block rounded-md border bg-white py-2 text-sm font-medium dark:border-transparent",
brand === "#fff" || brand === "#ffffff" ? "" : ""
)}
data-testid="time">
{dayjs(slot.time).tz(timeZone()).format(timeFormat)}
{!!seatsPerTimeSlot && (
<p
className={`${
slot.attendees && slot.attendees / seatsPerTimeSlot >= 0.8
? "text-rose-600"
: slot.attendees && slot.attendees / seatsPerTimeSlot >= 0.33
? "text-yellow-500"
: "text-emerald-400"
} text-sm`}>
{slot.attendees ? seatsPerTimeSlot - slot.attendees : seatsPerTimeSlot} /{" "}
{seatsPerTimeSlot} {t("seats_available")}
</p>
)}
</Link>
)}
</div>
);
})}
{!isLoading && !slots.length && (
<div className="-mt-4 flex h-full w-full flex-col content-center items-center justify-center">
<h1 className="my-6 text-xl text-black dark:text-white">{t("all_booked_today")}</h1>
<div ref={slotPickerRef}>
{!!date ? (
<div className="dark:bg-darkgray-100 mt-8 flex h-full w-full flex-col px-4 text-center sm:mt-0 sm:p-5 md:-mb-5 md:min-w-[200px] lg:min-w-[300px]">
<div className="mb-6 flex items-center text-left text-base">
<div className="mr-4">
<span className="text-bookingdarker dark:text-darkgray-800 font-semibold text-gray-900">
{nameOfDay(i18n.language, Number(date.format("d")), "short")}
</span>
<span className="text-bookinglight font-medium">
, {date.toDate().toLocaleString(i18n.language, { month: "short" })} {date.format(" D ")}
</span>
</div>
<div className="ml-auto">
<ToggleGroup
onValueChange={(timeFormat) => onTimeFormatChange(timeFormat === "24")}
defaultValue={timeFormat === TimeFormat.TWELVE_HOUR ? "12" : "24"}
options={[
{ value: "12", label: t("12_hour_short") },
{ value: "24", label: t("24_hour_short") },
]}
/>
</div>
</div>
)}
<div className="flex-grow overflow-y-auto sm:block md:h-[364px]">
{slots.length > 0 &&
slots.map((slot) => {
type BookingURL = {
pathname: string;
query: Record<string, string | number | string[] | undefined>;
};
const bookingUrl: BookingURL = {
pathname: router.pathname.endsWith("/embed") ? "../book" : "book",
query: {
...router.query,
date: dayjs.utc(slot.time).tz(timeZone()).format(),
type: eventTypeId,
slug: eventTypeSlug,
/** Treat as recurring only when a count exist and it's not a rescheduling workflow */
count: recurringCount && !rescheduleUid ? recurringCount : undefined,
...(ethSignature ? { ethSignature } : {}),
},
};
{isLoading && !slots.length && (
<>
<SkeletonContainer className="mb-2">
<SkeletonText className="h-5 w-full" />
</SkeletonContainer>
<SkeletonContainer className="mb-2">
<SkeletonText className="h-5 w-full" />
</SkeletonContainer>
<SkeletonContainer className="mb-2">
<SkeletonText className="h-5 w-full" />
</SkeletonContainer>
</>
)}
</div>
if (rescheduleUid) {
bookingUrl.query.rescheduleUid = rescheduleUid as string;
}
// If event already has an attendee add booking id
if (slot.bookingUid) {
bookingUrl.query.bookingUid = slot.bookingUid;
}
return (
<div data-slot-owner={(slot.userIds || []).join(",")} key={`${dayjs(slot.time).format()}`}>
{/* ^ data-slot-owner is helpful in debugging and used to identify the owners of the slot. Owners are the users which have the timeslot in their schedule. It doesn't consider if a user has that timeslot booked */}
{/* Current there is no way to disable Next.js Links */}
{seatsPerTimeSlot && slot.attendees && slot.attendees >= seatsPerTimeSlot ? (
<div
className={classNames(
"text-primary-500 dark:bg-darkgray-200 dark:text-darkgray-900 mb-2 block rounded-sm border bg-white py-2 font-medium opacity-25 dark:border-transparent ",
brand === "#fff" || brand === "#ffffff" ? "" : ""
)}>
{dayjs(slot.time).tz(timeZone()).format(timeFormat)}
{!!seatsPerTimeSlot && <p className="text-sm">{t("booking_full")}</p>}
</div>
) : (
<Link
href={bookingUrl}
prefetch={false}
className={classNames(
"text-primary-500 hover:border-gray-900 hover:bg-gray-50",
"dark:bg-darkgray-200 dark:hover:bg-darkgray-300 dark:hover:border-darkmodebrand dark:text-darkgray-800 mb-2 block rounded-md border bg-white py-2 text-sm font-medium dark:border-transparent",
brand === "#fff" || brand === "#ffffff" ? "" : ""
)}
data-testid="time">
{dayjs(slot.time).tz(timeZone()).format(timeFormat)}
{!!seatsPerTimeSlot && (
<p
className={`${
slot.attendees && slot.attendees / seatsPerTimeSlot >= 0.8
? "text-rose-600"
: slot.attendees && slot.attendees / seatsPerTimeSlot >= 0.33
? "text-yellow-500"
: "text-emerald-400"
} text-sm`}>
{slot.attendees ? seatsPerTimeSlot - slot.attendees : seatsPerTimeSlot} /{" "}
{seatsPerTimeSlot} {t("seats_available")}
</p>
)}
</Link>
)}
</div>
);
})}
{!isLoading && !slots.length && (
<div className="-mt-4 flex h-full w-full flex-col content-center items-center justify-center">
<h1 className="my-6 text-xl text-black dark:text-white">{t("all_booked_today")}</h1>
</div>
)}
{isLoading && !slots.length && (
<>
<SkeletonContainer className="mb-2">
<SkeletonText className="h-5 w-full" />
</SkeletonContainer>
<SkeletonContainer className="mb-2">
<SkeletonText className="h-5 w-full" />
</SkeletonContainer>
<SkeletonContainer className="mb-2">
<SkeletonText className="h-5 w-full" />
</SkeletonContainer>
</>
)}
</div>
</div>
) : null}
</div>
);
};
@@ -1,8 +1,9 @@
import { SchedulingType } from "@prisma/client";
import { FC, ReactNode, useEffect } from "react";
import type { FC, ReactNode } from "react";
import { useEffect } from "react";
import dayjs from "@calcom/dayjs";
import { classNames } from "@calcom/lib";
import classNames from "@calcom/lib/classNames";
import { useLocale } from "@calcom/lib/hooks/useLocale";
import { Badge } from "@calcom/ui";
import { FiCheckSquare, FiClock, FiInfo } from "@calcom/ui/components/icon";
+21 -21
View File
@@ -2,14 +2,17 @@ import { BookingStatus } from "@prisma/client";
import { useRouter } from "next/router";
import { useState } from "react";
import { EventLocationType, getEventLocationType } from "@calcom/app-store/locations";
import type { EventLocationType } from "@calcom/app-store/locations";
import { getEventLocationType } from "@calcom/app-store/locations";
import dayjs from "@calcom/dayjs";
import ViewRecordingsDialog from "@calcom/features/ee/video/ViewRecordingsDialog";
import classNames from "@calcom/lib/classNames";
import { formatTime } from "@calcom/lib/date-fns";
import { useLocale } from "@calcom/lib/hooks/useLocale";
import { getEveryFreqFor } from "@calcom/lib/recurringStrings";
import { RouterInputs, RouterOutputs, trpc } from "@calcom/trpc/react";
import type { RouterInputs, RouterOutputs } from "@calcom/trpc/react";
import { trpc } from "@calcom/trpc/react";
import type { ActionType } from "@calcom/ui";
import {
Badge,
Button,
@@ -17,13 +20,11 @@ import {
DialogClose,
DialogContent,
DialogFooter,
DialogHeader,
MeetingTimeInTimezones,
showToast,
TextArea,
Tooltip,
ActionType,
TableActions,
TextAreaField,
} from "@calcom/ui";
import { FiCheck, FiClock, FiMapPin, FiRefreshCcw, FiSend, FiSlash, FiX } from "@calcom/ui/components/icon";
@@ -53,7 +54,7 @@ function BookingListItem(booking: BookingItemProps) {
const [viewRecordingsDialogIsOpen, setViewRecordingsDialogIsOpen] = useState<boolean>(false);
const mutation = trpc.viewer.bookings.confirm.useMutation({
onSuccess: (data) => {
if (data.status === BookingStatus.REJECTED) {
if (data?.status === BookingStatus.REJECTED) {
setRejectionDialogIsOpen(false);
showToast(t("booking_rejection_success"), "success");
} else {
@@ -245,24 +246,23 @@ function BookingListItem(booking: BookingItemProps) {
)}
{/* NOTE: Should refactor this dialog component as is being rendered multiple times */}
<Dialog open={rejectionDialogIsOpen} onOpenChange={setRejectionDialogIsOpen}>
<DialogContent>
<DialogHeader title={t("rejection_reason_title")} />
<p className="-mt-4 text-sm text-gray-500">{t("rejection_reason_description")}</p>
<p className="mt-6 mb-2 text-sm font-bold text-black">
{t("rejection_reason")}
<span className="font-normal text-gray-500"> (Optional)</span>
</p>
<TextArea
name={t("rejection_reason")}
value={rejectionReason}
onChange={(e) => setRejectionReason(e.target.value)}
className="mb-5 sm:mb-6"
/>
<DialogContent title={t("rejection_reason_title")} description={t("rejection_reason_description")}>
<div>
<TextAreaField
name="rejectionReason"
label={
<>
{t("rejection_reason")}
<span className="font-normal text-gray-500"> (Optional)</span>
</>
}
value={rejectionReason}
onChange={(e) => setRejectionReason(e.target.value)}
/>
</div>
<DialogFooter>
<DialogClose />
<Button
disabled={mutation.isLoading}
onClick={() => {
@@ -29,7 +29,7 @@ export default function CancelBooking(props: Props) {
const [cancellationReason, setCancellationReason] = useState<string>("");
const { t } = useLocale();
const router = useRouter();
const { booking, profile, team, allRemainingBookings } = props;
const { booking, allRemainingBookings } = props;
const [loading, setLoading] = useState(false);
const telemetry = useTelemetry();
const [error, setError] = useState<string | null>(booking ? null : t("booking_already_cancelled"));
+200
View File
@@ -0,0 +1,200 @@
import type { EventType } from "@prisma/client";
import dynamic from "next/dynamic";
import { useRouter } from "next/router";
import { useEffect, useState } from "react";
import type { z } from "zod";
import type { Dayjs } from "@calcom/dayjs";
import dayjs from "@calcom/dayjs";
import DatePicker from "@calcom/features/calendars/DatePicker";
import classNames from "@calcom/lib/classNames";
import { useLocale } from "@calcom/lib/hooks/useLocale";
import type { TimeFormat } from "@calcom/lib/timeFormat";
import type { EventTypeMetaDataSchema } from "@calcom/prisma/zod-utils";
import { trpc } from "@calcom/trpc/react";
import useRouterQuery from "@lib/hooks/useRouterQuery";
const AvailableTimes = dynamic(() => import("@components/booking/AvailableTimes"));
const getRefetchInterval = (refetchCount: number): number => {
const intervals = [3000, 3000, 5000, 10000, 20000, 30000] as const;
return intervals[refetchCount] || intervals[intervals.length - 1];
};
const useSlots = ({
eventTypeId,
eventTypeSlug,
startTime,
endTime,
usernameList,
timeZone,
duration,
enabled = true,
}: {
eventTypeId: number;
eventTypeSlug: string;
startTime?: Dayjs;
endTime?: Dayjs;
usernameList: string[];
timeZone?: string;
duration?: string;
enabled?: boolean;
}) => {
const [refetchCount, setRefetchCount] = useState(0);
const refetchInterval = getRefetchInterval(refetchCount);
const { data, isLoading, isPaused, fetchStatus } = trpc.viewer.public.slots.getSchedule.useQuery(
{
eventTypeId,
eventTypeSlug,
usernameList,
startTime: startTime?.toISOString() || "",
endTime: endTime?.toISOString() || "",
timeZone,
duration,
},
{
enabled: !!startTime && !!endTime && enabled,
refetchInterval,
trpc: { context: { skipBatch: true } },
}
);
useEffect(() => {
if (!!data && fetchStatus === "idle") {
setRefetchCount(refetchCount + 1);
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [fetchStatus, data]);
// The very first time isPaused is set if auto-fetch is disabled, so isPaused should also be considered a loading state.
return { slots: data?.slots || {}, isLoading: isLoading || isPaused };
};
export const SlotPicker = ({
eventType,
timeFormat,
onTimeFormatChange,
timeZone,
recurringEventCount,
users,
seatsPerTimeSlot,
weekStart = 0,
ethSignature,
}: {
eventType: Pick<
EventType & { metadata: z.infer<typeof EventTypeMetaDataSchema> },
"id" | "schedulingType" | "slug" | "length" | "metadata"
>;
timeFormat: TimeFormat;
onTimeFormatChange: (is24Hour: boolean) => void;
timeZone?: string;
seatsPerTimeSlot?: number;
recurringEventCount?: number;
users: string[];
weekStart?: 0 | 1 | 2 | 3 | 4 | 5 | 6;
ethSignature?: string;
}) => {
const [selectedDate, setSelectedDate] = useState<Dayjs>();
const [browsingDate, setBrowsingDate] = useState<Dayjs>();
let { duration = eventType.length.toString() } = useRouterQuery("duration");
const { date, setQuery: setDate } = useRouterQuery("date");
const { month, setQuery: setMonth } = useRouterQuery("month");
const router = useRouter();
if (!eventType.metadata?.multipleDuration) {
duration = eventType.length.toString();
}
useEffect(() => {
if (!router.isReady) return;
// Etc/GMT is not actually a timeZone, so handle this select option explicitly to prevent a hard crash.
if (timeZone === "Etc/GMT") {
setBrowsingDate(dayjs.utc(month).set("date", 1).set("hour", 0).set("minute", 0).set("second", 0));
if (date) {
setSelectedDate(dayjs.utc(date));
}
} else {
// Set the start of the month without shifting time like startOf() may do.
setBrowsingDate(
dayjs.tz(month, timeZone).set("date", 1).set("hour", 0).set("minute", 0).set("second", 0)
);
if (date) {
// It's important to set the date immediately to the timeZone, dayjs(date) will convert to browsertime.
setSelectedDate(dayjs.tz(date, timeZone));
}
}
}, [router.isReady, month, date, duration, timeZone]);
const { i18n, isLocaleReady } = useLocale();
const { slots: monthSlots, isLoading } = useSlots({
eventTypeId: eventType.id,
eventTypeSlug: eventType.slug,
usernameList: users,
startTime:
browsingDate === undefined || browsingDate.get("month") === dayjs.tz(undefined, timeZone).get("month")
? dayjs.tz(undefined, timeZone).subtract(2, "days").startOf("day")
: browsingDate?.startOf("month"),
endTime: browsingDate?.endOf("month"),
timeZone,
duration,
});
const { slots: selectedDateSlots, isLoading: _isLoadingSelectedDateSlots } = useSlots({
eventTypeId: eventType.id,
eventTypeSlug: eventType.slug,
usernameList: users,
startTime: selectedDate?.startOf("day"),
endTime: selectedDate?.endOf("day"),
timeZone,
duration,
/** Prevent refetching is we already have this data from month slots */
enabled: !!selectedDate,
});
/** Hide skeleton if we have the slot loaded in the month query */
const isLoadingSelectedDateSlots = (() => {
if (!selectedDate) return _isLoadingSelectedDateSlots;
if (!!selectedDateSlots[selectedDate.format("YYYY-MM-DD")]) return false;
if (!!monthSlots[selectedDate.format("YYYY-MM-DD")]) return false;
return false;
})();
return (
<>
<DatePicker
isLoading={isLoading}
className={classNames(
"mt-8 px-4 pb-4 sm:mt-0 md:min-w-[300px] md:px-5 lg:min-w-[455px]",
selectedDate ? "sm:dark:border-darkgray-200 border-gray-200 sm:border-r sm:p-4 sm:pr-6" : "sm:p-4"
)}
includedDates={Object.keys(monthSlots).filter((k) => monthSlots[k].length > 0)}
locale={isLocaleReady ? i18n.language : "en"}
selected={selectedDate}
onChange={(newDate) => {
setDate(newDate.format("YYYY-MM-DD"));
}}
onMonthChange={(newMonth) => {
setMonth(newMonth.format("YYYY-MM"));
}}
browsingDate={browsingDate}
weekStart={weekStart}
/>
<AvailableTimes
isLoading={isLoadingSelectedDateSlots}
slots={
selectedDate &&
(selectedDateSlots[selectedDate.format("YYYY-MM-DD")] ||
monthSlots[selectedDate.format("YYYY-MM-DD")])
}
date={selectedDate}
timeFormat={timeFormat}
onTimeFormatChange={onTimeFormatChange}
eventTypeId={eventType.id}
eventTypeSlug={eventType.slug}
seatsPerTimeSlot={seatsPerTimeSlot}
recurringCount={recurringEventCount}
ethSignature={ethSignature}
/>
</>
);
};
+63 -16
View File
@@ -1,7 +1,11 @@
import { FC, useEffect, useState } from "react";
import type { FC } from "react";
import { useEffect, useState } from "react";
import { useLocale } from "@calcom/lib/hooks/useLocale";
import { ITimezoneOption, TimezoneSelect } from "@calcom/ui";
import useTheme from "@calcom/lib/hooks/useTheme";
import type { ITimezoneOption } from "@calcom/ui";
import { TimezoneSelect } from "@calcom/ui";
import useMeQuery from "@lib/hooks/useMeQuery";
import { timeZone } from "../../lib/clock";
@@ -11,7 +15,8 @@ type Props = {
const TimeOptions: FC<Props> = ({ onSelectTimeZone }) => {
const [selectedTimeZone, setSelectedTimeZone] = useState("");
const { t } = useLocale();
const query = useMeQuery();
const userTheme = useTheme(query?.data?.theme).resolvedTheme;
useEffect(() => {
setSelectedTimeZone(timeZone());
@@ -23,18 +28,60 @@ const TimeOptions: FC<Props> = ({ onSelectTimeZone }) => {
}
}, [selectedTimeZone, onSelectTimeZone]);
return selectedTimeZone !== "" ? (
<div className="dark:border-darkgray-300 dark:bg-darkgray-200 rounded-sm border border-gray-200 bg-white px-4 pt-4 pb-3 shadow-sm">
<div className="mb-4 flex">
<div className="text-sm font-medium text-gray-600 dark:text-white">{t("time_options")}</div>
</div>
<TimezoneSelect
id="timeZone"
value={selectedTimeZone}
onChange={(tz: ITimezoneOption) => setSelectedTimeZone(tz.value)}
className="focus:border-brand mt-1 mb-2 block w-full rounded-md border-gray-300 text-sm focus:ring-black"
/>
</div>
const customStyles = {
option: (_provided: object, state: { isSelected: boolean; isFocused: boolean }) => ({
padding: "10px 12px !important",
color: state.isSelected || state.isFocused ? "#101010" : "#374151",
backgroundColor: state.isSelected ? "#E5E7EB !important" : "white",
...(userTheme === "dark" && {
color: state.isSelected || state.isFocused ? "white" : "#80868B",
}),
}),
control: () => ({
display: "flex",
cursor: "pointer",
backgroundColor: "transparent !important",
minWidth: "5rem",
height: "24px",
minHeight: "24px !important",
boxShadow: "none !important",
}),
singleValue: (provided: object, state: { selectProps: { menuIsOpen: boolean } }) => ({
...provided,
color: state.selectProps.menuIsOpen ? "#111827" : "#4B5563",
...(userTheme === "dark" && {
color: "#a5a5a5 !important",
}),
}),
menu: (provided: object) => ({
...provided,
minWidth: "20rem",
margin: "8px 0 0 -20px",
}),
valueContainer: (provided: object) => ({
...provided,
padding: "0 0 0 6px",
}),
dropdownIndicator: (provided: object, state: { selectProps: { menuIsOpen: boolean } }) => ({
...provided,
transform: state.selectProps.menuIsOpen ? "rotate(180deg)" : "",
color: state.selectProps.menuIsOpen ? "#111827" : "#4B5563",
marginLeft: 4,
padding: 0,
...(userTheme === "dark" && {
color: "#80868B",
}),
}),
};
return !!selectedTimeZone ? (
<TimezoneSelect
id="timeZone"
value={selectedTimeZone}
onChange={(tz: ITimezoneOption) => setSelectedTimeZone(tz.value)}
className="flex h-6 text-sm font-medium"
styles={customStyles}
/>
) : null;
};
@@ -0,0 +1,26 @@
import { FiGlobe } from "@calcom/ui/components/icon";
import { timeZone as localStorageTimeZone } from "@lib/clock";
import TimeOptions from "@components/booking/TimeOptions";
export function TimezoneDropdown({
onChangeTimeZone,
}: {
onChangeTimeZone: (newTimeZone: string) => void;
timeZone?: string;
}) {
const handleSelectTimeZone = (newTimeZone: string) => {
onChangeTimeZone(newTimeZone);
localStorageTimeZone(newTimeZone);
};
return (
<>
<div className="dark:focus-within:bg-darkgray-200 dark:bg-darkgray-100 dark:hover:bg-darkgray-200 -mx-[2px] !mt-3 flex w-fit items-center rounded-[4px] px-1 py-[2px] text-sm font-medium focus-within:bg-gray-200 hover:bg-gray-100 [&_svg]:focus-within:text-gray-900 dark:[&_svg]:focus-within:text-white [&_p]:focus-within:text-gray-900 dark:[&_p]:focus-within:text-white">
<FiGlobe className="dark:text-darkgray-600 flex h-4 w-4 text-gray-600 ltr:mr-[2px] rtl:ml-[2px]" />
<TimeOptions onSelectTimeZone={handleSelectTimeZone} />
</div>
</>
);
}
+2 -1
View File
@@ -1,5 +1,6 @@
import { CAL_URL } from "@calcom/lib/constants";
import { AvatarGroup, AvatarGroupProps } from "@calcom/ui";
import type { AvatarGroupProps } from "@calcom/ui";
import { AvatarGroup } from "@calcom/ui";
export const UserAvatars = ({
profile,
@@ -1,15 +1,12 @@
import { useAutoAnimate } from "@formkit/auto-animate/react";
import { EventType } from "@prisma/client";
import * as Popover from "@radix-ui/react-popover";
import dynamic from "next/dynamic";
import { useRouter } from "next/router";
import { useReducer, useEffect, useMemo, useState } from "react";
import { Toaster } from "react-hot-toast";
import { useEffect, useMemo, useReducer, useState } from "react";
import { FormattedNumber, IntlProvider } from "react-intl";
import { z } from "zod";
import BookingPageTagManager from "@calcom/app-store/BookingPageTagManager";
import { getEventTypeAppData } from "@calcom/app-store/utils";
import dayjs, { Dayjs } from "@calcom/dayjs";
import dayjs from "@calcom/dayjs";
import {
useEmbedNonStylesConfig,
useEmbedStyles,
@@ -17,230 +14,39 @@ import {
useIsBackgroundTransparent,
useIsEmbed,
} from "@calcom/embed-core/embed-iframe";
import DatePicker from "@calcom/features/calendars/DatePicker";
import CustomBranding from "@calcom/lib/CustomBranding";
import classNames from "@calcom/lib/classNames";
import getStripeAppData from "@calcom/lib/getStripeAppData";
import getPaymentAppData from "@calcom/lib/getPaymentAppData";
import { useLocale } from "@calcom/lib/hooks/useLocale";
import useTheme from "@calcom/lib/hooks/useTheme";
import notEmpty from "@calcom/lib/notEmpty";
import { getRecurringFreq } from "@calcom/lib/recurringStrings";
import { collectPageParameters, telemetryEventTypes, useTelemetry } from "@calcom/lib/telemetry";
import { detectBrowserTimeFormat, setIs24hClockInLocalStorage, TimeFormat } from "@calcom/lib/timeFormat";
import { trpc } from "@calcom/trpc/react";
import { HeadSeo } from "@calcom/ui";
import { FiChevronDown, FiChevronUp, FiCreditCard, FiGlobe, FiRefreshCcw } from "@calcom/ui/components/icon";
import { FiCreditCard, FiRefreshCcw } from "@calcom/ui/components/icon";
import { timeZone as localStorageTimeZone } from "@lib/clock";
import useRouterQuery from "@lib/hooks/useRouterQuery";
import Gates, { Gate, GateState } from "@components/Gates";
import AvailableTimes from "@components/booking/AvailableTimes";
import type { Gate, GateState } from "@components/Gates";
import Gates from "@components/Gates";
import BookingDescription from "@components/booking/BookingDescription";
import TimeOptions from "@components/booking/TimeOptions";
import PoweredByCal from "@components/ui/PoweredByCal";
import { SlotPicker } from "@components/booking/SlotPicker";
import type { AvailabilityPageProps } from "../../../pages/[user]/[type]";
import type { DynamicAvailabilityPageProps } from "../../../pages/d/[link]/[slug]";
import type { AvailabilityTeamPageProps } from "../../../pages/team/[slug]/[type]";
const useSlots = ({
eventTypeId,
eventTypeSlug,
startTime,
endTime,
usernameList,
timeZone,
duration,
}: {
eventTypeId: number;
eventTypeSlug: string;
startTime?: Dayjs;
endTime?: Dayjs;
usernameList: string[];
timeZone?: string;
duration?: string;
}) => {
const { data, isLoading, isPaused } = trpc.viewer.public.slots.getSchedule.useQuery(
{
eventTypeId,
eventTypeSlug,
usernameList,
startTime: startTime?.toISOString() || "",
endTime: endTime?.toISOString() || "",
timeZone,
duration,
},
{
enabled: !!startTime && !!endTime,
}
);
const [cachedSlots, setCachedSlots] = useState<NonNullable<typeof data>["slots"]>({});
const PoweredByCal = dynamic(() => import("@components/ui/PoweredByCal"));
useEffect(() => {
if (data?.slots) {
setCachedSlots((c) => ({ ...c, ...data?.slots }));
}
}, [data]);
// The very first time isPaused is set if auto-fetch is disabled, so isPaused should also be considered a loading state.
return { slots: cachedSlots, isLoading: isLoading || isPaused };
};
const SlotPicker = ({
eventType,
timeFormat,
onTimeFormatChange,
timeZone,
recurringEventCount,
users,
seatsPerTimeSlot,
weekStart = 0,
ethSignature,
}: {
eventType: Pick<EventType, "id" | "schedulingType" | "slug">;
timeFormat: TimeFormat;
onTimeFormatChange: (is24Hour: boolean) => void;
timeZone?: string;
seatsPerTimeSlot?: number;
recurringEventCount?: number;
users: string[];
weekStart?: 0 | 1 | 2 | 3 | 4 | 5 | 6;
ethSignature?: string;
}) => {
const [selectedDate, setSelectedDate] = useState<Dayjs>();
const [browsingDate, setBrowsingDate] = useState<Dayjs>();
const { duration } = useRouterQuery("duration");
const { date, setQuery: setDate } = useRouterQuery("date");
const { month, setQuery: setMonth } = useRouterQuery("month");
const router = useRouter();
const [slotPickerRef] = useAutoAnimate<HTMLDivElement>();
useEffect(() => {
if (!router.isReady) return;
// Etc/GMT is not actually a timeZone, so handle this select option explicitly to prevent a hard crash.
if (timeZone === "Etc/GMT") {
setBrowsingDate(dayjs.utc(month).set("date", 1).set("hour", 0).set("minute", 0).set("second", 0));
if (date) {
setSelectedDate(dayjs.utc(date));
}
} else {
// Set the start of the month without shifting time like startOf() may do.
setBrowsingDate(
dayjs.tz(month, timeZone).set("date", 1).set("hour", 0).set("minute", 0).set("second", 0)
);
if (date) {
// It's important to set the date immediately to the timeZone, dayjs(date) will convert to browsertime.
setSelectedDate(dayjs.tz(date, timeZone));
}
}
}, [router.isReady, month, date, duration, timeZone]);
const { i18n, isLocaleReady } = useLocale();
const { slots: _1 } = useSlots({
eventTypeId: eventType.id,
eventTypeSlug: eventType.slug,
usernameList: users,
startTime: selectedDate?.startOf("day"),
endTime: selectedDate?.endOf("day"),
timeZone,
duration,
});
const { slots: _2, isLoading } = useSlots({
eventTypeId: eventType.id,
eventTypeSlug: eventType.slug,
usernameList: users,
startTime:
browsingDate === undefined || browsingDate.get("month") === dayjs.tz(undefined, timeZone).get("month")
? dayjs.tz(undefined, timeZone).subtract(2, "days").startOf("day")
: browsingDate?.startOf("month"),
endTime: browsingDate?.endOf("month"),
timeZone,
duration,
});
const slots = useMemo(() => ({ ..._2, ..._1 }), [_1, _2]);
return (
<>
<DatePicker
isLoading={isLoading}
className={classNames(
"mt-8 px-4 pb-4 sm:mt-0 md:min-w-[300px] md:px-5 lg:min-w-[455px]",
selectedDate ? "sm:dark:border-darkgray-200 border-gray-200 sm:border-r sm:p-4 sm:pr-6" : "sm:p-4"
)}
includedDates={Object.keys(slots).filter((k) => slots[k].length > 0)}
locale={isLocaleReady ? i18n.language : "en"}
selected={selectedDate}
onChange={(newDate) => {
setDate(newDate.format("YYYY-MM-DD"));
}}
onMonthChange={(newMonth) => {
setMonth(newMonth.format("YYYY-MM"));
}}
browsingDate={browsingDate}
weekStart={weekStart}
/>
<div ref={slotPickerRef}>
<AvailableTimes
isLoading={isLoading}
slots={selectedDate && slots[selectedDate.format("YYYY-MM-DD")]}
date={selectedDate}
timeFormat={timeFormat}
onTimeFormatChange={onTimeFormatChange}
eventTypeId={eventType.id}
eventTypeSlug={eventType.slug}
seatsPerTimeSlot={seatsPerTimeSlot}
recurringCount={recurringEventCount}
ethSignature={ethSignature}
/>
</div>
</>
);
};
function TimezoneDropdown({
onChangeTimeZone,
timeZone,
}: {
onChangeTimeZone: (newTimeZone: string) => void;
timeZone?: string;
}) {
const [isTimeOptionsOpen, setIsTimeOptionsOpen] = useState(false);
const handleSelectTimeZone = (newTimeZone: string) => {
onChangeTimeZone(newTimeZone);
localStorageTimeZone(newTimeZone);
setIsTimeOptionsOpen(false);
};
return (
<Popover.Root open={isTimeOptionsOpen} onOpenChange={setIsTimeOptionsOpen}>
<Popover.Trigger className="min-w-32 dark:text-darkgray-600 radix-state-open:bg-gray-200 dark:radix-state-open:bg-darkgray-200 group relative mb-2 -ml-2 !mt-2 inline-block self-start rounded-md px-2 py-2 text-left text-gray-600">
<p className="flex items-center text-sm font-medium">
<FiGlobe className="min-h-4 min-w-4 ml-[2px] -mt-[2px] inline-block ltr:mr-[10px] rtl:ml-[10px]" />
{timeZone}
{isTimeOptionsOpen ? (
<FiChevronUp className="min-h-4 min-w-4 ml-1 inline-block" />
) : (
<FiChevronDown className="min-h-4 min-w-4 ml-1 inline-block" />
)}
</p>
</Popover.Trigger>
<Popover.Portal>
<Popover.Content
hideWhenDetached
align="start"
className="animate-fade-in-up absolute left-0 top-2 w-80 max-w-[calc(100vw_-_1.5rem)]">
<TimeOptions onSelectTimeZone={handleSelectTimeZone} />
</Popover.Content>
</Popover.Portal>
</Popover.Root>
);
}
const Toaster = dynamic(() => import("react-hot-toast").then((mod) => mod.Toaster), { ssr: false });
/*const SlotPicker = dynamic(() => import("../SlotPicker").then((mod) => mod.SlotPicker), {
ssr: false,
loading: () => <div className="mt-8 px-4 pb-4 sm:mt-0 sm:p-4 md:min-w-[300px] md:px-5 lg:min-w-[455px]" />,
});*/
const TimezoneDropdown = dynamic(() => import("../TimezoneDropdown").then((mod) => mod.TimezoneDropdown), {
ssr: false,
});
const dateQuerySchema = z.object({
rescheduleUid: z.string().optional().default(""),
@@ -303,7 +109,7 @@ const AvailabilityPage = ({ profile, eventType, ...restProps }: Props) => {
() => <TimezoneDropdown timeZone={timeZone} onChangeTimeZone={setTimeZone} />,
[timeZone]
);
const stripeAppData = getStripeAppData(eventType);
const paymentAppData = getPaymentAppData(eventType);
const rainbowAppData = getEventTypeAppData(eventType, "rainbow") || {};
const rawSlug = profile.slug ? profile.slug.split("/") : [];
if (rawSlug.length > 1) rawSlug.pop(); //team events have team name as slug, but user events have [user]/[type] as slug.
@@ -354,10 +160,10 @@ const AvailabilityPage = ({ profile, eventType, ...restProps }: Props) => {
isBackgroundTransparent
? ""
: "dark:bg-darkgray-100 sm:dark:border-darkgray-300 bg-white pb-4 md:pb-0",
"border-bookinglightest overflow-hidden md:rounded-md md:border",
"border-bookinglightest md:rounded-md md:border",
isEmbed && "mx-auto"
)}>
<div className="overflow-hidden md:flex">
<div className="md:flex">
{showEventTypeDetails && (
<div
className={classNames(
@@ -391,14 +197,14 @@ const AvailabilityPage = ({ profile, eventType, ...restProps }: Props) => {
</div>
</div>
)}
{stripeAppData.price > 0 && (
{paymentAppData.price > 0 && (
<p className="-ml-2 px-2 text-sm font-medium">
<FiCreditCard className="ml-[2px] -mt-1 inline-block h-4 w-4 ltr:mr-[10px] rtl:ml-[10px]" />
<IntlProvider locale="en">
<FormattedNumber
value={stripeAppData.price / 100.0}
value={paymentAppData.price / 100.0}
style="currency"
currency={stripeAppData.currency.toUpperCase()}
currency={paymentAppData.currency?.toUpperCase()}
/>
</IntlProvider>
</p>
+153 -88
View File
@@ -6,15 +6,14 @@ import { useSession } from "next-auth/react";
import Head from "next/head";
import { useRouter } from "next/router";
import { useEffect, useMemo, useReducer, useState } from "react";
import { Controller, useForm, useWatch } from "react-hook-form";
import { useFieldArray, useForm, useWatch } from "react-hook-form";
import { FormattedNumber, IntlProvider } from "react-intl";
import { ReactMultiEmail } from "react-multi-email";
import { v4 as uuidv4 } from "uuid";
import { z } from "zod";
import BookingPageTagManager from "@calcom/app-store/BookingPageTagManager";
import type { EventLocationType } from "@calcom/app-store/locations";
import {
EventLocationType,
getEventLocationType,
getEventLocationValue,
getHumanReadableLocationValue,
@@ -22,7 +21,8 @@ import {
} from "@calcom/app-store/locations";
import { createPaymentLink } from "@calcom/app-store/stripepayment/lib/client";
import { getEventTypeAppData } from "@calcom/app-store/utils";
import { LocationObject, LocationType } from "@calcom/core/location";
import type { LocationObject } from "@calcom/core/location";
import { LocationType } from "@calcom/core/location";
import dayjs from "@calcom/dayjs";
import {
useEmbedNonStylesConfig,
@@ -33,21 +33,33 @@ import {
import CustomBranding from "@calcom/lib/CustomBranding";
import classNames from "@calcom/lib/classNames";
import { APP_NAME } from "@calcom/lib/constants";
import getStripeAppData from "@calcom/lib/getStripeAppData";
import getPaymentAppData from "@calcom/lib/getPaymentAppData";
import { useLocale } from "@calcom/lib/hooks/useLocale";
import useTheme from "@calcom/lib/hooks/useTheme";
import { HttpError } from "@calcom/lib/http-error";
import { getEveryFreqFor } from "@calcom/lib/recurringStrings";
import slugify from "@calcom/lib/slugify";
import { collectPageParameters, telemetryEventTypes, useTelemetry } from "@calcom/lib/telemetry";
import { AddressInput, Button, EmailInput, Form, PhoneInput, Tooltip, Group, RadioField } from "@calcom/ui";
import {
FiAlertTriangle,
AddressInput,
Button,
EmailField,
EmailInput,
Form,
Group,
PhoneInput,
RadioField,
Tooltip,
} from "@calcom/ui";
import {
FiUserPlus,
FiCalendar,
FiCreditCard,
FiX,
FiInfo,
FiCreditCard,
FiRefreshCw,
FiUser,
FiUserPlus,
FiAlertTriangle,
} from "@calcom/ui/components/icon";
import { asStringOrNull } from "@lib/asStringOrNull";
@@ -57,14 +69,14 @@ import useRouterQuery from "@lib/hooks/useRouterQuery";
import createBooking from "@lib/mutations/bookings/create-booking";
import createRecurringBooking from "@lib/mutations/bookings/create-recurring-booking";
import { parseDate, parseRecurringDates } from "@lib/parseDate";
import slugify from "@lib/slugify";
import Gates, { Gate, GateState } from "@components/Gates";
import type { Gate, GateState } from "@components/Gates";
import Gates from "@components/Gates";
import BookingDescription from "@components/booking/BookingDescription";
import { BookPageProps } from "../../../pages/[user]/book";
import { HashLinkPageProps } from "../../../pages/d/[link]/book";
import { TeamBookingPageProps } from "../../../pages/team/[slug]/book";
import type { BookPageProps } from "../../../pages/[user]/book";
import type { HashLinkPageProps } from "../../../pages/d/[link]/book";
import type { TeamBookingPageProps } from "../../../pages/team/[slug]/book";
type BookingPageProps = BookPageProps | TeamBookingPageProps | HashLinkPageProps;
@@ -73,7 +85,7 @@ type BookingFormValues = {
email: string;
notes?: string;
locationType?: EventLocationType["type"];
guests?: string[];
guests?: { email: string }[];
address?: string;
attendeeAddress?: string;
phone?: string;
@@ -112,10 +124,15 @@ const BookingPage = ({
}),
{}
);
const stripeAppData = getStripeAppData(eventType);
const paymentAppData = getPaymentAppData(eventType);
// Define duration now that we support multiple duration eventTypes
let duration = eventType.length;
if (queryDuration && !isNaN(Number(queryDuration))) {
if (
queryDuration &&
!isNaN(Number(queryDuration)) &&
eventType.metadata?.multipleDuration &&
eventType.metadata?.multipleDuration.includes(Number(queryDuration))
) {
duration = Number(queryDuration);
}
@@ -133,6 +150,7 @@ const BookingPage = ({
const mutation = useMutation(createBooking, {
onSuccess: async (responseData) => {
const { uid, paymentUid } = responseData;
if (paymentUid) {
return await router.push(
createPaymentLink({
@@ -151,7 +169,7 @@ const BookingPage = ({
isSuccessBookingPage: true,
email: bookingForm.getValues("email"),
eventTypeSlug: eventType.slug,
formerTime: booking?.startTime.toString(),
...(rescheduleUid && booking?.startTime && { formerTime: booking.startTime.toString() }),
},
});
},
@@ -192,7 +210,9 @@ const BookingPage = ({
const loggedInIsOwner = eventType?.users[0]?.id === session?.user?.id;
const guestListEmails = !isDynamicGroupBooking
? booking?.attendees.slice(1).map((attendee) => attendee.email)
? booking?.attendees.slice(1).map((attendee) => {
return { email: attendee.email };
})
: [];
// There should only exists one default userData variable for primaryAttendee.
@@ -211,7 +231,9 @@ const BookingPage = ({
name: defaultUserValues.name || (!loggedInIsOwner && session?.user?.name) || "",
email: defaultUserValues.email || (!loggedInIsOwner && session?.user?.email) || "",
notes: (router.query.notes as string) || "",
guests: ensureArray(router.query.guest) as string[],
guests: ensureArray(router.query.guest).map((guest) => {
return { email: guest as string };
}),
customInputs: eventType.customInputs.reduce(
(customInputs, input) => ({
...customInputs,
@@ -253,6 +275,7 @@ const BookingPage = ({
.object({
name: z.string().min(1),
email: z.string().trim().email(),
guests: z.array(z.object({ email: z.string().email() })).optional(),
phone: z
.string()
.refine((val) => isValidPhoneNumber(val))
@@ -271,6 +294,10 @@ const BookingPage = ({
defaultValues: defaultValues(),
resolver: zodResolver(bookingFormSchema), // Since this isn't set to strict we only validate the fields in the schema
});
const guestsField = useFieldArray({
name: "guests",
control: bookingForm.control,
});
const selectedLocationType = useWatch({
control: bookingForm.control,
@@ -309,6 +336,7 @@ const BookingPage = ({
}
const bookEvent = (booking: BookingFormValues) => {
bookingForm.clearErrors();
const bookingCustomInputs = Object.keys(booking.customInputs || {}).map((inputId) => ({
label: eventType.customInputs.find((input) => input.id === parseInt(inputId))?.label || "",
value: booking.customInputs && booking.customInputs[inputId] ? booking.customInputs[inputId] : "",
@@ -376,6 +404,29 @@ const BookingPage = ({
}
}
// Validate that guests are unique
let alreadyInvited = false;
booking.guests?.forEach((guest, index) => {
if (guest.email === booking.email) {
bookingForm.setError(`guests.${index}`, { type: "validate", message: t("already_invited") });
alreadyInvited = true;
}
if (booking.guests) {
let guestCount = 0;
for (const checkGuest of booking.guests) {
if (checkGuest.email === guest.email) guestCount++;
if (guestCount > 1) {
bookingForm.setError(`guests.${index}`, { type: "validate", message: t("already_invited") });
alreadyInvited = true;
break;
}
}
}
});
if (alreadyInvited) return;
if (recurringDates.length) {
// Identify set of bookings to one intance of recurring event to support batch changes
const recurringEventId = uuidv4();
@@ -406,6 +457,7 @@ const BookingPage = ({
? booking.phone
: booking.smsReminderNumber || undefined,
ethSignature: gateState.rainbowToken,
guests: booking.guests?.map((guest) => guest.email),
}));
recurringMutation.mutate(recurringBookings);
} else {
@@ -434,6 +486,7 @@ const BookingPage = ({
? booking.phone
: booking.smsReminderNumber || undefined,
ethSignature: gateState.rainbowToken,
guests: booking.guests?.map((guest) => guest.email),
});
}
};
@@ -507,14 +560,14 @@ const BookingPage = ({
{showEventTypeDetails && (
<div className="sm:dark:border-darkgray-300 dark:text-darkgray-600 flex flex-col px-6 pt-6 pb-0 text-gray-600 sm:w-1/2 sm:border-r sm:pb-6">
<BookingDescription isBookingPage profile={profile} eventType={eventType}>
{stripeAppData.price > 0 && (
{paymentAppData.price > 0 && (
<p className="text-bookinglight -ml-2 px-2 text-sm ">
<FiCreditCard className="ml-[2px] -mt-1 inline-block h-4 w-4 ltr:mr-[10px] rtl:ml-[10px]" />
<IntlProvider locale="en">
<FormattedNumber
value={stripeAppData.price / 100.0}
value={paymentAppData.price / 100.0}
style="currency"
currency={stripeAppData.currency.toUpperCase()}
currency={paymentAppData?.currency?.toUpperCase()}
/>
</IntlProvider>
</p>
@@ -850,60 +903,7 @@ const BookingPage = ({
)}
</div>
))}
{!eventType.disableGuests && guestToggle && (
<div className="mb-4">
<div>
<label
htmlFor="guests"
className="mb-1 block text-sm font-medium text-gray-700 dark:text-white">
{t("guests")}
</label>
{!disableInput && (
<Controller
control={bookingForm.control}
name="guests"
render={({ field: { onChange, value } }) => (
<ReactMultiEmail
className="relative"
placeholder={<span className="dark:text-darkgray-600">guest@example.com</span>}
emails={value}
onChange={onChange}
getLabel={(
email: string,
index: number,
removeEmail: (index: number) => void
) => {
return (
<div data-tag key={index} className="cursor-pointer">
{email}
{!disableInput && (
<span data-tag-handle onClick={() => removeEmail(index)}>
×
</span>
)}
</div>
);
}}
/>
)}
/>
)}
{/* Custom code when guest emails should not be editable */}
{disableInput && guestListEmails && guestListEmails.length > 0 && (
<div data-tag className="react-multi-email">
{/* // @TODO: user owners are appearing as guest here when should be only user input */}
{guestListEmails.map((email, index) => {
return (
<div key={index} className="cursor-pointer">
<span data-tag>{email}</span>
</div>
);
})}
</div>
)}
</div>
</div>
)}
{isSmsReminderNumberNeeded && selectedLocationType !== LocationType.Phone && (
<div className="mb-4">
<label
@@ -956,19 +956,84 @@ const BookingPage = ({
/>
)}
</div>
{!eventType.disableGuests && guestsField.fields.length ? (
<div className="mb-4">
<div>
<label
htmlFor="guests"
className="mb-1 block text-sm font-medium text-gray-700 dark:text-white">
{t("guests")}
</label>
<ul>
{guestsField.fields.map((field, index) => (
<li key={field.id}>
<EmailField
{...bookingForm.register(`guests.${index}.email` as const)}
className={classNames(
inputClassName,
bookingForm.formState.errors.guests?.[index] &&
"!focus:ring-red-700 !border-red-700",
"border-r-0"
)}
addOnClassname={classNames(
"border-gray-300 border block border-l-0 disabled:bg-gray-200 disabled:hover:cursor-not-allowed bg-transparent disabled:text-gray-500 dark:border-darkgray-300 ",
bookingForm.formState.errors.guests?.[index] &&
"!focus:ring-red-700 !border-red-700"
)}
placeholder="guest@example.com"
label={<></>}
required
addOnSuffix={
<Tooltip content="Remove guest">
<button
className="m-1 disabled:hover:cursor-not-allowed"
type="button"
onClick={() => guestsField.remove(index)}>
<FiX className="text-gray-600" />
</button>
</Tooltip>
}
/>
{bookingForm.formState.errors.guests?.[index] && (
<div className="mt-2 flex items-center text-sm text-red-700 ">
<FiInfo className="h-3 w-3 ltr:mr-2 rtl:ml-2" />
<p className="text-red-700">
{bookingForm.formState.errors.guests?.[index]?.message}
</p>
</div>
)}
</li>
))}
</ul>
<Button
type="button"
color="minimal"
StartIcon={FiUserPlus}
className="my-2.5"
// className="mb-1 block text-sm font-medium text-gray-700 dark:text-white"
onClick={() => guestsField.append({ email: "" })}>
{t("add_another")}
</Button>
</div>
</div>
) : (
<></>
)}
{!eventType.disableGuests && !guestsField.fields.length && (
<Button
color="minimal"
variant="button"
StartIcon={FiUserPlus}
onClick={() => {
guestsField.append({ email: "" });
}}
className="mr-auto">
{t("additional_guests")}
</Button>
)}
<div className="flex justify-end space-x-2 rtl:space-x-reverse">
{!eventType.disableGuests && !guestToggle && (
<Button
type="button"
color="minimal"
variant="icon"
tooltip={t("additional_guests")}
StartIcon={FiUserPlus}
onClick={() => setGuestToggle(!guestToggle)}
className="mr-auto"
/>
)}
<Button color="minimal" type="button" onClick={() => router.back()}>
{t("cancel")}
</Button>
@@ -1,27 +1,30 @@
import { ErrorMessage } from "@hookform/error-message";
import { zodResolver } from "@hookform/resolvers/zod";
import { isValidPhoneNumber } from "libphonenumber-js";
import { Trans } from "next-i18next";
import Link from "next/link";
import { useEffect } from "react";
import { Controller, useForm, useWatch } from "react-hook-form";
import { z } from "zod";
import type { EventLocationType, LocationObject } from "@calcom/app-store/locations";
import {
EventLocationType,
getEventLocationType,
getHumanReadableLocationValue,
getMessageForOrganizer,
LocationObject,
LocationType,
} from "@calcom/app-store/locations";
import { useLocale } from "@calcom/lib/hooks/useLocale";
import { RouterOutputs, trpc } from "@calcom/trpc/react";
import type { RouterOutputs } from "@calcom/trpc/react";
import { trpc } from "@calcom/trpc/react";
import { Button, Dialog, DialogContent, DialogFooter, Form, PhoneInput } from "@calcom/ui";
import { FiMapPin } from "@calcom/ui/components/icon";
import { QueryCell } from "@lib/QueryCell";
import CheckboxField from "@components/ui/form/CheckboxField";
import LocationSelect, { LocationOption } from "@components/ui/form/LocationSelect";
import type { LocationOption } from "@components/ui/form/LocationSelect";
import LocationSelect from "@components/ui/form/LocationSelect";
type BookingItem = RouterOutputs["viewer"]["bookings"]["get"]["bookings"][number];
@@ -216,7 +219,15 @@ export const EditLocationDialog = (props: ISetLocationDialog) => {
{t("edit_location")}
</h3>
{!booking && (
<p className="text-sm text-gray-400">{t("this_input_will_shown_booking_this_event")}</p>
<p className="text-sm text-gray-400">
<Trans i18nKey="cant_find_the_right_video_app_visit_our_app_store">
Can&apos;t find the right video app? Visit our
<Link className="cursor-pointer text-blue-500 underline" href="/apps/categories/video">
App Store
</Link>
.
</Trans>
</p>
)}
</div>
<div className="mt-3 text-center sm:mt-0 sm:text-left" />
@@ -327,7 +338,7 @@ export const EditLocationDialog = (props: ISetLocationDialog) => {
setShowLocationModal(false);
setSelectedLocation?.(undefined);
setEditingLocationType?.("");
locationFormMethods.unregister("locationType");
locationFormMethods.unregister(["locationType", "locationLink"]);
}}
type="button"
color="secondary">
@@ -1,4 +1,5 @@
import { Dispatch, SetStateAction, useState } from "react";
import type { Dispatch, SetStateAction } from "react";
import { useState } from "react";
import { useLocale } from "@calcom/lib/hooks/useLocale";
import { trpc } from "@calcom/trpc/react";
+103 -87
View File
@@ -1,6 +1,7 @@
import { FormValues } from "pages/event-types/[type]";
import type { FormValues } from "pages/event-types/[type]";
import { Controller, useFormContext } from "react-hook-form";
import { components, OptionProps, SingleValueProps } from "react-select";
import type { OptionProps, SingleValueProps } from "react-select";
import { components } from "react-select";
import dayjs from "@calcom/dayjs";
import classNames from "@calcom/lib/classNames";
@@ -99,100 +100,106 @@ const format = (date: Date, hour12: boolean) =>
new Date(dayjs.utc(date).format("YYYY-MM-DDTHH:mm:ss"))
);
export const AvailabilityTab = ({ isTeamEvent }: { isTeamEvent: boolean }) => {
const EventTypeScheduleDetails = () => {
const { data: loggedInUser } = useMeQuery();
const timeFormat = loggedInUser?.timeFormat;
const { t, i18n } = useLocale();
const { watch } = useFormContext<FormValues>();
const EventTypeSchedule = () => {
const me = useMeQuery();
const timeFormat = me?.data?.timeFormat;
return (
<div className="space-y-4">
<div>
<div className="min-w-4 mb-2">
<label htmlFor="availability" className="mt-0 flex text-sm font-medium text-gray-700">
{t("availability")}
</label>
</div>
<Controller
name="schedule"
render={({ field }) => (
<AvailabilitySelect
value={field.value}
onBlur={field.onBlur}
name={field.name}
onChange={(selected) => {
field.onChange(selected?.value || null);
}}
/>
)}
/>
</div>
<div className="space-y-4 rounded border p-4 py-6 pt-2 md:p-8">
<ol className="table border-collapse text-sm">
{weekdayNames(i18n.language, 1, "long").map((day, index) => {
const isAvailable = !!filterDays(index).length;
return (
<li key={day} className="my-6 flex border-transparent last:mb-2">
<span
className={classNames(
"w-20 font-medium sm:w-32",
!isAvailable && "text-gray-500 opacity-50"
)}>
{day}
</span>
{isLoading ? (
<SkeletonText className="block h-5 w-60" />
) : isAvailable ? (
<div className="space-y-3 text-right">
{filterDays(index).map((dayRange, i) => (
<div key={i} className="flex items-center leading-4">
<span className="w-16 sm:w-28 sm:text-left">
{format(dayRange.startTime, timeFormat === 12)}
</span>
<span className="ltr:ml-4 rtl:mr-4">-</span>
<div className="ml-6">{format(dayRange.endTime, timeFormat === 12)}</div>
</div>
))}
</div>
) : (
<span className="ml-6 text-gray-500 opacity-50 sm:ml-0">{t("unavailable")}</span>
)}
</li>
);
})}
</ol>
<hr />
<div className="flex flex-col justify-center gap-2 sm:flex-row sm:justify-between">
<span className="flex items-center justify-center text-sm text-gray-600 sm:justify-start">
<FiGlobe className="ltr:mr-2 rtl:ml-2" />
{schedule?.timeZone || <SkeletonText className="block h-5 w-32" />}
</span>
<Button
href={`/availability/${schedule?.schedule.id}`}
color="minimal"
EndIcon={FiExternalLink}
target="_blank"
className="justify-center border sm:border-0"
rel="noopener noreferrer">
{t("edit_availability")}
</Button>
</div>
</div>
</div>
);
};
const scheduleId = watch("schedule");
const { isLoading, data: schedule } = trpc.viewer.availability.schedule.get.useQuery({ scheduleId });
const { isLoading, data: schedule } = trpc.viewer.availability.schedule.get.useQuery(
{ scheduleId: scheduleId || loggedInUser?.defaultScheduleId || undefined },
{ enabled: !!scheduleId || !!loggedInUser?.defaultScheduleId }
);
const filterDays = (dayNum: number) =>
schedule?.schedule.availability.filter((item) => item.days.includes((dayNum + 1) % 7)) || [];
if (!isTeamEvent) {
return <EventTypeSchedule />;
}
return (
<div className="space-y-4 rounded border px-6 pb-4">
<ol className="table border-collapse text-sm">
{weekdayNames(i18n.language, 1, "long").map((day, index) => {
const isAvailable = !!filterDays(index).length;
return (
<li key={day} className="my-6 flex border-transparent last:mb-2">
<span
className={classNames(
"w-20 font-medium sm:w-32",
!isAvailable && "text-gray-500 opacity-50"
)}>
{day}
</span>
{isLoading ? (
<SkeletonText className="block h-5 w-60" />
) : isAvailable ? (
<div className="space-y-3 text-right">
{filterDays(index).map((dayRange, i) => (
<div key={i} className="flex items-center leading-4">
<span className="w-16 sm:w-28 sm:text-left">
{format(dayRange.startTime, timeFormat === 12)}
</span>
<span className="ltr:ml-4 rtl:mr-4">-</span>
<div className="ml-6">{format(dayRange.endTime, timeFormat === 12)}</div>
</div>
))}
</div>
) : (
<span className="ml-6 text-gray-500 opacity-50 sm:ml-0">{t("unavailable")}</span>
)}
</li>
);
})}
</ol>
<hr />
<div className="flex flex-col justify-center gap-2 sm:flex-row sm:justify-between">
<span className="flex items-center justify-center text-sm text-gray-600 sm:justify-start">
<FiGlobe className="ltr:mr-2 rtl:ml-2" />
{schedule?.timeZone || <SkeletonText className="block h-5 w-32" />}
</span>
<Button
href={`/availability/${schedule?.schedule.id}`}
disabled={isLoading}
color="minimal"
EndIcon={FiExternalLink}
target="_blank"
rel="noopener noreferrer">
{t("edit_availability")}
</Button>
</div>
</div>
);
};
const EventTypeSchedule = () => {
const { t } = useLocale();
return (
<div className="space-y-4">
<div>
<label htmlFor="availability" className="mb-2 block text-sm font-medium leading-none text-gray-700">
{t("availability")}
</label>
<Controller
name="schedule"
render={({ field }) => (
<AvailabilitySelect
value={field.value}
onBlur={field.onBlur}
name={field.name}
onChange={(selected) => {
field.onChange(selected?.value || null);
}}
/>
)}
/>
</div>
<EventTypeScheduleDetails />
</div>
);
};
const UseCommonScheduleSettingsToggle = () => {
const { t } = useLocale();
const { resetField, setValue } = useFormContext<FormValues>();
return (
<Controller
name="metadata.config.useHostSchedulesForTeamEvent"
@@ -201,6 +208,11 @@ export const AvailabilityTab = ({ isTeamEvent }: { isTeamEvent: boolean }) => {
checked={!value}
onCheckedChange={(checked) => {
onChange(!checked);
if (checked) {
resetField("schedule");
} else {
setValue("schedule", null);
}
}}
title={t("choose_common_schedule_team_event")}
description={t("choose_common_schedule_team_event_description")}>
@@ -210,3 +222,7 @@ export const AvailabilityTab = ({ isTeamEvent }: { isTeamEvent: boolean }) => {
/>
);
};
export const AvailabilityTab = ({ isTeamEvent }: { isTeamEvent: boolean }) => {
return isTeamEvent ? <UseCommonScheduleSettingsToggle /> : <EventTypeSchedule />;
};
@@ -1,8 +1,9 @@
import { useAutoAnimate } from "@formkit/auto-animate/react";
import { EventTypeCustomInputType } from "@prisma/client";
import type { CustomInputParsed } from "pages/event-types/[type]";
import { FC } from "react";
import { Control, Controller, useFieldArray, useForm, UseFormRegister, useWatch } from "react-hook-form";
import type { FC } from "react";
import type { Control, UseFormRegister } from "react-hook-form";
import { Controller, useFieldArray, useForm, useWatch } from "react-hook-form";
import { useLocale } from "@calcom/lib/hooks/useLocale";
import { Button, Label, Select, TextField } from "@calcom/ui";
@@ -5,6 +5,8 @@ import { Controller, useFormContext } from "react-hook-form";
import short from "short-uuid";
import { v5 as uuidv5 } from "uuid";
import type { EventNameObjectType } from "@calcom/core/event";
import { getEventName } from "@calcom/core/event";
import DestinationCalendarSelector from "@calcom/features/calendars/DestinationCalendarSelector";
import CustomInputItem from "@calcom/features/eventtypes/components/CustomInputItem";
import { APP_NAME, CAL_URL, IS_SELF_HOSTED } from "@calcom/lib/constants";
@@ -57,6 +59,14 @@ export const EventAdvancedTab = ({ eventType, team }: Pick<EventTypeSetupProps,
const [hashedLinkVisible, setHashedLinkVisible] = useState(!!eventType.hashedLink);
const [redirectUrlVisible, setRedirectUrlVisible] = useState(!!eventType.successRedirectUrl);
const [hashedUrl, setHashedUrl] = useState(eventType.hashedLink?.link);
const eventNameObject: EventNameObjectType = {
attendeeName: t("scheduler"),
eventType: eventType.title,
eventName: eventType.eventName,
host: eventType.users[0]?.name || "Nameless",
t,
};
const [previewText, setPreviewText] = useState(getEventName(eventNameObject));
const [customInputs, setCustomInputs] = useState<CustomInputParsed[]>(
eventType.customInputs.sort((a, b) => a.id - b.id) || []
);
@@ -64,7 +74,7 @@ export const EventAdvancedTab = ({ eventType, team }: Pick<EventTypeSetupProps,
const [selectedCustomInputModalOpen, setSelectedCustomInputModalOpen] = useState(false);
const [requiresConfirmation, setRequiresConfirmation] = useState(eventType.requiresConfirmation);
const placeholderHashedLink = `${CAL_URL}/d/${hashedUrl}/${eventType.slug}`;
const seatsEnabled = formMethods.getValues("seatsPerTimeSlotEnabled");
const seatsEnabled = formMethods.watch("seatsPerTimeSlotEnabled");
const removeCustom = (index: number) => {
formMethods.getValues("customInputs").splice(index, 1);
@@ -72,6 +82,15 @@ export const EventAdvancedTab = ({ eventType, team }: Pick<EventTypeSetupProps,
setCustomInputs([...customInputs]);
};
const changePreviewText = (eventNameObject: EventNameObjectType, previewEventName: string) => {
setPreviewText(
previewEventName
.replace("{Event type title}", eventNameObject.eventType)
.replace("{Scheduler}", eventNameObject.attendeeName)
.replace("{Organiser}", eventNameObject.host)
);
};
useEffect(() => {
!hashedUrl && setHashedUrl(generateHashedLink(eventType.users[0]?.id ?? team?.id));
}, [eventType.users, hashedUrl, team?.id]);
@@ -120,11 +139,18 @@ export const EventAdvancedTab = ({ eventType, team }: Pick<EventTypeSetupProps,
)}
<div className="w-full">
<TextField
label={t("event_name")}
label={t("event_name_in_calendar")}
type="text"
placeholder={t("meeting_with_user", { attendeeName: eventType.users[0]?.name })}
placeholder={t("meeting_with_user")}
defaultValue={eventType.eventName || ""}
{...formMethods.register("eventName")}
{...formMethods.register("eventName", {
onChange: (e) => {
if (!e.target.value || !formMethods.getValues("eventName")) {
return setPreviewText(getEventName(eventNameObject));
}
changePreviewText(eventNameObject, e.target.value);
},
})}
addOnSuffix={
<Button
type="button"
@@ -382,25 +408,66 @@ export const EventAdvancedTab = ({ eventType, team }: Pick<EventTypeSetupProps,
<DialogContent
title={t("custom_event_name")}
description={t("custom_event_name_description")}
type="creation">
type="creation"
enableOverflow>
<TextField
label={t("event_name")}
label={t("event_name_in_calendar")}
type="text"
placeholder={t("meeting_with_user", { attendeeName: eventType.users[0]?.name })}
placeholder={t("meeting_with_user")}
defaultValue={eventType.eventName || ""}
{...formMethods.register("eventName")}
{...formMethods.register("eventName", {
onChange: (e) => {
if (!e.target.value || !formMethods.getValues("eventName")) {
return setPreviewText(getEventName(eventNameObject));
}
changePreviewText(eventNameObject, e.target.value);
},
})}
className="mb-0"
/>
<div className="mt-1 text-gray-500">
<p>{`{HOST} = ${t("your_name")}`}</p>
<p>{`{ATTENDEE} = ${t("attendee_name")}`}</p>
<p>{`{HOST/ATTENDEE} = ${t("dynamically_display_attendee_or_organizer")}`}</p>
<p>{`{LOCATION} = ${t("event_location")}`}</p>
<div className="text-sm">
<div className="mb-6 rounded-md bg-gray-100 p-2">
<h1 className="mb-2 ml-1 font-medium text-gray-900">{t("available_variables")}</h1>
<div className="mb-2.5 flex font-normal">
<p className="ml-1 mr-5 w-28 text-gray-400">{`{Event type title}`}</p>
<p className="text-gray-900">{t("event_name_info")}</p>
</div>
<div className="mb-2.5 flex font-normal">
<p className="ml-1 mr-5 w-28 text-gray-400">{`{Organiser}`}</p>
<p className="text-gray-900">{t("your_full_name")}</p>
</div>
<div className="mb-2.5 flex font-normal">
<p className="ml-1 mr-5 w-28 text-gray-400">{`{Scheduler}`}</p>
<p className="text-gray-900">{t("scheduler_full_name")}</p>
</div>
<div className="mb-1 flex font-normal">
<p className="ml-1 mr-5 w-28 text-gray-400">{`{Location}`}</p>
<p className="text-gray-900">{t("location_info")}</p>
</div>
</div>
<h1 className="mb-2 text-[14px] font-medium leading-4">{t("preview")}</h1>
<div
className="flex h-[212px] w-full rounded-md border-y bg-cover bg-center"
style={{
backgroundImage: "url(/calendar-preview.svg)",
}}>
<div className="m-auto flex items-center justify-center self-stretch">
<div className="mt-3 ml-11 box-border h-[110px] w-[120px] flex-col items-start gap-1 rounded-md border border-solid border-black bg-gray-100 text-[12px] leading-3">
<p className="overflow-hidden text-ellipsis p-1.5 font-medium text-gray-900">
{previewText}
</p>
<p className="ml-1.5 text-[10px] font-normal text-gray-600">8 - 10 AM</p>
</div>
</div>
</div>
</div>
<DialogFooter>
<DialogClose onClick={() => formMethods.setValue("eventName", eventType.eventName ?? "")}>
{t("cancel")}
</DialogClose>
<Button color="primary" onClick={() => setShowEventNameTip(false)}>
{t("create")}
</Button>
<DialogClose onClick={() => formMethods.setValue("eventName", eventType.eventName ?? "")} />
</DialogFooter>
</DialogContent>
</Dialog>
@@ -1,10 +1,10 @@
import { EventTypeSetupProps, FormValues } from "pages/event-types/[type]";
import type { EventTypeSetupProps, FormValues } from "pages/event-types/[type]";
import { useFormContext } from "react-hook-form";
import { GetAppData, SetAppData } from "@calcom/app-store/EventTypeAppContext";
import type { GetAppData, SetAppData } from "@calcom/app-store/EventTypeAppContext";
import { EventTypeAppCard } from "@calcom/app-store/_components/EventTypeAppCardInterface";
import { EventTypeAppCardComponentProps } from "@calcom/app-store/types";
import { EventTypeAppsList } from "@calcom/app-store/utils";
import type { EventTypeAppCardComponentProps } from "@calcom/app-store/types";
import type { EventTypeAppsList } from "@calcom/app-store/utils";
import { useLocale } from "@calcom/lib/hooks/useLocale";
import { trpc } from "@calcom/trpc/react";
import { Button, EmptyScreen } from "@calcom/ui";
@@ -1,14 +1,16 @@
import { useAutoAnimate } from "@formkit/auto-animate/react";
import * as RadioGroup from "@radix-ui/react-radio-group";
import { EventTypeSetupProps, FormValues } from "pages/event-types/[type]";
import type { EventTypeSetupProps, FormValues } from "pages/event-types/[type]";
import React, { useEffect, useState } from "react";
import { Controller, useFormContext, UseFormRegisterReturn, useWatch } from "react-hook-form";
import type { UseFormRegisterReturn } from "react-hook-form";
import { Controller, useFormContext, useWatch } from "react-hook-form";
import { classNames } from "@calcom/lib";
import convertToNewDurationType, { DurationType } from "@calcom/lib/convertToNewDurationType";
import type { DurationType } from "@calcom/lib/convertToNewDurationType";
import convertToNewDurationType from "@calcom/lib/convertToNewDurationType";
import findDurationType from "@calcom/lib/findDurationType";
import { useLocale } from "@calcom/lib/hooks/useLocale";
import { PeriodType } from "@calcom/prisma/client";
import type { PeriodType } from "@calcom/prisma/client";
import type { BookingLimit } from "@calcom/types/Calendar";
import { Button, DateRangePicker, Input, InputField, Label, Select, SettingsToggle } from "@calcom/ui";
import { FiPlus, FiTrash } from "@calcom/ui/components/icon";
@@ -420,12 +422,14 @@ const BookingLimits = () => {
defaultValue={BOOKING_LIMIT_OPTIONS.find((option) => option.value === key)}
onChange={(val) => {
const current = currentBookingLimits;
const currentValue = watchBookingLimits[bookingLimitKey];
// Removes limit from previous selected value (eg when changed from per_week to per_month, we unset per_week here)
delete current[bookingLimitKey];
const newData = {
...current,
// Set limit to new selected value (in the example above this means we set the limit to per_week here).
[val?.value as BookingLimitsKey]: watchBookingLimits[bookingLimitKey],
[val?.value as BookingLimitsKey]: currentValue,
};
onChange(newData);
}}
@@ -459,7 +463,7 @@ const BookingLimits = () => {
setValue("bookingLimits", {
...watchBookingLimits,
[rest[0].value]: undefined,
[rest[0].value]: 1,
});
}}>
{t("add_limit")}
@@ -1,13 +1,13 @@
import { EventTypeSetupProps } from "pages/event-types/[type]";
import type { EventTypeSetupProps } from "pages/event-types/[type]";
import getStripeAppData from "@calcom/lib/getStripeAppData";
import getPaymentAppData from "@calcom/lib/getPaymentAppData";
import RecurringEventController from "./RecurringEventController";
export const EventRecurringTab = ({ eventType }: Pick<EventTypeSetupProps, "eventType">) => {
const stripeAppData = getStripeAppData(eventType);
const paymentAppData = getPaymentAppData(eventType);
const requirePayment = stripeAppData.price > 0;
const requirePayment = paymentAppData.price > 0;
return (
<div className="">
+40 -22
View File
@@ -6,22 +6,20 @@ import Link from "next/link";
import type { EventTypeSetupProps, FormValues } from "pages/event-types/[type]";
import { useState } from "react";
import { Controller, useForm, useFormContext } from "react-hook-form";
import { MultiValue } from "react-select";
import type { MultiValue } from "react-select";
import { z } from "zod";
import { EventLocationType, getEventLocationType, MeetLocationType } from "@calcom/app-store/locations";
import type { EventLocationType } from "@calcom/app-store/locations";
import { getEventLocationType, MeetLocationType, LocationType } from "@calcom/app-store/locations";
import { CAL_URL } from "@calcom/lib/constants";
import { useLocale } from "@calcom/lib/hooks/useLocale";
import { slugify } from "@calcom/lib/slugify";
import { Button, Label, Select, SettingsToggle, Skeleton, TextField } from "@calcom/ui";
import { FiEdit2, FiCheck, FiX, FiPlus } from "@calcom/ui/components/icon";
import { slugify } from "@lib/slugify";
import { EditLocationDialog } from "@components/dialog/EditLocationDialog";
import LocationSelect, {
SingleValueLocationOption,
LocationOption,
} from "@components/ui/form/LocationSelect";
import type { SingleValueLocationOption, LocationOption } from "@components/ui/form/LocationSelect";
import LocationSelect from "@components/ui/form/LocationSelect";
const getLocationFromType = (
type: EventLocationType["type"],
@@ -35,6 +33,16 @@ const getLocationFromType = (
}
};
const getDefaultLocationValue = (options: EventTypeSetupProps["locationOptions"], type: string) => {
for (const locationType of options) {
for (const location of locationType.options) {
if (location.value === type && location.disabled === false) {
return location;
}
}
}
};
export const EventSetupTab = (
props: Pick<EventTypeSetupProps, "eventType" | "locationOptions" | "team" | "teamMembers">
) => {
@@ -67,10 +75,15 @@ export const EventSetupTab = (
setShowLocationModal(true);
};
const removeLocation = (selectedLocation: typeof eventType.locations[number]) => {
const removeLocation = (selectedLocation: (typeof eventType.locations)[number]) => {
formMethods.setValue(
"locations",
formMethods.getValues("locations").filter((location) => location.type !== selectedLocation.type),
formMethods.getValues("locations").filter((location) => {
if (location.type === LocationType.InPerson) {
return location.address !== selectedLocation.address;
}
return location.type !== selectedLocation.type;
}),
{ shouldValidate: true }
);
};
@@ -85,14 +98,14 @@ export const EventSetupTab = (
...details,
type: newLocationType,
};
} else {
copy[existingIdx] = {
...formMethods.getValues("locations")[existingIdx],
...details,
};
}
formMethods.setValue("locations", copy);
formMethods.setValue("locations", [
...copy,
...(newLocationType === LocationType.InPerson && editingLocationType === ""
? [{ ...details, type: newLocationType }]
: []),
]);
} else {
formMethods.setValue(
"locations",
@@ -139,17 +152,16 @@ export const EventSetupTab = (
return true;
});
const defaultValue = locationOptions.find((item) => item.label === "video")?.options;
return (
<div className="w-full">
{validLocations.length === 0 && (
<div className="flex">
<LocationSelect
defaultValue={defaultValue}
placeholder={t("select")}
options={locationOptions}
isSearchable={false}
className="block w-full min-w-0 flex-1 rounded-sm text-sm"
menuPlacement="auto"
onChange={(e: SingleValueLocationOption) => {
if (e?.value) {
const newLocationType = e.value;
@@ -175,8 +187,16 @@ export const EventSetupTab = (
if (!eventLocationType) {
return null;
}
// We dont want to translate the string link - it doesnt exist in common.json and it gets prefixed/suffixed with __ or //
const eventLabel =
eventLocationType.defaultValueVariable === "link"
? eventLocationType.label
: t(location[eventLocationType.defaultValueVariable] || eventLocationType.label);
return (
<li key={location.type} className="mb-2 rounded-md border border-gray-300 py-1.5 px-2">
<li
key={`${location.type}${index}`}
className="mb-2 rounded-md border border-gray-300 py-1.5 px-2">
<div className="flex max-w-full justify-between">
<div key={index} className="flex flex-grow items-center">
<img
@@ -184,9 +204,7 @@ export const EventSetupTab = (
className="h-4 w-4"
alt={`${eventLocationType.label} logo`}
/>
<span className="truncate text-sm ltr:ml-1 rtl:mr-1">
{t(location[eventLocationType.defaultValueVariable] || eventLocationType.label)}
</span>
<span className="truncate text-sm ltr:ml-1 rtl:mr-1">{eventLabel}</span>
</div>
<div className="flex">
<button
+20 -12
View File
@@ -1,12 +1,12 @@
import { SchedulingType } from "@prisma/client";
import { EventTypeSetupProps, FormValues } from "pages/event-types/[type]";
import { ComponentProps } from "react";
import { Controller, useFormContext, useWatch, Control } from "react-hook-form";
import { Options } from "react-select";
import type { EventTypeSetupProps, FormValues } from "pages/event-types/[type]";
import type { ComponentProps } from "react";
import type { Control } from "react-hook-form";
import { Controller, useFormContext, useWatch } from "react-hook-form";
import type { Options } from "react-select";
import CheckedTeamSelect, {
CheckedSelectOption,
} from "@calcom/features/eventtypes/components/CheckedTeamSelect";
import type { CheckedSelectOption } from "@calcom/features/eventtypes/components/CheckedTeamSelect";
import CheckedTeamSelect from "@calcom/features/eventtypes/components/CheckedTeamSelect";
import { WEBAPP_URL } from "@calcom/lib/constants";
import { useLocale } from "@calcom/lib/hooks/useLocale";
import { Label, Select } from "@calcom/ui";
@@ -25,6 +25,16 @@ const mapUserToValue = ({ id, name, username, email }: IMemberToValue) => ({
email,
});
const sortByLabel = (a: ReturnType<typeof mapUserToValue>, b: ReturnType<typeof mapUserToValue>) => {
if (a.label < b.label) {
return -1;
}
if (a.label > b.label) {
return 1;
}
return 0;
};
const FixedHosts = ({
control,
labelText,
@@ -103,7 +113,6 @@ export const EventTeamTab = ({ team, teamMembers }: Pick<EventTypeSetupProps, "t
];
const teamMembersOptions = teamMembers.map(mapUserToValue);
return (
<div>
{team && (
@@ -128,17 +137,16 @@ export const EventTeamTab = ({ team, teamMembers }: Pick<EventTypeSetupProps, "t
{schedulingType === SchedulingType.COLLECTIVE && (
<FixedHosts
options={teamMembersOptions}
options={teamMembersOptions.sort(sortByLabel)}
placeholder={t("add_attendees")}
labelText={t("team")}
control={formMethods.control}
/>
)}
{schedulingType === SchedulingType.ROUND_ROBIN && (
<>
<FixedHosts
options={teamMembersOptions}
options={teamMembersOptions.sort(sortByLabel)}
isOptionDisabled={(option) =>
!!formMethods.getValues("hosts").find((host) => host.userId.toString() === option.value)
}
@@ -173,7 +181,7 @@ export const EventTeamTab = ({ team, teamMembers }: Pick<EventTypeSetupProps, "t
)
.filter(Boolean)}
controlShouldRenderValue={false}
options={teamMembers.map(mapUserToValue)}
options={teamMembersOptions.sort(sortByLabel)}
isOptionDisabled={(option) =>
!!formMethods
.getValues("hostsFixed")
@@ -1,13 +1,13 @@
import { EventTypeSetupProps, FormValues } from "pages/event-types/[type]";
import type { EventTypeSetupProps } from "pages/event-types/[type]";
import { useState } from "react";
import { TbWebhook } from "react-icons/tb";
import { WebhookForm } from "@calcom/features/webhooks/components";
import { WebhookFormSubmitData } from "@calcom/features/webhooks/components/WebhookForm";
import type { WebhookFormSubmitData } from "@calcom/features/webhooks/components/WebhookForm";
import WebhookListItem from "@calcom/features/webhooks/components/WebhookListItem";
import { APP_NAME } from "@calcom/lib/constants";
import { useLocale } from "@calcom/lib/hooks/useLocale";
import { Webhook } from "@calcom/prisma/client";
import type { Webhook } from "@calcom/prisma/client";
import { trpc } from "@calcom/trpc/react";
import { Button, Dialog, DialogContent, EmptyScreen, showToast } from "@calcom/ui";
import { FiPlus } from "@calcom/ui/components/icon";
@@ -100,7 +100,7 @@ export const EventTeamWebhooksTab = ({
<>
{webhooks.length ? (
<>
<div className="mt-4 mb-8 rounded-md border">
<div className="mb-8 rounded-md border">
{webhooks.map((webhook, index) => {
return (
<WebhookListItem
@@ -1,8 +1,8 @@
import { TFunction } from "next-i18next";
import type { TFunction } from "next-i18next";
import { useRouter } from "next/router";
import { EventTypeSetupProps, FormValues } from "pages/event-types/[type]";
import type { EventTypeSetupProps, FormValues } from "pages/event-types/[type]";
import { useMemo, useState, Suspense } from "react";
import { UseFormReturn } from "react-hook-form";
import type { UseFormReturn } from "react-hook-form";
import { TbWebhook } from "react-icons/tb";
import Shell from "@calcom/features/shell/Shell";
@@ -195,7 +195,6 @@ function EventTypeSingleLayout({
backPath="/event-types"
title={eventType.title + " | " + t("event_type")}
heading={eventType.title}
subtitle={eventType.description || ""}
CTA={
<div className="flex items-center justify-end">
<div className="hidden items-center rounded-md px-2 sm:flex sm:hover:bg-gray-100">
@@ -287,6 +286,7 @@ function EventTypeSingleLayout({
<DropdownMenuItem className="focus:ring-gray-100">
<DropdownItem
type="button"
color="destructive"
StartIcon={FiTrash}
disabled={!hasPermsToDelete}
onClick={() => setDeleteDialogOpen(true)}>
@@ -323,7 +323,7 @@ function EventTypeSingleLayout({
</div>
}>
<Suspense fallback={<FiLoader />}>
<div className="-mt-2 flex flex-col xl:flex-row xl:space-x-8">
<div className="flex flex-col xl:flex-row xl:space-x-6">
<div className="hidden xl:block">
<VerticalTabs
className="primary-navigation"
@@ -339,7 +339,7 @@ function EventTypeSingleLayout({
<div
className={classNames(
"mt-4 rounded-md border-gray-200 bg-white sm:mx-0 xl:mt-0",
disableBorder ? "border-0 xl:-mt-4 " : "p-2 md:border md:p-6"
disableBorder ? "border-0 " : "p-2 md:border md:p-6"
)}>
{children}
</div>
@@ -1,13 +1,14 @@
import * as RadioGroup from "@radix-ui/react-radio-group";
import { UnitTypeLongPlural } from "dayjs";
import type { UnitTypeLongPlural } from "dayjs";
import { Trans } from "next-i18next";
import type { FormValues } from "pages/event-types/[type]";
import { Dispatch, SetStateAction, useEffect, useState } from "react";
import type { Dispatch, SetStateAction } from "react";
import { useEffect, useState } from "react";
import { Controller, useFormContext } from "react-hook-form";
import z from "zod";
import type z from "zod";
import { useLocale } from "@calcom/lib/hooks/useLocale";
import { EventTypeMetaDataSchema } from "@calcom/prisma/zod-utils";
import type { EventTypeMetaDataSchema } from "@calcom/prisma/zod-utils";
import { Alert, Input, Label, SettingsToggle } from "@calcom/ui";
type RequiresConfirmationControllerProps = {
@@ -1,5 +1,3 @@
import { useLocale } from "@calcom/lib/hooks/useLocale";
import { CalendarSwitch } from "./CalendarSwitch";
interface IConnectedCalendarItem {
@@ -21,7 +19,7 @@ interface IConnectedCalendarItem {
const ConnectedCalendarItem = (prop: IConnectedCalendarItem) => {
const { name, logo, externalId, calendars, integrationType } = prop;
const { t } = useLocale();
return (
<>
<div className="flex flex-row items-center p-4">
@@ -1,5 +1,6 @@
import { useLocale } from "@calcom/lib/hooks/useLocale";
import { RouterInputs, trpc } from "@calcom/trpc/react";
import type { RouterInputs } from "@calcom/trpc/react";
import { trpc } from "@calcom/trpc/react";
import DestinationCalendarSelector from "@components/DestinationCalendarSelector";
@@ -5,8 +5,9 @@ import { useForm } from "react-hook-form";
import { Schedule } from "@calcom/features/schedules";
import { DEFAULT_SCHEDULE } from "@calcom/lib/availability";
import { useLocale } from "@calcom/lib/hooks/useLocale";
import { trpc, TRPCClientErrorLike } from "@calcom/trpc/react";
import { AppRouter } from "@calcom/trpc/server/routers/_app";
import type { TRPCClientErrorLike } from "@calcom/trpc/react";
import { trpc } from "@calcom/trpc/react";
import type { AppRouter } from "@calcom/trpc/server/routers/_app";
import { Button, Form } from "@calcom/ui";
interface ISetupAvailabilityProps {
@@ -1,15 +1,21 @@
import { ArrowRightIcon } from "@heroicons/react/solid";
import MarkdownIt from "markdown-it";
import { useRouter } from "next/router";
import { FormEvent, useRef, useState } from "react";
import type { FormEvent } from "react";
import { useRef, useState } from "react";
import { useForm } from "react-hook-form";
import { useLocale } from "@calcom/lib/hooks/useLocale";
import { telemetryEventTypes, useTelemetry } from "@calcom/lib/telemetry";
import turndown from "@calcom/lib/turndownService";
import { trpc } from "@calcom/trpc/react";
import { Button, ImageUploader, showToast, TextArea } from "@calcom/ui";
import { Button, Editor, ImageUploader, Label, showToast } from "@calcom/ui";
import { Avatar } from "@calcom/ui";
import type { IOnboardingPageProps } from "../../../pages/getting-started/[[...step]]";
const md = new MarkdownIt("default", { html: true, breaks: true });
type FormData = {
bio: string;
};
@@ -21,18 +27,16 @@ const UserProfile = (props: IUserProfileProps) => {
const { user } = props;
const { t } = useLocale();
const avatarRef = useRef<HTMLInputElement>(null!);
const bioRef = useRef<HTMLTextAreaElement>(null);
const {
register,
setValue,
handleSubmit,
formState: { errors },
} = useForm<FormData>({ defaultValues: { bio: user?.bio || "" } });
const { setValue, handleSubmit, getValues } = useForm<FormData>({
defaultValues: { bio: user?.bio || "" },
});
const { data: eventTypes } = trpc.viewer.eventTypes.list.useQuery();
const [imageSrc, setImageSrc] = useState<string>(user?.avatar || "");
const utils = trpc.useContext();
const router = useRouter();
const createEventType = trpc.viewer.eventTypes.create.useMutation();
const telemetry = useTelemetry();
const mutation = trpc.viewer.updateProfile.useMutation({
onSuccess: async (_data, context) => {
@@ -63,6 +67,8 @@ const UserProfile = (props: IUserProfileProps) => {
const onSubmit = handleSubmit((data: { bio: string }) => {
const { bio } = data;
telemetry.event(telemetryEventTypes.onboardingFinished);
mutation.mutate({
bio,
completedOnboarding: true,
@@ -138,25 +144,12 @@ const UserProfile = (props: IUserProfileProps) => {
</div>
</div>
<fieldset className="mt-8">
<label htmlFor="bio" className="mb-2 block text-sm font-medium text-gray-700">
{t("about")}
</label>
<TextArea
{...register("bio", { required: true })}
ref={bioRef}
name="bio"
id="bio"
className="mt-1 block h-[60px] w-full rounded-sm border border-gray-300 px-3 py-2 focus:border-gray-500 focus:outline-none focus:ring-gray-500 sm:text-sm"
defaultValue={user?.bio || undefined}
onChange={(event) => {
setValue("bio", event.target.value);
}}
<Label className="mb-2 block text-sm font-medium text-gray-700">{t("about")}</Label>
<Editor
getText={() => md.render(getValues("bio") || user?.bio || "")}
setText={(value: string) => setValue("bio", turndown(value))}
excludedToolbarItems={["blockType"]}
/>
{errors.bio && (
<p data-testid="required" className="py-2 text-xs text-red-500">
{t("required")}
</p>
)}
<p className="mt-2 font-sans text-sm font-normal text-gray-600 dark:text-white">
{t("few_sentences_about_yourself")}
</p>
@@ -1,9 +1,10 @@
import { ArrowRightIcon } from "@heroicons/react/outline";
import { useState } from "react";
import { useEffect, useState } from "react";
import { useForm } from "react-hook-form";
import dayjs from "@calcom/dayjs";
import { useLocale } from "@calcom/lib/hooks/useLocale";
import { telemetryEventTypes, useTelemetry } from "@calcom/lib/telemetry";
import { trpc } from "@calcom/trpc/react";
import { Button, TimezoneSelect } from "@calcom/ui";
@@ -20,7 +21,7 @@ const UserSettings = (props: IUserSettingsProps) => {
const { user, nextStep } = props;
const { t } = useLocale();
const [selectedTimeZone, setSelectedTimeZone] = useState(dayjs.tz.guess());
const telemetry = useTelemetry();
const {
register,
handleSubmit,
@@ -31,6 +32,11 @@ const UserSettings = (props: IUserSettingsProps) => {
},
reValidateMode: "onChange",
});
useEffect(() => {
telemetry.event(telemetryEventTypes.onboardingStarted);
}, [telemetry]);
const defaultOptions = { required: true, maxLength: 255 };
const utils = trpc.useContext();
@@ -1,4 +1,4 @@
import { ReactNode } from "react";
import type { ReactNode } from "react";
import { Badge } from "@calcom/ui";
@@ -1,4 +1,5 @@
import { SyntheticEvent, useState } from "react";
import type { SyntheticEvent } from "react";
import { useState } from "react";
import { ErrorCode } from "@calcom/lib/auth";
import { useLocale } from "@calcom/lib/hooks/useLocale";
@@ -1,4 +1,5 @@
import React, { BaseSyntheticEvent, useState } from "react";
import type { BaseSyntheticEvent } from "react";
import React, { useState } from "react";
import { useForm } from "react-hook-form";
import { ErrorCode } from "@calcom/lib/auth";
@@ -1,9 +1,8 @@
import { useState } from "react";
import { useLocale } from "@calcom/lib/hooks/useLocale";
import { Badge, Button } from "@calcom/ui";
import { useLocale } from "@lib/hooks/useLocale";
import DisableTwoFactorModal from "./DisableTwoFactorModal";
import EnableTwoFactorModal from "./EnableTwoFactorModal";
@@ -1,4 +1,5 @@
import React, { BaseSyntheticEvent, useState } from "react";
import type { BaseSyntheticEvent } from "react";
import React, { useState } from "react";
import { useForm } from "react-hook-form";
import { ErrorCode } from "@calcom/lib/auth";
@@ -1,17 +1,39 @@
import { zodResolver } from "@hookform/resolvers/zod";
import classNames from "classnames";
import { signIn } from "next-auth/react";
import { useRouter } from "next/router";
import React from "react";
import { Controller, FormProvider, useForm } from "react-hook-form";
import * as z from "zod";
import { isPasswordValid } from "@calcom/lib/auth";
import { WEBSITE_URL } from "@calcom/lib/constants";
import { useLocale } from "@calcom/lib/hooks/useLocale";
import { EmailField, Label, PasswordField, TextField } from "@calcom/ui";
import { EmailField, EmptyScreen, Label, PasswordField, TextField } from "@calcom/ui";
import { FiUserCheck } from "@calcom/ui/components/icon";
const SetupFormStep1 = (props: { setIsLoading: (val: boolean) => void }) => {
const router = useRouter();
export const AdminUserContainer = (props: React.ComponentProps<typeof AdminUser> & { userCount: number }) => {
const { t } = useLocale();
if (props.userCount > 0)
return (
<form
id="wizard-step-1"
name="wizard-step-1"
className="space-y-4"
onSubmit={(e) => {
e.preventDefault();
props.onSuccess();
}}>
<EmptyScreen
Icon={FiUserCheck}
headline={t("admin_user_created")}
description={t("admin_user_created_description")}
/>
</form>
);
return <AdminUser {...props} />;
};
export const AdminUser = (props: { onSubmit: () => void; onError: () => void; onSuccess: () => void }) => {
const { t } = useLocale();
const formSchema = z.object({
@@ -45,11 +67,11 @@ const SetupFormStep1 = (props: { setIsLoading: (val: boolean) => void }) => {
});
const onError = () => {
props.setIsLoading(false);
props.onError();
};
const onSubmit = formMethods.handleSubmit(async (data: z.infer<typeof formSchema>) => {
props.setIsLoading(true);
props.onSubmit();
const response = await fetch("/api/auth/setup", {
method: "POST",
body: JSON.stringify({
@@ -69,9 +91,9 @@ const SetupFormStep1 = (props: { setIsLoading: (val: boolean) => void }) => {
email: data.email_address.toLowerCase(),
password: data.password,
});
router.replace(`/auth/setup?step=2&category=calendar`);
props.onSuccess();
} else {
router.replace("/auth/setup");
props.onError();
}
}, onError);
@@ -186,5 +208,3 @@ const SetupFormStep1 = (props: { setIsLoading: (val: boolean) => void }) => {
</FormProvider>
);
};
export default SetupFormStep1;
@@ -0,0 +1,76 @@
import * as RadioGroup from "@radix-ui/react-radio-group";
import classNames from "classnames";
import { useState } from "react";
import { useLocale } from "@calcom/lib/hooks/useLocale";
const ENTERPRISE_BOOKING_FEE = "$99"; // TODO: get this from a new API endpoint
const ChooseLicense = (
props: {
value: string;
onChange: (value: string) => void;
onSubmit: (value: string) => void;
} & Omit<JSX.IntrinsicElements["form"], "onSubmit" | "onChange">
) => {
const { value: initialValue = "FREE", onChange, onSubmit, ...rest } = props;
const [value, setValue] = useState(initialValue);
const { t } = useLocale();
return (
<form
{...rest}
className="space-y-4"
onSubmit={(e) => {
e.preventDefault();
onSubmit(value);
}}>
<RadioGroup.Root
defaultValue={initialValue}
value={value}
aria-label={t("choose_a_license")}
className="grid grid-rows-2 gap-4 md:grid-cols-2 md:grid-rows-1"
onValueChange={(value) => {
onChange(value);
setValue(value);
}}>
<RadioGroup.Item value="FREE">
<div
className={classNames(
"cursor-pointer space-y-2 rounded-md border bg-white p-4 hover:border-black",
value === "FREE" && "ring-2 ring-black"
)}>
<h2 className="font-cal text-xl text-black">{t("agplv3_license")}</h2>
<p className="font-medium text-green-800">{t("free_license_fee")}</p>
<p className="text-gray-500">{t("forever_open_and_free")}</p>
<ul className="ml-4 list-disc text-left text-xs text-gray-500">
<li>{t("required_to_keep_your_code_open_source")}</li>
<li>{t("cannot_repackage_and_resell")}</li>
<li>{t("no_enterprise_features")}</li>
</ul>
</div>
</RadioGroup.Item>
<RadioGroup.Item value="EE">
<div
className={classNames(
"cursor-pointer space-y-2 rounded-md border bg-white p-4 hover:border-black",
value === "EE" && "ring-2 ring-black"
)}>
<h2 className="font-cal text-xl text-black">{t("ee_enterprise_license")}</h2>
<p className="font-medium text-green-800">
{t("enterprise_booking_fee", { enterprise_booking_fee: ENTERPRISE_BOOKING_FEE })}
</p>
<p className="text-gray-500">{t("enterprise_license_includes")}</p>
<ul className="ml-4 list-disc text-left text-xs text-gray-500">
<li>{t("no_need_to_keep_your_code_open_source")}</li>
<li>{t("repackage_rebrand_resell")}</li>
<li>{t("a_vast_suite_of_enterprise_features")}</li>
</ul>
</div>
</RadioGroup.Item>
</RadioGroup.Root>
</form>
);
};
export default ChooseLicense;
@@ -0,0 +1,145 @@
import { zodResolver } from "@hookform/resolvers/zod";
import { noop } from "lodash";
import { useCallback, useState } from "react";
import { Controller, FormProvider, useForm, useFormState } from "react-hook-form";
import * as z from "zod";
import { classNames } from "@calcom/lib";
import { CONSOLE_URL } from "@calcom/lib/constants";
import { useLocale } from "@calcom/lib/hooks/useLocale";
import type { RouterInputs, RouterOutputs } from "@calcom/trpc/react";
import { trpc } from "@calcom/trpc/react";
import { Button, TextField } from "@calcom/ui";
import { FiCheck, FiExternalLink, FiLoader } from "@calcom/ui/components/icon";
type EnterpriseLicenseFormValues = {
licenseKey: string;
};
const makeSchemaLicenseKey = (args: { callback: (valid: boolean) => void; onSuccessValidate: () => void }) =>
z.object({
licenseKey: z
.string()
.uuid({
message: "License key must follow UUID format: 8-4-4-4-12",
})
.superRefine(async (data, ctx) => {
const parse = z.string().uuid().safeParse(data);
if (parse.success) {
args.callback(true);
const response = await fetch(`${CONSOLE_URL}/api/license?key=${data}`);
args.callback(false);
const json = await response.json();
if (!json.valid) {
ctx.addIssue({
code: z.ZodIssueCode.custom,
message: `License key ${json.message.toLowerCase()}`,
});
} else {
args.onSuccessValidate();
}
}
}),
});
const EnterpriseLicense = (
props: {
licenseKey?: string;
initialValue?: Partial<EnterpriseLicenseFormValues>;
onSuccessValidate: () => void;
onSubmit: (value: EnterpriseLicenseFormValues) => void;
onSuccess?: (
data: RouterOutputs["viewer"]["deploymentSetup"]["update"],
variables: RouterInputs["viewer"]["deploymentSetup"]["update"]
) => void;
} & Omit<JSX.IntrinsicElements["form"], "onSubmit">
) => {
const { onSubmit, onSuccess = noop, onSuccessValidate = noop, ...rest } = props;
const { t } = useLocale();
const [checkLicenseLoading, setCheckLicenseLoading] = useState(false);
const mutation = trpc.viewer.deploymentSetup.update.useMutation({
onSuccess,
});
const schemaLicenseKey = useCallback(
() =>
makeSchemaLicenseKey({
callback: setCheckLicenseLoading,
onSuccessValidate,
}),
[setCheckLicenseLoading, onSuccessValidate]
);
const formMethods = useForm<EnterpriseLicenseFormValues>({
defaultValues: {
licenseKey: props.licenseKey || "",
},
resolver: zodResolver(schemaLicenseKey()),
});
const handleSubmit = formMethods.handleSubmit((values) => {
onSubmit(values);
setCheckLicenseLoading(false);
mutation.mutate(values);
});
const { isDirty, errors } = useFormState(formMethods);
return (
<FormProvider {...formMethods}>
<form {...rest} className="space-y-4 rounded-md bg-white px-8 py-10" onSubmit={handleSubmit}>
<div>
<Button
className="w-full justify-center text-lg"
EndIcon={FiExternalLink}
href="https://console.cal.com"
target="_blank">
{t("purchase_license")}
</Button>
<div className="relative flex justify-center">
<hr className="my-8 w-full border-[1.5px] border-gray-200" />
<span className="absolute mt-[22px] bg-white px-3.5 text-sm">OR</span>
</div>
{t("already_have_key")}
<Controller
name="licenseKey"
control={formMethods.control}
render={({ field: { onBlur, onChange, value } }) => (
<TextField
{...formMethods.register("licenseKey")}
className={classNames(
"mb-0 group-hover:border-gray-400",
(checkLicenseLoading || (errors.licenseKey === undefined && isDirty)) && "border-r-0"
)}
placeholder="xxxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxxx"
labelSrOnly={true}
value={value}
addOnFilled={false}
addOnClassname={classNames(
"hover:border-gray-300",
errors.licenseKey === undefined && isDirty && "group-hover:border-gray-400"
)}
addOnSuffix={
checkLicenseLoading ? (
<FiLoader className="h-5 w-5 animate-spin" />
) : errors.licenseKey === undefined && isDirty ? (
<FiCheck className="h-5 w-5 text-green-700" />
) : undefined
}
color={errors.licenseKey ? "warn" : ""}
onBlur={onBlur}
onChange={async (e: React.ChangeEvent<HTMLInputElement>) => {
onChange(e.target.value);
formMethods.setValue("licenseKey", e.target.value);
await formMethods.trigger("licenseKey");
}}
/>
)}
/>
</div>
</form>
</FormProvider>
);
};
export default EnterpriseLicense;
@@ -1,20 +1,26 @@
import { useRouter } from "next/router";
import type { Dispatch, SetStateAction } from "react";
import { useLocale } from "@calcom/lib/hooks/useLocale";
import { FiCheck } from "@calcom/ui/components/icon";
const StepDone = () => {
const StepDone = (props: {
currentStep: number;
nextStepPath: string;
setIsLoading: Dispatch<SetStateAction<boolean>>;
}) => {
const router = useRouter();
const { t } = useLocale();
return (
<form
id="wizard-step-1"
name="wizard-step-1"
className="space-y-4"
id={`wizard-step-${props.currentStep}`}
name={`wizard-step-${props.currentStep}`}
className="flex justify-center space-y-4"
onSubmit={(e) => {
props.setIsLoading(true);
e.preventDefault();
router.replace(`/auth/setup?step=2&category=calendar`);
router.replace(props.nextStepPath);
}}>
<div className="min-h-36 my-6 flex flex-col items-center justify-center">
<div className="flex h-[72px] w-[72px] items-center justify-center rounded-full bg-gray-600 dark:bg-white">
+20 -7
View File
@@ -1,10 +1,12 @@
import MarkdownIt from "markdown-it";
import Link from "next/link";
import { TeamPageProps } from "pages/team/[slug]";
import type { TeamPageProps } from "pages/team/[slug]";
import { WEBAPP_URL } from "@calcom/lib/constants";
import { useLocale } from "@calcom/lib/hooks/useLocale";
import { Avatar } from "@calcom/ui";
import { useLocale } from "@lib/hooks/useLocale";
const md = new MarkdownIt("default", { html: true, breaks: true, linkify: true });
type TeamType = TeamPageProps["team"];
type MembersType = TeamType["members"];
@@ -13,9 +15,11 @@ type MemberType = MembersType[number];
const Member = ({ member, teamName }: { member: MemberType; teamName: string | null }) => {
const { t } = useLocale();
const isBioEmpty = !member.bio || !member.bio.replace("<p><br></p>", "").length;
return (
<Link key={member.id} href={`/${member.username}`}>
<div className="sm:min-w-80 sm:max-w-80 dark:bg-darkgray-200 dark:hover:bg-darkgray-300 group flex min-h-full w-[90%] flex-col space-y-2 rounded-md bg-white p-4 hover:cursor-pointer hover:bg-gray-50 ">
<div className="sm:min-w-80 sm:max-w-80 dark:bg-darkgray-200 dark:hover:bg-darkgray-300 group flex min-h-full flex-col space-y-2 rounded-md bg-white p-4 hover:cursor-pointer hover:bg-gray-50 ">
<Avatar
size="md"
alt={member.name || ""}
@@ -23,9 +27,18 @@ const Member = ({ member, teamName }: { member: MemberType; teamName: string | n
/>
<section className="line-clamp-4 mt-2 w-full space-y-1">
<p className="font-medium text-gray-900 dark:text-white">{member.name}</p>
<p className="line-clamp-3 overflow-ellipsis text-sm font-normal text-gray-500 dark:text-white">
{member.bio || t("user_from_team", { user: member.name, team: teamName })}
</p>
<div className="line-clamp-3 overflow-ellipsis text-sm font-normal text-gray-500 dark:text-white">
{!isBioEmpty ? (
<>
<div
className="dark:text-darkgray-600 text-sm text-gray-500 [&_a]:text-blue-500 [&_a]:underline [&_a]:hover:text-blue-600"
dangerouslySetInnerHTML={{ __html: md.render(member.bio || "") }}
/>
</>
) : (
t("user_from_team", { user: member.name, team: teamName })
)}
</div>
</section>
</div>
</Link>
@@ -46,7 +59,7 @@ const Members = ({ members, teamName }: { members: MembersType; teamName: string
);
};
const Team = ({ team }: TeamPageProps) => {
const Team = ({ team }: Omit<TeamPageProps, "trpcState">) => {
return (
<div>
<Members members={team.members} teamName={team.name} />
+2 -1
View File
@@ -1,5 +1,6 @@
import { useSession } from "next-auth/react";
import { FC, Fragment } from "react";
import type { FC } from "react";
import { Fragment } from "react";
type AdminRequiredProps = {
as?: keyof JSX.IntrinsicElements;
+2 -5
View File
@@ -1,7 +1,7 @@
import classNames from "classnames";
import { APP_NAME, LOGO } from "@calcom/lib/constants";
import { Credits, HeadSeo } from "@calcom/ui";
import { HeadSeo } from "@calcom/ui";
import Loader from "@components/Loader";
@@ -35,10 +35,7 @@ export default function AuthContainer(props: React.PropsWithChildren<Props>) {
<div className="mx-2 rounded-md border border-gray-200 bg-white px-4 py-10 sm:px-10">
{props.children}
</div>
<div className="mt-8 text-center text-sm text-gray-600">
{props.footerText}
<Credits />
</div>
<div className="mt-8 text-center text-sm text-gray-600">{props.footerText}</div>
</div>
</div>
);
+2 -2
View File
@@ -1,6 +1,6 @@
import classNames from "classnames";
import { useState } from "react";
import { ControllerRenderProps } from "react-hook-form";
import type { ControllerRenderProps } from "react-hook-form";
import { FiEdit2 } from "@calcom/ui/components/icon";
@@ -21,7 +21,7 @@ const EditableHeading = function EditableHeading({
<label className="min-w-8 relative inline-block">
<span className="whitespace-pre text-xl tracking-normal text-transparent">{value}&nbsp;</span>
{!isEditing && isReady && (
<FiEdit2 className="ml-1 inline h-4 w-4 align-top text-gray-700 group-hover:text-gray-500" />
<FiEdit2 className=" ml-1 -mt-px inline h-3 w-3 text-gray-500 group-hover:text-gray-500" />
)}
<input
{...passThroughProps}
+1 -1
View File
@@ -1,6 +1,6 @@
import React from "react";
import { SVGComponent } from "@lib/types/SVGComponent";
import type { SVGComponent } from "@lib/types/SVGComponent";
interface LinkIconButtonProps extends React.ButtonHTMLAttributes<HTMLButtonElement> {
Icon: SVGComponent;
+2 -1
View File
@@ -1,5 +1,6 @@
import classNames from "classnames";
import React, { PropsWithChildren } from "react";
import type { PropsWithChildren } from "react";
import React from "react";
import { Dialog, DialogContent } from "@calcom/ui";
@@ -1,15 +1,17 @@
import classNames from "classnames";
import { debounce, noop } from "lodash";
import { useRouter } from "next/router";
import { RefCallback, useEffect, useMemo, useState } from "react";
import type { RefCallback } from "react";
import { useEffect, useMemo, useState } from "react";
import { getPremiumPlanPriceValue } from "@calcom/app-store/stripepayment/lib/utils";
import { fetchUsername } from "@calcom/lib/fetchUsername";
import hasKeyInMetadata from "@calcom/lib/hasKeyInMetadata";
import { useLocale } from "@calcom/lib/hooks/useLocale";
import { User } from "@calcom/prisma/client";
import { TRPCClientErrorLike } from "@calcom/trpc/client";
import { RouterOutputs, trpc } from "@calcom/trpc/react";
import type { User } from "@calcom/prisma/client";
import type { TRPCClientErrorLike } from "@calcom/trpc/client";
import type { RouterOutputs } from "@calcom/trpc/react";
import { trpc } from "@calcom/trpc/react";
import type { AppRouter } from "@calcom/trpc/server/routers/_app";
import { Button, Dialog, DialogClose, DialogContent, DialogHeader, Input, Label } from "@calcom/ui";
import { FiCheck, FiEdit2, FiExternalLink, StarIconSolid } from "@calcom/ui/components/icon";
@@ -1,12 +1,13 @@
import classNames from "classnames";
import { debounce, noop } from "lodash";
import { RefCallback, useEffect, useMemo, useState } from "react";
import type { RefCallback } from "react";
import { useEffect, useMemo, useState } from "react";
import { fetchUsername } from "@calcom/lib/fetchUsername";
import { useLocale } from "@calcom/lib/hooks/useLocale";
import { TRPCClientErrorLike } from "@calcom/trpc/client";
import type { TRPCClientErrorLike } from "@calcom/trpc/client";
import { trpc } from "@calcom/trpc/react";
import { AppRouter } from "@calcom/trpc/server/routers/_app";
import type { AppRouter } from "@calcom/trpc/server/routers/_app";
import { Button, Dialog, DialogClose, DialogContent, DialogHeader, TextField } from "@calcom/ui";
import { FiCheck, FiEdit2 } from "@calcom/ui/components/icon";
@@ -1,10 +1,13 @@
import { useRouter } from "next/router";
import { useState } from "react";
import { Controller, useForm } from "react-hook-form";
import { IS_SELF_HOSTED } from "@calcom/lib/constants";
import { User } from "@calcom/prisma/client";
import { TRPCClientErrorLike } from "@calcom/trpc/client";
import { AppRouter } from "@calcom/trpc/server/routers/_app";
import type { User } from "@calcom/prisma/client";
import type { TRPCClientErrorLike } from "@calcom/trpc/client";
import type { AppRouter } from "@calcom/trpc/server/routers/_app";
import useRouterQuery from "@lib/hooks/useRouterQuery";
import { PremiumTextfield } from "./PremiumTextfield";
import { UsernameTextfield } from "./UsernameTextfield";
@@ -21,7 +24,13 @@ export const UsernameAvailabilityField = ({
onErrorMutation,
user,
}: UsernameAvailabilityFieldProps) => {
const [currentUsername, setCurrentUsername] = useState(user.username ?? "");
const router = useRouter();
const [currentUsernameState, setCurrentUsernameState] = useState(user.username || "");
const { username: usernameFromQuery, setQuery: setUsernameFromQuery } = useRouterQuery("username");
const { username: currentUsername, setQuery: setCurrentUsername } =
router.query["username"] && user.username === null
? { username: usernameFromQuery, setQuery: setUsernameFromQuery }
: { username: currentUsernameState || "", setQuery: setCurrentUsernameState };
const formMethods = useForm({
defaultValues: {
username: currentUsername,
-102
View File
@@ -1,102 +0,0 @@
import { useCallback, useRef, useState } from "react";
import { useEffect } from "react";
import { HexColorInput, HexColorPicker } from "react-colorful";
import { isValidHexCode, fallBackHex } from "@calcom/lib/CustomBranding";
import { Swatch } from "@calcom/ui";
type Handler = (event: MouseEvent | Event) => void;
function useEventListener<
KW extends keyof WindowEventMap,
KH extends keyof HTMLElementEventMap,
T extends HTMLElement | void = void
>(
eventName: KW | KH,
handler: (event: WindowEventMap[KW] | HTMLElementEventMap[KH] | Event) => void,
element?: React.RefObject<T>
) {
// Create a ref that stores handler
const savedHandler = useRef<typeof handler>();
useEffect(() => {
// Define the listening target
const targetElement: T | Window = element?.current || window;
if (!(targetElement && targetElement.addEventListener)) {
return;
}
// Update saved handler if necessary
if (savedHandler.current !== handler) {
savedHandler.current = handler;
}
// Create event listener that calls handler function stored in ref
const eventListener: typeof handler = (event) => {
// eslint-disable-next-line no-extra-boolean-cast
if (!!savedHandler?.current) {
savedHandler.current(event);
}
};
targetElement.addEventListener(eventName, eventListener);
// Remove event listener on cleanup
return () => {
targetElement.removeEventListener(eventName, eventListener);
};
}, [eventName, element, handler]);
}
function useOnClickOutside<T extends HTMLElement = HTMLElement>(
ref: React.RefObject<T>,
handler: Handler,
mouseEvent: "mousedown" | "mouseup" = "mousedown"
): void {
useEventListener(mouseEvent, (event) => {
const el = ref?.current;
// Do nothing if clicking ref's element or descendent elements
if (!el || el.contains(event.target as Node)) {
return;
}
handler(event);
});
}
export type ColorPickerProps = {
defaultValue: string;
onChange: (text: string) => void;
};
const ColorPicker = (props: ColorPickerProps) => {
const init = !isValidHexCode(props.defaultValue)
? fallBackHex(props.defaultValue, false)
: props.defaultValue;
const [color, setColor] = useState(init);
const [isOpen, toggle] = useState(false);
const popover = useRef() as React.MutableRefObject<HTMLInputElement>;
const close = useCallback(() => toggle(false), []);
useOnClickOutside(popover, close);
return (
<div className="relative mt-1 flex items-center justify-center">
<Swatch size="sm" backgroundColor={color} onClick={() => toggle(!isOpen)} />
{isOpen && (
<div className="popover" ref={popover}>
<HexColorPicker
className="!absolute !top-10 !left-0 !z-10 !h-32 !w-32"
color={color}
onChange={(val) => {
setColor(val);
props.onChange(val);
}}
/>
</div>
)}
<HexColorInput
className="ml-1 block w-full rounded-r-md border border-gray-300 px-3 py-2 sm:text-sm"
color={color}
onChange={(val) => {
setColor(val);
props.onChange(val);
}}
type="text"
/>
</div>
);
};
export default ColorPicker;
@@ -1,4 +1,5 @@
import React, { forwardRef, InputHTMLAttributes } from "react";
import type { InputHTMLAttributes } from "react";
import React, { forwardRef } from "react";
import classNames from "@calcom/lib/classNames";
@@ -1,5 +1,5 @@
import React from "react";
import { Props } from "react-select";
import type { Props } from "react-select";
import { useLocale } from "@calcom/lib/hooks/useLocale";
import { Avatar } from "@calcom/ui";
@@ -1,4 +1,5 @@
import { components, GroupBase, Props, SingleValue } from "react-select";
import type { GroupBase, Props, SingleValue } from "react-select";
import { components } from "react-select";
import type { EventLocationType } from "@calcom/app-store/locations";
import { classNames } from "@calcom/lib";
+2 -1
View File
@@ -1,5 +1,6 @@
import classNames from "classnames";
import React, { forwardRef, InputHTMLAttributes, ReactNode } from "react";
import type { InputHTMLAttributes, ReactNode } from "react";
import React, { forwardRef } from "react";
type Props = InputHTMLAttributes<HTMLInputElement> & {
label?: ReactNode;
+10 -3
View File
@@ -1,5 +1,6 @@
import React, { useCallback, useEffect, useState } from "react";
import ReactSelect, { components, GroupBase, Props, InputProps, SingleValue, MultiValue } from "react-select";
import type { GroupBase, Props, InputProps, SingleValue, MultiValue } from "react-select";
import ReactSelect, { components } from "react-select";
import classNames from "@calcom/lib/classNames";
import useTheme from "@calcom/lib/hooks/useTheme";
@@ -28,7 +29,8 @@ function Select<
IsMulti extends boolean = false,
Group extends GroupBase<Option> = GroupBase<Option>
>({ className, ...props }: SelectProps<Option, IsMulti, Group>) {
const { resolvedTheme, forcedTheme, isReady } = useTheme();
const [mounted, setMounted] = useState<boolean>(false);
const { resolvedTheme, forcedTheme } = useTheme();
const hasDarkTheme = !forcedTheme && resolvedTheme === "dark";
const darkThemeColors = {
/** Dark Theme starts */
@@ -72,10 +74,15 @@ function Select<
/** Dark Theme ends */
};
useEffect(() => {
setMounted(true);
}, []);
// Till we know in JS the theme is ready, we can't render react-select as it would render with light theme instead
if (!isReady) {
if (!mounted) {
return <input type="text" className={className} />;
}
return (
<ReactSelect
theme={(theme) => ({
Binary file not shown.
+3 -3
View File
@@ -1,11 +1,11 @@
import {
import type {
QueryObserverLoadingErrorResult,
QueryObserverLoadingResult,
QueryObserverRefetchErrorResult,
QueryObserverSuccessResult,
UseQueryResult,
} from "@tanstack/react-query";
import { ReactNode } from "react";
import type { ReactNode } from "react";
import { useLocale } from "@calcom/lib/hooks/useLocale";
import type { TRPCClientErrorLike } from "@calcom/trpc/client";
@@ -88,7 +88,7 @@ const withQuery = <
TInput = inferProcedureInput<TQuery>,
TOutput = inferProcedureOutput<TQuery>
>(
queryProcedure: DecorateProcedure<TQuery, any>,
queryProcedure: DecorateProcedure<TQuery, any, any>,
input?: TInput,
params?: UseTRPCQueryOptions<any, TInput, TOutput, TOutput, TError>
) => {
+8 -4
View File
@@ -1,11 +1,12 @@
import { TooltipProvider } from "@radix-ui/react-tooltip";
import { SessionProvider } from "next-auth/react";
import { EventCollectionProvider } from "next-collect/client";
import { appWithTranslation, SSRConfig } from "next-i18next";
import type { SSRConfig } from "next-i18next";
import { appWithTranslation } from "next-i18next";
import { ThemeProvider } from "next-themes";
import type { AppProps as NextAppProps, AppProps as NextJsAppProps } from "next/app";
import { NextRouter } from "next/router";
import { ComponentProps, ReactNode } from "react";
import type { NextRouter } from "next/router";
import type { ComponentProps, ReactNode } from "react";
import DynamicHelpscoutProvider from "@calcom/features/ee/support/lib/helpscout/providerDynamic";
import DynamicIntercomProvider from "@calcom/features/ee/support/lib/intercom/providerDynamic";
@@ -13,18 +14,20 @@ import { trpc } from "@calcom/trpc/react";
import { MetaProvider } from "@calcom/ui";
import usePublicPage from "@lib/hooks/usePublicPage";
import type { WithNonceProps } from "@lib/withNonce";
const I18nextAdapter = appWithTranslation<NextJsAppProps<SSRConfig> & { children: React.ReactNode }>(
({ children }) => <>{children}</>
);
// Workaround for https://github.com/vercel/next.js/issues/8592
export type AppProps = Omit<NextAppProps, "Component"> & {
export type AppProps = Omit<NextAppProps<WithNonceProps & Record<string, unknown>>, "Component"> & {
Component: NextAppProps["Component"] & {
requiresLicense?: boolean;
isThemeSupported?: boolean | ((arg: { router: NextRouter }) => boolean);
getLayout?: (page: React.ReactElement, router: NextRouter) => ReactNode;
};
/** Will be defined only is there was an error */
err?: Error;
};
@@ -77,6 +80,7 @@ const AppProviders = (props: AppPropsWithChildren) => {
<TooltipProvider>
{/* color-scheme makes background:transparent not work which is required by embed. We need to ensure next-theme adds color-scheme to `body` instead of `html`(https://github.com/pacocoursey/next-themes/blob/main/src/index.tsx#L74). Once that's done we can enable color-scheme support */}
<ThemeProvider
nonce={props.pageProps.nonce}
enableColorScheme={false}
storageKey={storageKey}
forcedTheme={forcedTheme}
+3 -2
View File
@@ -1,7 +1,8 @@
import { IdentityProvider } from "@prisma/client";
import { compare, hash } from "bcryptjs";
import { Session } from "next-auth";
import { getSession as getSessionInner, GetSessionParams } from "next-auth/react";
import type { Session } from "next-auth";
import type { GetSessionParams } from "next-auth/react";
import { getSession as getSessionInner } from "next-auth/react";
/** @deprecated use the one from `@calcom/lib/auth` */
export async function hashPassword(password: string) {
@@ -1,4 +1,11 @@
import { Account, IdentityProvider, Prisma, PrismaClient, User, VerificationToken } from "@prisma/client";
import type {
Account,
IdentityProvider,
Prisma,
PrismaClient,
User,
VerificationToken,
} from "@prisma/client";
import { PrismaClientKnownRequestError } from "@prisma/client/runtime";
import { identityProviderNameMap } from "@lib/auth";
-1
View File
@@ -1 +0,0 @@
export * from "@calcom/lib/availability";
-2
View File
@@ -1,2 +0,0 @@
// TODO: Remove this file once everything is imported from `@calcom/lib`
export * from "@calcom/lib/constants";
+1 -1
View File
@@ -1,4 +1,4 @@
import { DefaultSeoProps, NextSeoProps } from "next-seo";
import type { DefaultSeoProps, NextSeoProps } from "next-seo";
import { APP_NAME, SEO_IMG_DEFAULT, SEO_IMG_OGIMG } from "@calcom/lib/constants";
+2 -2
View File
@@ -1,7 +1,7 @@
import parser from "accept-language-parser";
import { IncomingMessage } from "http";
import type { IncomingMessage } from "http";
import { Maybe } from "@calcom/trpc/server";
import type { Maybe } from "@calcom/trpc/server";
import { getSession } from "@lib/auth";
-1
View File
@@ -1 +0,0 @@
export * from "@calcom/lib/weekday";
+83
View File
@@ -0,0 +1,83 @@
import crypto from "crypto";
import type { IncomingMessage, OutgoingMessage } from "http";
import { z } from "zod";
import { IS_PRODUCTION } from "@calcom/lib/constants";
function getCspPolicy(nonce: string) {
//TODO: Do we need to explicitly define it in turbo.json
const CSP_POLICY = process.env.CSP_POLICY;
// Note: "non-strict" policy only allows inline styles otherwise it's the same as "strict"
// We can remove 'unsafe-inline' from style-src when we add nonces to all style tags
// Maybe see how @next-safe/middleware does it if it's supported.
const useNonStrictPolicy = CSP_POLICY === "non-strict";
return `
default-src 'self' ${IS_PRODUCTION ? "" : "data:"};
script-src ${
IS_PRODUCTION
? // 'self' 'unsafe-inline' https: added for Browsers not supporting strict-dynamic not supporting strict-dynamic
"'nonce-" + nonce + "' 'strict-dynamic' 'self' 'unsafe-inline' https:"
: // Note: We could use 'strict-dynamic' with 'nonce-..' instead of unsafe-inline but there are some streaming related scripts that get blocked(because they don't have nonce on them). It causes a really frustrating full page error model by Next.js to show up sometimes
"'unsafe-inline' 'unsafe-eval' https: http:"
};
object-src 'none';
base-uri 'none';
child-src app.cal.com;
style-src 'self' ${
IS_PRODUCTION ? (useNonStrictPolicy ? "'unsafe-inline'" : "") : "'unsafe-inline'"
} app.cal.com;
font-src 'self';
img-src 'self' https://www.gravatar.com https://img.youtube.com https://eu.ui-avatars.com/api/ data:
`;
}
// Taken from @next-safe/middleware
const isPagePathRequest = (url: URL) => {
const isNonPagePathPrefix = /^\/(?:_next|api)\//;
const isFile = /\..*$/;
const { pathname } = url;
return !isNonPagePathPrefix.test(pathname) && !isFile.test(pathname);
};
export function csp(req: IncomingMessage | null, res: OutgoingMessage | null) {
if (!req) {
return { nonce: undefined };
}
const existingNonce = req.headers["x-nonce"];
if (existingNonce) {
const existingNoneParsed = z.string().safeParse(existingNonce);
return { nonce: existingNoneParsed.success ? existingNoneParsed.data : "" };
}
if (!req.url) {
return { nonce: undefined };
}
const CSP_POLICY = process.env.CSP_POLICY;
const cspEnabledForInstance = CSP_POLICY;
const nonce = crypto.randomBytes(16).toString("base64");
const parsedUrl = new URL(req.url, "http://base_url");
const cspEnabledForPage = cspEnabledForInstance && isPagePathRequest(parsedUrl);
if (!cspEnabledForPage) {
return {
nonce: undefined,
};
}
// Set x-nonce request header to be used by `getServerSideProps` or similar fns and `Document.getInitialProps` to read the nonce from
// It is generated for all page requests but only used by pages that need CSP
req.headers["x-nonce"] = nonce;
if (res) {
res.setHeader(
req.headers["x-csp-enforce"] === "true"
? "Content-Security-Policy"
: "Content-Security-Policy-Report-Only",
getCspPolicy(nonce)
.replace(/\s{2,}/g, " ")
.trim()
);
}
return { nonce };
}
+1 -1
View File
@@ -1,4 +1,4 @@
import { Prisma, PrismaClient } from "@prisma/client";
import type { Prisma, PrismaClient } from "@prisma/client";
async function getBooking(prisma: PrismaClient, uid: string) {
const booking = await prisma.booking.findFirst({

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