Compare commits

..
473 Commits
Author SHA1 Message Date
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
Alex van Andel 865663646a v2.5.5
release.yml / release (push) Canceled after 0s
2023-01-24 16:54:35 +00:00
Alex van Andel b7c92063c2 Revert "v2.5.4"
This reverts commit 4f293edb6b.
2023-01-24 16:54:05 +00:00
Alex van Andel 4f293edb6b v2.5.4 2023-01-24 16:52:33 +00:00
Ben HybertandAlex van Andel 0c88cf75e0 corrected avatars inside users block (#6667)
* corrected avatars inside users block

* ensured the team avatar didnt shrink too

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

Co-authored-by: Alex van Andel <me@alexvanandel.com>
2023-01-24 16:10:43 +00:00
Nafees NazikandUdit Takkar 0b93647209 fix: double border issue in Location Select (#6646)
* fix: border issue

* fix: remove border from dropdown

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-01-24 17:05:35 +01:00
Alex van Andel b931b00714 Add env variables to turbo.json relevant to the website build (#6654) 2023-01-24 15:47:46 +00:00
Nafees Nazik 796a5f8d51 feat: use cal video as the default location (#6643)
* feat: use cal video as default while creating new events

* feat: use cal video as default value

* chore: remove default value

* fix: default value logic

* chore: remove console.log
2023-01-24 15:28:40 +00:00
sean-brydon 905a110377 Invites (#6665) 2023-01-24 15:27:05 +00:00
Alex van Andel 6ccc19985f Add sizePropsBySize to avatarPrimitive root (#6666) 2023-01-24 14:01:27 +00:00
Udit Takkar 8f71474303 fix: add allowOverflow property (#6636)
* fix: add allowOverlfow property

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

* fix: date override input dialog

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

Signed-off-by: Udit Takkar <udit.07814802719@cse.mait.ac.in>
2023-01-24 14:00:45 +00:00
zomars 5f351230ff Ignores auth submodule 2023-01-23 16:50:17 -07:00
Alex van Andel 3e005919c1 Only return enabled apps in getEnabledApps (#6653) 2023-01-23 16:27:20 -07:00
cfa8fd8b67 Reduce bundle size by importing single icons at a time (#6644)
* Removed barrel import for icons to reduce bundle size.

* Fixed replacement mistakes

* Reverted unneccesary yarn.lock updates

* Added some missed Icon. import conversions

* Remove merge artifact import in @calcom/ui

* Don't import Icon in pages/[user]

* Update packages/ui/package.json

Co-authored-by: Alex van Andel <me@alexvanandel.com>
Co-authored-by: Omar López <zomars@me.com>
2023-01-23 23:08:01 +00:00
Alex van Andel a888be6e04 Support both https/git by detection of origin root (#6651)
* Support both https/git by detection of origin root

* Remove unnecessary .

* Minor comment fixup
2023-01-23 23:05:53 +00:00
Joe Au-Yeung 6aa2cba3ce Msteams access token refresh (#6607)
* Add is valid call

* WIP

* Change logic for Microsoft refresh token

* remove async
2023-01-23 15:36:24 -07:00
sean-brydon 12ab615684 Fix weird avatar issue (#6645) 2023-01-23 15:48:40 +00:00
1d792a2c6c 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>
2023-01-23 10:58:41 +01:00
Hariom Balhara 9602ac29fb Fix Ga4 tracking (#6630) 2023-01-23 09:09:16 +00:00
Leo Giovanetti 5714471b9a Temporary fix (#6626)
release.yml / release (push) Canceled after 0s
2023-01-22 17:27:27 +00:00
Mohammed CherfaouiandAlex van Andel a99e93a4bd 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>
2023-01-22 20:31:25 +05:30
Udit Takkar 7f044ff92f fix: use items-center (#6618) 2023-01-22 13:36:07 +01:00
Alex van Andel 17a0a61313 v2.5.3
release.yml / release (push) Canceled after 0s
2023-01-22 00:06:41 +00:00
Alex van Andel 12b7739c9a 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
2023-01-21 17:03:59 -07:00
Alex van Andel ff283a25d2 Reduce the avatar size to 'sm' for now 2023-01-21 22:09:32 +00:00
sean-brydon 4b343f20a4 Update booking filters design (#6543)
* Update booking filters

* Add filter on YOUR bookings

* Fix pending members showing up in list
2023-01-21 18:15:59 +01:00
Udit Takkar 5bb6904ffd 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>
2023-01-21 16:52:21 +00:00
sean-brydon 0e04f5d338 Fix FAB (#6611) 2023-01-21 16:14:08 +00:00
Nafees Nazik da0ea5d9d0 fix: case-sensitivity in apps path (#6552)
* fix: lowercase slug

* fix: make fallback blocking
2023-01-21 16:13:55 +00:00
Peer Richelsen 1a19261b8f remove 1 on 1 icon (#6609)
* removed 1-on-1 badge

* changed user to users for group events
2023-01-21 16:07:45 +00:00
Luis Cadillo 55a6c65db6 fix: remove annoying outline when <Button /> clicked (#6537)
* fix: remove annoying outline when <Button /> clicked

* Delete yarn.lock
2023-01-21 16:07:30 +00:00
Alex van Andel c9ed3388ae Regenerated lockfile without upgrade (#6610) 2023-01-21 15:49:35 +00:00
2588b7ef84 Harsh/add member invite (#6598)
Co-authored-by: Guest <guest@pop-os.localdomain>
Co-authored-by: root <harsh.singh@gocomet.com>
2023-01-21 16:32:00 +01:00
7ce83542e2 [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>
2023-01-21 11:41:49 +00:00
Alex van Andel 0bb0883e64 Fix string equality check in git-setup.sh 2023-01-21 06:24:29 +00:00
zomars d3be62fbdd Yarn lock fixes 2023-01-20 16:28:22 -07:00
zomars 736308e43a Test fixes 2023-01-20 15:10:09 -07:00
Peer Richelsen 791927e45e Update package.json
release.yml / release (push) Canceled after 0s
2023-01-20 23:06:43 +01:00
Alex van Andel fa984e1568 Changed a neutral- classes to gray (#6603)
* Changed a neutral- classes to gray

* Changed all border-1 to border
2023-01-20 23:04:58 +01:00
Peer Richelsen 9b197da5be Update README.md
release.yml / release (push) Canceled after 0s
2023-01-20 21:58:11 +01:00
Peer Richelsen b7c316b01b Update README.md 2023-01-20 21:57:52 +01:00
Udit Takkar 5ab56310bf 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>
2023-01-20 14:57:14 -05:00
Udit Takkar 52e318ca18 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>
2023-01-20 12:27:58 -07:00
Omar López 8d078564dd 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
2023-01-20 12:17:51 -07:00
7b5482e83d [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>
2023-01-20 17:56:28 +00:00
sean-brydon 23086476b3 Tailwind Merge (#6596)
* Tailwind Merge

* Fix merge classNames
2023-01-20 15:19:12 +01:00
Nafees Nazik 00cab5c41f fix: react-select overflow issue in some modals. (#6587)
* feat: add a disable overflow prop

* feat: use the disable overflow prop
2023-01-20 13:29:37 +00:00
sean-brydon fbc27e1d52 Fix booking filters not working for admin (#6576) 2023-01-19 19:23:58 +01:00
Nafees Nazik e1c9a8cbfc fix: i18n placeholder in awaiting approval email (#6573) 2023-01-19 16:56:44 +01:00
Nafees Nazik 8ee109e975 fix: app list item ui issues in /settings/my-account/conferencing (#6565)
* fix: border color

* fix: padding and title line-height

* feat: add app-list card

* feat: use the AppListCard component

* nit: remove unused imports
2023-01-19 15:02:01 +00:00
sean-brydonandAlex van Andel cfaecc3e02 Icon small button variant (#6525)
* Icon small button variant

* Rename

* Update CVA + Update button WIP

* add ticket ref and fix padding

* Update button and all uses of Icon button

* SB deployment test

* Fixing type error

* Fix lint

* Add icon button to canvas

Co-authored-by: Alex van Andel <me@alexvanandel.com>
2023-01-19 14:55:32 +00:00
Syed Ali Shahbaz 18246e0dc1 path.join causing issues on windows so we keep path like the other exports (#6568) 2023-01-19 13:21:51 +00:00
sean-brydon 6dcb16724c Fixing tabs again (#6566) 2023-01-19 12:05:00 +00:00
d4c5a906b5 App Store Templates (#5289)
* Start by moving what we have to _templates

* WIP

* WIP

* Add create/edit/delete template commands

* Type fixes cli

Co-authored-by: Peer Richelsen <peeroke@gmail.com>
Co-authored-by: zomars <zomars@me.com>
2023-01-18 15:30:25 -07:00
Alex van Andel 27e8d73b82 Revert "experiment: disco border (#6531)"
This reverts commit b5f274d663.
2023-01-18 19:29:36 +00:00
Alex van Andel 25eae4a546 find indexes instead of just one (#6547) 2023-01-18 12:26:07 -07:00
Udit Takkar f663774fee feat: add most popular section in apps (#6539)
* feat: add most popular section in apps

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

* chore: remove margin

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

* fix: merge conflict

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

Signed-off-by: Udit Takkar <udit.07814802719@cse.mait.ac.in>
2023-01-18 11:48:10 -07:00
Nafees NazikandLeo Giovanetti e2258fba27 Feat: webhook form UX improvement (#6448)
* feat: add type and required attribute

* feat: disable ping button when subscriberUrl is
not present

Co-authored-by: Leo Giovanetti <hello@leog.me>
2023-01-18 16:02:20 +00:00
Carina WollendorferandCarinaWolli d0d8878f34 Adds ability to add custom sender names for workflow emails (#6463)
Co-authored-by: CarinaWolli <wollencarina@gmail.com>
2023-01-18 15:32:39 +01:00
Udit Takkar 59ff6c35ee fix: limits tab in event types (#6545)
Signed-off-by: Udit Takkar <udit.07814802719@cse.mait.ac.in>

Signed-off-by: Udit Takkar <udit.07814802719@cse.mait.ac.in>
2023-01-18 12:58:13 +01:00
Alex van Andel 3c07e305ce Create local next.config.js, add storybook-static to .gitignore (#6544) 2023-01-18 11:54:03 +00:00
Alex van Andel b5f274d663 experiment: disco border (#6531)
* Had a play, looking good (now needs isLoading state or however we want to do that)

* Also add tailwind config..

* Don't show conic bg on lightmode

* Slow down animation, show on light mode

* Apply disco border both on light/dark mode & only on success page

* 5s->8s animation speed, remove border crisping up the corners
2023-01-18 10:40:06 +00:00
Peer Richelsen 6c3ae984fc add tracking URL to LicenseRequired (#6526) 2023-01-17 21:49:40 +00:00
Mohammed Cherfaoui a2e9bf0504 fix toast dimensions issues (#6522) 2023-01-18 02:45:04 +05:30
GitStart-Cal.comandgitstart-calcom 8aa089efe6 [CAL-760] Emails: Design Tokens are not update to 2.0 (#6530)
Co-authored-by: gitstart-calcom <gitstart@users.noreply.github.com>
2023-01-17 22:14:16 +01:00
sean-brydonandzomars de64d3d9d4 Move exports up a folder (#6519)
* Move exports up a folder

* Fix imports

* Fix imports again

Co-authored-by: zomars <zomars@me.com>
2023-01-17 12:10:47 -07:00
Udit Takkar 71833c0737 fix: type error and border (#6520)
* fix: type error and border

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

* fix: sepeator

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

Signed-off-by: Udit Takkar <udit.07814802719@cse.mait.ac.in>
2023-01-17 17:12:22 +00:00
Udit Takkar c78f4deaf7 fix: use suffix in text field (#6532)
Signed-off-by: Udit Takkar <udit.07814802719@cse.mait.ac.in>

Signed-off-by: Udit Takkar <udit.07814802719@cse.mait.ac.in>
2023-01-17 18:08:00 +01:00
Hariom Balhara 24fc7d611f Add routing-forms README (#6506) 2023-01-17 17:58:10 +01:00
sean-brydonandHariom Balhara 8afbc3b457 Fixing horizontal tabs (#6454)
* Fix spacing and height

* Testing if its timing out or something else

* So, timep=out is the problem. Increase the timeout to 1s for now

Co-authored-by: Hariom Balhara <hariombalhara@gmail.com>
2023-01-17 16:36:06 +00:00
sean-brydon da18aae21c Adding rtl support for SB (#6523) 2023-01-17 13:38:14 +01:00
Nafees Nazik 87a0d533ef fix: german translation (#6512) 2023-01-17 13:35:35 +01:00
Nafees Nazik 7cdd453953 fix: button shifting while focusing (#6521)
* fix: remove border on focus

* refactor: remove dark mode styles
2023-01-17 12:21:05 +00:00
Omar López 8143816c18 v2.5.0
release.yml / release (push) Canceled after 0s
2023-01-16 15:34:47 -07:00
Nafees Nazik 8243ac3c00 Fix: modal content hidden (#6508) 2023-01-16 18:08:34 +01:00
Alex van Andel 207e120d66 Bring back PublicShell (#6505) 2023-01-16 14:59:54 +01:00
Ronit PandaandPeer Richelsen b25d04da1c 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>
2023-01-16 12:57:38 +00:00
Alex van Andel 7064acf756 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
2023-01-16 12:18:18 +00:00
Alex van Andel 716407ad90 Added fallback to hostsFixed too which is used in COLLECTIVE (#6500) 2023-01-16 10:46:06 +00:00
GitStart-Cal.comandgitstart-calcom af0b08bb2b [CAL-677] /event-type : Event Setup sidebar item doesn't reflect multiple durations (#6390)
Co-authored-by: gitstart-calcom <gitstart@users.noreply.github.com>
2023-01-16 11:45:54 +01:00
Hariom Balhara 3e27735ccb Disable redirect for cancellation page (#6498) 2023-01-16 09:20:50 +00:00
Nafees Nazik 76c087f29c 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
2023-01-16 08:48:07 +00:00
Peer RichelsenandAlex van Andel e05bcf98c2 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>
2023-01-15 18:54:52 +01:00
Udit TakkarandPeer Richelsen 636e88d467 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>
2023-01-15 11:40:40 +00:00
Nafees Nazik 34a61214d3 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
2023-01-14 20:11:28 +01:00
Nafees Nazik b1af30e026 fix: german translation for reschedule booking email subject (#6483)
* fix: german translation for reschedule subject

* fix: add a full stop
2023-01-14 19:10:30 +01:00
Nafees Nazik 870b59d617 fix: darkmode in booking/[id] page (#6458)
* fix: text-area style

* fix: border styles
2023-01-14 16:49:15 +01:00
Peer Richelsen e25094ccab i18n udpate 2023-01-14 02:12:07 +01:00
Carina WollendorferandCarinaWolli 1376f0991f Reusable Upgrade component for teams only features (#6473)
Co-authored-by: CarinaWolli <wollencarina@gmail.com>
2023-01-14 01:48:19 +01:00
443329b99f 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>
2023-01-13 17:42:13 -07:00
Joe Au-Yeung a1fc4ec26d Disable email input if new user invited to team (#6471) 2023-01-13 17:21:57 -07:00
Udit TakkarandPeer Richelsen d462298e79 fix: remove website url in download recording (#6466)
Co-authored-by: Peer Richelsen <peeroke@gmail.com>
2023-01-14 00:03:13 +00:00
Nafees NazikandPeer Richelsen 965cff38c2 fix: HOSTED_CAL_FEATURES env doesn't get passed to the frontend (#6392)
* fix: rename HOSTED_CAL_FEATURES into NEXT_PUBLIC_HOSTED_CAL_FEATURES

* chore: add the new env to example

* fix: docs link

Co-authored-by: Peer Richelsen <peeroke@gmail.com>
2023-01-13 23:51:37 +00:00
Joe Au-Yeungandkodiakhq[bot] f96e909dce Team invites - transform email or username to lower case (#6470)
* Fix string

* Use current hashPassword

* Transform email to lowercase

Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com>
2023-01-13 18:58:41 +00:00
Leo Giovanetti a4d6f7da62 Fixing GCal emailing notif and sequential deleting (#6460) 2023-01-13 11:29:42 -07:00
Nafees Nazikandkodiakhq[bot] ce9413e0dd fix: missing empty state in /apps/installed/web3 (#6377)
* refactor: turn enum into const assertion

* feat: add web3 to icon list

* fix: type

* fix: type cast query params and add category list

* fix: conditional rendering

* feat: add i18n keys

* fix: type errors

Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com>
2023-01-13 14:12:43 +00:00
Peer Richelsen 8fc0dfb763 booking page: only scroll to bottom on mobile (#6453)
* move useMediaQuery into packages

* revert logo.tsx
2023-01-13 17:40:02 +05:30
690edcf0a7 New Crowdin translations by Github Action (#6444)
Co-authored-by: Crowdin Bot <support+bot@crowdin.com>
Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com>
2023-01-12 23:21:06 +00:00
Omar López b7dbf10068 v2.4.7
release.yml / release (push) Canceled after 0s
2023-01-12 16:10:07 -07:00
zomars 83b4ba94fc testing auto crowdin 2023-01-12 16:01:40 -07:00
62a09e7098 Small improvements for constants (#6409)
* use IS_SELF_HOSTED for CalComVersion instead of an additional check for hosted and self-hosted versions

* use IS_SELF_HOSTED for HOSTED_CAL_FEATURES constant to prevent an additional check

Co-authored-by: René Müller <rene.mueller@clicksports.de>
Co-authored-by: Omar López <zomars@me.com>
Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com>
2023-01-12 22:25:25 +00:00
d2c4e2894d Check for session in addition for isPublic prop (#6443)
* Check for session in addition for isPublic prop

* Cleaner, more readable version

* Less code same result, no rerender

Co-authored-by: Peer Richelsen <peeroke@gmail.com>
Co-authored-by: zomars <zomars@me.com>
2023-01-12 22:11:15 +00:00
Joe Au-YeungandOmar López 070d314897 Increase error logging details (#6442)
Co-authored-by: Omar López <zomars@me.com>
2023-01-12 21:43:40 +00:00
zomars 0a76368e98 Run required checks from Crowin PRs 2023-01-12 14:22:11 -07:00
99287d9eb4 Feature/fixed hosts (#6423)
* Save design updates for fixed round robin support

* wip - added Host relation

* DRY hostsFixed select

* Changes to allow isFixed in the Availability page

* Allow booking with fixed hosts

* Replace users with hosts if hosts is set

* Also prefer hosts over users here

* Prevent duplicates when hosts is saved

* Accidental slot duplication

* Attempt at making isFixed optional

* Sydney and Shiraz can live in harmony again

* No fixed hosts causes every to be true..

* Make hosts undefinable

* Small handleNewBooking fixes

* Similar fix to the hosts to check for empty-ness

* Default to isFixed false instead of true

* Fix event type list avatars

* Filter availableTimeSlots, collective ts's wont magically re-enable.

* (Further) Fixes to getAggregateWorkingHours

* Weird userId artifact that preceeds this branch, investigate later

* On user delete, remove host, on event type delete, also remove host

* Dynamic event types were incorrectly marked as isFixed=false

* Fixed notFound error when there are no users (but hosts)

* Fixes userIsOwner

* Oops, fixed isFixed users being included correctly

* Fixed Button styling on secondary darkmode

* Create exclusivity in selectable options

* fix: Location dropdown is overflowing #6376 (#6415)

* add `menuPlacement` react-select's props to `getReactSelectProps` to avoid dropdown overflow on small screen.
By default, set to "auto".

* CALCOM-6362 - [CAL-728] App Sidebar. Child items aren't sized/spaced properly (#6424)

* [CAL-728] App Sidebar. Child items aren't sized/spaced properly

* fix: undo logo size

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: gitstart-calcom <gitstart@users.noreply.github.com>
Co-authored-by: Udit Takkar <udit.07814802719@cse.mait.ac.in>

* Fixing colors (#6429)

* Update website

* Update console

* Update yarn.lock

* Uses disable instead of filtering to be more clear

* Update EventTeamTab.tsx

* Merge conflict cleanup

* During test cases the dayjs() utcOffset is local time, this fixes that

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: Thomas Brodusch <3238312+thomasbrodusch@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: Udit Takkar <udit.07814802719@cse.mait.ac.in>
Co-authored-by: sean-brydon <55134778+sean-brydon@users.noreply.github.com>
Co-authored-by: zomars <zomars@me.com>
2023-01-12 14:09:12 -07:00
zomars 100035cb89 Update yarn.lock 2023-01-12 11:37:19 -07:00
zomars 1750dbead6 Update console 2023-01-12 11:37:11 -07:00
zomars 4c8ed3d11f Update website 2023-01-12 11:36:54 -07:00
sean-brydon f21c4eb11e Fixing colors (#6429) 2023-01-12 16:57:43 +00:00
3f71a41d7e CALCOM-6362 - [CAL-728] App Sidebar. Child items aren't sized/spaced properly (#6424)
* [CAL-728] App Sidebar. Child items aren't sized/spaced properly

* fix: undo logo size

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: gitstart-calcom <gitstart@users.noreply.github.com>
Co-authored-by: Udit Takkar <udit.07814802719@cse.mait.ac.in>
2023-01-12 16:44:41 +00:00
Thomas Brodusch 1ba191c4ed fix: Location dropdown is overflowing #6376 (#6415)
* add `menuPlacement` react-select's props to `getReactSelectProps` to avoid dropdown overflow on small screen.
By default, set to "auto".
2023-01-12 09:29:37 -07:00
Nafees NazikandPeer Richelsen 6414903567 fix: guess correct timezone when onboarding (#6430)
* fix: guess correct timezone

* fix: redirect if on boarded

Co-authored-by: Peer Richelsen <peeroke@gmail.com>
2023-01-12 16:17:57 +00:00
e62d8b4596 fix: long words break UI (#6410)
Co-authored-by: Peer Richelsen <peeroke@gmail.com>
Co-authored-by: alannnc <alannnc@gmail.com>
Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com>
2023-01-12 09:05:20 -07:00
Carina WollendorferandCarinaWolli e27b1b1bc2 Removes 'Test Action' button in workflows (#6418)
* comment out test action feature

* code clean up

Co-authored-by: CarinaWolli <wollencarina@gmail.com>
2023-01-12 09:03:30 -07:00
zomars 9507138f29 Labeler fixes 2023-01-12 08:52:21 -07:00
GitStart-Cal.comandgitstart-calcom e5fa202a09 CALCOM-6398 - [CAL-749] remove ethSignature from query if unused (#6425)
Co-authored-by: gitstart-calcom <gitstart@users.noreply.github.com>
2023-01-12 14:55:00 +01:00
Udit TakkarandAlex van Andel 447098bc97 fix: use i18n properly in utils (#6363)
* fix: use i18n properly in utils

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

* chore

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: Alex van Andel <me@alexvanandel.com>
2023-01-12 05:22:55 +00:00
Udit Takkar dc5e042cdd fix: remove flex-nowrap (#6416)
Signed-off-by: Udit Takkar <udit.07814802719@cse.mait.ac.in>

Signed-off-by: Udit Takkar <udit.07814802719@cse.mait.ac.in>
2023-01-12 01:24:39 +00:00
Leo Giovanetti 92fb365b54 Fix for Request Email Reminder (#6421)
* Fix

* Selecting id
2023-01-11 22:12:11 -03:00
161f5c7000 Adds "Upgrade" paywall to Workflow SMS features instead of disabling them (#6412)
* adds upgrade badge to dropdown

* add space between batch and check

* add upgrade tool tip

* fix import

* code clean up

* fix type error

* fix type error

* fix type errors

Co-authored-by: CarinaWolli <wollencarina@gmail.com>
Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com>
2023-01-11 18:41:45 +00:00
c8744768c4 Refactored buildSlots (#6389)
* Refactored buildSlots

* Added typing for computedAvailableSlots

* Adds very simple boundary logic to make sure slots start at the right times

* Logic was cutting off too early

* Woops, should be eventLength, not frequency

* Expect 12:15 slots as availability is till 12:30 for booking

* Deliberately skip test for testing purposes

* slotInterval overrides intervals, but not duration

* Fix calendar mocking

* Another 45m length

* Unskip :(

* Fix test

Co-authored-by: Hariom Balhara <hariombalhara@gmail.com>
Co-authored-by: Omar López <zomars@me.com>
2023-01-11 17:33:34 +00:00
Udit TakkarandPeer Richelsen b34a568a93 fix: show recordings even to free plan users (#6411)
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>
2023-01-11 09:58:50 -07:00
sean-brydon a669403604 Fix avatars not overlapping (#6405)
* Fix avatars being weird

* Fix useravatar import

* Fix type error

* Fixing spacing
2023-01-11 15:00:46 +00:00
Peer Richelsen 7b2bfc2a64 added GITHUB_API_REPO_TOKEN for console (#6408) 2023-01-11 14:47:37 +00:00
Alex van Andel 7655c0c867 Testing in isolation 2023-01-11 13:24:02 +00:00
Nafees Nazikandsean-brydon 6fbabb4b26 fix: remove border (#6391)
Co-authored-by: sean-brydon <55134778+sean-brydon@users.noreply.github.com>
2023-01-11 10:28:57 +00:00
sean-brydon edfc9ff082 Fixes ultrawide breaking booking limits selects (#6396) 2023-01-11 10:16:04 +00:00
Leo Giovanetti 59a9a77e3f Fixes cancelling all recurring events (#6384) 2023-01-10 14:09:28 -07:00
Joe Au-Yeungandkodiakhq[bot] 8e756d7648 Fix custom event names in emails (#6375)
* Fix What for normal bookings

* Fix subject on bookings with seats

* WIP

* Change more strings

Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com>
2023-01-10 18:32:50 +00:00
Udit Takkarandsean-brydon 5763c1c2f1 fix: use default length in form (#6378)
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: sean-brydon <55134778+sean-brydon@users.noreply.github.com>
2023-01-10 17:25:09 +00:00
Alex van Andel 6c5ae0b4d9 Fixed default value for ordering correctly (#6372) 2023-01-10 17:06:53 +01:00
9cb9ce2e42 Chor/bulk UI migration (#6367)
* Big bulk commit

* Switch and settings toggle

* Popover Kbar Timezones

* Image Uploader

* Fix core export

* Meta

* Swatch

* Remove shell

* Fix shell imports

* Moved ShellSubHeading component to UI, to prevent recursive imports from shell component

* Removed shell from ui ts config since shell doesnt have a dependency on shell anymore.

Co-authored-by: Jeroen Reumkens <hello@jeroenreumkens.nl>
Co-authored-by: Omar López <zomars@me.com>
2023-01-10 15:39:29 +00:00
Omar LópezandCrowdin Bot 018be43017 New Crowdin translations by Github Action (#6365)
Co-authored-by: Crowdin Bot <support+bot@crowdin.com>
2023-01-10 08:11:59 -07:00
zomars 4f720c8c9b Update crowdin.yml 2023-01-10 08:05:14 -07:00
Udit TakkarandPeer Richelsen 06e1e113f0 fix: margin and padding (#6358)
Co-authored-by: Peer Richelsen <peeroke@gmail.com>
2023-01-10 12:44:30 +00:00
sean-brydonandOmar López 3fc6f38da9 Chor/more UI migrations (#6353)
* Move tabs to components

* Lots of form components

* Update apps/web/components/apps/layouts/InstalledAppsLayout.tsx

Co-authored-by: Omar López <zomars@me.com>
2023-01-10 12:25:39 +00:00
Omar López 8e8c96c267 v2.4.6
release.yml / release (push) Canceled after 0s
2023-01-09 20:26:21 -07:00
github-actions[bot]andCrowdin Bot fab765c5ee New Crowdin translations by Github Action (#6349)
Co-authored-by: Crowdin Bot <support+bot@crowdin.com>
2023-01-09 20:25:22 -07:00
zomars 89ed07a097 Update crowdin.yml 2023-01-09 20:17:03 -07:00
zomars d7d73d2caf Update crowdin.yml 2023-01-09 20:15:53 -07:00
zomars aa92730e28 Fix labeler 2023-01-09 19:52:02 -07:00
430430e0cd Feedback of reusable wysiwyg editor (#6357)
* make text editor reusable

* use dropdown component for block type

* remove ring when clicking on block type

* allow excluding items in toolbar

* refactor code

* make AddVariableDropdown reusable

* fixed missed translations

* fixes variable translation issue

* change missed translation variables

* make AddVariablesDropdown reusable

* reorder block types in dropdown

* remove not needed prop

* code clean up

* center add variable dropwdown icon

* remove rounded borders in dropwdown on hover and active

* center icons

* fix tool bar items dropdown

* add constant for dynamic text variables

* remove not needed variables (added from merge)

Co-authored-by: CarinaWolli <wollencarina@gmail.com>
Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com>
Co-authored-by: Peer Richelsen <peeroke@gmail.com>
Co-authored-by: alannnc <alannnc@gmail.com>
2023-01-09 19:22:17 -07:00
62713940b0 Chor/v2 more tidyup - Card - link icon button - tooltip (#6312)
* Card

* Step card

* Already in components

* Link Icon Button

* Tooltip

* Fix types

Co-authored-by: Peer Richelsen <peeroke@gmail.com>
Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com>
2023-01-09 19:22:04 -07:00
75aef09338 Google Meet - installable app (#5904)
* Abstract app category navigation

* Send key schema to frontend

Co-authored-by: Omar López <zomars@users.noreply.github.com>

* Render keys for apps on admin

* Add enabled col for apps

* Save app keys to DB

* Add checks for admin role

* Abstract setup components

* Add AdminAppsList to setup wizard

* Migrate to v10 tRPC

* Default hide keys

* Display enabled apps

* Merge branch 'main' into admin-apps-ui

* Toggle calendars

* WIP

* Add params and include AppCategoryNavigation

* Refactor getEnabledApps

* Add warning for disabling apps

* Fallback to cal video when a video app is disabled

* WIP send disabled email

* Send email to all users of  event types with payment app

* Disable Stripe when app is disabled

* Disable apps in event types

* Send email to users on disabled apps

* Send email based on what app was disabled

* WIP type fix

* Disable navigation to apps list if already setup

* UI import fixes

* Waits for session data before redirecting

* Updates admin seeded password

To comply with admin password requirements

* Update yarn.lock

* Flex fixes

* Adds admin middleware

* Clean up

* WIP

* WIP

* NTS

* Add dirName to app metadata

* Upsert app if not in db

* Upsert app if not in db

* Add dirName to app metadata

* Add keys to app packages w/ keys

* Merge with main

* Toggle show keys & on enable

* Fix empty keys

* Fix lark calendar metadata

* Fix some type errors

* Fix Lark metadata & check for category when upserting

* More type fixes

* Fix types & add keys to google cal

* WIP

* WIP

* WIP

* More type fixes

* Fix type errors

* Fix type errors

* More type fixes

* More type fixes

* More type fixes

* Feedback

* Fixes default value

* Feedback

* Migrate credential invalid col default value "false"

* Upsert app on saving keys

* Clean up

* Validate app keys on frontend

* Add nonempty to app keys schemas

* Add web3

* Listlocale filter on categories / category

* Grab app metadata via category or categories

* Show empty screen if no apps are enabled

* Fix type checks

* Fix type checks

* Fix type checks

* Fix type checks

* Fix type checks

* Fix type checks

* Replace .nonempty() w/ .min(1)

* Fix type error

* Address feedback

* Draft Google Meet install button

* Add install button and warning dialog

* WIP

* WIP

* Display warning when Meet is selected

* Display Google Meet warning on email to organizer

* Fix email

* Fix type errors

* Fix type error

* Add connected account component

* Add warning message

* Address comments

* Address feedback

* Clean up & add MeetLocationType

* Use useApp hook

* Translate to new API approach

* Remove console.log

* Refactor

* Fix missing backup Cal video link

* WIP

* Address feedback

* Update submodules

* Feedback

* Submodule sync

Co-authored-by: Omar López <zomars@users.noreply.github.com>
Co-authored-by: Peer Richelsen <peeroke@gmail.com>
Co-authored-by: zomars <zomars@me.com>
Co-authored-by: sean-brydon <55134778+sean-brydon@users.noreply.github.com>
Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com>
Co-authored-by: Peer Richelsen <peer@cal.com>
2023-01-10 02:01:57 +00:00
4e65c30e18 fix: Parameterize Stripe Payment Fee configs (#6024)
* Parameterize Stripe Payment Fee configs

* Restore constant values for Payment Fee params

* Restore constant values for all Payment Fee params

* Remove STRIPE_ prefix on payment fee vars

* Cast Payment Fee params as Number

Co-authored-by: Peer Richelsen <peeroke@gmail.com>
Co-authored-by: Joe Au-Yeung <65426560+joeauyeung@users.noreply.github.com>
Co-authored-by: Omar López <zomars@me.com>
2023-01-09 18:50:49 -07:00
8b873e2828 Adding a bunch of performance markers (#6303)
* Adding a bunch of performance markers

* Update packages/lib/server/perfObserver.ts

Co-authored-by: Peer Richelsen <peeroke@gmail.com>
Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com>
2023-01-09 18:42:46 -07:00
zomars e70d179628 Update website 2023-01-09 18:31:38 -07:00
Nafees Nazik ca9a836300 fix: remove padding from username field (#6356) 2023-01-09 19:35:00 +01:00
Alex van Andel abdf72dc0f Fixup yarn.lock 2023-01-09 14:36:49 +00:00
dependabot[bot]andBailey Pumfleet 227cd165f6 Bump json5 from 1.0.1 to 1.0.2 (#6351)
Bumps [json5](https://github.com/json5/json5) from 1.0.1 to 1.0.2.
- [Release notes](https://github.com/json5/json5/releases)
- [Changelog](https://github.com/json5/json5/blob/main/CHANGELOG.md)
- [Commits](https://github.com/json5/json5/compare/v1.0.1...v1.0.2)

---
updated-dependencies:
- dependency-name: json5
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Bailey Pumfleet <bailey@pumfleet.co.uk>
2023-01-09 14:19:51 +00:00
a0135cdc59 Make WYSIWYG editor reusable (#6293)
* make text editor reusable

* use dropdown component for block type

* remove ring when clicking on block type

* allow excluding items in toolbar

* refactor code

* make AddVariableDropdown reusable

* fixed missed translations

* fixes variable translation issue

* change missed translation variables

* make AddVariablesDropdown reusable

* reorder block types in dropdown

* remove not needed prop

* code clean up

Co-authored-by: CarinaWolli <wollencarina@gmail.com>
Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com>
2023-01-09 14:15:11 +00:00
112d504148 Chor/v2 UI tidy - Dialog & Toasts (#6307)
* Dialog Tidyup

* Move toasts

Co-authored-by: Peer Richelsen <peeroke@gmail.com>
Co-authored-by: Peer Richelsen <peer@cal.com>
2023-01-09 13:57:12 +00:00
Peer Richelsen d275930732 link to event-types in settings to fix cal.com usage (#6348) 2023-01-09 13:15:10 +01:00
Alex van Andel 97e33bdd7e Set bg-white to secondary variant (#6339) 2023-01-08 17:50:37 +01:00
Hariom Balhara 3f13791faf Add app-store installed page navigationt ests (#6333) 2023-01-08 09:29:20 +01:00
Omar LópezandAlex van Andel 359cfc4be0 Replaces mdx-remote with markdown-it (#6326)
* Replaces mdx-remote with react-markdown

* Replaces react-markdown with already available markdown-it

* Renames readme to description

Co-authored-by: Alex van Andel <me@alexvanandel.com>
2023-01-08 00:05:35 +00:00
Alex van AndelandPeer Richelsen 1ad6bba0ab set useQueryParam to false for app categories (#6330)
* set useQueryParam to false for app categories

* New param 'useQueryParam' for AppCategoryNavigation/AdminAppsList

Co-authored-by: Peer Richelsen <peeroke@gmail.com>
2023-01-07 23:21:21 +00:00
Alex van Andel 6dc4211d81 Fixes hydration error, uses useTypedQuery for tabName (#6327) 2023-01-07 22:42:30 +00:00
Alex van Andel e5f0452728 Don't initialize KBar when unauthed (#6328)
* Don't initialize KBar when unauthed

* Don't render trigger when query is undefined
2023-01-07 22:31:15 +00:00
zomars d95bba63f4 Submodule sync 2023-01-07 11:19:16 -07:00
zomars 6f48869021 Add missing slash to custom import 2023-01-07 10:17:38 -07:00
Jeff Loiselle 845bfae887 adds event types to kbar (#6210) 2023-01-07 10:06:53 -07:00
zomars 3fe02fba26 Update basic.e2e.ts 2023-01-07 09:55:30 -07:00
zomars 4ca5ca9fe2 Update hash-my-url.e2e.ts 2023-01-07 09:50:02 -07:00
Hariom BalharaandPeer Richelsen 364e187080 Fix/Next.js-13/Circular Dependency in Routing Forms (#6321)
Co-authored-by: Peer Richelsen <peeroke@gmail.com>
2023-01-07 15:50:28 +00:00
Peer Richelsen b1193eef1e Update README.md 2023-01-07 16:27:56 +01:00
Peer Richelsen e110f12cf1 Update README.md 2023-01-07 16:26:47 +01:00
Peer Richelsen 022b513935 Update package.json 2023-01-07 11:55:50 +01:00
Jeff LoiselleandPeer Richelsen 010f39a7a4 adds render.com url constant (#6287)
* adds render.com url constant

* fixes webapp_url constant

Co-authored-by: Peer Richelsen <peeroke@gmail.com>
2023-01-07 10:28:02 +00:00
Peer Richelsen 6b6eed66eb fixed mobile sidebar in settings (#6317) 2023-01-07 10:10:35 +00:00
Udit Takkar c214e01f03 fix: use overflow-auto (#6295)
* fix: use overflow-auto

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

* fix: scroll issues with too many filters

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

* chore: merge conflict

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

Signed-off-by: Udit Takkar <udit.07814802719@cse.mait.ac.in>
2023-01-07 11:00:11 +01:00
Carina WollendorferandCarinaWolli a28ac3634d Add start and end time of rescheduled booking to webhook payload (#6297)
* add start and end time of rescheduled booking

* fix type error

Co-authored-by: CarinaWolli <wollencarina@gmail.com>
2023-01-06 13:37:06 -07:00
zomars a0709fac88 Circular dependecy hotfix 2023-01-06 13:15:34 -07:00
Alex van Andel e5b6a3332e Feature/new design radio area group (#6289)
* Refactor of the RadioAreaGroup component

* Move RadioAreaGroup outside of v2/core

* Use useTypedQuery

* Removed unused (broken) imports

* Fix type for Select
2023-01-06 20:05:23 +00:00
Jeff Loiselle 979686920a fixes codespace login msg spelling (#6288) 2023-01-06 12:37:03 -07:00
zomars 793850f3aa Update console 2023-01-06 11:10:17 -07:00
Nafees NazikandPeer Richelsen fa9d72fc0a fix: flash of untranslated title in settings/my-account/profile (#6163)
* fix: flash of untranslated content

* feat: extract loading into a variable

* fix: use optional chaining because typescript complaining

* feat: render Meta component even if not loading for seo purpose

* fix: received an array with more than 1 element as
children warning

* fix: changes

Co-authored-by: Peer Richelsen <peeroke@gmail.com>
2023-01-06 10:35:32 -07:00
zomars 0d485ffed6 Updates website 2023-01-06 10:18:18 -07:00
Peer Richelsen 9a2e55d528 revert version change 2023-01-06 16:59:26 +01:00
github-actions[bot]andCrowdin Bot 81ecbb86a5 New Crowdin translations by Github Action (#6308)
Co-authored-by: Crowdin Bot <support+bot@crowdin.com>
2023-01-06 16:58:09 +01:00
Peer Richelsen 2cd816932b Update package.json 2023-01-06 16:55:01 +01:00
Peer Richelsenandzomars d83411162d Upgrade to next 13.1 (#6265)
Co-authored-by: zomars <zomars@me.com>
2023-01-06 12:13:56 +00:00
Nafees NazikandPeer Richelsen c9c54db3a1 fix: remove duplicate font preload (#6291)
Co-authored-by: Peer Richelsen <peeroke@gmail.com>
2023-01-06 12:35:48 +01:00
Udit Takkarandkodiakhq[bot] d100600789 feat: update team schema, update team query (#6294)
team appearance section

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: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com>
2023-01-06 10:55:57 +00:00
Omar López 6f9011a167 Update package.json
release.yml / release (push) Canceled after 0s
2023-01-05 18:41:30 -07:00
Omar López ae004c8a6c Fixes extension check for URL with dots in segments (#6301) 2023-01-05 16:38:44 -07:00
Omar López ccbb16fe76 Upgrades prisma (#6298) 2023-01-05 16:24:17 -07:00
Omar López b77ce4a010 Allows to override default debug level for logger (#6300) 2023-01-05 16:23:50 -07:00
Omar Lópezandalannnc f72f709e34 Adds availablity and schedule indexes (#6296)
Co-authored-by: alannnc <alannnc@gmail.com>
2023-01-05 22:29:03 +00:00
Hariom Balhara 37ceb25f8c Make sure returnTo is correct URL (#6189)
* make sure returno is safe

* More fixes
2023-01-05 12:55:55 -07:00
sean-brydon 0141d8f954 Adding border to tabs (#6284)
* Adding border to tabs

* Fix rounded

* Fixing mb on >= lg
2023-01-05 17:14:27 +00:00
sean-brydon 47fe791006 Tidy up v2 layouts (#6266)
* Lots of places use layouts huh

* Fix imports

* FIx merge removing rtl settings

* Fixing Icon Import

* Fix shell import

* Fix tab exports
2023-01-05 18:00:16 +01:00
Jeroen Reumkensandsean-brydon 0cbaba73e4 🧹 Chore/move v2 components to components dir (#6261)
* Removed old root UI components.

* Fixed import path

* Moved first v2 components to new components dir.

* Changed icon to not import from root, since it somehow creates a recursive import

* Removed irrelevant todo

* Added docs for new components

* Fixed type errors

* Update packages/ui/components/index.ts

Removing as per comment

Co-authored-by: sean-brydon <55134778+sean-brydon@users.noreply.github.com>
2023-01-05 12:04:28 +00:00
Hariom Balhara aaac491dc7 HotFix: Admin Apps Listing (#6282) 2023-01-05 17:20:41 +05:30
zomars fc4203e963 Update api 2023-01-04 16:05:48 -07:00
Hariom Balhara 8430e9612e Revive getSchedule Tests and add more (#6200)
* Revive getSchedule Tests

* Cleanup tests

* More Tests

* Add tests for date override
2023-01-04 15:40:06 -07:00
Jeff Loiselle de81934619 adds devcontainer/codespaces support (#6250) 2023-01-04 15:29:25 -07:00
Jeff Loiselle 5aedcbee55 adds render.com deploy button (#6276) 2023-01-04 23:22:07 +01:00
7bc8d7e991 New Crowdin translations by Github Action (#6274)
Co-authored-by: Crowdin Bot <support+bot@crowdin.com>
Co-authored-by: Peer Richelsen <peeroke@gmail.com>
2023-01-04 23:20:54 +01:00
LoneRifleandPeer Richelsen df183f5882 chore(web): update .nvmrc to node 16 (#6214)
Follow up on #2711 by ensuring that `app/web/.nvmrc` lines up with `.nvmrc`

Co-authored-by: Peer Richelsen <peeroke@gmail.com>
2023-01-04 15:20:05 -07:00
27d9fad292 Feature/whitelabel part 2 (#5821)
* applied whitelabel to additional parts of the app

* format .md files

* updated metadata of all apps

* applied whitelabel to PoweredByCal.tsx

* fixed `team_upgrade_banner_action` with better german

* fixed import of APP_NAME in email templates

* revert "applied whitelabel" in CalEventParser.test.ts

* Revert "updated metadata of all apps"

This reverts commit 9c1621788d2c4c4a4e4a545f48898d4af7a39f33.

* revert app-store whitelabel changes

* Revert "applied whitelabel to PoweredByCal.tsx"

This reverts commit f2b2d79aa51cca3a70af6bf649b24e22f2fca73a.

* Update website

* Sync

* Update constants.ts

* Prevent unit test error

Co-authored-by: René Müller <rene.mueller@clicksports.de>
Co-authored-by: Peer Richelsen <peeroke@gmail.com>
Co-authored-by: zomars <zomars@me.com>
2023-01-04 22:14:46 +00:00
zomars bed798d440 Formatting 2023-01-04 13:49:20 -07:00
zomars e5a8a4e34d Submodule sync 2023-01-04 13:47:13 -07:00
Peer Richelsen de446db434 v2.4.3
release.yml / release (push) Canceled after 0s
2023-01-04 21:00:14 +01:00
81546412bf add missing variables for variable translations (#6271)
Co-authored-by: CarinaWolli <wollencarina@gmail.com>
Co-authored-by: Peer Richelsen <peeroke@gmail.com>
2023-01-04 19:57:47 +00:00
Peer Richelsen 459530fba3 Revert "sidebar improvements" (#6273) 2023-01-04 15:46:42 +00:00
Marlo Kesser 42766b42c0 fix localization issues with default locations (#5569) 2023-01-04 15:31:50 +00:00
Hariom Balhara 38b3563350 Feature/Routing Forms: Add the concepts of reusable Router and Router Linked Fields. (#5566)
* WIP

* Fix all TS errors

* Move to using isRouter everywhere

* wip

* Add Router Picker and fix TS issues

* Fix tests and add option to connect during duplication

* Misc changes

* Fixes

* Fixes

* Fix TS errors

* Disable certain options in Router

* Fix connected Form fields not updating

* Some fixes

* reert shell.tsx

* Disable already used router instead of removing it

* Import prisma from correct place

* Simplify loop using Object.entries

* SimpliAdd playwright test and fix issues found
2023-01-04 13:30:46 +00:00
Jeroen Reumkens 37159914cf 🧹 Removed old root UI components. (#6249)
* Removed old root UI components.

* Fixed import path

* Changed icon to not import from root, since it somehow creates a recursive import

* Removed irrelevant todo

* Fixed merge issues.

* Fixed shell export
2023-01-04 14:05:00 +01:00
Peer Richelsen 268bf68532 sidebar improvements (#6259)
* added bottom-0 to sidebar nav

* open sidebar on right for RTL
2023-01-04 11:15:30 +00:00
sean-brydon b02c7e01d5 Move Apps to ui/components (#6245)
* Move Apps to components

* Update packages/features/ee/sso/page/teams-sso-view.tsx
2023-01-04 11:00:01 +00:00
45d10a3bc4 a11y: right-to-left improvements (#6235)
* fixed a ton of rtl issues

* removed duplicant

Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com>
Co-authored-by: sean-brydon <55134778+sean-brydon@users.noreply.github.com>
2023-01-04 07:38:45 +00:00
Jeff LoiselleandPeer Richelsen 9250b20c1d fixes available times overflow bug on safari (#6208)
* fixes available times overflow bug on safari

* WIP

* remove extranous grid classes

Co-authored-by: Peer Richelsen <peeroke@gmail.com>
2023-01-03 22:05:40 +00:00
sean-brydon d9da311141 Move Skeleton to ui/components (#6247)
* Inital Move

* Skeleton story
2023-01-03 15:54:00 +00:00
Nafees Nazik 89a52dad21 fix: cutoff text and align text (#6248) 2023-01-03 14:12:36 +00:00
Hariom Balhara 2a1acc1294 Fix lang and dir attributes not being set (#6243) 2023-01-03 11:09:05 +01:00
8302990f84 fix: use hasMounted to render calcom versionm (#6239)
* fix: use hasMounted to render calcom versionm

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

* added Credits component but struggling with import

* only made it work with v2 folder. sorry jerone

* added link to releases

* added link to cal.com

* removing script calcomversion for now until we need it

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-01-02 19:44:51 +00:00
LoneRifleandPeer Richelsen 5a03b61d63 refactor(web): remove fonts.css, rely on shared-globals.css (#6220)
`styles/fonts.css` is identical to `shared-globals.css`, as found in
`packages/ui/styles`, and as referenced by `styles/globals.css`. Remove
`fonts.css` and its references, leaning instead on the fonts described
in `shared-globals.css`

Co-authored-by: Peer Richelsen <peeroke@gmail.com>
2023-01-02 19:11:06 +00:00
github-actions[bot]andCrowdin Bot 6b6f239936 New Crowdin translations by Github Action (#6242)
Co-authored-by: Crowdin Bot <support+bot@crowdin.com>
2023-01-02 19:50:31 +01:00
Jeff LoiselleandPeer Richelsen 9c2748e8e9 adds team prefix to url when creating team (#6211)
Co-authored-by: Peer Richelsen <peeroke@gmail.com>
2023-01-02 18:34:32 +00:00
Peer Richelsen bb5cc33737 Update README.md 2023-01-02 18:05:53 +01:00
Udit TakkarandPeer Richelsen 5616a64827 fix: use border-0 (#6233)
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>
2023-01-02 15:10:00 +00:00
33530ad8c8 Make cal.com version available on all pages, even on login page. (#6221)
* Make cal.com version available on all pages, even on login page.

* Extract out calcom version as a utility

* added version to login screen

* added ee and ce to version

* fixed lint

* Fix import

* removed  version info component

Co-authored-by: Peer Richelsen <peer@cal.com>
Co-authored-by: Peer Richelsen <peeroke@gmail.com>
2023-01-02 20:24:35 +05:30
Peer Richelsen fe14839f1b fixed sidebar position, added toHide to <LicenseRequired> (#6228)
* fixed sidebar position

* fixed sidebar position

* fixed sidebar position

* removed gradient overlay from user dropdown

* added toHide prop to license check to hide a component if a license is available

* show children if toHide is true
2023-01-02 10:13:27 +00:00
Hariom Balharaandkodiakhq[bot] 15123c1aa5 Add disable success page config[Platform Only] (#6225)
* Add disable success page config

* Change text

Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com>
2023-01-02 08:41:39 +00:00
Peer Richelsen 71ee9c72fe introduced size="fab" prop to Button, added to CTA buttons (#6176)
* introduced size="fab" prop to Button, added to CTA buttons

* increased size of FAB

* nit
2023-01-02 09:28:12 +01:00
github-actions[bot]andCrowdin Bot 5503539856 New Crowdin translations by Github Action (#6222)
Co-authored-by: Crowdin Bot <support+bot@crowdin.com>
2023-01-01 13:32:19 +01:00
sean-brydon 6548f01efa Show admin password top banner (#6226)
* Invalid-admin fake role

* Reset password link + shell
2023-01-01 11:19:58 +00:00
Udit TakkarandPeer Richelsen 518a4484d6 fix: add allowScroll prop (#6215)
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>
2022-12-30 18:16:37 +00:00
Siddhant KhareandPeer Richelsen 3535a25a59 fix: consistency on menu hover border bug 🔧 (#6218)
Signed-off-by: Siddhant Khare <Siddhantkhare2694@gmail.com>

Signed-off-by: Siddhant Khare <Siddhantkhare2694@gmail.com>
Co-authored-by: Peer Richelsen <peeroke@gmail.com>
2022-12-30 18:04:54 +00:00
Stefano Maffeis 06cc6741e6 Make radio field id unique by adding custom input id to their identifier (#6224) 2022-12-30 18:52:03 +01:00
Peer Richelsen ed1478e1ba Update README.md 2022-12-30 10:17:31 +01:00
Jeff Loiselle 854c05d673 fixes required custom radio element on firefox (#6209)
Fixes https://github.com/calcom/cal.com/issues/6160
2022-12-28 19:43:18 +00:00
bcf5fb18c5 Cal Video (Daily) Recording (#6039)
* feat: wip

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

* feat: add download recording button

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

* moved video recording into /ee/, wrapped in LicenseRequired

* fix: security issues in downloading recording
updates designs

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

* feat: add upgradation banner

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

* chore: remove default room

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

* chore: fix type error

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

* fix: add type in get recording

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

* fix: add suggestions and zod type for recording

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

* fix: add types in getRecordings

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: type error

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

* fix: finally all type errors fixed

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

* Server side validation for users in team plans for recordings

* fix: remove any type

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>

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>
Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com>
Co-authored-by: Alan <alannnc@gmail.com>
2022-12-27 21:03:39 +00:00
3f822e814b event type setting refactor (#5959)
Co-authored-by: alannnc <alannnc@gmail.com>
Co-authored-by: zomars <zomars@me.com>
Co-authored-by: Peer Richelsen <peeroke@gmail.com>
2022-12-26 10:55:58 +00:00
Peer Richelsen 4fd25c7215 fixed booking layout (#6188) 2022-12-26 16:11:28 +05:30
github-actions[bot]andCrowdin Bot f42bed2a55 New Crowdin translations by Github Action (#6175)
Co-authored-by: Crowdin Bot <support+bot@crowdin.com>
2022-12-26 11:25:47 +01:00
469c205033 fix: setting sidebar improvements (#6177)
Co-authored-by: Peer Richelsen <peeroke@gmail.com>
Co-authored-by: Peer Richelsen <peer@cal.com>
2022-12-26 11:23:03 +01:00
Nafees Nazik 31551f3b9e fix: button focus (#6178) 2022-12-26 09:44:43 +00:00
Carina WollendorferandCarinaWolli 69925af17c Fix skeleton loader for /workflows (#6172)
* return latest bookings for example bookings for zapier

* remove mt on skeleton loader

* Revert "return latest bookings for example bookings for zapier"

This reverts commit b69f393a73a59a05fe99f01d8caa4ac0fd5cf992.

Co-authored-by: CarinaWolli <wollencarina@gmail.com>
2022-12-23 12:27:40 +00:00
Carina WollendorferandCarinaWolli 2502868ebc Return latest bookings for zapier example bookings (#6170)
Co-authored-by: CarinaWolli <wollencarina@gmail.com>
2022-12-23 12:00:03 +01:00
1126 changed files with 24370 additions and 22195 deletions
+42
View File
@@ -0,0 +1,42 @@
// For format details, see https://aka.ms/devcontainer.json. For config options, see the
// README at: https://github.com/devcontainers/templates/tree/main/src/docker-outside-of-docker
{
"name": "Docker outside of Docker",
// Or use a Dockerfile or Docker Compose file. More info: https://containers.dev/guide/dockerfile
"image": "mcr.microsoft.com/devcontainers/base:bullseye",
"features": {
"ghcr.io/devcontainers/features/docker-from-docker:1": {
"version": "latest",
"enableNonRootDocker": "true",
"moby": "true"
},
"ghcr.io/devcontainers/features/node:1": {},
"ghcr.io/devcontainers-contrib/features/npm-package:1": {},
"ghcr.io/devcontainers-contrib/features/jest:2": {},
"ghcr.io/devcontainers-contrib/features/prisma:2": {},
"ghcr.io/guiyomh/features/vim:0": {}
},
// Use this environment variable if you need to bind mount your local source code into a new container.
"remoteEnv": {
"LOCAL_WORKSPACE_FOLDER": "${localWorkspaceFolder}"
},
"hostRequirements": {
"cpus": 4,
"memory": "8gb"
},
// Use 'postCreateCommand' to run commands after the container is created.
"postCreateCommand": "./deploy/install.sh"
// Use 'forwardPorts' to make a list of ports inside the container available locally.
// "forwardPorts": [],
// Configure tool-specific properties.
// "customizations": {},
// Uncomment to connect as root instead. More info: https://aka.ms/dev-containers-non-root.
// "remoteUser": "root"
}
+22 -5
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=
# ***********************************************************************************************************
@@ -31,11 +32,14 @@ NEXT_PUBLIC_CONSOLE_URL='http://localhost:3004'
NEXT_PUBLIC_EMBED_LIB_URL='http://localhost:3000/embed/embed.js'
# To enable SAML login, set both these variables
# @see https://github.com/calcom/cal.com/tree/main/packages/ee#setting-up-saml-login
# @see https://github.com/calcom/cal.com/tree/main/packages/features/ee#setting-up-saml-login
# SAML_DATABASE_URL="postgresql://postgres:@localhost:5450/cal-saml"
SAML_DATABASE_URL=
# SAML_ADMINS='pro@example.com'
SAML_ADMINS=
# NEXT_PUBLIC_HOSTED_CAL_FEATURES=1
NEXT_PUBLIC_HOSTED_CAL_FEATURES=
# If you use Heroku to deploy Postgres (or use self-signed certs for Postgres) then uncomment the follow line.
# @see https://devcenter.heroku.com/articles/connecting-heroku-postgres#connecting-in-node-js
# PGSSLMODE='no-verify'
@@ -79,6 +83,7 @@ SEND_FEEDBACK_EMAIL=
# Used for email reminders in workflows and internal sync services
SENDGRID_API_KEY=
SENDGRID_EMAIL=
NEXT_PUBLIC_SENDGRID_SENDER_NAME=
# Twilio
# Used to send SMS reminders in workflows
@@ -86,6 +91,7 @@ TWILIO_SID=
TWILIO_TOKEN=
TWILIO_MESSAGING_SID=
TWILIO_PHONE_NUMBER=
# For NEXT_PUBLIC_SENDER_ID only letters, numbers and spaces are allowed (max. 11 characters)
NEXT_PUBLIC_SENDER_ID=
TWILIO_VERIFY_SID=
@@ -102,6 +108,8 @@ STRIPE_TEAM_MONTHLY_PRICE_ID=
STRIPE_WEBHOOK_SECRET=
STRIPE_PRIVATE_KEY=
STRIPE_CLIENT_ID=
PAYMENT_FEE_FIXED=
PAYMENT_FEE_PERCENTAGE=
# Use for internal Public API Keys and optional
API_KEY_PREFIX=cal_
@@ -147,3 +155,12 @@ SENTRY_IGNORE_API_RESOLUTION_ERROR=
NEXT_PUBLIC_APP_NAME="Cal.com"
NEXT_PUBLIC_SUPPORT_MAIL_ADDRESS="help@cal.com"
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=
-6
View File
@@ -1,9 +1,3 @@
"♻️ autoupdate":
- apps/web/public/static/locales/**/*.json
automerge:
- apps/web/public/static/locales/**/*.json
"❗️ migrations":
- packages/prisma/migrations/**/migration.sql
+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
+3
View File
@@ -9,6 +9,8 @@ concurrency:
cancel-in-progress: true
jobs:
required-checks:
uses: calcom/cal.com/.github/workflows/required-checks.yml@main
synchronize-with-crowdin:
runs-on: ubuntu-latest
@@ -21,6 +23,7 @@ jobs:
with:
upload_translations: true
download_translations: true
pull_request_labels: "♻️ autoupdate, automerge"
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
CROWDIN_PROJECT_ID: ${{ secrets.CROWDIN_PROJECT_ID }}
+1
View File
@@ -7,6 +7,7 @@ on:
paths:
- apps/web/**
- packages/embeds/**
workflow_call:
concurrency:
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
cancel-in-progress: true
+2 -3
View File
@@ -1,20 +1,19 @@
name: E2E test
on:
push:
branches: [fixes/e2e-consolidation] # TODO: Remove this after merged in main
pull_request_target: # So we can test on forks
branches:
- main
paths:
- apps/web/**
- packages/**
workflow_call:
concurrency:
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
cancel-in-progress: true
jobs:
e2e:
timeout-minutes: 20
runs-on: ubuntu-latest
runs-on: buildjet-4vcpu-ubuntu-2204
env:
DATABASE_URL: postgresql://postgres:@localhost:5432/calendso
+2
View File
@@ -14,3 +14,5 @@ jobs:
- uses: actions/labeler@v4
with:
repo-token: "${{ secrets.GITHUB_TOKEN }}"
# https://github.com/actions/labeler/issues/442#issuecomment-1297359481
sync-labels: ""
+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
+1 -2
View File
@@ -1,10 +1,9 @@
name: "Meta Workflow: Require Conditional Status Checks"
on:
push:
branches: [fixes/e2e-consolidation] # TODO: Remove this after merged in main
pull_request:
branches:
- main
workflow_call:
concurrency:
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
cancel-in-progress: true
+3 -2
View File
@@ -1,13 +1,14 @@
name: Unit tests
on:
push:
branches: [ feat/routing-forms/reporting ] # TODO: Remove this after merged in main
pull_request_target: # So we can test on forks
branches:
- main
paths:
- apps/web/**
- packages/**
workflow_run:
workflows: [Crowdin Action]
types: [completed]
concurrency:
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
cancel-in-progress: true
+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"]}]'
+10
View File
@@ -77,6 +77,16 @@ lint-results
#Storybook
apps/storybook/build-storybook.log
# Infisical
.infisical.json
# Snaplet
.snaplet/snapshots
.snaplet/structure.d.ts
# Submodules
.gitmodules
apps/api
apps/website
apps/console
apps/auth
-12
View File
@@ -1,12 +0,0 @@
[submodule "apps/console"]
path = apps/console
url = https://github.com/calcom/console.git
branch = main
[submodule "apps/api"]
path = apps/api
url = https://github.com/calcom/api.git
branch = main
[submodule "apps/website"]
path = apps/website
url = https://github.com/calcom/website.git
branch = main
+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
+65 -24
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",
Submodule apps/api deleted from 604d937661
Submodule apps/console deleted from 2d577dd9ed
-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.
+2 -2
View File
@@ -17,7 +17,7 @@
"license": "MIT",
"dependencies": {
"iframe-resizer-react": "^1.1.0",
"next": "^12.3.1",
"next": "^13.1.1",
"nextra": "^1.1.0",
"nextra-theme-docs": "^1.2.2",
"react": "^18.2.0",
@@ -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";
+1 -2
View File
@@ -14,14 +14,13 @@ Cal.com uses [TailwindCSS](https://tailwindcss.com) as a replacement for traditi
CSS files should be stored in the `styles` directory within the codebase.
Within the `styles` directory, you will find two CSS files, `fonts.css` and `global.css`. We suggest not to add to these files, and instead create new CSS files and import them into the application. This helps reduce conflicts when pulling in changes that we've made to either of the existing CSS files.
Within the `styles` directory, you will find a single CSS file, `global.css`. We suggest not to add to this file, and instead create new CSS files and import them into the application. This helps reduce conflicts when pulling in changes that we've made to either of the existing CSS files.
## Adding new stylesheets
Firstly, create the CSS file inside the `styles` directory.
Then, open the `pages/_app.tsx` file, and you will see the following two lines:
```javascript
import "../styles/fonts.css";
import "../styles/globals.css";
```
+3 -3
View File
@@ -31,7 +31,7 @@ All apps can be found under `packages/app-store`. In this folder is `_example` w
| ├──index.ts
| ├──package.json
| ├──.env.example
| ├──README.mdx
| ├──DESCRIPTION.md
```
## Getting Started
@@ -48,9 +48,9 @@ Under the `/components` folder, this is where the install button for your app sh
The `/lib` folder is where the functions of your app live. For example, when creating a booking with a MS Teams link the function to make the call to grab the link lives in the `/lib` folder. Export your endpoints in an `index.ts` file under `/lib` folder and import them in your main `index.ts` file.
On the app store page you can customize your apps description by adding a markdown file called `README.mdx`. If you do not add one then the description from you `package.json` will be used instead.
On the app store page you can customize your apps description by adding a markdown file called `DESCRIPTION.md`. If you do not add one then the description from you `package.json` will be used instead.
The `/static` folder is where you can store your app icon and any images that your `README.mdx` may use.
The `/static` folder is where you can store your app icon and any images that your `DESCRIPTION.md` may use.
## Adding Your App to the App Store
To render your app on the app store page, go to `packages/app-store/index.ts`. Import your app into the file and add it to the `appStore` object.
+2 -1
View File
@@ -8,6 +8,7 @@ pnpm-debug.log*
lerna-debug.log*
node_modules
storybook-static
dist
dist-ssr
*.local
@@ -21,4 +22,4 @@ dist-ssr
*.ntvs*
*.njsproj
*.sln
*.sw?
*.sw?
+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",
});
+4 -2
View File
@@ -11,13 +11,15 @@ module.exports = {
"@storybook/addon-links",
"@storybook/addon-essentials",
"@storybook/addon-interactions",
"storybook-addon-rtl-direction",
"storybook-react-i18next",
{
"storybook-addon-next",
/*{
name: "storybook-addon-next",
options: {
nextConfigPath: path.resolve(__dirname, "../../web/next.config.js"),
},
},
},*/
],
framework: "@storybook/react",
core: {
+7
View File
@@ -0,0 +1,7 @@
import { addons } from "@storybook/addons";
import yourTheme from "./YourTheme";
addons.setConfig({
theme: yourTheme,
});
+45
View File
@@ -0,0 +1,45 @@
const withBundleAnalyzer = require("@next/bundle-analyzer");
const withTM = require("next-transpile-modules")([
"@calcom/app-store",
"@calcom/dayjs",
"@calcom/emails",
"@calcom/trpc",
"@calcom/embed-core",
"@calcom/embed-react",
"@calcom/features",
"@calcom/lib",
"@calcom/prisma",
"@calcom/ui",
]);
const glob = require("glob");
const plugins = [];
plugins.push(withTM, withBundleAnalyzer({ enabled: process.env.ANALYZE === "true" }));
/** @type {import("next").NextConfig} */
const nextConfig = {
reactStrictMode: true,
images: {
domains: ["www.datocms-assets.com"],
formats: ["image/avif", "image/webp"],
},
typescript: {
ignoreBuildErrors: true,
},
experimental: { images: { allowFutureImage: true } },
eslint: {
ignoreDuringBuilds: true,
},
webpack: (config, { isServer }) => {
if (!isServer) {
// don't resolve 'fs' module on the client to prevent this error on build --> Error: Can't resolve 'fs'
config.resolve.fallback = {
fs: false,
};
}
return config;
},
};
module.exports = () => plugins.reduce((acc, next) => next(acc), nextConfig);
+7 -6
View File
@@ -15,14 +15,15 @@
"@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",
"@radix-ui/react-tooltip": "^1.0.0",
"next": "^12.3.1",
"next": "^13.1.1",
"react": "^18.2.0",
"react-dom": "^18.2.0"
"react-dom": "^18.2.0",
"storybook-addon-rtl-direction": "^0.0.19"
},
"devDependencies": {
"@babel/core": "^7.19.6",
@@ -35,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",
@@ -48,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";
}
+4 -4
View File
@@ -14,7 +14,7 @@
"dependencies": {
"highlight.js": "^11.6.0",
"isarray": "2.0.5",
"next": "^12.3.1",
"next": "^13.1.1",
"openapi-snippet": "^0.13.0",
"react": "^18.2.0",
"react-dom": "^18.2.0",
@@ -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 -1
View File
@@ -1 +1 @@
14.17
v16
+2 -2
View File
@@ -1,7 +1,7 @@
import { useState } from "react";
import { useLocale } from "@calcom/lib/hooks/useLocale";
import { Icon } from "@calcom/ui";
import { FiX } from "@calcom/ui/components/icon";
export default function AddToHomescreen() {
const { t } = useLocale();
@@ -40,7 +40,7 @@ export default function AddToHomescreen() {
type="button"
className="-mr-1 flex rounded-md p-2 hover:bg-gray-800 focus:outline-none focus:ring-2 focus:ring-white">
<span className="sr-only">{t("dismiss")}</span>
<Icon.FiX className="h-6 w-6 text-white" aria-hidden="true" />
<FiX className="h-6 w-6 text-white" aria-hidden="true" />
</button>
</div>
</div>
@@ -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";
+93
View File
@@ -0,0 +1,93 @@
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";
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,
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={`${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>
<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>
);
}
-9
View File
@@ -1,9 +0,0 @@
import { Suspense, SuspenseProps } from "react";
/**
* Wrapper around `<Suspense />` which will render the `fallback` when on server
* Can be simply replaced by `<Suspense />` once React 18 is ready.
*/
export const ClientSuspense = (props: SuspenseProps) => {
return <>{typeof window !== "undefined" ? <Suspense {...props} /> : props.fallback}</>;
};
@@ -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 {
+32 -30
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,
Icon,
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";
@@ -488,7 +490,7 @@ const tabs = [
{
name: "HTML",
href: "embedTabName=embed-code",
icon: Icon.FiCode,
icon: FiCode,
type: "code",
Component: forwardRef<
HTMLTextAreaElement | HTMLIFrameElement | null,
@@ -504,7 +506,7 @@ const tabs = [
return (
<>
<div>
<small className="flex py-4 text-neutral-500">
<small className="flex py-4 text-gray-500">
{t("place_where_cal_widget_appear", { appName: APP_NAME })}
</small>
</div>
@@ -541,7 +543,7 @@ ${getEmbedTypeSpecificString({ embedFramework: "HTML", embedType, calLink, previ
{
name: "React",
href: "embedTabName=embed-react",
icon: Icon.FiCode,
icon: FiCode,
type: "code",
Component: forwardRef<
HTMLTextAreaElement | HTMLIFrameElement | null,
@@ -556,7 +558,7 @@ ${getEmbedTypeSpecificString({ embedFramework: "HTML", embedType, calLink, previ
}
return (
<>
<small className="flex py-4 text-neutral-500">{t("create_update_react_component")}</small>
<small className="flex py-4 text-gray-500">{t("create_update_react_component")}</small>
<TextArea
data-testid="embed-react"
ref={ref as typeof ref & MutableRefObject<HTMLTextAreaElement>}
@@ -581,7 +583,7 @@ ${getEmbedTypeSpecificString({ embedFramework: "react", embedType, calLink, prev
{
name: "Preview",
href: "embedTabName=embed-preview",
icon: Icon.FiTrello,
icon: FiTrello,
type: "iframe",
Component: forwardRef<
HTMLIFrameElement | HTMLTextAreaElement | null,
@@ -597,7 +599,7 @@ ${getEmbedTypeSpecificString({ embedFramework: "react", embedType, calLink, prev
<iframe
ref={ref as typeof ref & MutableRefObject<HTMLIFrameElement>}
data-testid="embed-preview"
className="border-1 h-[100vh] border"
className="h-[100vh] border"
width="100%"
height="100%"
src={`${WEBAPP_URL}/embed/preview.html?embedType=${embedType}&calLink=${calLink}`}
@@ -617,7 +619,7 @@ Cal("init", {origin:"${WEBAPP_URL}"});
const ThemeSelectControl = ({ children, ...props }: ControlProps<{ value: Theme; label: string }, false>) => {
return (
<components.Control {...props}>
<Icon.FiSun className="ml-2 h-4 w-4 text-gray-500" />
<FiSun className="ml-2 h-4 w-4 text-gray-500" />
{children}
</components.Control>
);
@@ -639,7 +641,7 @@ const ChooseEmbedTypesDialogContent = () => {
<div className="flex items-start">
{embeds.map((embed, index) => (
<button
className="mr-2 w-1/3 border border-transparent p-3 text-left hover:rounded-md hover:border-gray-200 hover:bg-neutral-100"
className="w-1/3 border border-transparent p-3 text-left hover:rounded-md hover:border-gray-200 hover:bg-gray-100 ltr:mr-2 rtl:ml-2"
key={index}
data-testid={embed.type}
onClick={() => {
@@ -650,7 +652,7 @@ const ChooseEmbedTypesDialogContent = () => {
<div className="order-none box-border flex-none rounded-sm border border-solid bg-white">
{embed.illustration}
</div>
<div className="mt-2 font-medium text-neutral-900">{embed.title}</div>
<div className="mt-2 font-medium text-gray-900">{embed.title}</div>
<p className="text-sm text-gray-500">{embed.subtitle}</p>
</button>
))}
@@ -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,
@@ -815,7 +817,7 @@ const EmbedTypeCodeAndPreviewDialogContent = ({
onClick={() => {
removeQueryParams(router, ["embedType", "embedTabName"]);
}}>
<Icon.FiArrowLeft className="mr-4 w-4" />
<FiArrowLeft className="mr-4 w-4" />
</button>
{embed.title}
</h3>
@@ -827,7 +829,7 @@ const EmbedTypeCodeAndPreviewDialogContent = ({
onOpenChange={() => setIsEmbedCustomizationOpen((val) => !val)}>
<CollapsibleTrigger
type="button"
className="flex w-full items-center text-base font-medium text-neutral-900">
className="flex w-full items-center text-base font-medium text-gray-900">
<div>
{embedType === "inline"
? "Inline Embed Customization"
@@ -835,10 +837,10 @@ const EmbedTypeCodeAndPreviewDialogContent = ({
? "Floating Popup Customization"
: "Element Click Customization"}
</div>
<Icon.FiChevronRight
<FiChevronRight
className={`${
isEmbedCustomizationOpen ? "rotate-90 transform" : ""
} ml-auto h-5 w-5 text-neutral-500`}
} ml-auto h-5 w-5 text-gray-500`}
/>
</CollapsibleTrigger>
<CollapsibleContent className="text-sm">
@@ -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>
@@ -914,7 +916,7 @@ const EmbedTypeCodeAndPreviewDialogContent = ({
<div
className={classNames(
"mt-4 flex items-center justify-start",
embedType === "floating-popup" ? "space-x-2" : "hidden"
embedType === "floating-popup" ? "space-x-2 rtl:space-x-reverse" : "hidden"
)}>
<Switch
defaultChecked={true}
@@ -1001,16 +1003,16 @@ const EmbedTypeCodeAndPreviewDialogContent = ({
open={isBookingCustomizationOpen}
onOpenChange={() => setIsBookingCustomizationOpen((val) => !val)}>
<CollapsibleTrigger className="flex w-full" type="button">
<div className="text-base font-medium text-neutral-900">Cal Booking Customization</div>
<Icon.FiChevronRight
<div className="text-base font-medium text-gray-900">Cal Booking Customization</div>
<FiChevronRight
className={`${
isBookingCustomizationOpen ? "rotate-90 transform" : ""
} ml-auto h-5 w-5 text-neutral-500`}
} ml-auto h-5 w-5 text-gray-500`}
/>
</CollapsibleTrigger>
<CollapsibleContent>
<div className="mt-6 text-sm">
<div className="mb-4 flex items-center justify-start space-x-2">
<div className="mb-4 flex items-center justify-start space-x-2 rtl:space-x-reverse">
<Switch
checked={previewState.hideEventTypeDetails}
onCheckedChange={(checked) => {
@@ -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,
});
}}
/>
@@ -1163,7 +1165,7 @@ export const EmbedButton = <T extends React.ElementType>({
...props
}: EmbedButtonProps<T> & React.ComponentPropsWithoutRef<T>) => {
const router = useRouter();
className = classNames(className, "hidden lg:inline-flex");
className = classNames("hidden lg:inline-flex", className);
const openEmbedModal = () => {
goto(router, {
dialog: "embed",
+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"`
+6 -1
View File
@@ -1,6 +1,7 @@
import { useTranslation } from "next-i18next";
import { useEffect } from "react";
import { getDirFromLang } from "@calcom/lib/i18n";
import { trpc } from "@calcom/trpc/react";
export function useViewerI18n() {
@@ -21,12 +22,16 @@ export function useViewerI18n() {
*/
const I18nLanguageHandler = (): null => {
const { i18n } = useTranslation("common");
const locale = useViewerI18n().data?.locale;
const locale = useViewerI18n().data?.locale || "en";
useEffect(() => {
if (locale && i18n.language && i18n.language !== locale) {
if (typeof i18n.changeLanguage === "function") i18n.changeLanguage(locale);
}
const dir = getDirFromLang(locale);
document.documentElement.setAttribute("lang", locale);
document.documentElement.setAttribute("dir", dir);
}, [locale, i18n]);
return null;
+6 -4
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";
@@ -142,7 +144,7 @@ export default function ImageUploader({
</div>
)}
{result && <CropContainer imageSrc={result as string} onCropComplete={setCroppedAreaPixels} />}
<label className="mt-8 rounded-sm border border-gray-300 bg-white px-3 py-1 text-xs font-medium leading-4 text-gray-700 hover:bg-gray-50 hover:text-gray-900 focus:outline-none focus:ring-2 focus:ring-neutral-900 focus:ring-offset-1 dark:border-gray-800 dark:bg-transparent dark:text-white dark:hover:bg-gray-900">
<label className="mt-8 rounded-sm border border-gray-300 bg-white px-3 py-1 text-xs font-medium leading-4 text-gray-700 hover:bg-gray-50 hover:text-gray-900 focus:outline-none focus:ring-2 focus:ring-gray-900 focus:ring-offset-1 dark:border-gray-800 dark:bg-transparent dark:text-white dark:hover:bg-gray-900">
<input
onInput={onInputFile}
type="file"
+8 -6
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: {
@@ -62,12 +64,12 @@ const NavTabs: FC<NavTabProps> = ({ tabs, linkProps, ...props }) => {
const className = tab.className || "";
return (
<Component key={tab.name}>
<Link key={tab.name} href={href} {...linkProps}>
<Link key={tab.name} href={href} {...linkProps} legacyBehavior>
<a
onClick={onClick}
className={classNames(
isCurrent
? "border-neutral-900 text-neutral-900"
? "border-gray-900 text-gray-900"
: "border-transparent text-gray-500 hover:border-gray-300 hover:text-gray-700",
"group inline-flex items-center border-b-2 py-4 px-1 text-sm font-medium",
className
@@ -76,7 +78,7 @@ const NavTabs: FC<NavTabProps> = ({ tabs, linkProps, ...props }) => {
{tab.icon && (
<tab.icon
className={classNames(
isCurrent ? "text-neutral-900" : "text-gray-400 group-hover:text-gray-500",
isCurrent ? "text-gray-900" : "text-gray-400 group-hover:text-gray-500",
"-ml-0.5 hidden h-4 w-4 ltr:mr-2 rtl:ml-2 sm:inline-block"
)}
aria-hidden="true"
+11 -8
View File
@@ -1,6 +1,9 @@
import React, { ComponentProps } from "react";
import type { ComponentProps } from "react";
import React from "react";
import { ErrorBoundary, Icon, Shell } from "@calcom/ui";
import Shell from "@calcom/features/shell/Shell";
import { ErrorBoundary } from "@calcom/ui";
import { FiCreditCard, FiKey, FiLock, FiTerminal, FiUser, FiUsers } from "@calcom/ui/components/icon";
import NavTabs from "./NavTabs";
@@ -8,32 +11,32 @@ const tabs = [
{
name: "profile",
href: "/settings/profile",
icon: Icon.FiUser,
icon: FiUser,
},
{
name: "teams",
href: "/settings/teams",
icon: Icon.FiUsers,
icon: FiUsers,
},
{
name: "security",
href: "/settings/security",
icon: Icon.FiKey,
icon: FiKey,
},
{
name: "developer",
href: "/settings/developer",
icon: Icon.FiTerminal,
icon: FiTerminal,
},
{
name: "billing",
href: "/settings/billing",
icon: Icon.FiCreditCard,
icon: FiCreditCard,
},
{
name: "admin",
href: "/settings/admin",
icon: Icon.FiLock,
icon: FiLock,
adminRequired: true,
},
];
@@ -1,10 +1,11 @@
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";
import { trpc } from "@calcom/trpc/react";
import type { App } from "@calcom/types/App";
import { Button, Icon, Select } from "@calcom/ui";
import { Button, Select } from "@calcom/ui";
import { FiPlus } from "@calcom/ui/components/icon";
import { QueryCell } from "@lib/QueryCell";
@@ -31,7 +32,7 @@ const ImageOption = (optionProps: OptionProps<{ [key: string]: string; type: App
/>
) : (
<Button className="w-full" color="minimal" href="/apps/categories/calendar">
<Icon.FiPlus className="text-color mr-3 ml-1 h-4 w-4" />
<FiPlus className="text-color mr-3 ml-1 h-4 w-4" />
<p>{t("install_new_calendar_app")}</p>
</Button>
);
@@ -61,7 +62,7 @@ const AdditionalCalendarSelector = ({ isLoading }: AdditionalCalendarSelectorPro
<Select
name="additionalCalendar"
placeholder={
<Button StartIcon={Icon.FiPlus} color="secondary">
<Button StartIcon={FiPlus} color="secondary">
{t("add")}
</Button>
}
+34 -20
View File
@@ -6,14 +6,23 @@ import useAddAppMutation from "@calcom/app-store/_utils/useAddAppMutation";
import { InstallAppButton } from "@calcom/app-store/components";
import DisconnectIntegration from "@calcom/features/apps/components/DisconnectIntegration";
import LicenseRequired from "@calcom/features/ee/common/components/v2/LicenseRequired";
import Shell from "@calcom/features/shell/Shell";
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 { Button, Icon, Shell, showToast, SkeletonButton, SkeletonText } from "@calcom/ui";
import HeadSeo from "@components/seo/head-seo";
import type { App as AppType } from "@calcom/types/App";
import { Button, showToast, SkeletonButton, SkeletonText, HeadSeo, Badge } from "@calcom/ui";
import {
FiBookOpen,
FiCheck,
FiExternalLink,
FiFile,
FiFlag,
FiMail,
FiPlus,
FiShield,
} from "@calcom/ui/components/icon";
const Component = ({
name,
@@ -35,6 +44,7 @@ const Component = ({
privacy,
isProOnly,
images,
isTemplate,
}: Parameters<typeof App>[0]) => {
const { t } = useLocale();
const hasImages = images && images.length > 0;
@@ -100,18 +110,25 @@ const Component = ({
<h1 className="font-cal ml-4 text-3xl text-gray-900">{name}</h1>
</div>
<h2 className="text-sm font-medium text-gray-600">
<Link href={`categories/${categories[0]}`}>
<a className="rounded-md bg-gray-100 p-1 text-xs capitalize text-gray-800">{categories[0]}</a>
<Link
href={`categories/${categories[0]}`}
className="rounded-md bg-gray-100 p-1 text-xs capitalize text-gray-800">
{categories[0]}
</Link>{" "}
• {t("published_by", { author })}
</h2>
{isTemplate && (
<Badge variant="red" className="mt-4">
Template - Available in Dev Environment only for testing
</Badge>
)}
</header>
</div>
{!appCredentials.isLoading ? (
isGlobal ||
(existingCredentials.length > 0 && allowedMultipleInstalls ? (
<div className="flex space-x-3">
<Button StartIcon={Icon.FiCheck} color="secondary" disabled>
<Button StartIcon={FiCheck} color="secondary" disabled>
{existingCredentials.length > 0
? t("active_install", { count: existingCredentials.length })
: t("default")}
@@ -132,7 +149,7 @@ const Component = ({
}
return (
<Button
StartIcon={Icon.FiPlus}
StartIcon={FiPlus}
{...props}
// @TODO: Overriding color and size prevent us from
// having to duplicate InstallAppButton for now.
@@ -193,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 ? (
@@ -219,7 +236,7 @@ const Component = ({
rel="noreferrer"
className="text-sm font-normal text-black no-underline hover:underline"
href={docs}>
<Icon.FiBookOpen className="mr-1 -mt-1 inline h-4 w-4 text-gray-500" />
<FiBookOpen className="mr-1 -mt-1 inline h-4 w-4 text-gray-500" />
{t("documentation")}
</a>
</li>
@@ -231,7 +248,7 @@ const Component = ({
rel="noreferrer"
className="font-normal text-black no-underline hover:underline"
href={website}>
<Icon.FiExternalLink className="mr-1 -mt-px inline h-4 w-4 text-gray-500" />
<FiExternalLink className="mr-1 -mt-px inline h-4 w-4 text-gray-500" />
{website.replace("https://", "")}
</a>
</li>
@@ -243,7 +260,7 @@ const Component = ({
rel="noreferrer"
className="font-normal text-black no-underline hover:underline"
href={"mailto:" + email}>
<Icon.FiMail className="mr-1 -mt-px inline h-4 w-4 text-gray-500" />
<FiMail className="mr-1 -mt-px inline h-4 w-4 text-gray-500" />
{email}
</a>
@@ -256,7 +273,7 @@ const Component = ({
rel="noreferrer"
className="font-normal text-black no-underline hover:underline"
href={tos}>
<Icon.FiFile className="mr-1 -mt-px inline h-4 w-4 text-gray-500" />
<FiFile className="mr-1 -mt-px inline h-4 w-4 text-gray-500" />
{t("terms_of_service")}
</a>
</li>
@@ -268,7 +285,7 @@ const Component = ({
rel="noreferrer"
className="font-normal text-black no-underline hover:underline"
href={privacy}>
<Icon.FiShield className="mr-1 -mt-px inline h-4 w-4 text-gray-500" />
<FiShield className="mr-1 -mt-px inline h-4 w-4 text-gray-500" />
{t("privacy_policy")}
</a>
</li>
@@ -279,7 +296,7 @@ const Component = ({
{t("every_app_published", { appName: APP_NAME, companyName: COMPANY_NAME })}
</span>
<a className="mt-2 block text-xs text-red-500" href={`mailto:${SUPPORT_MAIL_ADDRESS}`}>
<Icon.FiFlag className="inline h-3 w-3" /> {t("report_app")}
<FiFlag className="inline h-3 w-3" /> {t("report_app")}
</a>
</div>
</div>
@@ -309,19 +326,16 @@ export default function App(props: {
licenseRequired: AppType["licenseRequired"];
isProOnly: AppType["isProOnly"];
images?: string[];
isTemplate?: boolean;
}) {
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>
@@ -11,18 +11,18 @@ import {
Alert,
Button,
EmptyScreen,
Icon,
List,
ShellSubHeading,
showToast,
SkeletonLoader,
AppSkeletonLoader as SkeletonLoader,
Switch,
ShellSubHeading,
} from "@calcom/ui";
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 = {
@@ -100,7 +100,7 @@ function CalendarSwitch(props: {
/>
{!!props.destination && (
<span className="ml-4 inline-flex items-center gap-1 rounded-md bg-gray-100 px-2 py-1 text-sm font-normal text-gray-800">
<Icon.FiArrowLeft className="h-4 w-4" />
<FiArrowLeft className="h-4 w-4" />
{t("adding_events_to")}
</span>
)}
@@ -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
@@ -184,9 +184,7 @@ function ConnectedCalendarsList(props: Props) {
<div className="border-t border-gray-200">
{!fromOnboarding && (
<>
<p className="px-4 pt-4 text-sm text-neutral-500">
{t("toggle_calendars_conflict")}
</p>
<p className="px-4 pt-4 text-sm text-gray-500">{t("toggle_calendars_conflict")}</p>
<ul className="space-y-2 p-4">
{item.calendars.map((cal) => (
<CalendarSwitch
@@ -202,7 +200,7 @@ function ConnectedCalendarsList(props: Props) {
</>
)}
</div>
</IntegrationListItem>
</AppListCard>
) : (
<Alert
severity="warning"
@@ -284,8 +282,8 @@ export function CalendarListContainer(props: { heading?: boolean; fromOnboarding
<div className="flex justify-between rounded-md border border-gray-200 bg-gray-50 p-4">
<div className="flex w-full flex-col items-start gap-4 md:flex-row md:items-center">
<div className="relative rounded-md border border-gray-200 bg-white p-1.5">
<Icon.FiCalendar className="h-8 w-8" strokeWidth="1" />
<Icon.FiPlus
<FiCalendar className="h-8 w-8" strokeWidth="1" />
<FiPlus
className="absolute left-4 top-1/2 ml-0.5 mt-[1px] h-2 w-2 text-black"
strokeWidth="4"
/>
@@ -324,13 +322,16 @@ export function CalendarListContainer(props: { heading?: boolean; fromOnboarding
</>
) : (
<EmptyScreen
Icon={Icon.FiCalendar}
Icon={FiCalendar}
headline={t("no_category_apps", {
category: t("calendar").toLowerCase(),
})}
description={t(`no_category_apps_description_calendar`)}
buttonRaw={
<Button color="secondary" href="/apps/categories/calendar">
<Button
color="secondary"
data-testid="connect-calendar-apps"
href="/apps/categories/calendar">
{t(`connect_calendar_apps`)}
</Button>
}
@@ -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,74 +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 { Icon, ListItem, ListItemText, ListItemTitle, showToast } from "@calcom/ui";
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;
}): 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">
<Link href={"/apps/" + props.slug}>{props.name || title}</Link>
</ListItemTitle>
<ListItemText component="p">{props.description}</ListItemText>
{/* Alert error that key stopped working. */}
{props.invalidCredential && (
<div className="flex items-center space-x-2">
<Icon.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,24 +1,12 @@
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";
import { EmptyScreen, Icon } from "@calcom/ui";
import Shell from "../Shell";
import type { HorizontalTabItemProps } from "../navigation/tabs/HorizontalTabItem";
import HorizontalTabs from "../navigation/tabs/HorizontalTabs";
const tabs: HorizontalTabItemProps[] = [
{
name: "app_store",
href: "/apps",
},
{
name: "installed_apps",
href: "/apps/installed",
},
];
import { EmptyScreen } from "@calcom/ui";
import { FiAlertCircle } from "@calcom/ui/components/icon";
type AppsLayoutProps = {
children: React.ReactNode;
@@ -34,15 +22,12 @@ export default function AppsLayout({ children, actions, emptyStore, ...rest }: A
if (session.status === "loading") return <></>;
return (
<Shell {...rest} actions={actions?.("hidden sm:block")}>
<Shell {...rest} actions={actions?.("block")}>
<div className="flex flex-col xl:flex-row">
<div className="block lg:hidden">
<HorizontalTabs tabs={tabs} actions={actions?.("ml-6 mr-4 mt-3 block sm:hidden")} />
</div>
<main className="w-full">
{emptyStore ? (
<EmptyScreen
Icon={Icon.FiAlertCircle}
Icon={FiAlertCircle}
headline={t("no_apps")}
description={session.data?.user.role === "ADMIN" ? "You can enable apps in the settings" : ""}
buttonText={session.data?.user.role === "ADMIN" ? t("apps_settings") : ""}
@@ -1,44 +1,43 @@
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 { Icon } from "../../../Icon";
import Shell from "../Shell";
import type { HorizontalTabItemProps } from "../navigation/tabs/HorizontalTabItem";
import type { VerticalTabItemProps } from "../navigation/tabs/VerticalTabItem";
import type { HorizontalTabItemProps, VerticalTabItemProps } from "@calcom/ui";
import { FiBarChart, FiCalendar, FiCreditCard, FiGrid, FiShare2, FiVideo } from "@calcom/ui/components/icon";
const tabs: (VerticalTabItemProps | HorizontalTabItemProps)[] = [
{
name: "calendar",
href: "/apps/installed/calendar",
icon: Icon.FiCalendar,
icon: FiCalendar,
},
{
name: "conferencing",
href: "/apps/installed/conferencing",
icon: Icon.FiVideo,
icon: FiVideo,
},
{
name: "payment",
href: "/apps/installed/payment",
icon: Icon.FiCreditCard,
icon: FiCreditCard,
},
{
name: "automation",
href: "/apps/installed/automation",
icon: Icon.FiShare2,
icon: FiShare2,
},
{
name: "analytics",
href: "/apps/installed/analytics",
icon: Icon.FiBarChart,
icon: FiBarChart,
},
{
name: "other",
href: "/apps/installed/other",
icon: Icon.FiGrid,
icon: FiGrid,
},
];
@@ -46,20 +45,20 @@ export default function InstalledAppsLayout({
children,
...rest
}: { children: React.ReactNode } & ComponentProps<typeof Shell>) {
const variant: (typeof InstalledAppVariants)[number] = "payment";
const query = trpc.viewer.integrations.useQuery({
variant: InstalledAppVariants.payment,
variant,
onlyInstalled: true,
});
let actualTabs = tabs;
if (query.data?.items.length === 0) {
actualTabs = tabs.filter((tab) => tab.name !== InstalledAppVariants.payment);
actualTabs = tabs.filter((tab) => tab.name !== variant);
}
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,14 +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 ErrorBoundary from "../../../ErrorBoundary";
import Shell from "../Shell";
import SettingsLayout from "./SettingsLayout";
import { UserPermissionRole } from ".prisma/client";
import SettingsLayout from "@calcom/features/settings/layouts/SettingsLayout";
import type Shell from "@calcom/features/shell/Shell";
import { ErrorBoundary } from "@calcom/ui";
export default function AdminLayout({
children,
...rest
}: { children: React.ReactNode } & ComponentProps<typeof Shell>) {
const session = useSession();
@@ -21,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>
@@ -6,7 +6,7 @@ import classNames from "@lib/classNames";
function SkeletonLoader() {
return (
<ul className="animate-pulse divide-y divide-neutral-200 rounded-md border border-gray-200 bg-white sm:mx-0 sm:overflow-hidden">
<ul className="animate-pulse divide-y divide-gray-200 rounded-md border border-gray-200 bg-white sm:mx-0 sm:overflow-hidden">
<SkeletonItem />
<SkeletonItem />
<SkeletonItem />
@@ -1,34 +1,38 @@
import { getEventLocationType, locationKeyToString } from "@calcom/app-store/locations";
import { classNames } from "@calcom/lib";
import { Icon, Tooltip } from "@calcom/ui";
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" ? (
<Icon.FiLink className="dark:text-darkgray-600 mr-[10px] ml-[2px] h-4 w-4 opacity-70 dark:opacity-100 " />
<FiLink className="dark:text-darkgray-600 ml-[2px] h-4 w-4 opacity-70 ltr:mr-[10px] rtl:ml-[10px] dark:opacity-100 " />
) : (
<img
src={eventLocationType.iconUrl}
className={classNames(
"mr-[10px] ml-[2px] h-4 w-4 opacity-70 dark:opacity-100 ",
!eventLocationType.iconUrl?.includes("api") ? "dark:invert" : ""
"ml-[2px] h-4 w-4 opacity-70 ltr:mr-[10px] rtl:ml-[10px] dark:opacity-100 ",
!eventLocationType.iconUrl?.includes("api") ? "dark:invert-[.65]" : ""
)}
alt={`${eventLocationType.label} icon`}
/>
)}
<Tooltip content={locationKeyToString(location)}>
<p className="truncate">{locationKeyToString(location)}</p>
<Tooltip content={t(locationKeyToString(location) ?? "")}>
<p className="truncate">{t(locationKeyToString(location) ?? "")}</p>
</Tooltip>
</div>
);
+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="-mb-5 grid flex-grow grid-cols-1 gap-x-2 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,
},
};
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}>
<a
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 mb-2 block rounded-md border bg-white py-2 text-sm font-medium dark:border-transparent dark:text-neutral-200",
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>
)}
</a>
</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,10 +1,12 @@
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 { Icon, Badge } from "@calcom/ui";
import { Badge } from "@calcom/ui";
import { FiCheckSquare, FiClock, FiInfo } from "@calcom/ui/components/icon";
import useRouterQuery from "@lib/hooks/useRouterQuery";
@@ -76,7 +78,7 @@ const BookingDescription: FC<Props> = (props) => {
profile={profile}
users={eventType.users}
showMembers={eventType.schedulingType !== SchedulingType.ROUND_ROBIN}
size={10}
size="sm"
truncateAfter={3}
/>
<h2 className="mt-2 break-words text-sm font-medium text-gray-600 dark:text-gray-300">
@@ -93,9 +95,9 @@ const BookingDescription: FC<Props> = (props) => {
isBookingPage && "dark:text-darkgray-600 text-sm font-medium text-gray-600"
)}>
<div>
<Icon.FiInfo
<FiInfo
className={classNames(
"mr-[10px] ml-[2px] inline-block h-4 w-4",
"ml-[2px] inline-block h-4 w-4 ltr:mr-[10px] rtl:ml-[10px]",
isBookingPage && "dark:text-darkgray-600 -mt-1 text-gray-500"
)}
/>
@@ -112,7 +114,7 @@ const BookingDescription: FC<Props> = (props) => {
isBookingPage && "dark:text-darkgray-600 text-sm font-medium text-gray-600"
)}>
<div>
<Icon.FiCheckSquare className="mr-[10px] ml-[2px] inline-block h-4 w-4 " />
<FiCheckSquare className="ml-[2px] inline-block h-4 w-4 ltr:mr-[10px] rtl:ml-[10px] " />
</div>
{requiresConfirmationText}
</div>
@@ -123,11 +125,12 @@ const BookingDescription: FC<Props> = (props) => {
<div
className={classNames(
"flex flex-nowrap text-sm font-medium",
isBookingPage && "dark:text-darkgray-600 text-gray-600"
isBookingPage && "dark:text-darkgray-600 text-gray-600",
!eventType.metadata?.multipleDuration && "items-center"
)}>
<Icon.FiClock
<FiClock
className={classNames(
"min-h-4 min-w-4 mr-[10px] ml-[2px] inline-block",
"min-h-4 min-w-4 ml-[2px] inline-block ltr:mr-[10px] rtl:ml-[10px]",
isBookingPage && "mt-[2px]"
)}
/>
+58 -35
View File
@@ -2,13 +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,
@@ -16,14 +20,13 @@ import {
DialogClose,
DialogContent,
DialogFooter,
DialogHeader,
Icon,
MeetingTimeInTimezones,
showToast,
TextArea,
Tooltip,
TableActions,
TextAreaField,
} from "@calcom/ui";
import { ActionType, TableActions } from "@calcom/ui";
import { FiCheck, FiClock, FiMapPin, FiRefreshCcw, FiSend, FiSlash, FiX } from "@calcom/ui/components/icon";
import useMeQuery from "@lib/hooks/useMeQuery";
@@ -48,9 +51,10 @@ function BookingListItem(booking: BookingItemProps) {
const router = useRouter();
const [rejectionReason, setRejectionReason] = useState<string>("");
const [rejectionDialogIsOpen, setRejectionDialogIsOpen] = useState(false);
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 {
@@ -97,7 +101,7 @@ function BookingListItem(booking: BookingItemProps) {
onClick: () => {
setRejectionDialogIsOpen(true);
},
icon: Icon.FiSlash,
icon: FiSlash,
disabled: mutation.isLoading,
},
{
@@ -106,12 +110,23 @@ function BookingListItem(booking: BookingItemProps) {
onClick: () => {
bookingConfirm(true);
},
icon: Icon.FiCheck,
icon: FiCheck,
disabled: mutation.isLoading,
color: "primary",
},
];
const showRecordingActions: ActionType[] = [
{
id: "view_recordings",
label: t("view_recordings"),
onClick: () => {
setViewRecordingsDialogIsOpen(true);
},
disabled: mutation.isLoading,
},
];
let bookedActions: ActionType[] = [
{
id: "cancel",
@@ -121,7 +136,7 @@ function BookingListItem(booking: BookingItemProps) {
href: `/booking/${booking.uid}?cancel=true${
isTabRecurring && isRecurring ? "&allRemainingBookings=true" : ""
}`,
icon: Icon.FiX,
icon: FiX,
},
{
id: "edit_booking",
@@ -129,13 +144,13 @@ function BookingListItem(booking: BookingItemProps) {
actions: [
{
id: "reschedule",
icon: Icon.FiClock,
icon: FiClock,
label: t("reschedule_booking"),
href: `/reschedule/${booking.uid}`,
},
{
id: "reschedule_request",
icon: Icon.FiSend,
icon: FiSend,
iconClassName: "rotate-45 w-[16px] -translate-x-0.5 ",
label: t("send_reschedule_request"),
onClick: () => {
@@ -148,7 +163,7 @@ function BookingListItem(booking: BookingItemProps) {
onClick: () => {
setIsOpenLocationDialog(true);
},
icon: Icon.FiMapPin,
icon: FiMapPin,
},
],
},
@@ -165,7 +180,7 @@ function BookingListItem(booking: BookingItemProps) {
const RequestSentMessage = () => {
return (
<div className="ml-1 mr-8 flex text-gray-500" data-testid="request_reschedule_sent">
<Icon.FiSend className="-mt-[1px] w-4 rotate-45" />
<FiSend className="-mt-[1px] w-4 rotate-45" />
<p className="ml-2 ">{t("reschedule_request_sent")}</p>
</div>
);
@@ -206,7 +221,8 @@ function BookingListItem(booking: BookingItemProps) {
},
});
};
const showRecordingsButtons =
(booking.location === "integrations:daily" || booking?.location?.trim() === "") && isPast && isConfirmed;
return (
<>
<RescheduleDialog
@@ -220,27 +236,33 @@ function BookingListItem(booking: BookingItemProps) {
isOpenDialog={isOpenSetLocationDialog}
setShowLocationModal={setIsOpenLocationDialog}
/>
{showRecordingsButtons && (
<ViewRecordingsDialog
booking={booking}
isOpenDialog={viewRecordingsDialogIsOpen}
setIsOpenDialog={setViewRecordingsDialogIsOpen}
timeFormat={user?.timeFormat ?? null}
/>
)}
{/* 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={() => {
@@ -252,7 +274,7 @@ function BookingListItem(booking: BookingItemProps) {
</DialogContent>
</Dialog>
<tr className="group flex flex-col hover:bg-neutral-50 sm:flex-row">
<tr className="group flex flex-col hover:bg-gray-50 sm:flex-row">
<td
className="hidden align-top ltr:pl-6 rtl:pr-6 sm:table-cell sm:min-w-[12rem]"
onClick={onClickTableData}>
@@ -335,14 +357,14 @@ function BookingListItem(booking: BookingItemProps) {
<div
title={booking.title}
className={classNames(
"max-w-10/12 sm:max-w-56 text-sm font-medium leading-6 text-neutral-900 md:max-w-full",
"max-w-10/12 sm:max-w-56 text-sm font-medium leading-6 text-gray-900 md:max-w-full",
isCancelled ? "line-through" : ""
)}>
{booking.title}
<span> </span>
{!!booking?.eventType?.price && !booking.paid && (
<Badge className="hidden ltr:ml-2 rtl:mr-2 sm:inline-flex" variant="orange">
<Badge className="hidden ltr:ml-2 ltr:mr-2 rtl:ml-2 sm:inline-flex" variant="orange">
{t("pending_payment")}
</Badge>
)}
@@ -377,6 +399,7 @@ function BookingListItem(booking: BookingItemProps) {
</>
) : null}
{isPast && isPending && !isConfirmed ? <TableActions actions={bookedActions} /> : null}
{showRecordingsButtons && <TableActions actions={showRecordingActions} />}
{isCancelled && booking.rescheduled && (
<div className="hidden h-full items-center md:flex">
<RequestSentMessage />
@@ -432,7 +455,7 @@ const RecurringBookingsTooltip = ({ booking, recurringDates }: RecurringBookings
);
})}>
<div className="text-gray-600 dark:text-white">
<Icon.FiRefreshCcw
<FiRefreshCcw
strokeWidth="3"
className="float-left mr-1 mt-1.5 inline-block h-3 w-3 text-gray-400"
/>
@@ -5,7 +5,8 @@ import { useLocale } from "@calcom/lib/hooks/useLocale";
import useTheme from "@calcom/lib/hooks/useTheme";
import { collectPageParameters, telemetryEventTypes, useTelemetry } from "@calcom/lib/telemetry";
import type { RecurringEvent } from "@calcom/types/Calendar";
import { Button, Icon, TextArea } from "@calcom/ui";
import { Button, TextArea } from "@calcom/ui";
import { FiX } from "@calcom/ui/components/icon";
type Props = {
booking: {
@@ -28,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"));
@@ -39,7 +40,7 @@ export default function CancelBooking(props: Props) {
{error && (
<div className="mt-8">
<div className="mx-auto flex h-12 w-12 items-center justify-center rounded-full bg-red-100">
<Icon.FiX className="h-6 w-6 text-red-600" />
<FiX className="h-6 w-6 text-red-600" />
</div>
<div className="mt-3 text-center sm:mt-5">
<h3 className="text-lg font-medium leading-6 text-gray-900" id="modal-title">
@@ -55,7 +56,7 @@ export default function CancelBooking(props: Props) {
placeholder={t("cancellation_reason_placeholder")}
value={cancellationReason}
onChange={(e) => setCancellationReason(e.target.value)}
className="mt-2 mb-4 w-full dark:border-gray-900 dark:bg-gray-700 dark:text-white "
className="dark:bg-darkgray-100 dark:border-darkgray-400 mt-2 mb-4 w-full dark:text-white "
rows={3}
/>
<div className="flex flex-col-reverse rtl:space-x-reverse ">
@@ -4,7 +4,7 @@ import { SkeletonText } from "@calcom/ui";
function SkeletonLoader() {
return (
<ul className="animate-pulse divide-y divide-neutral-200 rounded-md border border-gray-200 bg-white sm:overflow-hidden">
<ul className="animate-pulse divide-y divide-gray-200 rounded-md border border-gray-200 bg-white sm:overflow-hidden">
<SkeletonItem />
<SkeletonItem />
<SkeletonItem />
+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>
</>
);
}
+3 -4
View File
@@ -1,6 +1,6 @@
import { CAL_URL } from "@calcom/lib/constants";
import AvatarGroup, { AvatarGroupProps } from "@components/ui/AvatarGroup";
import type { AvatarGroupProps } from "@calcom/ui";
import { AvatarGroup } from "@calcom/ui";
export const UserAvatars = ({
profile,
@@ -14,7 +14,6 @@ export const UserAvatars = ({
const showMembers = !users.find((user) => user.name === profile.name) && props.showMembers;
return (
<AvatarGroup
border="border-2 dark:border-darkgray-100 border-white"
items={
[
{
@@ -38,7 +37,7 @@ export const UserAvatars = ({
href?: string;
}[]
}
size={props.size}
size="sm"
truncateAfter={props.truncateAfter}
/>
);
@@ -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 { Icon } from "@calcom/ui";
import { HeadSeo } from "@calcom/ui";
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 { HeadSeo } from "@components/seo/head-seo";
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">
<Icon.FiGlobe className="min-h-4 min-w-4 mr-[10px] ml-[2px] -mt-[2px] inline-block" />
{timeZone}
{isTimeOptionsOpen ? (
<Icon.FiChevronUp className="min-h-4 min-w-4 ml-1 inline-block" />
) : (
<Icon.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(
@@ -368,7 +174,7 @@ const AvailabilityPage = ({ profile, eventType, ...restProps }: Props) => {
<BookingDescription profile={profile} eventType={eventType} rescheduleUid={rescheduleUid}>
{!rescheduleUid && eventType.recurringEvent && (
<div className="flex items-start text-sm font-medium">
<Icon.FiRefreshCcw className="float-left mr-[10px] mt-[7px] ml-[2px] inline-block h-4 w-4 " />
<FiRefreshCcw className="float-left mt-[7px] ml-[2px] inline-block h-4 w-4 ltr:mr-[10px] rtl:ml-[10px] " />
<div>
<p className="mb-1 -ml-2 inline px-2 py-1">
{getRecurringFreq({ t, recurringEvent: eventType.recurringEvent })}
@@ -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">
<Icon.FiCreditCard className="mr-[10px] ml-[2px] -mt-1 inline-block h-4 w-4" />
<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>
@@ -414,7 +220,7 @@ const AvailabilityPage = ({ profile, eventType, ...restProps }: Props) => {
{t("former_time")}
</p>
<p className="text-gray-500 line-through dark:text-darkgray-600">
<CalendarIcon className="mr-[10px] -mt-1 inline-block h-4 w-4 text-gray-500" />
<CalendarIcon className="ltr:mr-[10px] rtl:ml-[10px] -mt-1 inline-block h-4 w-4 text-gray-500" />
{typeof booking.startTime === "string" && parseDate(dayjs(booking.startTime), i18n)}
</p>
</div>
+178 -109
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,14 +33,34 @@ 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, Icon, PhoneInput, Tooltip } from "@calcom/ui";
import { Group, RadioField } from "@calcom/ui";
import {
AddressInput,
Button,
EmailField,
EmailInput,
Form,
Group,
PhoneInput,
RadioField,
Tooltip,
} from "@calcom/ui";
import {
FiUserPlus,
FiCalendar,
FiX,
FiInfo,
FiCreditCard,
FiRefreshCw,
FiUser,
FiAlertTriangle,
} from "@calcom/ui/components/icon";
import { asStringOrNull } from "@lib/asStringOrNull";
import { timeZone } from "@lib/clock";
@@ -49,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;
@@ -65,7 +85,7 @@ type BookingFormValues = {
email: string;
notes?: string;
locationType?: EventLocationType["type"];
guests?: string[];
guests?: { email: string }[];
address?: string;
attendeeAddress?: string;
phone?: string;
@@ -104,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);
}
@@ -125,6 +150,7 @@ const BookingPage = ({
const mutation = useMutation(createBooking, {
onSuccess: async (responseData) => {
const { uid, paymentUid } = responseData;
if (paymentUid) {
return await router.push(
createPaymentLink({
@@ -143,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() }),
},
});
},
@@ -184,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.
@@ -203,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,
@@ -245,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))
@@ -263,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,
@@ -301,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] : "",
@@ -368,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();
@@ -398,6 +457,7 @@ const BookingPage = ({
? booking.phone
: booking.smsReminderNumber || undefined,
ethSignature: gateState.rainbowToken,
guests: booking.guests?.map((guest) => guest.email),
}));
recurringMutation.mutate(recurringBookings);
} else {
@@ -426,6 +486,7 @@ const BookingPage = ({
? booking.phone
: booking.smsReminderNumber || undefined,
ethSignature: gateState.rainbowToken,
guests: booking.guests?.map((guest) => guest.email),
});
}
};
@@ -479,7 +540,7 @@ const BookingPage = ({
})}{" "}
| {APP_NAME}
</title>
<link rel="icon" href="/favicon.ico" />
<link rel="icon" href="/favico.ico" />
</Head>
<BookingPageTagManager eventType={eventType} />
<CustomBranding lightVal={profile.brandColor} darkVal={profile.darkBrandColor} />
@@ -492,28 +553,28 @@ const BookingPage = ({
<div
className={classNames(
"main overflow-hidden",
isBackgroundTransparent ? "" : "dark:border-1 dark:bg-darkgray-100 bg-white",
isBackgroundTransparent ? "" : "dark:bg-darkgray-100 bg-white dark:border",
"dark:border-darkgray-300 rounded-md sm:border"
)}>
<div className="sm:flex">
{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 ">
<Icon.FiCreditCard className="mr-[10px] ml-[2px] -mt-1 inline-block h-4 w-4" />
<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>
)}
{!rescheduleUid && eventType.recurringEvent?.freq && recurringEventCount && (
<div className="items-start text-sm font-medium text-gray-600 dark:text-white">
<Icon.FiRefreshCw className="mr-[10px] ml-[2px] inline-block h-4 w-4" />
<FiRefreshCw className="ml-[2px] inline-block h-4 w-4 ltr:mr-[10px] rtl:ml-[10px]" />
<p className="-ml-2 inline-block items-center px-2">
{getEveryFreqFor({
t,
@@ -524,7 +585,7 @@ const BookingPage = ({
</div>
)}
<div className="text-bookinghighlight flex items-start text-sm">
<Icon.FiCalendar className="mr-[10px] ml-[2px] mt-[2px] inline-block h-4 w-4" />
<FiCalendar className="ml-[2px] mt-[2px] inline-block h-4 w-4 ltr:mr-[10px] rtl:ml-[10px]" />
<div className="text-sm font-medium">
{(rescheduleUid || !eventType.recurringEvent?.freq) && `${parseDate(date, i18n)}`}
{!rescheduleUid &&
@@ -552,15 +613,15 @@ const BookingPage = ({
{t("former_time")}
</p>
<p className="line-through ">
<Icon.FiCalendar className="mr-[10px] ml-[2px] -mt-1 inline-block h-4 w-4" />
<FiCalendar className="ml-[2px] -mt-1 inline-block h-4 w-4 ltr:mr-[10px] rtl:ml-[10px]" />
{typeof booking.startTime === "string" && parseDate(dayjs(booking.startTime), i18n)}
</p>
</div>
)}
{!!eventType.seatsPerTimeSlot && (
<div className="text-bookinghighlight flex items-start text-sm">
<Icon.FiUser
className={`mr-[10px] ml-[2px] mt-[2px] inline-block h-4 w-4 ${
<FiUser
className={`ml-[2px] mt-[2px] inline-block h-4 w-4 ltr:mr-[10px] rtl:ml-[10px] ${
booking && booking.attendees.length / eventType.seatsPerTimeSlot >= 0.5
? "text-rose-600"
: booking && booking.attendees.length / eventType.seatsPerTimeSlot >= 0.33
@@ -623,7 +684,7 @@ const BookingPage = ({
/>
{bookingForm.formState.errors.email && (
<div className="mt-2 flex items-center text-sm text-red-700 ">
<Icon.FiInfo className="mr-2 h-3 w-3" />
<FiInfo className="h-3 w-3 ltr:mr-2 rtl:ml-2" />
<p>{t("email_validation_error")}</p>
</div>
)}
@@ -664,8 +725,8 @@ const BookingPage = ({
value={location.type}
defaultChecked={i === 0}
/>
<span className="text-sm ltr:ml-2 rtl:mr-2 dark:text-white">
{locationKeyToString(location)}
<span className="text-sm ltr:ml-2 ltr:mr-2 rtl:ml-2 dark:text-white">
{t(locationKeyToString(location) ?? "")}
</span>
</label>
);
@@ -689,7 +750,7 @@ const BookingPage = ({
{selectedLocationType === LocationType.Phone
? t("phone_number")
: selectedLocationType === LocationType.AttendeeInPerson
? t("Address")
? t("address")
: ""}
</label>
<div className="mt-1">
@@ -716,7 +777,7 @@ const BookingPage = ({
</div>
{bookingForm.formState.errors.phone && (
<div className="mt-2 flex items-center text-sm text-red-700 ">
<Icon.FiInfo className="mr-2 h-3 w-3" />
<FiInfo className="h-3 w-3 ltr:mr-2 rtl:ml-2" />
<p>{t("invalid_number")}</p>
</div>
)}
@@ -800,6 +861,7 @@ const BookingPage = ({
{input.options && input.type === EventTypeCustomInputType.RADIO && (
<div className="flex">
<Group
name={`customInputs.${input.id}`}
required={input.required}
onValueChange={(e) => {
bookingForm.setValue(`customInputs.${input.id}`, e);
@@ -808,9 +870,9 @@ const BookingPage = ({
{input.options.map((option, i) => (
<RadioField
label={option.label}
key={`option.${i}.radio`}
key={`option.${input.id}.${i}.radio`}
value={option.label}
id={`option.${i}.radio`}
id={`option.${input.id}.${i}.radio`}
/>
))}
</>
@@ -833,7 +895,7 @@ const BookingPage = ({
/>
{bookingForm.formState.errors?.customInputs?.[input.id] && (
<div className="mt-2 flex items-center text-sm text-red-700 ">
<Icon.FiInfo className="mr-2 h-3 w-3" />
<FiInfo className="h-3 w-3 ltr:mr-2 rtl:ml-2" />
<p>{t("invalid_number")}</p>
</div>
)}
@@ -841,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
@@ -913,7 +922,7 @@ const BookingPage = ({
</div>
{bookingForm.formState.errors.smsReminderNumber && (
<div className="mt-2 flex items-center text-sm text-red-700 ">
<Icon.FiInfo className="mr-2 h-3 w-3" />
<FiInfo className="h-3 w-3 ltr:mr-2 rtl:ml-2" />
<p>{t("invalid_number")}</p>
</div>
)}
@@ -947,25 +956,85 @@ 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>
) : (
<></>
)}
<div className="flex justify-end space-x-2 rtl:space-x-reverse">
{!eventType.disableGuests && !guestToggle && (
<Button
type="button"
color="minimal"
size="icon"
tooltip={t("additional_guests")}
StartIcon={Icon.FiUserPlus}
onClick={() => setGuestToggle(!guestToggle)}
className="mr-auto"
/>
)}
{!eventType.disableGuests && !guestsField.fields.length && (
<Button
color="minimal"
type="button"
onClick={() => router.back()}
// We override this for this component only for now - as we don't support darkmode everywhere in the app
className="dark:hover:bg-darkgray-200 dark:border-none dark:text-white">
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">
<Button color="minimal" type="button" onClick={() => router.back()}>
{t("cancel")}
</Button>
<Button
@@ -997,7 +1066,7 @@ function ErrorMessage({ error }: { error: unknown }) {
<div data-testid="booking-fail" className="mt-2 border-l-4 border-yellow-400 bg-yellow-50 p-4">
<div className="flex">
<div className="flex-shrink-0">
<Icon.FiAlertTriangle className="h-5 w-5 text-yellow-400" aria-hidden="true" />
<FiAlertTriangle className="h-5 w-5 text-yellow-400" aria-hidden="true" />
</div>
<div className="ltr:ml-3 rtl:mr-3">
<p className="text-sm text-yellow-700">
@@ -1,45 +1,41 @@
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 { components } from "react-select";
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 { classNames } from "@calcom/lib";
import { useLocale } from "@calcom/lib/hooks/useLocale";
import { RouterOutputs, trpc } from "@calcom/trpc/react";
import { Button, Dialog, DialogClose, DialogContent, DialogFooter, Form, Icon, PhoneInput } from "@calcom/ui";
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 Select from "@components/ui/form/Select";
import type { LocationOption } from "@components/ui/form/LocationSelect";
import LocationSelect from "@components/ui/form/LocationSelect";
type BookingItem = RouterOutputs["viewer"]["bookings"]["get"]["bookings"][number];
type OptionTypeBase = {
label: string;
value: EventLocationType["type"];
disabled?: boolean;
};
interface ISetLocationDialog {
saveLocation: (newLocationType: EventLocationType["type"], details: { [key: string]: string }) => void;
selection?: OptionTypeBase;
selection?: LocationOption;
booking?: BookingItem;
defaultValues?: LocationObject[];
setShowLocationModal: React.Dispatch<React.SetStateAction<boolean>>;
isOpenDialog: boolean;
setSelectedLocation?: (param: OptionTypeBase | undefined) => void;
setSelectedLocation?: (param: LocationOption | undefined) => void;
setEditingLocationType?: (param: string) => void;
}
@@ -211,11 +207,11 @@ export const EditLocationDialog = (props: ISetLocationDialog) => {
})();
return (
<Dialog open={isOpenDialog}>
<Dialog open={isOpenDialog} onOpenChange={(open) => setShowLocationModal(open)}>
<DialogContent>
<div className="flex flex-row space-x-3">
<div className="bg-secondary-100 mx-auto flex h-12 w-12 flex-shrink-0 items-center justify-center rounded-full sm:mx-0 sm:h-10 sm:w-10">
<Icon.FiMapPin className="text-primary-600 h-6 w-6" />
<FiMapPin className="text-primary-600 h-6 w-6" />
</div>
<div className="w-full">
<div className="mt-3 text-center sm:mt-0 sm:text-left">
@@ -223,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" />
@@ -296,57 +300,31 @@ export const EditLocationDialog = (props: ISetLocationDialog) => {
name="locationType"
control={locationFormMethods.control}
render={() => (
<Select<{ label: string; value: string; icon?: string }>
maxMenuHeight={300}
name="location"
defaultValue={selection}
options={locationOptions}
components={{
Option: (props) => (
<components.Option {...props}>
<div className="flex items-center gap-3">
{props.data.icon && (
<img src={props.data.icon} alt="cover" className="h-3.5 w-3.5" />
)}
<span
className={classNames(
"text-sm font-medium",
props.isSelected ? "text-white" : "text-gray-900"
)}>
{props.data.label}
</span>
</div>
</components.Option>
),
}}
formatOptionLabel={(e) => (
<div className="flex items-center gap-3">
{e.icon && <img src={e.icon} alt="app-icon" className="h-5 w-5" />}
<span>{e.label}</span>
</div>
)}
formatGroupLabel={(e) => (
<p className="text-xs font-medium text-gray-600">{e.label}</p>
)}
isSearchable
className="my-4 block w-full min-w-0 flex-1 rounded-sm border border-gray-300 text-sm"
onChange={(val) => {
if (val) {
locationFormMethods.setValue("locationType", val.value);
locationFormMethods.unregister([
"locationLink",
"locationAddress",
"locationPhoneNumber",
]);
locationFormMethods.clearErrors([
"locationLink",
"locationPhoneNumber",
"locationAddress",
]);
setSelectedLocation?.(val);
}
}}
/>
<div className="py-4">
<LocationSelect
maxMenuHeight={300}
name="location"
defaultValue={selection}
options={locationOptions}
isSearchable
onChange={(val) => {
if (val) {
locationFormMethods.setValue("locationType", val.value);
locationFormMethods.unregister([
"locationLink",
"locationAddress",
"locationPhoneNumber",
]);
locationFormMethods.clearErrors([
"locationLink",
"locationPhoneNumber",
"locationAddress",
]);
setSelectedLocation?.(val);
}
}}
/>
</div>
)}
/>
);
@@ -354,13 +332,13 @@ export const EditLocationDialog = (props: ISetLocationDialog) => {
/>
{selectedLocation && LocationOptions}
<DialogFooter>
<div className="mt-4 flex justify-end space-x-2">
<div className="mt-4 flex justify-end space-x-2 rtl:space-x-reverse">
<Button
onClick={() => {
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";
@@ -9,10 +10,10 @@ import {
DialogContent,
DialogFooter,
DialogHeader,
Icon,
showToast,
TextArea,
} from "@calcom/ui";
import { FiClock } from "@calcom/ui/components/icon";
interface IRescheduleDialog {
isOpenDialog: boolean;
@@ -43,7 +44,7 @@ export const RescheduleDialog = (props: IRescheduleDialog) => {
<DialogContent>
<div className="flex flex-row space-x-3">
<div className="flex h-10 w-10 flex-shrink-0 justify-center rounded-full bg-[#FAFAFA]">
<Icon.FiClock className="m-auto h-6 w-6" />
<FiClock className="m-auto h-6 w-6" />
</div>
<div className="pt-1">
<DialogHeader title={t("send_reschedule_request")} />
+105 -88
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";
@@ -8,7 +9,8 @@ import { useLocale } from "@calcom/lib/hooks/useLocale";
import { weekdayNames } from "@calcom/lib/weekday";
import { trpc } from "@calcom/trpc/react";
import useMeQuery from "@calcom/trpc/react/hooks/useMeQuery";
import { Badge, Button, Icon, Select, SettingsToggle, SkeletonText } from "@calcom/ui";
import { Badge, Button, Select, SettingsToggle, SkeletonText } from "@calcom/ui";
import { FiExternalLink, FiGlobe } from "@calcom/ui/components/icon";
import { SelectSkeletonLoader } from "@components/availability/SkeletonLoader";
@@ -98,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-neutral-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="ml-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">
<Icon.FiGlobe className="mr-2" />
{schedule?.timeZone || <SkeletonText className="block h-5 w-32" />}
</span>
<Button
href={`/availability/${schedule?.schedule.id}`}
color="minimal"
EndIcon={Icon.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"
@@ -200,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")}>
@@ -209,3 +222,7 @@ export const AvailabilityTab = ({ isTeamEvent }: { isTeamEvent: boolean }) => {
/>
);
};
export const AvailabilityTab = ({ isTeamEvent }: { isTeamEvent: boolean }) => {
return isTeamEvent ? <UseCommonScheduleSettingsToggle /> : <EventTypeSchedule />;
};
@@ -1,11 +1,13 @@
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, Icon, Label, Select, TextField } from "@calcom/ui";
import { Button, Label, Select, TextField } from "@calcom/ui";
import { FiPlus, FiX } from "@calcom/ui/components/icon";
interface OptionTypeBase {
label: string;
@@ -77,7 +79,7 @@ const CustomInputTypeForm: FC<Props> = (props) => {
defaultValue={selectedInputOption}
options={inputOptions}
isSearchable={false}
className="mt-1 mb-2 block w-full min-w-0 flex-1 text-sm"
className="mt-1 mb-2 block w-full min-w-0 flex-1 text-sm"
onChange={(option) => option && field.onChange(option.value)}
value={selectedInputOption}
onBlur={field.onBlur}
@@ -134,8 +136,8 @@ const CustomInputTypeForm: FC<Props> = (props) => {
value={selectedCustomInput?.id || -1}
{...register("id", { valueAsNumber: true })}
/>
<div className="mt-5 flex justify-end space-x-2 sm:mt-4">
<Button onClick={onCancel} type="button" color="secondary" className="ltr:mr-2">
<div className="mt-5 flex justify-end space-x-2 rtl:space-x-reverse sm:mt-4">
<Button onClick={onCancel} type="button" color="secondary" className="ltr:mr-2 rtl:ml-2">
{t("cancel")}
</Button>
<Button
@@ -183,9 +185,9 @@ function RadioInputHandler({
{...register(`options.${index}.label` as const, { required: true })}
addOnSuffix={
<Button
size="icon"
variant="icon"
color="minimal"
StartIcon={Icon.FiX}
StartIcon={FiX}
onClick={() => {
remove(index);
}}
@@ -196,7 +198,7 @@ function RadioInputHandler({
))}
<Button
color="minimal"
StartIcon={Icon.FiPlus}
StartIcon={FiPlus}
className="!text-sm !font-medium"
onClick={() => {
append({ label: "", type: "text" });
@@ -1,29 +1,32 @@
import Link from "next/link";
import type { CustomInputParsed, EventTypeSetupInfered, FormValues } from "pages/event-types/[type]";
import type { CustomInputParsed, EventTypeSetupProps, FormValues } from "pages/event-types/[type]";
import { useEffect, useState } from "react";
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 } from "@calcom/lib/constants";
import { APP_NAME, CAL_URL, IS_SELF_HOSTED } from "@calcom/lib/constants";
import { useLocale } from "@calcom/lib/hooks/useLocale";
import { trpc } from "@calcom/trpc/react";
import {
Badge,
Button,
Checkbox,
Dialog,
DialogClose,
DialogContent,
DialogFooter,
Icon,
Label,
SettingsToggle,
showToast,
TextField,
Tooltip,
} from "@calcom/ui";
import { FiEdit, FiCopy, FiPlus } from "@calcom/ui/components/icon";
import CustomInputTypeForm from "@components/eventtype/CustomInputTypeForm";
@@ -36,7 +39,19 @@ const generateHashedLink = (id: number) => {
return uid;
};
export const EventAdvancedTab = ({ eventType, team }: Pick<EventTypeSetupInfered, "eventType" | "team">) => {
const getRandomId = (length = 8) => {
return (
-1 *
parseInt(
Math.ceil(Math.random() * Date.now())
.toPrecision(length)
.toString()
.replace(".", "")
)
);
};
export const EventAdvancedTab = ({ eventType, team }: Pick<EventTypeSetupProps, "eventType" | "team">) => {
const connectedCalendarsQuery = trpc.viewer.connectedCalendars.useQuery();
const formMethods = useFormContext<FormValues>();
const { t } = useLocale();
@@ -44,6 +59,14 @@ export const EventAdvancedTab = ({ eventType, team }: Pick<EventTypeSetupInfered
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) || []
);
@@ -51,8 +74,7 @@ export const EventAdvancedTab = ({ eventType, team }: Pick<EventTypeSetupInfered
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);
@@ -60,10 +82,25 @@ export const EventAdvancedTab = ({ eventType, team }: Pick<EventTypeSetupInfered
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]);
useEffect(() => {
if (eventType.customInputs) {
setCustomInputs(eventType.customInputs.sort((a, b) => a.id - b.id));
}
}, [eventType.customInputs]);
return (
<div className="flex flex-col space-y-8">
{/**
@@ -75,10 +112,11 @@ export const EventAdvancedTab = ({ eventType, team }: Pick<EventTypeSetupInfered
<div className="flex flex-col">
<div className="flex justify-between">
<Label>{t("add_to_calendar")}</Label>
<Link href="/apps/categories/calendar">
<a target="_blank" className="text-sm text-gray-600 hover:text-gray-900">
{t("add_another_calendar")}
</a>
<Link
href="/apps/categories/calendar"
target="_blank"
className="text-sm text-gray-600 hover:text-gray-900">
{t("add_another_calendar")}
</Link>
</div>
<div className="-mt-1 w-full">
@@ -101,16 +139,23 @@ export const EventAdvancedTab = ({ eventType, team }: Pick<EventTypeSetupInfered
)}
<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"
StartIcon={Icon.FiEdit}
size="icon"
StartIcon={FiEdit}
variant="icon"
color="minimal"
className="hover:stroke-3 min-w-fit px-0 hover:bg-transparent hover:text-black"
onClick={() => setShowEventNameTip((old) => !old)}
@@ -149,7 +194,7 @@ export const EventAdvancedTab = ({ eventType, team }: Pick<EventTypeSetupInfered
</ul>
{customInputs.length > 0 && (
<Button
StartIcon={Icon.FiPlus}
StartIcon={FiPlus}
color="minimal"
type="button"
onClick={() => {
@@ -239,13 +284,28 @@ export const EventAdvancedTab = ({ eventType, team }: Pick<EventTypeSetupInfered
defaultValue={eventType.successRedirectUrl || ""}
{...formMethods.register("successRedirectUrl")}
/>
<div className="mt-2 flex">
<Checkbox
description={t("disable_success_page")}
// Disable if it's not Self Hosted or if the redirect url is not set
disabled={!IS_SELF_HOSTED || !formMethods.watch("successRedirectUrl")}
{...formMethods.register("metadata.disableSuccessPage")}
/>
{/*TODO: Extract it out into a component when used more than once*/}
{!IS_SELF_HOSTED && (
<Link href="https://cal.com/pricing" target="_blank">
<Badge variant="orange" className="ml-2">
Platform Only
</Badge>
</Link>
)}
</div>
</div>
</SettingsToggle>
</>
)}
/>
<hr />
<SettingsToggle
data-testid="hashedLinkCheck"
title={t("private_link")}
@@ -280,7 +340,7 @@ export const EventAdvancedTab = ({ eventType, team }: Pick<EventTypeSetupInfered
}}
className="hover:stroke-3 hover:bg-transparent hover:text-black"
type="button">
<Icon.FiCopy />
<FiCopy />
</Button>
</Tooltip>
}
@@ -350,23 +410,63 @@ export const EventAdvancedTab = ({ eventType, team }: Pick<EventTypeSetupInfered
description={t("custom_event_name_description")}
type="creation">
<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>
@@ -374,25 +474,26 @@ export const EventAdvancedTab = ({ eventType, team }: Pick<EventTypeSetupInfered
<Controller
name="customInputs"
control={formMethods.control}
defaultValue={eventType.customInputs.sort((a, b) => a.id - b.id) || []}
defaultValue={customInputs}
render={() => (
<Dialog open={selectedCustomInputModalOpen} onOpenChange={setSelectedCustomInputModalOpen}>
<DialogContent
type="creation"
Icon={Icon.FiPlus}
Icon={FiPlus}
title={t("add_new_custom_input_field")}
description={t("this_input_will_shown_booking_this_event")}>
<CustomInputTypeForm
selectedCustomInput={selectedCustomInput}
onSubmit={(values) => {
const customInput: CustomInputParsed = {
id: -1,
id: getRandomId(),
eventTypeId: -1,
label: values.label,
placeholder: values.placeholder,
required: values.required,
type: values.type,
options: values.options,
hasToBeCreated: true,
};
if (selectedCustomInput) {
selectedCustomInput.label = customInput.label;
@@ -400,6 +501,7 @@ export const EventAdvancedTab = ({ eventType, team }: Pick<EventTypeSetupInfered
selectedCustomInput.required = customInput.required;
selectedCustomInput.type = customInput.type;
selectedCustomInput.options = customInput.options || undefined;
selectedCustomInput.hasToBeCreated = false;
// Update by id
const inputIndex = customInputs.findIndex((input) => input.id === values.id);
customInputs[inputIndex] = selectedCustomInput;
+12 -37
View File
@@ -1,43 +1,18 @@
import { EventTypeSetupInfered, FormValues } from "pages/event-types/[type]";
import type { EventTypeSetupProps, FormValues } from "pages/event-types/[type]";
import { useFormContext } from "react-hook-form";
import EventTypeAppContext, { GetAppData, SetAppData } from "@calcom/app-store/EventTypeAppContext";
import { EventTypeAddonMap } from "@calcom/app-store/apps.browser.generated";
import { EventTypeAppCardComponentProps } from "@calcom/app-store/types";
import { EventTypeAppsList } from "@calcom/app-store/utils";
import type { GetAppData, SetAppData } from "@calcom/app-store/EventTypeAppContext";
import { EventTypeAppCard } from "@calcom/app-store/_components/EventTypeAppCardInterface";
import type { EventTypeAppCardComponentProps } from "@calcom/app-store/types";
import type { EventTypeAppsList } from "@calcom/app-store/utils";
import { useLocale } from "@calcom/lib/hooks/useLocale";
import { RouterOutputs, trpc } from "@calcom/trpc/react";
import { Button, EmptyScreen, ErrorBoundary, Icon } from "@calcom/ui";
import { trpc } from "@calcom/trpc/react";
import { Button, EmptyScreen } from "@calcom/ui";
import { FiGrid } from "@calcom/ui/components/icon";
type EventType = Pick<EventTypeSetupInfered, "eventType">["eventType"] &
export type EventType = Pick<EventTypeSetupProps, "eventType">["eventType"] &
EventTypeAppCardComponentProps["eventType"];
function AppCardWrapper({
app,
eventType,
getAppData,
setAppData,
}: {
app: RouterOutputs["viewer"]["apps"][number];
eventType: EventType;
getAppData: GetAppData;
setAppData: SetAppData;
}) {
const dirName = app.slug === "stripe" ? "stripepayment" : app.slug;
const Component = EventTypeAddonMap[dirName as keyof typeof EventTypeAddonMap];
if (!Component) {
throw new Error('No component found for "' + dirName + '"');
}
return (
<ErrorBoundary message={`There is some problem with ${app.name} App`}>
<EventTypeAppContext.Provider value={[getAppData, setAppData]}>
<Component key={app.slug} app={app} eventType={eventType} />
</EventTypeAppContext.Provider>
</ErrorBoundary>
);
}
export const EventAppsTab = ({ eventType }: { eventType: EventType }) => {
const { t } = useLocale();
const { data: eventTypeApps, isLoading } = trpc.viewer.apps.useQuery({
@@ -86,7 +61,7 @@ export const EventAppsTab = ({ eventType }: { eventType: EventType }) => {
<div className="before:border-0">
{!isLoading && !installedApps?.length ? (
<EmptyScreen
Icon={Icon.FiGrid}
Icon={FiGrid}
headline={t("empty_installed_apps_headline")}
description={t("empty_installed_apps_description")}
buttonRaw={
@@ -97,7 +72,7 @@ export const EventAppsTab = ({ eventType }: { eventType: EventType }) => {
/>
) : null}
{installedApps?.map((app) => (
<AppCardWrapper
<EventTypeAppCard
getAppData={getAppDataGetter(app.slug as EventTypeAppsList)}
setAppData={getAppDataSetter(app.slug as EventTypeAppsList)}
key={app.slug}
@@ -113,7 +88,7 @@ export const EventAppsTab = ({ eventType }: { eventType: EventType }) => {
) : null}
<div className="before:border-0">
{notInstalledApps?.map((app) => (
<AppCardWrapper
<EventTypeAppCard
getAppData={getAppDataGetter(app.slug as EventTypeAppsList)}
setAppData={getAppDataSetter(app.slug as EventTypeAppsList)}
key={app.slug}
+212 -219
View File
@@ -1,24 +1,109 @@
import { useAutoAnimate } from "@formkit/auto-animate/react";
import * as RadioGroup from "@radix-ui/react-radio-group";
import { EventTypeSetupInfered, FormValues } from "pages/event-types/[type]";
import { useMemo, useRef, useState } from "react";
import type { EventTypeSetupProps, FormValues } from "pages/event-types/[type]";
import React, { useEffect, useState } from "react";
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, Icon, Input, InputField, Label, Select, SettingsToggle } from "@calcom/ui";
import { Button, DateRangePicker, Input, InputField, Label, Select, SettingsToggle } from "@calcom/ui";
import { FiPlus, FiTrash } from "@calcom/ui/components/icon";
export const EventLimitsTab = ({ eventType }: Pick<EventTypeSetupInfered, "eventType">) => {
const MinimumBookingNoticeInput = React.forwardRef<
HTMLInputElement,
Omit<UseFormRegisterReturn<"minimumBookingNotice">, "ref">
>(function MinimumBookingNoticeInput({ ...passThroughProps }, ref) {
const { t } = useLocale();
const { setValue, getValues } = useFormContext<FormValues>();
const durationTypeOptions: {
value: DurationType;
label: string;
}[] = [
{
label: t("minutes"),
value: "minutes",
},
{
label: t("hours"),
value: "hours",
},
{
label: t("days"),
value: "days",
},
];
const [minimumBookingNoticeDisplayValues, setMinimumBookingNoticeDisplayValues] = useState<{
type: DurationType;
value: number;
}>({
type: findDurationType(getValues(passThroughProps.name)),
value: convertToNewDurationType(
"minutes",
findDurationType(getValues(passThroughProps.name)),
getValues(passThroughProps.name)
),
});
// keep hidden field in sync with minimumBookingNoticeDisplayValues
useEffect(() => {
setValue(
passThroughProps.name,
convertToNewDurationType(
minimumBookingNoticeDisplayValues.type,
"minutes",
minimumBookingNoticeDisplayValues.value
)
);
}, [minimumBookingNoticeDisplayValues, setValue, passThroughProps.name]);
return (
<div className="flex items-end justify-end">
<div className="w-1/2 md:w-full">
<InputField
required
defaultValue={minimumBookingNoticeDisplayValues.value}
onChange={(e) =>
setMinimumBookingNoticeDisplayValues({
...minimumBookingNoticeDisplayValues,
value: parseInt(e.target.value || "0", 10),
})
}
label={t("minimum_booking_notice")}
type="number"
placeholder="0"
className="mb-0 h-[38px] rounded-[4px] ltr:mr-2 rtl:ml-2"
/>
<input type="hidden" ref={ref} {...passThroughProps} />
</div>
<Select
isSearchable={false}
className="mb-0 ml-2 h-[38px] w-full capitalize md:min-w-[150px] md:max-w-[200px]"
defaultValue={durationTypeOptions.find(
(option) => option.value === minimumBookingNoticeDisplayValues.type
)}
onChange={(input) => {
if (input) {
setMinimumBookingNoticeDisplayValues({
...minimumBookingNoticeDisplayValues,
type: input.value,
});
}
}}
options={durationTypeOptions}
/>
</div>
);
});
export const EventLimitsTab = ({ eventType }: Pick<EventTypeSetupProps, "eventType">) => {
const { t } = useLocale();
const formMethods = useFormContext<FormValues>();
const minimumBookingNoticeType = useRef<DurationType>(findDurationType(eventType.minimumBookingNotice));
const prevBookingNoticeType = useRef<DurationType>(minimumBookingNoticeType.current);
const minimumBookingNoticeInDurationTypeFormValue = formMethods.watch("minimumBookingNoticeInDurationType");
const PERIOD_TYPES = [
{
@@ -49,212 +134,115 @@ export const EventLimitsTab = ({ eventType }: Pick<EventTypeSetupInfered, "event
defaultValue: periodType?.type,
});
const onMinimumNoticeDurationTypeChange = useMemo(
() => (durationType?: DurationType) => {
if (typeof durationType === "undefined") return;
// Store current selected type in ref to use in previous run for comparrison.
minimumBookingNoticeType.current = durationType;
// Uses the previous selected type and converts the value to the new type.
// Eg day was selected before, user selects hours now, so we multiple * 24 and round up.
const minimumBookingNoticeInDurationType = convertToNewDurationType(
prevBookingNoticeType.current,
durationType,
Number(minimumBookingNoticeInDurationTypeFormValue)
);
// Uses the round up value in the new type to calculate the value in minutes.
// We should NOT use minimumBookingNoticeInDurationTypeFormValue here, since that
// would break in the case that the user enters 90 minutes, changes the type to
// hours (that will show 2 hours), but the value in minutes would then remain 90,
// which is something else than the user things they save.
const minimumBookingNoticeInMinutes = convertToNewDurationType(
durationType,
"minutes",
Number(minimumBookingNoticeInDurationType)
);
// Updates both form values as well as stores the current type as previous type in ref.
formMethods.setValue("minimumBookingNotice", minimumBookingNoticeInMinutes);
formMethods.setValue("minimumBookingNoticeInDurationType", minimumBookingNoticeInDurationType);
prevBookingNoticeType.current = durationType;
},
[formMethods, minimumBookingNoticeInDurationTypeFormValue]
);
/**
* When the user inputs a new value for minimumBookingNoticeInDurationType,
* we calculate the value in minutes, and update this hidden field as well.
*/
const onMinimumNoticeChange = useMemo(
() => (duration: string) => {
const minimumBookingNoticeInMinutes = convertToNewDurationType(
minimumBookingNoticeType.current,
"minutes",
Number(duration)
);
formMethods.setValue("minimumBookingNotice", minimumBookingNoticeInMinutes);
},
[formMethods]
);
return (
<div>
<div className="flex flex-col space-y-4 lg:flex-row lg:space-y-0 lg:space-x-4">
<div className="w-full">
<Label htmlFor="beforeBufferTime">{t("before_event")} </Label>
<Controller
name="beforeBufferTime"
control={formMethods.control}
defaultValue={eventType.beforeEventBuffer || 0}
render={({ field: { onChange, value } }) => {
const beforeBufferOptions = [
{
label: t("event_buffer_default"),
value: 0,
},
...[5, 10, 15, 20, 30, 45, 60, 90, 120].map((minutes) => ({
label: minutes + " " + t("minutes"),
value: minutes,
})),
];
return (
<Select
isSearchable={false}
onChange={(val) => {
if (val) onChange(val.value);
}}
defaultValue={
beforeBufferOptions.find((option) => option.value === value) || beforeBufferOptions[0]
}
options={beforeBufferOptions}
/>
);
}}
/>
</div>
<div className="w-full">
<Label htmlFor="afterBufferTime">{t("after_event")} </Label>
<Controller
name="afterBufferTime"
control={formMethods.control}
defaultValue={eventType.afterEventBuffer || 0}
render={({ field: { onChange, value } }) => {
const afterBufferOptions = [
{
label: t("event_buffer_default"),
value: 0,
},
...[5, 10, 15, 20, 30, 45, 60, 90, 120].map((minutes) => ({
label: minutes + " " + t("minutes"),
value: minutes,
})),
];
return (
<Select
isSearchable={false}
onChange={(val) => {
if (val) onChange(val.value);
}}
defaultValue={
afterBufferOptions.find((option) => option.value === value) || afterBufferOptions[0]
}
options={afterBufferOptions}
/>
);
}}
/>
</div>
</div>
<div className="flex flex-col space-y-4 pt-4 lg:flex-row lg:space-y-0 lg:space-x-4">
<div className="flex w-full items-end justify-end">
<Controller
name="minimumBookingNotice"
control={formMethods.control}
render={() => {
const durationTypeOptions = [
{
label: t("minutes"),
value: "minutes",
},
{
label: t("hours"),
value: "hours",
},
{
label: t("days"),
value: "days",
},
];
return (
<>
<div className="w-1/2 md:w-3/4">
<InputField
required
label={t("minimum_booking_notice")}
type="number"
placeholder="120"
className="mr-2 mb-0 h-[38px] rounded-[4px]"
{...formMethods.register("minimumBookingNoticeInDurationType", {
onChange: (event: React.ChangeEvent<HTMLInputElement>) =>
onMinimumNoticeChange(event.target.value),
})}
/>
<input type="hidden" {...formMethods.register("minimumBookingNotice")} />
</div>
<div className="space-y-8">
<div className="space-y-4 lg:space-y-8">
<div className="flex flex-col space-y-4 lg:flex-row lg:space-y-0 lg:space-x-4">
<div className="w-full">
<Label htmlFor="beforeBufferTime">{t("before_event")} </Label>
<Controller
name="beforeBufferTime"
control={formMethods.control}
defaultValue={eventType.beforeEventBuffer || 0}
render={({ field: { onChange, value } }) => {
const beforeBufferOptions = [
{
label: t("event_buffer_default"),
value: 0,
},
...[5, 10, 15, 20, 30, 45, 60, 90, 120].map((minutes) => ({
label: minutes + " " + t("minutes"),
value: minutes,
})),
];
return (
<Select
isSearchable={false}
className="mb-0 ml-2 h-[38px] w-full capitalize md:min-w-[150px] md:max-w-[200px]"
defaultValue={durationTypeOptions.find(
(option) => option.value === minimumBookingNoticeType.current
)}
onChange={(input) => onMinimumNoticeDurationTypeChange(input?.value as DurationType)}
options={durationTypeOptions}
onChange={(val) => {
if (val) onChange(val.value);
}}
defaultValue={
beforeBufferOptions.find((option) => option.value === value) || beforeBufferOptions[0]
}
options={beforeBufferOptions}
/>
</>
);
}}
/>
);
}}
/>
</div>
<div className="w-full">
<Label htmlFor="afterBufferTime">{t("after_event")} </Label>
<Controller
name="afterBufferTime"
control={formMethods.control}
defaultValue={eventType.afterEventBuffer || 0}
render={({ field: { onChange, value } }) => {
const afterBufferOptions = [
{
label: t("event_buffer_default"),
value: 0,
},
...[5, 10, 15, 20, 30, 45, 60, 90, 120].map((minutes) => ({
label: minutes + " " + t("minutes"),
value: minutes,
})),
];
return (
<Select
isSearchable={false}
onChange={(val) => {
if (val) onChange(val.value);
}}
defaultValue={
afterBufferOptions.find((option) => option.value === value) || afterBufferOptions[0]
}
options={afterBufferOptions}
/>
);
}}
/>
</div>
</div>
<div className="w-full">
<Label htmlFor="slotInterval">{t("slot_interval")} </Label>
<Controller
name="slotInterval"
control={formMethods.control}
render={() => {
const slotIntervalOptions = [
{
label: t("slot_interval_default"),
value: -1,
},
...[5, 10, 15, 20, 30, 45, 60, 75, 90, 105, 120].map((minutes) => ({
label: minutes + " " + t("minutes"),
value: minutes,
})),
];
return (
<Select
isSearchable={false}
onChange={(val) => {
formMethods.setValue("slotInterval", val && (val.value || 0) > 0 ? val.value : null);
}}
defaultValue={
slotIntervalOptions.find((option) => option.value === eventType.slotInterval) ||
slotIntervalOptions[0]
}
options={slotIntervalOptions}
/>
);
}}
/>
<div className="flex flex-col space-y-4 lg:flex-row lg:space-y-0 lg:space-x-4">
<div className="w-full">
<Label htmlFor="minimumBookingNotice">{t("minimum_booking_notice")} </Label>
<MinimumBookingNoticeInput {...formMethods.register("minimumBookingNotice")} />
</div>
<div className="w-full">
<Label htmlFor="slotInterval">{t("slot_interval")} </Label>
<Controller
name="slotInterval"
control={formMethods.control}
render={() => {
const slotIntervalOptions = [
{
label: t("slot_interval_default"),
value: -1,
},
...[5, 10, 15, 20, 30, 45, 60, 75, 90, 105, 120].map((minutes) => ({
label: minutes + " " + t("minutes"),
value: minutes,
})),
];
return (
<Select
isSearchable={false}
onChange={(val) => {
formMethods.setValue("slotInterval", val && (val.value || 0) > 0 ? val.value : null);
}}
defaultValue={
slotIntervalOptions.find((option) => option.value === eventType.slotInterval) ||
slotIntervalOptions[0]
}
options={slotIntervalOptions}
/>
);
}}
/>
</div>
</div>
</div>
<hr className="my-8" />
<hr />
<Controller
name="bookingLimits"
control={formMethods.control}
@@ -276,8 +264,7 @@ export const EventLimitsTab = ({ eventType }: Pick<EventTypeSetupInfered, "event
</SettingsToggle>
)}
/>
<hr className="my-8" />
<hr />
<Controller
name="periodType"
control={formMethods.control}
@@ -327,7 +314,7 @@ export const EventLimitsTab = ({ eventType }: Pick<EventTypeSetupInfered, "event
</div>
)}
{period.type === "RANGE" && (
<div className="inline-flex space-x-2 ltr:ml-2 rtl:mr-2 rtl:space-x-reverse">
<div className="inline-flex space-x-2 ltr:ml-2 ltr:mr-2 rtl:ml-2 rtl:space-x-reverse">
<Controller
name="periodDates"
control={formMethods.control}
@@ -347,7 +334,9 @@ export const EventLimitsTab = ({ eventType }: Pick<EventTypeSetupInfered, "event
/>
</div>
)}
{period.suffix ? <span className="ltr:ml-2 rtl:mr-2">&nbsp;{period.suffix}</span> : null}
{period.suffix ? (
<span className="ltr:ml-2 ltr:mr-2 rtl:ml-2">&nbsp;{period.suffix}</span>
) : null}
</div>
);
})}
@@ -410,7 +399,9 @@ const BookingLimits = () => {
.map(([key, bookingAmount]) => {
const bookingLimitKey = key as BookingLimitsKey;
return (
<div className="mb-2 flex items-center space-x-2 text-sm" key={bookingLimitKey}>
<div
className="mb-2 flex items-center space-x-2 text-sm rtl:space-x-reverse"
key={bookingLimitKey}>
<Input
id={`${bookingLimitKey}-limit`}
type="number"
@@ -431,19 +422,21 @@ 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);
}}
/>
<Button
size="icon"
StartIcon={Icon.FiTrash}
variant="icon"
StartIcon={FiTrash}
color="destructive"
onClick={() => {
const current = currentBookingLimits;
@@ -457,7 +450,7 @@ const BookingLimits = () => {
{currentBookingLimits && Object.keys(currentBookingLimits).length <= 3 && (
<Button
color="minimal"
StartIcon={Icon.FiPlus}
StartIcon={FiPlus}
onClick={() => {
if (!currentBookingLimits || !watchBookingLimits) return;
const currentKeys = Object.keys(watchBookingLimits);
@@ -470,7 +463,7 @@ const BookingLimits = () => {
setValue("bookingLimits", {
...watchBookingLimits,
[rest[0].value]: undefined,
[rest[0].value]: 1,
});
}}>
{t("add_limit")}
@@ -1,14 +1,13 @@
import { EventTypeSetupInfered } from "pages/event-types/[type]";
import { useState } from "react";
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<EventTypeSetupInfered, "eventType">) => {
const stripeAppData = getStripeAppData(eventType);
export const EventRecurringTab = ({ eventType }: Pick<EventTypeSetupProps, "eventType">) => {
const paymentAppData = getPaymentAppData(eventType);
const requirePayment = stripeAppData.price > 0;
const requirePayment = paymentAppData.price > 0;
return (
<div className="">
+89 -32
View File
@@ -1,36 +1,57 @@
import { useAutoAnimate } from "@formkit/auto-animate/react";
import { zodResolver } from "@hookform/resolvers/zod";
import { isValidPhoneNumber } from "libphonenumber-js";
import { EventTypeSetupInfered, FormValues } from "pages/event-types/[type]";
import { Trans } from "next-i18next";
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 } 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 { Button, Icon, Label, Select, Skeleton, TextField, SettingsToggle } from "@calcom/ui";
import { slugify } from "@lib/slugify";
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 { EditLocationDialog } from "@components/dialog/EditLocationDialog";
import type { SingleValueLocationOption, LocationOption } from "@components/ui/form/LocationSelect";
import LocationSelect from "@components/ui/form/LocationSelect";
type OptionTypeBase = {
label: string;
value: EventLocationType["type"];
disabled?: boolean;
const getLocationFromType = (
type: EventLocationType["type"],
locationOptions: Pick<EventTypeSetupProps, "locationOptions">["locationOptions"]
) => {
for (const locationOption of locationOptions) {
const option = locationOption.options.find((option) => option.value === type);
if (option) {
return option;
}
}
};
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<EventTypeSetupInfered, "eventType" | "locationOptions" | "team" | "teamMembers">
props: Pick<EventTypeSetupProps, "eventType" | "locationOptions" | "team" | "teamMembers">
) => {
const { t } = useLocale();
const formMethods = useFormContext<FormValues>();
const { eventType, locationOptions, team } = props;
const [showLocationModal, setShowLocationModal] = useState(false);
const [editingLocationType, setEditingLocationType] = useState<string>("");
const [selectedLocation, setSelectedLocation] = useState<OptionTypeBase | undefined>(undefined);
const [selectedLocation, setSelectedLocation] = useState<LocationOption | undefined>(undefined);
const [multipleDuration, setMultipleDuration] = useState(eventType.metadata.multipleDuration);
const multipleDurationOptions = [5, 10, 15, 20, 25, 30, 45, 50, 60, 75, 80, 90, 120, 180].map((mins) => ({
@@ -49,14 +70,20 @@ export const EventSetupTab = (
);
const openLocationModal = (type: EventLocationType["type"]) => {
setSelectedLocation(locationOptions.find((option) => option.value === type));
const option = getLocationFromType(type, locationOptions);
setSelectedLocation(option);
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 }
);
};
@@ -71,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",
@@ -125,18 +152,22 @@ export const EventSetupTab = (
return true;
});
const defaultValue = getDefaultLocationValue(locationOptions, "integrations:daily");
return (
<div className="w-full">
{validLocations.length === 0 && (
<div className="flex">
<Select
<LocationSelect
defaultValue={defaultValue}
placeholder={t("select")}
options={locationOptions}
isSearchable={false}
className="block w-full min-w-0 flex-1 rounded-sm text-sm"
onChange={(e) => {
menuPlacement="auto"
onChange={(e: SingleValueLocationOption) => {
if (e?.value) {
const newLocationType: EventLocationType["type"] = e.value;
const newLocationType = e.value;
const eventLocationType = getEventLocationType(newLocationType);
if (!eventLocationType) {
return;
@@ -159,8 +190,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-neutral-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
@@ -168,9 +207,7 @@ export const EventSetupTab = (
className="h-4 w-4"
alt={`${eventLocationType.label} logo`}
/>
<span className="truncate text-sm ltr:ml-1 rtl:mr-1">
{location[eventLocationType.defaultValueVariable] || eventLocationType.label}
</span>
<span className="truncate text-sm ltr:ml-1 rtl:mr-1">{eventLabel}</span>
</div>
<div className="flex">
<button
@@ -185,19 +222,36 @@ export const EventSetupTab = (
}}
aria-label={t("edit")}
className="mr-1 p-1 text-gray-500 hover:text-gray-900">
<Icon.FiEdit2 className="h-4 w-4" />
<FiEdit2 className="h-4 w-4" />
</button>
<button type="button" onClick={() => removeLocation(location)} aria-label={t("remove")}>
<Icon.FiX className="border-l-1 h-6 w-6 pl-1 text-gray-500 hover:text-gray-900 " />
<FiX className="border-l-1 h-6 w-6 pl-1 text-gray-500 hover:text-gray-900 " />
</button>
</div>
</div>
</li>
);
})}
{validLocations.some((location) => location.type === MeetLocationType) && (
<div className="flex text-sm text-gray-600">
<FiCheck className="mt-0.5 mr-1.5 h-2 w-2.5" />
<Trans i18nKey="event_type_requres_google_cal">
<p>
The “Add to calendar” for this event type needs to be a Google Calendar for Meet to work.
Change it{" "}
<Link
href={`${CAL_URL}/event-types/${eventType.id}?tabName=advanced`}
className="underline">
here.
</Link>{" "}
We will fall back to Cal video if you do not change it.
</p>
</Trans>
</div>
)}
{validLocations.length > 0 && validLocations.length !== locationOptions.length && (
<li>
<Button StartIcon={Icon.FiPlus} color="minimal" onClick={() => setShowLocationModal(true)}>
<Button StartIcon={FiPlus} color="minimal" onClick={() => setShowLocationModal(true)}>
{t("add_location")}
</Button>
</li>
@@ -326,6 +380,7 @@ export const EventSetupTab = (
<Skeleton as={Label} loadingClassName="w-16">
{t("location")}
</Skeleton>
<Controller
name="locations"
control={formMethods.control}
@@ -342,7 +397,9 @@ export const EventSetupTab = (
saveLocation={saveLocation}
defaultValues={formMethods.getValues("locations")}
selection={
selectedLocation ? { value: selectedLocation.value, label: selectedLocation.label } : undefined
selectedLocation
? { value: selectedLocation.value, label: t(selectedLocation.label), icon: selectedLocation.icon }
: undefined
}
setSelectedLocation={setSelectedLocation}
setEditingLocationType={setEditingLocationType}
+144 -83
View File
@@ -1,12 +1,15 @@
import { SchedulingType } from "@prisma/client/";
import { EventTypeSetupInfered, FormValues } from "pages/event-types/[type]";
import { useMemo } from "react";
import { Controller, useFormContext } from "react-hook-form";
import { SchedulingType } from "@prisma/client";
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 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 { Avatar, Button, Icon, Label, Select } from "@calcom/ui";
import { Label, Select } from "@calcom/ui";
interface IMemberToValue {
id: number | null;
@@ -22,15 +25,76 @@ const mapUserToValue = ({ id, name, username, email }: IMemberToValue) => ({
email,
});
export const EventTeamTab = ({
eventType,
team,
teamMembers,
currentUserMembership,
}: Pick<EventTypeSetupInfered, "eventType" | "teamMembers" | "team" | "currentUserMembership">) => {
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,
placeholder,
options = [],
...rest
}: {
control: Control<FormValues>;
labelText: string;
placeholder: string;
options?: Options<CheckedSelectOption>;
} & Partial<ComponentProps<typeof CheckedTeamSelect>>) => {
return (
<div className="flex flex-col space-y-5 bg-gray-50 p-4">
<div>
<Label>{labelText}</Label>
<Controller
name="hostsFixed"
control={control}
render={({ field: { onChange, value } }) => {
return (
<CheckedTeamSelect
isDisabled={false}
onChange={(options) => {
onChange(
options.map((option) => ({
isFixed: true,
userId: parseInt(option.value, 10),
}))
);
}}
value={value
.map(
(host) =>
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
options.find((member) => member.value === host.userId.toString())!
)
.filter(Boolean)}
controlShouldRenderValue={false}
options={options}
placeholder={placeholder}
{...rest}
/>
);
}}
/>
</div>
</div>
);
};
export const EventTeamTab = ({ team, teamMembers }: Pick<EventTypeSetupProps, "teamMembers" | "team">) => {
const formMethods = useFormContext<FormValues>();
const { t } = useLocale();
const schedulingType = useWatch({
control: formMethods.control,
name: "schedulingType",
});
const schedulingTypeOptions: {
value: SchedulingType;
label: string;
@@ -48,14 +112,12 @@ export const EventTeamTab = ({
},
];
const teamMembersToValues = useMemo(() => {
return teamMembers.map(mapUserToValue);
}, [teamMembers]);
const teamMembersOptions = teamMembers.map(mapUserToValue);
return (
<div>
{team && (
<div className="space-y-3">
<div className="flex flex-col pb-8">
<div className="space-y-5">
<div className="flex flex-col">
<Label>{t("scheduling_type")}</Label>
<Controller
name="schedulingType"
@@ -73,75 +135,74 @@ export const EventTeamTab = ({
/>
</div>
<div className="flex flex-col">
<Label>{t("team")}</Label>
<Controller
name="users"
{schedulingType === SchedulingType.COLLECTIVE && (
<FixedHosts
options={teamMembersOptions.sort(sortByLabel)}
placeholder={t("add_attendees")}
labelText={t("team")}
control={formMethods.control}
defaultValue={eventType.users.map((user) => user.id.toString())}
render={({ field: { onChange, value } }) => (
<CheckedTeamSelect
isDisabled={false}
onChange={(options) => onChange(options.map((user) => user.value))}
value={value
.map(
(userId) =>
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
teamMembers.map(mapUserToValue).find((member) => member.value === userId)!
)
.filter(Boolean)}
controlShouldRenderValue={false}
options={teamMembersToValues}
placeholder={t("add_attendees")}
/>
)}
/>
</div>
</div>
)}
</div>
);
};
const TeamProfileCard = ({
id,
name,
hasPermsToDelete,
email,
username,
}: {
id: number;
name: string | null;
email: string;
username: string | null;
hasPermsToDelete: boolean;
}) => {
const formMethods = useFormContext<FormValues>();
const avatar = `${WEBAPP_URL}/${username}/avatar.png`;
return (
<div className="flex items-center border border-gray-300 px-6 py-4 first:rounded-t-md last:rounded-b-md only:rounded-md">
<Avatar imageSrc={avatar} gravatarFallbackMd5="ajsdkwakhsd1231" size="md" alt="Team Image" />
<div className="flex flex-col pl-3">
<div className="">
<span className="pr-2 text-sm font-semibold leading-none text-black">{name}</span>
</div>
<p className="text-sm font-normal leading-normal text-gray-700">{email}</p>
</div>
{hasPermsToDelete && (
<div className="ml-auto">
<Button
type="button"
size="icon"
color="destructive"
StartIcon={Icon.FiTrash}
onClick={() => {
formMethods.setValue(
"users",
formMethods.getValues("users").filter((user) => user !== id.toString())
);
}}
/>
)}
{schedulingType === SchedulingType.ROUND_ROBIN && (
<>
<FixedHosts
options={teamMembersOptions.sort(sortByLabel)}
isOptionDisabled={(option) =>
!!formMethods.getValues("hosts").find((host) => host.userId.toString() === option.value)
}
placeholder={t("add_fixed_hosts")}
labelText={t("fixed_hosts")}
control={formMethods.control}
/>
<div className="flex flex-col space-y-5 bg-gray-50 p-4">
<div>
<Label>{t("round_robin_hosts")}</Label>
<Controller
name="hosts"
control={formMethods.control}
render={({ field: { onChange, value } }) => (
<CheckedTeamSelect
isDisabled={false}
onChange={(options) =>
onChange(
options.map((option) => ({
isFixed: false,
userId: parseInt(option.value, 10),
}))
)
}
value={value
.map(
(host) =>
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
teamMembers
.map(mapUserToValue)
.find((member) => member.value === host.userId.toString())!
)
.filter(Boolean)}
controlShouldRenderValue={false}
options={teamMembersOptions.sort(sortByLabel)}
isOptionDisabled={(option) =>
!!formMethods
.getValues("hostsFixed")
.find((host) => host.userId.toString() === option.value)
}
placeholder={t("add_attendees")}
/>
)}
/>
</div>
{/*<TextField
required
type="number"
label={t("minimum_round_robin_hosts_count")}
defaultValue={1}
{...formMethods.register("minimumHostCount")}
addOnSuffix={<>{t("hosts")}</>}
/>*/}
</div>
</>
)}
</div>
)}
</div>
@@ -1,20 +1,21 @@
import { EventTypeSetupInfered, 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, Icon, showToast } from "@calcom/ui";
import { Button, Dialog, DialogContent, EmptyScreen, showToast } from "@calcom/ui";
import { FiPlus } from "@calcom/ui/components/icon";
export const EventTeamWebhooksTab = ({
eventType,
team,
}: Pick<EventTypeSetupInfered, "eventType" | "team">) => {
}: Pick<EventTypeSetupProps, "eventType" | "team">) => {
const { t } = useLocale();
const utils = trpc.useContext();
@@ -84,7 +85,7 @@ export const EventTeamWebhooksTab = ({
<Button
color="secondary"
data-testid="new_webhook"
StartIcon={Icon.FiPlus}
StartIcon={FiPlus}
onClick={() => setCreateModalOpen(true)}>
{t("new_webhook")}
</Button>
@@ -99,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
@@ -130,7 +131,10 @@ export const EventTeamWebhooksTab = ({
{/* New webhook dialog */}
<Dialog open={createModalOpen} onOpenChange={(isOpen) => !isOpen && setCreateModalOpen(false)}>
<DialogContent title={t("create_webhook")} description={t("create_webhook_team_event_type")}>
<DialogContent
enableOverflow
title={t("create_webhook")}
description={t("create_webhook_team_event_type")}>
<WebhookForm
onSubmit={onCreateWebhook}
onCancel={() => setCreateModalOpen(false)}
@@ -1,10 +1,11 @@
import { TFunction } from "next-i18next";
import type { TFunction } from "next-i18next";
import { useRouter } from "next/router";
import { EventTypeSetupInfered, FormValues } from "pages/event-types/[type]";
import { useMemo, useState } from "react";
import { UseFormReturn } from "react-hook-form";
import type { EventTypeSetupProps, FormValues } from "pages/event-types/[type]";
import { useMemo, useState, Suspense } from "react";
import type { UseFormReturn } from "react-hook-form";
import { TbWebhook } from "react-icons/tb";
import Shell from "@calcom/features/shell/Shell";
import { classNames } from "@calcom/lib";
import { CAL_URL } from "@calcom/lib/constants";
import { useLocale } from "@calcom/lib/hooks/useLocale";
@@ -15,15 +16,14 @@ import {
ButtonGroup,
ConfirmationDialogContent,
Dialog,
Divider,
DropdownMenuSeparator,
Dropdown,
DropdownMenuContent,
DropdownMenuItem,
DropdownItem,
DropdownMenuTrigger,
HorizontalTabs,
Icon,
Label,
Shell,
showToast,
Skeleton,
Switch,
@@ -31,15 +31,29 @@ import {
VerticalDivider,
VerticalTabs,
} from "@calcom/ui";
import {
FiLink,
FiCalendar,
FiClock,
FiSliders,
FiRepeat,
FiGrid,
FiZap,
FiUsers,
FiExternalLink,
FiCode,
FiTrash,
FiMoreHorizontal,
FiLoader,
} from "@calcom/ui/components/icon";
import { ClientSuspense } from "@components/ClientSuspense";
import { EmbedButton, EmbedDialog } from "@components/Embed";
type Props = {
children: React.ReactNode;
eventType: EventTypeSetupInfered["eventType"];
currentUserMembership: EventTypeSetupInfered["currentUserMembership"];
team: EventTypeSetupInfered["team"];
eventType: EventTypeSetupProps["eventType"];
currentUserMembership: EventTypeSetupProps["currentUserMembership"];
team: EventTypeSetupProps["team"];
disableBorder?: boolean;
enabledAppsNumber: number;
installedAppsNumber: number;
@@ -56,48 +70,51 @@ function getNavigation(props: {
installedAppsNumber: number;
}) {
const { eventType, t, enabledAppsNumber, installedAppsNumber, enabledWorkflowsNumber } = props;
const duration =
eventType.metadata?.multipleDuration?.map((duration) => ` ${duration}`) || eventType.length;
return [
{
name: "event_setup_tab_title",
href: `/event-types/${eventType.id}?tabName=setup`,
icon: Icon.FiLink,
info: `${eventType.length} Mins`, // TODO: Get this from props
icon: FiLink,
info: `${duration} ${t("minute_timeUnit")}`, // TODO: Get this from props
},
{
name: "availability",
href: `/event-types/${eventType.id}?tabName=availability`,
icon: Icon.FiCalendar,
icon: FiCalendar,
info: `default_schedule_name`, // TODO: Get this from props
},
{
name: "event_limit_tab_title",
href: `/event-types/${eventType.id}?tabName=limits`,
icon: Icon.FiClock,
icon: FiClock,
info: `event_limit_tab_description`,
},
{
name: "event_advanced_tab_title",
href: `/event-types/${eventType.id}?tabName=advanced`,
icon: Icon.FiSliders,
icon: FiSliders,
info: `event_advanced_tab_description`,
},
{
name: "recurring",
href: `/event-types/${eventType.id}?tabName=recurring`,
icon: Icon.FiRepeat,
icon: FiRepeat,
info: `recurring_event_tab_description`,
},
{
name: "apps",
href: `/event-types/${eventType.id}?tabName=apps`,
icon: Icon.FiGrid,
icon: FiGrid,
//TODO: Handle proper translation with count handling
info: `${installedAppsNumber} apps, ${enabledAppsNumber} ${t("active")}`,
},
{
name: "workflows",
href: `/event-types/${eventType.id}?tabName=workflows`,
icon: Icon.FiZap,
icon: FiZap,
info: `${enabledWorkflowsNumber} ${t("active")}`,
},
];
@@ -152,9 +169,9 @@ function EventTypeSingleLayout({
// If there is a team put this navigation item within the tabs
if (team) {
navigation.splice(2, 0, {
name: "scheduling_type",
name: "assignment",
href: `/event-types/${eventType.id}?tabName=team`,
icon: Icon.FiUsers,
icon: FiUsers,
info: eventType.schedulingType === "COLLECTIVE" ? "collective" : "round_robin",
});
navigation.push({
@@ -178,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">
@@ -205,17 +221,17 @@ function EventTypeSingleLayout({
<Button
color="secondary"
target="_blank"
size="icon"
variant="icon"
href={permalink}
rel="noreferrer"
StartIcon={Icon.FiExternalLink}
StartIcon={FiExternalLink}
/>
</Tooltip>
<Button
color="secondary"
size="icon"
StartIcon={Icon.FiLink}
variant="icon"
StartIcon={FiLink}
tooltip={t("copy_link")}
onClick={() => {
navigator.clipboard.writeText(permalink);
@@ -224,15 +240,15 @@ function EventTypeSingleLayout({
/>
<EmbedButton
embedUrl={encodeURIComponent(embedLink)}
StartIcon={Icon.FiCode}
StartIcon={FiCode}
color="secondary"
size="icon"
variant="icon"
tooltip={t("embed")}
/>
<Button
color="secondary"
size="icon"
StartIcon={Icon.FiTrash}
variant="icon"
StartIcon={FiTrash}
tooltip={t("delete")}
disabled={!hasPermsToDelete}
onClick={() => setDeleteDialogOpen(true)}
@@ -242,37 +258,42 @@ function EventTypeSingleLayout({
<VerticalDivider className="hidden lg:block" />
<Dropdown>
<DropdownMenuTrigger className="block h-9 w-9 justify-center rounded-md border border-gray-200 bg-transparent text-gray-700 lg:hidden">
<Icon.FiMoreHorizontal className="group-hover:text-gray-800" />
<DropdownMenuTrigger asChild>
<Button className="lg:hidden" StartIcon={FiMoreHorizontal} variant="icon" color="secondary" />
</DropdownMenuTrigger>
<DropdownMenuContent>
<DropdownMenuItem className="focus:ring-gray-100">
<Button
color="minimal"
StartIcon={Icon.FiExternalLink}
<DropdownItem
target="_blank"
type="button"
StartIcon={FiExternalLink}
href={permalink}
rel="noreferrer"
className="min-w-full">
rel="noreferrer">
{t("preview")}
</Button>
</DropdownItem>
</DropdownMenuItem>
<DropdownMenuItem className="focus:ring-gray-100">
<Button color="minimal" StartIcon={Icon.FiLink}>
<DropdownItem
type="button"
StartIcon={FiLink}
onClick={() => {
navigator.clipboard.writeText(permalink);
showToast("Link copied!", "success");
}}>
{t("copy_link")}
</Button>
</DropdownItem>
</DropdownMenuItem>
<DropdownMenuItem className="focus:ring-gray-100">
<Button
color="minimal"
StartIcon={Icon.FiTrash}
<DropdownItem
type="button"
color="destructive"
StartIcon={FiTrash}
disabled={!hasPermsToDelete}
onClick={() => setDeleteDialogOpen(true)}
className="min-w-full">
onClick={() => setDeleteDialogOpen(true)}>
{t("delete")}
</Button>
</DropdownItem>
</DropdownMenuItem>
<Divider />
<DropdownMenuSeparator className="block sm:hidden" />
<div className="flex items-center rounded-md py-1.5 px-4 sm:hidden sm:hover:bg-gray-100">
<Skeleton
as={Label}
@@ -301,8 +322,8 @@ function EventTypeSingleLayout({
</Button>
</div>
}>
<ClientSuspense fallback={<Icon.FiLoader />}>
<div className="-mt-2 flex flex-col xl:flex-row xl:space-x-8">
<Suspense fallback={<FiLoader />}>
<div className="flex flex-col xl:flex-row xl:space-x-6">
<div className="hidden xl:block">
<VerticalTabs
className="primary-navigation"
@@ -317,14 +338,14 @@ function EventTypeSingleLayout({
<div className="w-full ltr:mr-2 rtl:ml-2">
<div
className={classNames(
"mt-4 rounded-md border-neutral-200 bg-white sm:mx-0 xl:mt-0",
disableBorder ? "border-0 xl:-mt-4 " : "p-2 md:border md:p-6"
"mt-4 rounded-md border-gray-200 bg-white sm:mx-0 xl:mt-0",
disableBorder ? "border-0 " : "p-2 md:border md:p-6"
)}>
{children}
</div>
</div>
</div>
</ClientSuspense>
</Suspense>
<Dialog open={deleteDialogOpen} onOpenChange={setDeleteDialogOpen}>
<ConfirmationDialogContent
isLoading={deleteMutation.isLoading}
@@ -57,7 +57,7 @@ export default function RecurringEventController({
{recurringEventState && (
<div data-testid="recurring-event-collapsible" className="text-sm">
<div className="flex items-center">
<p className="mr-2 text-neutral-900">{t("repeats_every")}</p>
<p className="text-gray-900 ltr:mr-2 rtl:ml-2">{t("repeats_every")}</p>
<input
type="number"
min="1"
@@ -89,7 +89,7 @@ export default function RecurringEventController({
/>
</div>
<div className="mt-4 flex items-center">
<p className="mr-2 text-neutral-900">{t("for_a_maximum_of")}</p>
<p className="text-gray-900 ltr:mr-2 rtl:ml-2">{t("for_a_maximum_of")}</p>
<input
type="number"
min="1"
@@ -105,7 +105,7 @@ export default function RecurringEventController({
setRecurringEventState(newVal);
}}
/>
<p className="mr-2 text-neutral-900">
<p className="text-gray-900 ltr:mr-2 rtl:ml-2">
{t("events", {
count: recurringEventState.count,
})}
@@ -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,4 +1,5 @@
import { Icon, SkeletonAvatar, SkeletonContainer, SkeletonText } from "@calcom/ui";
import { SkeletonAvatar, SkeletonContainer, SkeletonText } from "@calcom/ui";
import { FiClock, FiUser } from "@calcom/ui/components/icon";
function SkeletonLoader() {
return (
@@ -10,7 +11,7 @@ function SkeletonLoader() {
<SkeletonText className="h-4 w-24" />
</div>
</div>
<ul className="divide-y divide-neutral-200 rounded-md border border-gray-200 bg-white sm:mx-0 sm:overflow-hidden">
<ul className="divide-y divide-gray-200 rounded-md border border-gray-200 bg-white sm:mx-0 sm:overflow-hidden">
<SkeletonItem />
<SkeletonItem />
<SkeletonItem />
@@ -31,11 +32,11 @@ function SkeletonItem() {
<div className="">
<ul className="mt-2 flex space-x-4 rtl:space-x-reverse ">
<li className="flex items-center whitespace-nowrap">
<Icon.FiClock className="mt-0.5 mr-1.5 inline h-4 w-4 text-gray-200" />
<FiClock className="mt-0.5 mr-1.5 inline h-4 w-4 text-gray-200" />
<SkeletonText className="h-4 w-12" />
</li>
<li className="flex items-center whitespace-nowrap">
<Icon.FiUser className="mt-0.5 mr-1.5 inline h-4 w-4 text-gray-200" />
<FiUser className="mt-0.5 mr-1.5 inline h-4 w-4 text-gray-200" />
<SkeletonText className="h-4 w-12" />
</li>
</ul>
@@ -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";
@@ -16,7 +17,7 @@ const CreateEventsOnCalendarSelect = (props: ICreateEventsOnCalendarSelectProps)
<>
<div className="mt-6 flex flex-row">
<div className="w-full">
<label htmlFor="createEventsOn" className="flex text-sm font-medium text-neutral-700">
<label htmlFor="createEventsOn" className="flex text-sm font-medium text-gray-700">
{t("create_events_on")}
</label>
<div className="mt-2">
@@ -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,
@@ -113,7 +119,7 @@ const UserProfile = (props: IUserProfileProps) => {
name="avatar"
id="avatar"
placeholder="URL"
className="mt-1 block w-full rounded-sm border border-gray-300 px-3 py-2 text-sm focus:border-neutral-800 focus:outline-none focus:ring-neutral-800"
className="mt-1 block w-full rounded-sm border border-gray-300 px-3 py-2 text-sm focus:border-gray-800 focus:outline-none focus:ring-gray-800"
defaultValue={imageSrc}
/>
<div className="flex items-center px-4">
@@ -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-neutral-500 focus:outline-none focus:ring-neutral-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";
@@ -19,7 +20,8 @@ interface IUserSettingsProps {
const UserSettings = (props: IUserSettingsProps) => {
const { user, nextStep } = props;
const { t } = useLocale();
const [selectedTimeZone, setSelectedTimeZone] = useState(user.timeZone ?? dayjs.tz.guess());
const [selectedTimeZone, setSelectedTimeZone] = useState(dayjs.tz.guess());
const telemetry = useTelemetry();
const {
register,
handleSubmit,
@@ -30,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";
@@ -3,7 +3,7 @@ import { useRouter } from "next/router";
import React, { useEffect, useState } from "react";
import { Toaster } from "react-hot-toast";
import { StepCard, Steps } from "../../..";
import { StepCard, Steps } from "@calcom/ui";
export default function WizardLayout({
children,
+4
View File
@@ -0,0 +1,4 @@
We don't have many layouts currently however, if they are relevant to a features - please put them in their relvant component folder
in `web/components` if you believe they will be reused in other apps please place them in `packages/features/[feature]`
Thanks Sean 🔥
@@ -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";
@@ -82,7 +82,7 @@ const DisableTwoFactorAuthModal = ({ onDisable, onCancel }: DisableTwoFactorAuth
</div>
<div className="mt-5 sm:mt-4 sm:flex sm:flex-row-reverse">
<Button type="submit" className="ltr:ml-2 rtl:mr-2" disabled={isDisabling}>
<Button type="submit" className="ltr:ml-2 ltr:mr-2 rtl:ml-2" disabled={isDisabling}>
{t("disable")}
</Button>
<Button color="secondary" onClick={onCancel}>
@@ -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";
@@ -177,7 +178,7 @@ const EnableTwoFactorModal = ({ onEnable, onCancel }: EnableTwoFactorModalProps)
<WithStep step={SetupStep.ConfirmPassword} current={step}>
<Button
type="submit"
className="ltr:ml-2 rtl:mr-2"
className="ltr:ml-2 ltr:mr-2 rtl:ml-2"
onClick={handleSetup}
disabled={password.length === 0 || isSubmitting}>
{t("continue")}
@@ -186,13 +187,13 @@ const EnableTwoFactorModal = ({ onEnable, onCancel }: EnableTwoFactorModalProps)
<WithStep step={SetupStep.DisplayQrCode} current={step}>
<Button
type="submit"
className="ltr:ml-2 rtl:mr-2"
className="ltr:ml-2 ltr:mr-2 rtl:ml-2"
onClick={() => setStep(SetupStep.EnterTotpCode)}>
{t("continue")}
</Button>
</WithStep>
<WithStep step={SetupStep.EnterTotpCode} current={step}>
<Button type="submit" className="ltr:ml-2 rtl:mr-2" disabled={isSubmitting}>
<Button type="submit" className="ltr:ml-2 ltr:mr-2 rtl:ml-2" disabled={isSubmitting}>
{t("enable")}
</Button>
</WithStep>
@@ -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,4 @@
import { ShieldCheckIcon } from "@calcom/ui";
import { ShieldCheckIcon } from "@calcom/ui/components/icon";
const TwoFactorModalHeader = ({ title, description }: { title: string; description: string }) => {
return (
@@ -2,7 +2,8 @@ import { useMutation } from "@tanstack/react-query";
import { useLocale } from "@calcom/lib/hooks/useLocale";
import { trpc } from "@calcom/trpc/react";
import { Badge, Icon, showToast, Switch } from "@calcom/ui";
import { Badge, showToast, Switch } from "@calcom/ui";
import { FiArrowLeft } from "@calcom/ui/components/icon";
export function CalendarSwitch(props: {
type: string;
@@ -62,7 +63,7 @@ export function CalendarSwitch(props: {
}
);
return (
<div className="flex space-x-2 py-1">
<div className="flex space-x-2 py-1 rtl:space-x-reverse">
<Switch
key={props.externalId}
name="enabled"
@@ -74,7 +75,7 @@ export function CalendarSwitch(props: {
/>
{props.defaultSelected && (
<Badge variant="gray">
<Icon.FiArrowLeft className="mr-1" /> {t("adding_events_to")}
<FiArrowLeft className="mr-1" /> {t("adding_events_to")}
</Badge>
)}
</div>
@@ -90,7 +90,7 @@ const DisableTwoFactorAuthModal = ({
</div>
<div className="mt-5 sm:mt-4 sm:flex sm:flex-row-reverse">
<Button type="submit" className="ltr:ml-2 rtl:mr-2" disabled={isDisabling}>
<Button type="submit" className="ltr:ml-2 ltr:mr-2 rtl:ml-2" disabled={isDisabling}>
{t("disable")}
</Button>
<Button color="secondary" onClick={onCancel}>
@@ -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";
@@ -170,7 +171,7 @@ const EnableTwoFactorModal = ({ onEnable, onCancel, open, onOpenChange }: Enable
<WithStep step={SetupStep.ConfirmPassword} current={step}>
<Button
type="submit"
className="ltr:ml-2 rtl:mr-2"
className="ltr:ml-2 ltr:mr-2 rtl:ml-2"
onClick={handleSetup}
disabled={password.length === 0 || isSubmitting}>
{t("continue")}
@@ -179,13 +180,13 @@ const EnableTwoFactorModal = ({ onEnable, onCancel, open, onOpenChange }: Enable
<WithStep step={SetupStep.DisplayQrCode} current={step}>
<Button
type="submit"
className="ltr:ml-2 rtl:mr-2"
className="ltr:ml-2 ltr:mr-2 rtl:ml-2"
onClick={() => setStep(SetupStep.EnterTotpCode)}>
{t("continue")}
</Button>
</WithStep>
<WithStep step={SetupStep.EnterTotpCode} current={step}>
<Button type="submit" className="ltr:ml-2 rtl:mr-2" disabled={isSubmitting}>
<Button type="submit" className="ltr:ml-2 ltr:mr-2 rtl:ml-2" disabled={isSubmitting}>
{t("enable")}
</Button>
</WithStep>
@@ -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);
@@ -97,7 +119,7 @@ const SetupFormStep1 = (props: { setIsLoading: (val: boolean) => void }) => {
<TextField
addOnLeading={
!longWebsiteUrl && (
<span className="items-centerpx-3 inline-flex rounded-none text-sm text-gray-500">
<span className="inline-flex items-center rounded-none px-3 text-sm text-gray-500">
{process.env.NEXT_PUBLIC_WEBSITE_URL}/
</span>
)
@@ -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;

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