2023-06-15 10:42:47 +00:00
import type { User as UserAuth } from "next-auth" ;
2022-08-09 09:21:15 +00:00
import { signOut , useSession } from "next-auth/react" ;
2023-04-03 17:25:45 +00:00
import dynamic from "next/dynamic" ;
2022-08-09 09:21:15 +00:00
import Link from "next/link" ;
2023-02-20 14:11:51 +00:00
import type { NextRouter } from "next/router" ;
import { useRouter } from "next/router" ;
2023-07-31 18:51:08 +00:00
import type { Dispatch , ReactNode , SetStateAction , ReactElement } from "react" ;
import React , { Fragment , useEffect , useState , useRef , useMemo , cloneElement } from "react" ;
2022-08-09 09:21:15 +00:00
import { Toaster } from "react-hot-toast" ;
import dayjs from "@calcom/dayjs" ;
import { useIsEmbed } from "@calcom/embed-core/embed-iframe" ;
2022-10-10 17:00:09 +00:00
import UnconfirmedBookingBadge from "@calcom/features/bookings/UnconfirmedBookingBadge" ;
2022-08-09 09:21:15 +00:00
import ImpersonatingBanner from "@calcom/features/ee/impersonation/components/ImpersonatingBanner" ;
feat: Org settings - profile,appearance, child teams, create new child (#9231)
* Initial commit
* Adding feature flag
* Desktop first banner, mobile pending
* Removing dead code and img
* AppInstallButtonBase
* WIP
* Adds Email verification template+translations for organizations (#9202)
* feat: Orgs Schema Changing `scopedMembers` to `orgUsers` (#9209)
* Change scopedMembers to orgMembers
* Change to orgUsers
* First step done
* Merge branch 'feat/organizations-onboarding' of github.com:calcom/cal.com into feat/organizations-onboarding
* Session logic to show org label
* Step 2 done, avatar not working
* List orgs and list teams specific if orgs exist
* Conditionally show org - fix settings layout - add labels for all pages
* Profile Page + update
* Org specific team creation
* appearance page
* Ensure members cant of org cant update settings in UI
* Fix update handler imports
* hide billing on sub teams
* Update profile slug page
* Letting duplicate slugs for teams to support orgs
* Add slug coliisions for org
* Covering null on unique clauses
* Covering null on unique clauses
* Extract to utils
* Update settings to use subdomain path in team url , team + org
* Supporting having the orgId in the session cookie
* Onboarding admins step
* Last step to create teams
* Update handler comments
* Upgrade ORG banner - disabled team banner for child teams
* Handle publishing ORGS
* Fix licenese issue
* Update packages/trpc/server/routers/viewer/teams/create.handler.ts
* Moving change password handler, improving verifying code flow
* Clearing error before submitting
* Reverting email testing api changes
* Reverting having the banner for now
* Consistent exported components
* Remove unneeded files from banner
* Removing uneeded code
* Fixing avatar selector
* Using meta component for head/descr
* Missing i18n strings
* A11ly
* Feedback
* Making an org avatar (temp)
* Add slug colission detection for user and team name
* Fix Import
* Remove update password func
* Fix module import over relative
* feat: organization event type filter (#9253)
Signed-off-by: Udit Takkar <udit.07814802719@cse.mait.ac.in>
* Missing changes to support orgs schema changes
* Remove app install button sa its in 9337
* Remove i18n key not being used
* feat: Onboarding process to create an organization (#9184)
* Desktop first banner, mobile pending
* Removing dead code and img
* WIP
* Adds Email verification template+translations for organizations (#9202)
* First step done
* Merge branch 'feat/organizations-onboarding' of github.com:calcom/cal.com into feat/organizations-onboarding
* Step 2 done, avatar not working
* Covering null on unique clauses
* Onboarding admins step
* Last step to create teams
* Moving change password handler, improving verifying code flow
* Clearing error before submitting
* Reverting email testing api changes
* Reverting having the banner for now
* Consistent exported components
* Remove unneeded files from banner
* Removing uneeded code
* Fixing avatar selector
* Using meta component for head/descr
* Missing i18n strings
* Feedback
* Making an org avatar (temp)
* Check for subteams slug clashes with usernames
* Fixing create teams onsuccess
* feedback
* Making sure we check requestedSlug now
---------
Co-authored-by: sean-brydon <55134778+sean-brydon@users.noreply.github.com>
* feat: [CAL-1816] Organization subdomain support (#9345)
* Desktop first banner, mobile pending
* Removing dead code and img
* WIP
* Adds Email verification template+translations for organizations (#9202)
* First step done
* Merge branch 'feat/organizations-onboarding' of github.com:calcom/cal.com into feat/organizations-onboarding
* Step 2 done, avatar not working
* Covering null on unique clauses
* Onboarding admins step
* Last step to create teams
* Moving change password handler, improving verifying code flow
* Clearing error before submitting
* Reverting email testing api changes
* Reverting having the banner for now
* Consistent exported components
* Remove unneeded files from banner
* Removing uneeded code
* Fixing avatar selector
* Using meta component for head/descr
* Missing i18n strings
* Feedback
* Making an org avatar (temp)
* Check for subteams slug clashes with usernames
* Fixing create teams onsuccess
* Covering users and subteams, excluding non-org users
* Unpublished teams shows correctly
* Create subdomain in Vercel
* feedback
* Renaming Vercel env vars
* Vercel domain check before creation
* Supporting cal-staging.com
* Change to have vercel detect it
* vercel domain check data message error
* Remove check domain
* Making sure we check requestedSlug now
* Feedback and unneeded code
* Reverting unneeded changes
* Unneeded changes
---------
Co-authored-by: sean-brydon <55134778+sean-brydon@users.noreply.github.com>
* Vercel subdomain creation in PROD only
* feat: organization settings general and members page (#9266)
* feat: organization settings general page
Signed-off-by: Udit Takkar <udit.07814802719@cse.mait.ac.in>
* feat: add members page
Signed-off-by: Udit Takkar <udit.07814802719@cse.mait.ac.in>
* chore: remove
Signed-off-by: Udit Takkar <udit.07814802719@cse.mait.ac.in>
* fix: use invalidate
Signed-off-by: Udit Takkar <udit.07814802719@cse.mait.ac.in>
* fix: delete mutation
Signed-off-by: Udit Takkar <udit.07814802719@cse.mait.ac.in>
* fix: remove organization id
Signed-off-by: Udit Takkar <udit.07814802719@cse.mait.ac.in>
* chore
Signed-off-by: Udit Takkar <udit.07814802719@cse.mait.ac.in>
* fix: use zod schema
Signed-off-by: Udit Takkar <udit.07814802719@cse.mait.ac.in>
---------
Signed-off-by: Udit Takkar <udit.07814802719@cse.mait.ac.in>
* Type fixes
* Reverting changes
* Update UsernameTextfield.tsx
* More reverts
* Update next-auth-options.ts
* Update common.json
* Type fixes
* Include invite token for orgs
* Update org schema
* Make token settings optional as it isnt used in orgs yet
* Fix missing prop
---------
Signed-off-by: Udit Takkar <udit.07814802719@cse.mait.ac.in>
Co-authored-by: Leo Giovanetti <hello@leog.me>
Co-authored-by: Joe Au-Yeung <65426560+joeauyeung@users.noreply.github.com>
Co-authored-by: Udit Takkar <53316345+Udit-takkar@users.noreply.github.com>
Co-authored-by: zomars <zomars@me.com>
Co-authored-by: Hariom Balhara <hariombalhara@gmail.com>
2023-06-15 17:27:39 +00:00
import { OrgUpgradeBanner } from "@calcom/features/ee/organizations/components/OrgUpgradeBanner" ;
2022-08-09 09:21:15 +00:00
import HelpMenuItem from "@calcom/features/ee/support/components/HelpMenuItem" ;
2022-11-16 21:07:20 +00:00
import { TeamsUpgradeBanner } from "@calcom/features/ee/teams/components" ;
2023-03-25 00:59:04 +00:00
import { useFlagMap } from "@calcom/features/flags/context/provider" ;
2023-01-10 15:39:29 +00:00
import { KBarContent , KBarRoot , KBarTrigger } from "@calcom/features/kbar/Kbar" ;
2023-01-09 13:57:12 +00:00
import TimezoneChangeDialog from "@calcom/features/settings/TimezoneChangeDialog" ;
2023-01-01 11:19:58 +00:00
import AdminPasswordBanner from "@calcom/features/users/components/AdminPasswordBanner" ;
2023-06-07 07:27:48 +00:00
import VerifyEmailBanner from "@calcom/features/users/components/VerifyEmailBanner" ;
2022-08-09 09:21:15 +00:00
import classNames from "@calcom/lib/classNames" ;
2023-07-04 22:11:10 +00:00
import { APP_NAME , DESKTOP_APP_LINK , JOIN_DISCORD , ROADMAP , WEBAPP_URL } from "@calcom/lib/constants" ;
2023-06-18 20:54:57 +00:00
import { getPlaceholderAvatar } from "@calcom/lib/defaultAvatarImage" ;
2023-04-05 18:14:46 +00:00
import getBrandColours from "@calcom/lib/getBrandColours" ;
2023-06-01 09:45:24 +00:00
import { useIsomorphicLayoutEffect } from "@calcom/lib/hooks/useIsomorphicLayoutEffect" ;
2022-08-09 09:21:15 +00:00
import { useLocale } from "@calcom/lib/hooks/useLocale" ;
2023-03-25 00:59:04 +00:00
import { isKeyInObject } from "@calcom/lib/isKeyInObject" ;
2023-06-15 10:42:47 +00:00
import type { User } from "@calcom/prisma/client" ;
2022-08-09 09:21:15 +00:00
import { trpc } from "@calcom/trpc/react" ;
2023-05-20 00:37:58 +00:00
import useAvatarQuery from "@calcom/trpc/react/hooks/useAvatarQuery" ;
2023-06-07 07:27:48 +00:00
import useEmailVerifyCheck from "@calcom/trpc/react/hooks/useEmailVerifyCheck" ;
2022-08-09 09:21:15 +00:00
import useMeQuery from "@calcom/trpc/react/hooks/useMeQuery" ;
2023-02-20 14:11:51 +00:00
import type { SVGComponent } from "@calcom/types/SVGComponent" ;
2022-11-23 02:55:25 +00:00
import {
feat: Organizations (#8993)
* Initial commit
* Adding feature flag
* feat: Orgs Schema Changing `scopedMembers` to `orgUsers` (#9209)
* Change scopedMembers to orgMembers
* Change to orgUsers
* Letting duplicate slugs for teams to support orgs
* Covering null on unique clauses
* Supporting having the orgId in the session cookie
* feat: organization event type filter (#9253)
Signed-off-by: Udit Takkar <udit.07814802719@cse.mait.ac.in>
* Missing changes to support orgs schema changes
* feat: Onboarding process to create an organization (#9184)
* Desktop first banner, mobile pending
* Removing dead code and img
* WIP
* Adds Email verification template+translations for organizations (#9202)
* First step done
* Merge branch 'feat/organizations-onboarding' of github.com:calcom/cal.com into feat/organizations-onboarding
* Step 2 done, avatar not working
* Covering null on unique clauses
* Onboarding admins step
* Last step to create teams
* Moving change password handler, improving verifying code flow
* Clearing error before submitting
* Reverting email testing api changes
* Reverting having the banner for now
* Consistent exported components
* Remove unneeded files from banner
* Removing uneeded code
* Fixing avatar selector
* Using meta component for head/descr
* Missing i18n strings
* Feedback
* Making an org avatar (temp)
* Check for subteams slug clashes with usernames
* Fixing create teams onsuccess
* feedback
* Making sure we check requestedSlug now
---------
Co-authored-by: sean-brydon <55134778+sean-brydon@users.noreply.github.com>
* feat: [CAL-1816] Organization subdomain support (#9345)
* Desktop first banner, mobile pending
* Removing dead code and img
* WIP
* Adds Email verification template+translations for organizations (#9202)
* First step done
* Merge branch 'feat/organizations-onboarding' of github.com:calcom/cal.com into feat/organizations-onboarding
* Step 2 done, avatar not working
* Covering null on unique clauses
* Onboarding admins step
* Last step to create teams
* Moving change password handler, improving verifying code flow
* Clearing error before submitting
* Reverting email testing api changes
* Reverting having the banner for now
* Consistent exported components
* Remove unneeded files from banner
* Removing uneeded code
* Fixing avatar selector
* Using meta component for head/descr
* Missing i18n strings
* Feedback
* Making an org avatar (temp)
* Check for subteams slug clashes with usernames
* Fixing create teams onsuccess
* Covering users and subteams, excluding non-org users
* Unpublished teams shows correctly
* Create subdomain in Vercel
* feedback
* Renaming Vercel env vars
* Vercel domain check before creation
* Supporting cal-staging.com
* Change to have vercel detect it
* vercel domain check data message error
* Remove check domain
* Making sure we check requestedSlug now
* Feedback and unneeded code
* Reverting unneeded changes
* Unneeded changes
---------
Co-authored-by: sean-brydon <55134778+sean-brydon@users.noreply.github.com>
* Vercel subdomain creation in PROD only
* Making sure we let localhost still work
* Feedback
* Type check fixes
* feat: Organization branding in side menu (#9279)
* Desktop first banner, mobile pending
* Removing dead code and img
* WIP
* Adds Email verification template+translations for organizations (#9202)
* First step done
* Merge branch 'feat/organizations-onboarding' of github.com:calcom/cal.com into feat/organizations-onboarding
* Step 2 done, avatar not working
* Covering null on unique clauses
* Onboarding admins step
* Last step to create teams
* Moving change password handler, improving verifying code flow
* Clearing error before submitting
* Reverting email testing api changes
* Reverting having the banner for now
* Consistent exported components
* Remove unneeded files from banner
* Removing uneeded code
* Fixing avatar selector
* Org branding provider used in shell sidebar
* Using meta component for head/descr
* Missing i18n strings
* Feedback
* Making an org avatar (temp)
* Using org avatar (temp)
* Not showing org logo if not set
* User onboarding with org branding (slug)
* Check for subteams slug clashes with usernames
* Fixing create teams onsuccess
* feedback
* Feedback
* Org public profile
* Public profiles for team event types
* Added setup profile alert
* Using org avatar on subteams avatar
* Making sure we show the set up profile on org only
* Profile username availability rely on org hook
* Update apps/web/pages/team/[slug].tsx
Co-authored-by: sean-brydon <55134778+sean-brydon@users.noreply.github.com>
* Update apps/web/pages/team/[slug].tsx
Co-authored-by: sean-brydon <55134778+sean-brydon@users.noreply.github.com>
---------
Co-authored-by: sean-brydon <55134778+sean-brydon@users.noreply.github.com>
* feat: Organization support for event types page (#9449)
* Desktop first banner, mobile pending
* Removing dead code and img
* WIP
* Adds Email verification template+translations for organizations (#9202)
* First step done
* Merge branch 'feat/organizations-onboarding' of github.com:calcom/cal.com into feat/organizations-onboarding
* Step 2 done, avatar not working
* Covering null on unique clauses
* Onboarding admins step
* Last step to create teams
* Moving change password handler, improving verifying code flow
* Clearing error before submitting
* Reverting email testing api changes
* Reverting having the banner for now
* Consistent exported components
* Remove unneeded files from banner
* Removing uneeded code
* Fixing avatar selector
* Org branding provider used in shell sidebar
* Using meta component for head/descr
* Missing i18n strings
* Feedback
* Making an org avatar (temp)
* Using org avatar (temp)
* Not showing org logo if not set
* User onboarding with org branding (slug)
* Check for subteams slug clashes with usernames
* Fixing create teams onsuccess
* feedback
* Feedback
* Org public profile
* Public profiles for team event types
* Added setup profile alert
* Using org avatar on subteams avatar
* Processing orgs and children as profile options
* Reverting change not belonging to this PR
* Making sure we show the set up profile on org only
* Removing console.log
* Comparing memberships to choose the highest one
---------
Co-authored-by: sean-brydon <55134778+sean-brydon@users.noreply.github.com>
* Type errors
* Refactor and type fixes
* Update orgDomains.ts
* Feedback
* Reverting
* NIT
* fix issue getting org slug from domain
* Improving orgDomains util
* Host comes with port
* Update useRouterQuery.ts
* Feedback
* Feedback
* Feedback
* Feedback: SSR for user event-types to have org context
* chore: Cache node_modules (#9492)
* Adding check for cache hit
* Adding a separate install step first
* Put the restore cache steps back
* Revert the uses type for restoring cache
* Added step to restore nm cache
* Removed the cache-hit check
* Comments and naming
* Removed extra install command
* Updated the name of the linting step to be more clear
* Removes the need for useEffect here
* Feedback
* Feedback
* Cookie domain needs a dot
* Type fix
* Update apps/web/public/static/locales/en/common.json
Co-authored-by: Omar López <zomars@me.com>
* Update packages/emails/src/templates/OrganizationAccountVerifyEmail.tsx
* Feedback
---------
Signed-off-by: Udit Takkar <udit.07814802719@cse.mait.ac.in>
Co-authored-by: Joe Au-Yeung <65426560+joeauyeung@users.noreply.github.com>
Co-authored-by: Udit Takkar <53316345+Udit-takkar@users.noreply.github.com>
Co-authored-by: sean-brydon <55134778+sean-brydon@users.noreply.github.com>
Co-authored-by: zomars <zomars@me.com>
Co-authored-by: Efraín Rochín <roae.85@gmail.com>
Co-authored-by: Keith Williams <keithwillcode@gmail.com>
2023-06-14 21:40:20 +00:00
Avatar ,
2022-11-23 02:55:25 +00:00
Button ,
2023-01-12 22:11:15 +00:00
Credits ,
2022-11-23 02:55:25 +00:00
Dropdown ,
2023-03-25 00:59:04 +00:00
DropdownItem ,
2022-08-09 09:21:15 +00:00
DropdownMenuContent ,
DropdownMenuItem ,
2022-11-16 21:07:20 +00:00
DropdownMenuPortal ,
2022-08-09 09:21:15 +00:00
DropdownMenuSeparator ,
DropdownMenuTrigger ,
2023-01-10 15:39:29 +00:00
ErrorBoundary ,
2023-01-23 23:08:01 +00:00
HeadSeo ,
2023-03-25 00:59:04 +00:00
Logo ,
2023-01-10 15:39:29 +00:00
SkeletonText ,
2023-05-30 14:18:21 +00:00
Tooltip ,
2023-03-25 00:59:04 +00:00
showToast ,
2023-04-05 18:14:46 +00:00
useCalcomTheme ,
2023-06-15 10:42:47 +00:00
ButtonOrLink ,
2023-01-10 15:39:29 +00:00
} from "@calcom/ui" ;
2023-01-23 23:08:01 +00:00
import {
2023-04-12 15:26:31 +00:00
ArrowLeft ,
ArrowRight ,
BarChart ,
Calendar ,
Clock ,
Download ,
ExternalLink ,
FileText ,
Grid ,
HelpCircle ,
Link as LinkIcon ,
LogOut ,
Map ,
Moon ,
MoreHorizontal ,
2023-06-15 10:42:47 +00:00
ChevronDown ,
Copy ,
2023-04-12 15:26:31 +00:00
Settings ,
Users ,
Zap ,
2023-06-15 10:42:47 +00:00
User as UserIcon ,
2023-01-23 23:08:01 +00:00
} from "@calcom/ui/components/icon" ;
2023-07-18 21:30:17 +00:00
import { Discord } from "@calcom/ui/components/icon/Discord" ;
2022-08-24 20:18:42 +00:00
2023-07-24 10:25:55 +00:00
import { useOrgBranding } from "../ee/organizations/context/provider" ;
2023-03-08 11:30:24 +00:00
import FreshChatProvider from "../ee/support/lib/freshchat/FreshChatProvider" ;
2023-07-17 20:00:44 +00:00
import { NProgressNextRouter } from "./NProgressPageIndicator" ;
2023-01-24 15:27:05 +00:00
import { TeamInviteBadge } from "./TeamInviteBadge" ;
2023-04-03 17:25:45 +00:00
// need to import without ssr to prevent hydration errors
const Tips = dynamic ( ( ) = > import ( "@calcom/features/tips" ) . then ( ( mod ) = > mod . Tips ) , {
ssr : false ,
} ) ;
2022-08-24 20:18:42 +00:00
/* TODO: Migate this */
2022-08-09 09:21:15 +00:00
export const ONBOARDING_INTRODUCED_AT = dayjs ( "September 1 2021" ) . toISOString ( ) ;
export const ONBOARDING_NEXT_REDIRECT = {
redirect : {
permanent : false ,
destination : "/getting-started" ,
} ,
} as const ;
feat: Organizations (#8993)
* Initial commit
* Adding feature flag
* feat: Orgs Schema Changing `scopedMembers` to `orgUsers` (#9209)
* Change scopedMembers to orgMembers
* Change to orgUsers
* Letting duplicate slugs for teams to support orgs
* Covering null on unique clauses
* Supporting having the orgId in the session cookie
* feat: organization event type filter (#9253)
Signed-off-by: Udit Takkar <udit.07814802719@cse.mait.ac.in>
* Missing changes to support orgs schema changes
* feat: Onboarding process to create an organization (#9184)
* Desktop first banner, mobile pending
* Removing dead code and img
* WIP
* Adds Email verification template+translations for organizations (#9202)
* First step done
* Merge branch 'feat/organizations-onboarding' of github.com:calcom/cal.com into feat/organizations-onboarding
* Step 2 done, avatar not working
* Covering null on unique clauses
* Onboarding admins step
* Last step to create teams
* Moving change password handler, improving verifying code flow
* Clearing error before submitting
* Reverting email testing api changes
* Reverting having the banner for now
* Consistent exported components
* Remove unneeded files from banner
* Removing uneeded code
* Fixing avatar selector
* Using meta component for head/descr
* Missing i18n strings
* Feedback
* Making an org avatar (temp)
* Check for subteams slug clashes with usernames
* Fixing create teams onsuccess
* feedback
* Making sure we check requestedSlug now
---------
Co-authored-by: sean-brydon <55134778+sean-brydon@users.noreply.github.com>
* feat: [CAL-1816] Organization subdomain support (#9345)
* Desktop first banner, mobile pending
* Removing dead code and img
* WIP
* Adds Email verification template+translations for organizations (#9202)
* First step done
* Merge branch 'feat/organizations-onboarding' of github.com:calcom/cal.com into feat/organizations-onboarding
* Step 2 done, avatar not working
* Covering null on unique clauses
* Onboarding admins step
* Last step to create teams
* Moving change password handler, improving verifying code flow
* Clearing error before submitting
* Reverting email testing api changes
* Reverting having the banner for now
* Consistent exported components
* Remove unneeded files from banner
* Removing uneeded code
* Fixing avatar selector
* Using meta component for head/descr
* Missing i18n strings
* Feedback
* Making an org avatar (temp)
* Check for subteams slug clashes with usernames
* Fixing create teams onsuccess
* Covering users and subteams, excluding non-org users
* Unpublished teams shows correctly
* Create subdomain in Vercel
* feedback
* Renaming Vercel env vars
* Vercel domain check before creation
* Supporting cal-staging.com
* Change to have vercel detect it
* vercel domain check data message error
* Remove check domain
* Making sure we check requestedSlug now
* Feedback and unneeded code
* Reverting unneeded changes
* Unneeded changes
---------
Co-authored-by: sean-brydon <55134778+sean-brydon@users.noreply.github.com>
* Vercel subdomain creation in PROD only
* Making sure we let localhost still work
* Feedback
* Type check fixes
* feat: Organization branding in side menu (#9279)
* Desktop first banner, mobile pending
* Removing dead code and img
* WIP
* Adds Email verification template+translations for organizations (#9202)
* First step done
* Merge branch 'feat/organizations-onboarding' of github.com:calcom/cal.com into feat/organizations-onboarding
* Step 2 done, avatar not working
* Covering null on unique clauses
* Onboarding admins step
* Last step to create teams
* Moving change password handler, improving verifying code flow
* Clearing error before submitting
* Reverting email testing api changes
* Reverting having the banner for now
* Consistent exported components
* Remove unneeded files from banner
* Removing uneeded code
* Fixing avatar selector
* Org branding provider used in shell sidebar
* Using meta component for head/descr
* Missing i18n strings
* Feedback
* Making an org avatar (temp)
* Using org avatar (temp)
* Not showing org logo if not set
* User onboarding with org branding (slug)
* Check for subteams slug clashes with usernames
* Fixing create teams onsuccess
* feedback
* Feedback
* Org public profile
* Public profiles for team event types
* Added setup profile alert
* Using org avatar on subteams avatar
* Making sure we show the set up profile on org only
* Profile username availability rely on org hook
* Update apps/web/pages/team/[slug].tsx
Co-authored-by: sean-brydon <55134778+sean-brydon@users.noreply.github.com>
* Update apps/web/pages/team/[slug].tsx
Co-authored-by: sean-brydon <55134778+sean-brydon@users.noreply.github.com>
---------
Co-authored-by: sean-brydon <55134778+sean-brydon@users.noreply.github.com>
* feat: Organization support for event types page (#9449)
* Desktop first banner, mobile pending
* Removing dead code and img
* WIP
* Adds Email verification template+translations for organizations (#9202)
* First step done
* Merge branch 'feat/organizations-onboarding' of github.com:calcom/cal.com into feat/organizations-onboarding
* Step 2 done, avatar not working
* Covering null on unique clauses
* Onboarding admins step
* Last step to create teams
* Moving change password handler, improving verifying code flow
* Clearing error before submitting
* Reverting email testing api changes
* Reverting having the banner for now
* Consistent exported components
* Remove unneeded files from banner
* Removing uneeded code
* Fixing avatar selector
* Org branding provider used in shell sidebar
* Using meta component for head/descr
* Missing i18n strings
* Feedback
* Making an org avatar (temp)
* Using org avatar (temp)
* Not showing org logo if not set
* User onboarding with org branding (slug)
* Check for subteams slug clashes with usernames
* Fixing create teams onsuccess
* feedback
* Feedback
* Org public profile
* Public profiles for team event types
* Added setup profile alert
* Using org avatar on subteams avatar
* Processing orgs and children as profile options
* Reverting change not belonging to this PR
* Making sure we show the set up profile on org only
* Removing console.log
* Comparing memberships to choose the highest one
---------
Co-authored-by: sean-brydon <55134778+sean-brydon@users.noreply.github.com>
* Type errors
* Refactor and type fixes
* Update orgDomains.ts
* Feedback
* Reverting
* NIT
* fix issue getting org slug from domain
* Improving orgDomains util
* Host comes with port
* Update useRouterQuery.ts
* Feedback
* Feedback
* Feedback
* Feedback: SSR for user event-types to have org context
* chore: Cache node_modules (#9492)
* Adding check for cache hit
* Adding a separate install step first
* Put the restore cache steps back
* Revert the uses type for restoring cache
* Added step to restore nm cache
* Removed the cache-hit check
* Comments and naming
* Removed extra install command
* Updated the name of the linting step to be more clear
* Removes the need for useEffect here
* Feedback
* Feedback
* Cookie domain needs a dot
* Type fix
* Update apps/web/public/static/locales/en/common.json
Co-authored-by: Omar López <zomars@me.com>
* Update packages/emails/src/templates/OrganizationAccountVerifyEmail.tsx
* Feedback
---------
Signed-off-by: Udit Takkar <udit.07814802719@cse.mait.ac.in>
Co-authored-by: Joe Au-Yeung <65426560+joeauyeung@users.noreply.github.com>
Co-authored-by: Udit Takkar <53316345+Udit-takkar@users.noreply.github.com>
Co-authored-by: sean-brydon <55134778+sean-brydon@users.noreply.github.com>
Co-authored-by: zomars <zomars@me.com>
Co-authored-by: Efraín Rochín <roae.85@gmail.com>
Co-authored-by: Keith Williams <keithwillcode@gmail.com>
2023-06-14 21:40:20 +00:00
export const shouldShowOnboarding = (
user : Pick < User , " createdDate " | " completedOnboarding " | " organizationId " >
) = > {
return (
! user . completedOnboarding &&
! user . organizationId &&
dayjs ( user . createdDate ) . isAfter ( ONBOARDING_INTRODUCED_AT )
) ;
2022-08-09 09:21:15 +00:00
} ;
function useRedirectToLoginIfUnauthenticated ( isPublic = false ) {
const { data : session , status } = useSession ( ) ;
const loading = status === "loading" ;
const router = useRouter ( ) ;
useEffect ( ( ) = > {
if ( isPublic ) {
return ;
}
if ( ! loading && ! session ) {
router . replace ( {
pathname : "/auth/login" ,
query : {
callbackUrl : ` ${ WEBAPP_URL } ${ location . pathname } ${ location . search } ` ,
} ,
} ) ;
}
// eslint-disable-next-line react-hooks/exhaustive-deps
} , [ loading , session , isPublic ] ) ;
return {
loading : loading && ! session ,
session ,
} ;
}
2023-07-18 21:18:08 +00:00
function AppTop ( { setBannersHeight } : { setBannersHeight : Dispatch < SetStateAction < number > > } ) {
const router = useRouter ( ) ;
const bannerRef = useRef < HTMLDivElement | null > ( null ) ;
useIsomorphicLayoutEffect ( ( ) = > {
const resizeObserver = new ResizeObserver ( ( entries ) = > {
const { offsetHeight } = entries [ 0 ] . target as HTMLElement ;
setBannersHeight ( offsetHeight ) ;
} ) ;
const currentBannerRef = bannerRef . current ;
if ( currentBannerRef ) {
resizeObserver . observe ( currentBannerRef ) ;
}
return ( ) = > {
if ( currentBannerRef ) {
resizeObserver . unobserve ( currentBannerRef ) ;
}
} ;
} , [ bannerRef ] ) ;
return (
< div ref = { bannerRef } className = "sticky top-0 z-10 w-full divide-y divide-black" >
< NProgressNextRouter router = { router } / >
< TeamsUpgradeBanner / >
< OrgUpgradeBanner / >
< ImpersonatingBanner / >
< AdminPasswordBanner / >
< VerifyEmailBanner / >
< / div >
) ;
}
2022-08-09 09:21:15 +00:00
function useRedirectToOnboardingIfNeeded() {
const router = useRouter ( ) ;
const query = useMeQuery ( ) ;
const user = query . data ;
2023-06-07 07:27:48 +00:00
const flags = useFlagMap ( ) ;
const { data : email } = useEmailVerifyCheck ( ) ;
const needsEmailVerification = ! email ? . isVerified && flags [ "email-verification" ] ;
2022-08-09 09:21:15 +00:00
const isRedirectingToOnboarding = user && shouldShowOnboarding ( user ) ;
useEffect ( ( ) = > {
2023-06-07 07:27:48 +00:00
if ( isRedirectingToOnboarding && ! needsEmailVerification ) {
2022-08-09 09:21:15 +00:00
router . replace ( {
pathname : "/getting-started" ,
} ) ;
}
// eslint-disable-next-line react-hooks/exhaustive-deps
2023-06-07 07:27:48 +00:00
} , [ isRedirectingToOnboarding , needsEmailVerification ] ) ;
2022-08-09 09:21:15 +00:00
return {
isRedirectingToOnboarding ,
} ;
}
const Layout = ( props : LayoutProps ) = > {
2023-05-30 15:05:46 +00:00
const [ bannersHeight , setBannersHeight ] = useState < number > ( 0 ) ;
2023-07-18 21:18:08 +00:00
const pageTitle = typeof props . heading === "string" && ! props . title ? props.heading : props.title ;
2022-08-09 09:21:15 +00:00
return (
< >
2022-10-18 17:46:22 +00:00
{ ! props . withoutSeo && (
< HeadSeo
2022-11-30 21:52:56 +00:00
title = { pageTitle ? ? APP_NAME }
2022-10-18 17:46:22 +00:00
description = { props . subtitle ? props . subtitle ? . toString ( ) : "" }
/ >
) }
2022-08-09 09:21:15 +00:00
< div >
< Toaster position = "bottom-right" / >
< / div >
2022-10-05 14:33:29 +00:00
{ /* todo: only run this if timezone is different */ }
< TimezoneChangeDialog / >
2023-06-26 12:12:57 +00:00
< div className = "flex min-h-screen flex-col" >
2023-07-18 21:18:08 +00:00
< AppTop setBannersHeight = { setBannersHeight } / >
2022-12-19 17:37:20 +00:00
< div className = "flex flex-1" data - testid = "dashboard-shell" >
2023-07-31 18:51:08 +00:00
{ props . SidebarContainer ? (
cloneElement ( props . SidebarContainer , { bannersHeight } )
) : (
< SideBarContainer bannersHeight = { bannersHeight } / >
) }
2022-12-19 17:37:20 +00:00
< div className = "flex w-0 flex-1 flex-col" >
2022-11-15 19:33:59 +00:00
< MainContainer { ...props } / >
< / div >
2022-08-09 09:21:15 +00:00
< / div >
< / div >
< / >
) ;
} ;
2022-09-07 01:33:50 +00:00
type DrawerState = [ isOpen : boolean , setDrawerOpen : Dispatch < SetStateAction < boolean > > ] ;
2022-08-09 09:21:15 +00:00
type LayoutProps = {
centered? : boolean ;
title? : string ;
heading? : ReactNode ;
subtitle? : ReactNode ;
2023-01-14 19:11:28 +00:00
headerClassName? : string ;
2022-08-09 09:21:15 +00:00
children : ReactNode ;
CTA? : ReactNode ;
large? : boolean ;
2022-09-07 01:33:50 +00:00
MobileNavigationContainer? : ReactNode ;
2023-07-31 18:51:08 +00:00
SidebarContainer? : ReactElement ;
2022-09-07 01:33:50 +00:00
TopNavContainer? : ReactNode ;
drawerState? : DrawerState ;
2022-08-09 09:21:15 +00:00
HeadingLeftIcon? : ReactNode ;
2022-10-25 00:29:49 +00:00
backPath? : string | boolean ; // renders back button to specified path
2022-08-09 09:21:15 +00:00
// use when content needs to expand with flex
flexChildrenContainer? : boolean ;
isPublic? : boolean ;
2022-09-02 19:00:41 +00:00
withoutMain? : boolean ;
2022-10-18 17:46:22 +00:00
// Gives you the option to skip HeadSEO and render your own.
withoutSeo? : boolean ;
2022-11-30 20:51:44 +00:00
// Gives the ability to include actions to the right of the heading
actions? : JSX.Element ;
feat: Organizations (#8993)
* Initial commit
* Adding feature flag
* feat: Orgs Schema Changing `scopedMembers` to `orgUsers` (#9209)
* Change scopedMembers to orgMembers
* Change to orgUsers
* Letting duplicate slugs for teams to support orgs
* Covering null on unique clauses
* Supporting having the orgId in the session cookie
* feat: organization event type filter (#9253)
Signed-off-by: Udit Takkar <udit.07814802719@cse.mait.ac.in>
* Missing changes to support orgs schema changes
* feat: Onboarding process to create an organization (#9184)
* Desktop first banner, mobile pending
* Removing dead code and img
* WIP
* Adds Email verification template+translations for organizations (#9202)
* First step done
* Merge branch 'feat/organizations-onboarding' of github.com:calcom/cal.com into feat/organizations-onboarding
* Step 2 done, avatar not working
* Covering null on unique clauses
* Onboarding admins step
* Last step to create teams
* Moving change password handler, improving verifying code flow
* Clearing error before submitting
* Reverting email testing api changes
* Reverting having the banner for now
* Consistent exported components
* Remove unneeded files from banner
* Removing uneeded code
* Fixing avatar selector
* Using meta component for head/descr
* Missing i18n strings
* Feedback
* Making an org avatar (temp)
* Check for subteams slug clashes with usernames
* Fixing create teams onsuccess
* feedback
* Making sure we check requestedSlug now
---------
Co-authored-by: sean-brydon <55134778+sean-brydon@users.noreply.github.com>
* feat: [CAL-1816] Organization subdomain support (#9345)
* Desktop first banner, mobile pending
* Removing dead code and img
* WIP
* Adds Email verification template+translations for organizations (#9202)
* First step done
* Merge branch 'feat/organizations-onboarding' of github.com:calcom/cal.com into feat/organizations-onboarding
* Step 2 done, avatar not working
* Covering null on unique clauses
* Onboarding admins step
* Last step to create teams
* Moving change password handler, improving verifying code flow
* Clearing error before submitting
* Reverting email testing api changes
* Reverting having the banner for now
* Consistent exported components
* Remove unneeded files from banner
* Removing uneeded code
* Fixing avatar selector
* Using meta component for head/descr
* Missing i18n strings
* Feedback
* Making an org avatar (temp)
* Check for subteams slug clashes with usernames
* Fixing create teams onsuccess
* Covering users and subteams, excluding non-org users
* Unpublished teams shows correctly
* Create subdomain in Vercel
* feedback
* Renaming Vercel env vars
* Vercel domain check before creation
* Supporting cal-staging.com
* Change to have vercel detect it
* vercel domain check data message error
* Remove check domain
* Making sure we check requestedSlug now
* Feedback and unneeded code
* Reverting unneeded changes
* Unneeded changes
---------
Co-authored-by: sean-brydon <55134778+sean-brydon@users.noreply.github.com>
* Vercel subdomain creation in PROD only
* Making sure we let localhost still work
* Feedback
* Type check fixes
* feat: Organization branding in side menu (#9279)
* Desktop first banner, mobile pending
* Removing dead code and img
* WIP
* Adds Email verification template+translations for organizations (#9202)
* First step done
* Merge branch 'feat/organizations-onboarding' of github.com:calcom/cal.com into feat/organizations-onboarding
* Step 2 done, avatar not working
* Covering null on unique clauses
* Onboarding admins step
* Last step to create teams
* Moving change password handler, improving verifying code flow
* Clearing error before submitting
* Reverting email testing api changes
* Reverting having the banner for now
* Consistent exported components
* Remove unneeded files from banner
* Removing uneeded code
* Fixing avatar selector
* Org branding provider used in shell sidebar
* Using meta component for head/descr
* Missing i18n strings
* Feedback
* Making an org avatar (temp)
* Using org avatar (temp)
* Not showing org logo if not set
* User onboarding with org branding (slug)
* Check for subteams slug clashes with usernames
* Fixing create teams onsuccess
* feedback
* Feedback
* Org public profile
* Public profiles for team event types
* Added setup profile alert
* Using org avatar on subteams avatar
* Making sure we show the set up profile on org only
* Profile username availability rely on org hook
* Update apps/web/pages/team/[slug].tsx
Co-authored-by: sean-brydon <55134778+sean-brydon@users.noreply.github.com>
* Update apps/web/pages/team/[slug].tsx
Co-authored-by: sean-brydon <55134778+sean-brydon@users.noreply.github.com>
---------
Co-authored-by: sean-brydon <55134778+sean-brydon@users.noreply.github.com>
* feat: Organization support for event types page (#9449)
* Desktop first banner, mobile pending
* Removing dead code and img
* WIP
* Adds Email verification template+translations for organizations (#9202)
* First step done
* Merge branch 'feat/organizations-onboarding' of github.com:calcom/cal.com into feat/organizations-onboarding
* Step 2 done, avatar not working
* Covering null on unique clauses
* Onboarding admins step
* Last step to create teams
* Moving change password handler, improving verifying code flow
* Clearing error before submitting
* Reverting email testing api changes
* Reverting having the banner for now
* Consistent exported components
* Remove unneeded files from banner
* Removing uneeded code
* Fixing avatar selector
* Org branding provider used in shell sidebar
* Using meta component for head/descr
* Missing i18n strings
* Feedback
* Making an org avatar (temp)
* Using org avatar (temp)
* Not showing org logo if not set
* User onboarding with org branding (slug)
* Check for subteams slug clashes with usernames
* Fixing create teams onsuccess
* feedback
* Feedback
* Org public profile
* Public profiles for team event types
* Added setup profile alert
* Using org avatar on subteams avatar
* Processing orgs and children as profile options
* Reverting change not belonging to this PR
* Making sure we show the set up profile on org only
* Removing console.log
* Comparing memberships to choose the highest one
---------
Co-authored-by: sean-brydon <55134778+sean-brydon@users.noreply.github.com>
* Type errors
* Refactor and type fixes
* Update orgDomains.ts
* Feedback
* Reverting
* NIT
* fix issue getting org slug from domain
* Improving orgDomains util
* Host comes with port
* Update useRouterQuery.ts
* Feedback
* Feedback
* Feedback
* Feedback: SSR for user event-types to have org context
* chore: Cache node_modules (#9492)
* Adding check for cache hit
* Adding a separate install step first
* Put the restore cache steps back
* Revert the uses type for restoring cache
* Added step to restore nm cache
* Removed the cache-hit check
* Comments and naming
* Removed extra install command
* Updated the name of the linting step to be more clear
* Removes the need for useEffect here
* Feedback
* Feedback
* Cookie domain needs a dot
* Type fix
* Update apps/web/public/static/locales/en/common.json
Co-authored-by: Omar López <zomars@me.com>
* Update packages/emails/src/templates/OrganizationAccountVerifyEmail.tsx
* Feedback
---------
Signed-off-by: Udit Takkar <udit.07814802719@cse.mait.ac.in>
Co-authored-by: Joe Au-Yeung <65426560+joeauyeung@users.noreply.github.com>
Co-authored-by: Udit Takkar <53316345+Udit-takkar@users.noreply.github.com>
Co-authored-by: sean-brydon <55134778+sean-brydon@users.noreply.github.com>
Co-authored-by: zomars <zomars@me.com>
Co-authored-by: Efraín Rochín <roae.85@gmail.com>
Co-authored-by: Keith Williams <keithwillcode@gmail.com>
2023-06-14 21:40:20 +00:00
beforeCTAactions? : JSX.Element ;
afterHeading? : ReactNode ;
2023-01-29 09:38:31 +00:00
smallHeading? : boolean ;
2023-04-19 20:17:54 +00:00
hideHeadingOnMobile? : boolean ;
2022-08-09 09:21:15 +00:00
} ;
2023-04-05 18:14:46 +00:00
const useBrandColors = ( ) = > {
2022-08-09 09:21:15 +00:00
const { data : user } = useMeQuery ( ) ;
2023-04-05 18:14:46 +00:00
const brandTheme = getBrandColours ( {
lightVal : user?.brandColor ,
darkVal : user?.darkBrandColor ,
} ) ;
useCalcomTheme ( brandTheme ) ;
2022-08-09 09:21:15 +00:00
} ;
2023-01-12 22:11:15 +00:00
const KBarWrapper = ( { children , withKBar = false } : { withKBar : boolean ; children : React.ReactNode } ) = >
withKBar ? (
< KBarRoot >
{ children }
< KBarContent / >
< / KBarRoot >
) : (
< > { children } < / >
) ;
2023-01-16 13:59:54 +00:00
const PublicShell = ( props : LayoutProps ) = > {
2023-01-12 22:11:15 +00:00
const { status } = useSession ( ) ;
2023-01-16 13:59:54 +00:00
return (
< KBarWrapper withKBar = { status === "authenticated" } >
< Layout { ...props } / >
< / KBarWrapper >
) ;
} ;
export default function Shell ( props : LayoutProps ) {
2023-01-12 22:11:15 +00:00
// if a page is unauthed and isPublic is true, the redirect does not happen.
2022-08-09 09:21:15 +00:00
useRedirectToLoginIfUnauthenticated ( props . isPublic ) ;
useRedirectToOnboardingIfNeeded ( ) ;
2023-04-17 12:16:54 +00:00
// System Theme is automatically supported using ThemeProvider. If we intend to use user theme throughout the app we need to uncomment this.
// useTheme(profile.theme);
2023-04-05 18:14:46 +00:00
useBrandColors ( ) ;
2023-01-12 22:11:15 +00:00
2023-01-16 13:59:54 +00:00
return ! props . isPublic ? (
< KBarWrapper withKBar >
2022-08-09 09:21:15 +00:00
< Layout { ...props } / >
2023-01-12 22:11:15 +00:00
< / KBarWrapper >
2023-01-16 13:59:54 +00:00
) : (
< PublicShell { ...props } / >
2022-08-09 09:21:15 +00:00
) ;
}
2023-06-15 10:42:47 +00:00
interface UserDropdownProps {
small? : boolean ;
}
function UserDropdown ( { small } : UserDropdownProps ) {
2022-08-09 09:21:15 +00:00
const { t } = useLocale ( ) ;
2023-05-20 00:37:58 +00:00
const { data : user } = useMeQuery ( ) ;
const { data : avatar } = useAvatarQuery ( ) ;
2023-07-28 12:18:29 +00:00
const utils = trpc . useContext ( ) ;
2022-08-09 09:21:15 +00:00
useEffect ( ( ) = > {
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
//@ts-ignore
const Beacon = window . Beacon ;
// window.Beacon is defined when user actually opens up HelpScout and username is available here. On every re-render update session info, so that it is always latest.
Beacon &&
Beacon ( "session-data" , {
username : user?.username || "Unknown" ,
screenResolution : ` ${ screen . width } x ${ screen . height } ` ,
} ) ;
} ) ;
2022-11-10 23:40:01 +00:00
const mutation = trpc . viewer . away . useMutation ( {
2023-07-28 12:18:29 +00:00
onMutate : async ( { away } ) = > {
await utils . viewer . me . cancel ( ) ;
const previousValue = utils . viewer . me . getData ( ) ;
if ( previousValue ) {
utils . viewer . me . setData ( undefined , { . . . previousValue , away } ) ;
}
return { previousValue } ;
} ,
onError : ( _ , __ , context ) = > {
if ( context ? . previousValue ) {
utils . viewer . me . setData ( undefined , context . previousValue ) ;
}
showToast ( t ( "toggle_away_error" ) , "error" ) ;
} ,
2022-08-09 09:21:15 +00:00
onSettled() {
2022-11-10 23:40:01 +00:00
utils . viewer . me . invalidate ( ) ;
2022-08-09 09:21:15 +00:00
} ,
} ) ;
const [ helpOpen , setHelpOpen ] = useState ( false ) ;
const [ menuOpen , setMenuOpen ] = useState ( false ) ;
2023-07-28 12:18:29 +00:00
2022-08-09 09:21:15 +00:00
const onHelpItemSelect = ( ) = > {
setHelpOpen ( false ) ;
setMenuOpen ( false ) ;
} ;
// Prevent rendering dropdown if user isn't available.
// We don't want to show nameless user.
if ( ! user ) {
return null ;
}
2023-07-28 12:18:29 +00:00
2022-08-09 09:21:15 +00:00
return (
2022-10-17 19:05:00 +00:00
< Dropdown open = { menuOpen } >
2023-06-19 11:44:47 +00:00
< DropdownMenuTrigger asChild onClick = { ( ) = > setMenuOpen ( ( menuOpen ) = > ! menuOpen ) } >
< button
className = { classNames (
"hover:bg-emphasis group mx-0 flex cursor-pointer appearance-none items-center rounded-full text-left outline-none focus:outline-none focus:ring-0 md:rounded-none lg:rounded" ,
2023-07-02 10:12:50 +00:00
small ? "p-2" : "px-2 py-1.5"
2023-06-19 11:44:47 +00:00
) } >
< span
2023-06-15 10:42:47 +00:00
className = { classNames (
2023-07-02 10:12:50 +00:00
small ? "h-4 w-4" : "h-5 w-5 ltr:mr-2 rtl:ml-2" ,
2023-06-19 11:44:47 +00:00
"relative flex-shrink-0 rounded-full bg-gray-300"
2023-06-15 10:42:47 +00:00
) } >
2023-06-19 11:44:47 +00:00
< Avatar
2023-07-02 10:12:50 +00:00
size = { small ? "xs" : "xsm" }
2023-06-19 11:44:47 +00:00
imageSrc = { avatar ? . avatar || WEBAPP_URL + "/" + user . username + "/avatar.png" }
alt = { user . username || "Nameless User" }
className = "overflow-hidden"
/ >
2023-01-02 08:28:12 +00:00
< span
className = { classNames (
2023-07-02 10:12:50 +00:00
"border-muted absolute -bottom-1 -right-1 rounded-full border bg-green-500" ,
2023-06-19 11:44:47 +00:00
user . away ? "bg-yellow-500" : "bg-green-500" ,
2023-07-02 10:12:50 +00:00
small ? "-bottom-0.5 -right-0.5 h-2.5 w-2.5" : "-bottom-0.5 -right-0 h-2 w-2"
2023-06-19 11:44:47 +00:00
) }
/ >
< / span >
{ ! small && (
2023-07-03 08:06:12 +00:00
< span className = "flex flex-grow items-center gap-2" >
2023-06-19 11:44:47 +00:00
< span className = "line-clamp-1 flex-grow text-sm leading-none" >
< span className = "text-emphasis block font-medium" > { user . name || "Nameless User" } < / span >
< / span >
< ChevronDown
className = "group-hover:text-subtle text-muted h-4 w-4 flex-shrink-0 rtl:mr-4"
aria - hidden = "true"
2023-06-15 10:42:47 +00:00
/ >
2023-01-02 08:28:12 +00:00
< / span >
2023-06-19 11:44:47 +00:00
) }
< / button >
< / DropdownMenuTrigger >
2023-01-02 08:28:12 +00:00
2022-09-30 10:29:22 +00:00
< DropdownMenuPortal >
2023-03-08 11:30:24 +00:00
< FreshChatProvider >
< DropdownMenuContent
2023-06-15 10:42:47 +00:00
align = "start"
2023-03-08 11:30:24 +00:00
onInteractOutside = { ( ) = > {
setMenuOpen ( false ) ;
setHelpOpen ( false ) ;
} }
2023-04-05 18:14:46 +00:00
className = "group overflow-hidden rounded-md" >
2023-03-08 11:30:24 +00:00
{ helpOpen ? (
< HelpMenuItem onHelpItemSelect = { ( ) = > onHelpItemSelect ( ) } / >
) : (
< >
2023-06-15 10:42:47 +00:00
< DropdownMenuItem >
< DropdownItem
type = "button"
StartIcon = { ( props ) = > (
< UserIcon className = { classNames ( "text-default" , props . className ) } aria - hidden = "true" / >
) }
href = "/settings/my-account/profile" >
{ t ( "my_profile" ) }
< / DropdownItem >
< / DropdownMenuItem >
< DropdownMenuItem >
< DropdownItem
type = "button"
StartIcon = { ( props ) = > (
< Settings className = { classNames ( "text-default" , props . className ) } aria - hidden = "true" / >
) }
href = "/settings/my-account/general" >
{ t ( "my_settings" ) }
< / DropdownItem >
< / DropdownMenuItem >
2023-03-08 11:30:24 +00:00
< DropdownMenuItem >
< DropdownItem
type = "button"
StartIcon = { ( props ) = > (
2023-04-12 15:26:31 +00:00
< Moon className = { classNames ( "text-default" , props . className ) } aria - hidden = "true" / >
2023-03-08 11:30:24 +00:00
) }
onClick = { ( ) = > {
2023-07-28 12:18:29 +00:00
mutation . mutate ( { away : ! user . away } ) ;
2023-03-08 11:30:24 +00:00
} } >
{ user . away ? t ( "set_as_free" ) : t ( "set_as_away" ) }
< / DropdownItem >
< / DropdownMenuItem >
< DropdownMenuSeparator / >
< DropdownMenuItem >
< DropdownItem
2023-07-28 12:18:29 +00:00
StartIcon = { ( ) = > < Discord className = "text-default h-4 w-4" / > }
2023-03-08 11:30:24 +00:00
target = "_blank"
rel = "noreferrer"
2023-07-04 22:11:10 +00:00
href = { JOIN_DISCORD } >
{ t ( "join_our_discord" ) }
2023-03-08 11:30:24 +00:00
< / DropdownItem >
< / DropdownMenuItem >
< DropdownMenuItem >
2023-04-12 15:26:31 +00:00
< DropdownItem StartIcon = { Map } target = "_blank" href = { ROADMAP } >
2023-03-08 11:30:24 +00:00
{ t ( "visit_roadmap" ) }
< / DropdownItem >
< / DropdownMenuItem >
< DropdownMenuItem >
< DropdownItem
type = "button"
2023-04-12 15:26:31 +00:00
StartIcon = { ( props ) = > < HelpCircle aria - hidden = "true" { ...props } / > }
2023-03-08 11:30:24 +00:00
onClick = { ( ) = > setHelpOpen ( true ) } >
{ t ( "help" ) }
< / DropdownItem >
< / DropdownMenuItem >
< DropdownMenuItem className = "desktop-hidden hidden lg:flex" >
2023-04-12 15:26:31 +00:00
< DropdownItem StartIcon = { Download } target = "_blank" rel = "noreferrer" href = { DESKTOP_APP_LINK } >
2023-03-08 11:30:24 +00:00
{ t ( "download_desktop_app" ) }
< / DropdownItem >
< / DropdownMenuItem >
2022-08-09 09:21:15 +00:00
2023-03-08 11:30:24 +00:00
< DropdownMenuSeparator / >
2023-04-24 21:51:17 +00:00
2023-03-08 11:30:24 +00:00
< DropdownMenuItem >
< DropdownItem
type = "button"
2023-04-12 15:26:31 +00:00
StartIcon = { ( props ) = > < LogOut aria - hidden = "true" { ...props } / > }
2023-03-08 11:30:24 +00:00
onClick = { ( ) = > signOut ( { callbackUrl : "/auth/logout" } ) } >
{ t ( "sign_out" ) }
< / DropdownItem >
< / DropdownMenuItem >
< / >
) }
< / DropdownMenuContent >
< / FreshChatProvider >
2022-09-30 10:29:22 +00:00
< / DropdownMenuPortal >
2022-08-09 09:21:15 +00:00
< / Dropdown >
) ;
}
2022-09-15 19:53:09 +00:00
export type NavigationItemType = {
2022-08-09 09:21:15 +00:00
name : string ;
href : string ;
2023-06-15 10:42:47 +00:00
onClick? : React.MouseEventHandler < HTMLAnchorElement | HTMLButtonElement > ;
target? : HTMLAnchorElement [ "target" ] ;
2022-10-10 17:00:09 +00:00
badge? : React.ReactNode ;
2022-08-09 09:21:15 +00:00
icon? : SVGComponent ;
child? : NavigationItemType [ ] ;
pro? : true ;
2022-09-17 17:53:31 +00:00
onlyMobile? : boolean ;
onlyDesktop? : boolean ;
2022-09-02 19:00:41 +00:00
isCurrent ? : ( {
item ,
isChild ,
router ,
} : {
2023-06-15 10:42:47 +00:00
item : Pick < NavigationItemType , " href " > ;
2022-09-02 19:00:41 +00:00
isChild? : boolean ;
router : NextRouter ;
} ) = > boolean ;
2022-08-09 09:21:15 +00:00
} ;
2022-09-02 19:00:41 +00:00
const requiredCredentialNavigationItems = [ "Routing Forms" ] ;
2022-09-07 04:13:31 +00:00
const MORE_SEPARATOR_NAME = "more" ;
2022-10-10 17:00:09 +00:00
2022-08-09 09:21:15 +00:00
const navigation : NavigationItemType [ ] = [
{
name : "event_types_page_title" ,
href : "/event-types" ,
2023-04-12 15:26:31 +00:00
icon : LinkIcon ,
2022-08-09 09:21:15 +00:00
} ,
{
name : "bookings" ,
href : "/bookings/upcoming" ,
2023-04-12 15:26:31 +00:00
icon : Calendar ,
2022-10-10 17:00:09 +00:00
badge : < UnconfirmedBookingBadge / > ,
2022-10-27 09:45:01 +00:00
isCurrent : ( { router } ) = > {
const path = router . asPath . split ( "?" ) [ 0 ] ;
return path . startsWith ( "/bookings" ) ;
} ,
2022-08-09 09:21:15 +00:00
} ,
{
name : "availability" ,
href : "/availability" ,
2023-04-12 15:26:31 +00:00
icon : Clock ,
2022-08-09 09:21:15 +00:00
} ,
2022-09-17 17:53:31 +00:00
{
name : "teams" ,
href : "/teams" ,
2023-04-12 15:26:31 +00:00
icon : Users ,
2022-09-17 17:53:31 +00:00
onlyDesktop : true ,
2023-01-24 15:27:05 +00:00
badge : < TeamInviteBadge / > ,
2022-09-17 17:53:31 +00:00
} ,
2022-08-09 09:21:15 +00:00
{
name : "apps" ,
href : "/apps" ,
2023-04-12 15:26:31 +00:00
icon : Grid ,
2022-09-02 19:00:41 +00:00
isCurrent : ( { router , item } ) = > {
const path = router . asPath . split ( "?" ) [ 0 ] ;
2022-09-15 19:53:09 +00:00
// During Server rendering path is /v2/apps but on client it becomes /apps(weird..)
2023-07-26 16:44:19 +00:00
return path . startsWith ( item . href ) || path . startsWith ( "/v2" + item . href ) ;
2022-09-02 19:00:41 +00:00
} ,
2022-08-09 09:21:15 +00:00
child : [
{
name : "app_store" ,
href : "/apps" ,
2022-09-15 19:53:09 +00:00
isCurrent : ( { router , item } ) = > {
const path = router . asPath . split ( "?" ) [ 0 ] ;
// During Server rendering path is /v2/apps but on client it becomes /apps(weird..)
return (
2023-07-26 16:44:19 +00:00
( path . startsWith ( item . href ) || path . startsWith ( "/v2" + item . href ) ) && ! path . includes ( "/installed" )
2022-09-15 19:53:09 +00:00
) ;
} ,
2022-08-09 09:21:15 +00:00
} ,
{
name : "installed_apps" ,
2022-09-15 19:53:09 +00:00
href : "/apps/installed/calendar" ,
isCurrent : ( { router } ) = > {
const path = router . asPath ;
return path . startsWith ( "/apps/installed/" ) || path . startsWith ( "/v2/apps/installed/" ) ;
} ,
2022-08-09 09:21:15 +00:00
} ,
] ,
} ,
2022-09-07 04:13:31 +00:00
{
name : MORE_SEPARATOR_NAME ,
href : "/more" ,
2023-04-12 15:26:31 +00:00
icon : MoreHorizontal ,
2022-09-07 04:13:31 +00:00
} ,
{
name : "Routing Forms" ,
2023-07-26 16:44:19 +00:00
href : "/routing-forms/forms" ,
2023-04-12 15:26:31 +00:00
icon : FileText ,
2022-09-07 04:13:31 +00:00
isCurrent : ( { router } ) = > {
2023-07-26 16:44:19 +00:00
return router . asPath . startsWith ( "/routing-forms/" ) ;
2022-09-07 04:13:31 +00:00
} ,
} ,
{
name : "workflows" ,
href : "/workflows" ,
2023-04-12 15:26:31 +00:00
icon : Zap ,
2022-09-07 04:13:31 +00:00
} ,
2023-03-23 22:10:01 +00:00
{
2023-03-28 23:24:57 +00:00
name : "insights" ,
2023-03-23 22:10:01 +00:00
href : "/insights" ,
2023-04-12 15:26:31 +00:00
icon : BarChart ,
2023-03-23 22:10:01 +00:00
} ,
2022-08-09 09:21:15 +00:00
] ;
2022-09-07 04:13:31 +00:00
const moreSeparatorIndex = navigation . findIndex ( ( item ) = > item . name === MORE_SEPARATOR_NAME ) ;
// We create all needed navigation items for the different use cases
const { desktopNavigationItems , mobileNavigationBottomItems , mobileNavigationMoreItems } = navigation . reduce <
Record < string , NavigationItemType [ ] >
> (
( items , item , index ) = > {
2022-12-19 17:37:20 +00:00
// We filter out the "more" separator in` desktop navigation
2022-09-07 04:13:31 +00:00
if ( item . name !== MORE_SEPARATOR_NAME ) items . desktopNavigationItems . push ( item ) ;
// Items for mobile bottom navigation
2023-06-15 10:42:47 +00:00
if ( index < moreSeparatorIndex + 1 && ! item . onlyDesktop ) {
items . mobileNavigationBottomItems . push ( item ) ;
} // Items for the "more" menu in mobile navigation
else {
items . mobileNavigationMoreItems . push ( item ) ;
}
2022-09-07 04:13:31 +00:00
return items ;
} ,
{ desktopNavigationItems : [ ] , mobileNavigationBottomItems : [ ] , mobileNavigationMoreItems : [ ] }
) ;
2022-08-09 09:21:15 +00:00
const Navigation = ( ) = > {
return (
2023-07-02 10:12:50 +00:00
< nav className = "mt-2 flex-1 md:px-2 lg:mt-4 lg:px-0" >
2022-09-07 04:13:31 +00:00
{ desktopNavigationItems . map ( ( item ) = > (
2022-08-09 09:21:15 +00:00
< NavigationItem key = { item . name } item = { item } / >
) ) }
2023-04-05 18:14:46 +00:00
< div className = "text-subtle mt-0.5 lg:hidden" >
2022-08-09 09:21:15 +00:00
< KBarTrigger / >
2022-09-05 10:02:21 +00:00
< / div >
2022-08-09 09:21:15 +00:00
< / nav >
) ;
} ;
function useShouldDisplayNavigationItem ( item : NavigationItemType ) {
2023-03-25 00:59:04 +00:00
const flags = useFlagMap ( ) ;
if ( isKeyInObject ( item . name , flags ) ) return flags [ item . name ] ;
2023-07-26 16:44:19 +00:00
return true ;
2022-08-09 09:21:15 +00:00
}
2022-09-02 19:00:41 +00:00
const defaultIsCurrent : NavigationItemType [ "isCurrent" ] = ( { isChild , item , router } ) = > {
2023-06-15 10:42:47 +00:00
return isChild ? item . href === router.asPath : item.href ? router . asPath . startsWith ( item . href ) : false ;
2022-09-02 19:00:41 +00:00
} ;
2022-08-09 09:21:15 +00:00
const NavigationItem : React.FC < {
2023-01-12 16:44:41 +00:00
index? : number ;
2022-08-09 09:21:15 +00:00
item : NavigationItemType ;
isChild? : boolean ;
} > = ( props ) = > {
const { item , isChild } = props ;
2022-09-05 19:06:34 +00:00
const { t , isLocaleReady } = useLocale ( ) ;
2022-08-09 09:21:15 +00:00
const router = useRouter ( ) ;
2022-09-02 19:00:41 +00:00
const isCurrent : NavigationItemType [ "isCurrent" ] = item . isCurrent || defaultIsCurrent ;
const current = isCurrent ( { isChild : ! ! isChild , item , router } ) ;
2022-08-09 09:21:15 +00:00
const shouldDisplayNavigationItem = useShouldDisplayNavigationItem ( props . item ) ;
2022-08-24 20:18:42 +00:00
2022-08-09 09:21:15 +00:00
if ( ! shouldDisplayNavigationItem ) return null ;
2022-08-24 20:18:42 +00:00
2022-08-09 09:21:15 +00:00
return (
< Fragment >
2023-05-30 14:18:21 +00:00
< Tooltip side = "right" content = { t ( item . name ) } className = "lg:hidden" >
2023-06-01 09:45:24 +00:00
< Link
href = { item . href }
aria - label = { t ( item . name ) }
className = { classNames (
2023-07-04 17:37:34 +00:00
"[&[aria-current='page']]:bg-emphasis text-default group flex items-center rounded-md px-2 py-1.5 text-sm font-medium" ,
2023-06-01 09:45:24 +00:00
isChild
? ` [&[aria-current='page']]:text-emphasis hidden h-8 pl-16 lg:flex lg:pl-11 [&[aria-current='page']]:bg-transparent ${
props . index === 0 ? "mt-0" : "mt-px"
} `
2023-06-05 09:24:16 +00:00
: "[&[aria-current='page']]:text-emphasis mt-0.5 text-sm" ,
isLocaleReady ? "hover:bg-emphasis hover:text-emphasis" : ""
2023-06-01 09:45:24 +00:00
) }
aria - current = { current ? "page" : undefined } >
{ item . icon && (
< item.icon
2023-06-05 09:24:16 +00:00
className = "mr-2 h-4 w-4 flex-shrink-0 ltr:mr-2 rtl:ml-2 [&[aria-current='page']]:text-inherit"
2023-06-01 09:45:24 +00:00
aria - hidden = "true"
aria - current = { current ? "page" : undefined }
/ >
) }
{ isLocaleReady ? (
< span className = "hidden w-full justify-between lg:flex" >
< div className = "flex" > { t ( item . name ) } < / div >
{ item . badge && item . badge }
< / span >
) : (
2023-06-05 09:24:16 +00:00
< SkeletonText style = { { width : ` ${ item . name . length * 10 } px ` } } className = "h-[20px]" / >
2023-06-01 09:45:24 +00:00
) }
< / Link >
2023-05-30 14:18:21 +00:00
< / Tooltip >
2022-08-09 09:21:15 +00:00
{ item . child &&
2022-09-02 19:00:41 +00:00
isCurrent ( { router , isChild , item } ) &&
2023-01-12 16:44:41 +00:00
item . child . map ( ( item , index ) = > < NavigationItem index = { index } key = { item . name } item = { item } isChild / > ) }
2022-08-09 09:21:15 +00:00
< / Fragment >
) ;
} ;
function MobileNavigationContainer() {
const { status } = useSession ( ) ;
if ( status !== "authenticated" ) return null ;
return < MobileNavigation / > ;
}
const MobileNavigation = ( ) = > {
const isEmbed = useIsEmbed ( ) ;
2022-09-21 15:39:54 +00:00
2022-08-09 09:21:15 +00:00
return (
< >
< nav
className = { classNames (
2023-05-14 11:06:10 +00:00
"pwa:pb-2.5 bg-muted border-subtle fixed bottom-0 z-30 -mx-4 flex w-full border-t bg-opacity-40 px-1 shadow backdrop-blur-md md:hidden" ,
2022-08-09 09:21:15 +00:00
isEmbed && "hidden"
) } >
2022-09-07 04:13:31 +00:00
{ mobileNavigationBottomItems . map ( ( item ) = > (
< MobileNavigationItem key = { item . name } item = { item } / >
) ) }
2022-08-09 09:21:15 +00:00
< / nav >
{ /* add padding to content for mobile navigation*/ }
< div className = "block pt-12 md:hidden" / >
< / >
) ;
} ;
const MobileNavigationItem : React.FC < {
item : NavigationItemType ;
isChild? : boolean ;
} > = ( props ) = > {
2022-09-07 04:13:31 +00:00
const { item , isChild } = props ;
2022-08-09 09:21:15 +00:00
const router = useRouter ( ) ;
2022-09-05 19:06:34 +00:00
const { t , isLocaleReady } = useLocale ( ) ;
2022-09-02 19:00:41 +00:00
const isCurrent : NavigationItemType [ "isCurrent" ] = item . isCurrent || defaultIsCurrent ;
const current = isCurrent ( { isChild : ! ! isChild , item , router } ) ;
2022-08-09 09:21:15 +00:00
const shouldDisplayNavigationItem = useShouldDisplayNavigationItem ( props . item ) ;
2022-09-05 19:06:34 +00:00
2022-08-09 09:21:15 +00:00
if ( ! shouldDisplayNavigationItem ) return null ;
return (
2023-01-06 12:13:56 +00:00
< Link
key = { item . name }
href = { item . href }
2023-04-05 18:14:46 +00:00
className = "[&[aria-current='page']]:text-emphasis hover:text-default text-muted relative my-2 min-w-0 flex-1 overflow-hidden rounded-md !bg-transparent p-1 text-center text-xs font-medium focus:z-10 sm:text-sm"
2023-01-06 12:13:56 +00:00
aria - current = { current ? "page" : undefined } >
{ item . badge && < div className = "absolute right-1 top-1" > { item . badge } < / div > }
{ item . icon && (
< item.icon
2023-04-05 18:14:46 +00:00
className = "[&[aria-current='page']]:text-emphasis mx-auto mb-1 block h-5 w-5 flex-shrink-0 text-center text-inherit"
2023-01-06 12:13:56 +00:00
aria - hidden = "true"
aria - current = { current ? "page" : undefined }
/ >
) }
{ isLocaleReady ? < span className = "block truncate" > { t ( item . name ) } < / span > : < SkeletonText / > }
2022-08-09 09:21:15 +00:00
< / Link >
) ;
} ;
2022-09-07 04:13:31 +00:00
const MobileNavigationMoreItem : React.FC < {
item : NavigationItemType ;
isChild? : boolean ;
} > = ( props ) = > {
const { item } = props ;
const { t , isLocaleReady } = useLocale ( ) ;
const shouldDisplayNavigationItem = useShouldDisplayNavigationItem ( props . item ) ;
if ( ! shouldDisplayNavigationItem ) return null ;
return (
2023-04-11 15:21:24 +00:00
< li className = "border-subtle border-b last:border-b-0" key = { item . name } >
2023-04-05 18:14:46 +00:00
< Link href = { item . href } className = "hover:bg-subtle flex items-center justify-between p-5" >
< span className = "text-default flex items-center font-semibold " >
2023-01-06 12:13:56 +00:00
{ item . icon && < item.icon className = "h-5 w-5 flex-shrink-0 ltr:mr-3 rtl:ml-3" aria - hidden = "true" / > }
{ isLocaleReady ? t ( item . name ) : < SkeletonText / > }
< / span >
2023-04-12 15:26:31 +00:00
< ArrowRight className = "text-subtle h-5 w-5" / >
2022-09-07 04:13:31 +00:00
< / Link >
< / li >
) ;
} ;
2023-05-30 15:05:46 +00:00
type SideBarContainerProps = {
bannersHeight : number ;
} ;
type SideBarProps = {
bannersHeight : number ;
2023-06-15 10:42:47 +00:00
user? : UserAuth | null ;
2023-05-30 15:05:46 +00:00
} ;
function SideBarContainer ( { bannersHeight } : SideBarContainerProps ) {
2023-06-15 10:42:47 +00:00
const { status , data } = useSession ( ) ;
2023-01-02 19:44:51 +00:00
2022-09-15 19:53:09 +00:00
// Make sure that Sidebar is rendered optimistically so that a refresh of pages when logged in have SideBar from the beginning.
// This improves the experience of refresh on app store pages(when logged in) which are SSG.
// Though when logged out, app store pages would temporarily show SideBar until session status is confirmed.
if ( status !== "loading" && status !== "authenticated" ) return null ;
2023-06-15 10:42:47 +00:00
return < SideBar bannersHeight = { bannersHeight } user = { data ? . user } / > ;
2022-08-09 09:21:15 +00:00
}
2023-06-15 10:42:47 +00:00
const getOrganizationUrl = ( slug : string ) = >
` ${ slug } . ${ process . env . NEXT_PUBLIC_WEBSITE_URL ? . replace ? . ( /http(s*):\/\// , "" ) } ` ;
function SideBar ( { bannersHeight , user } : SideBarProps ) {
const { t , isLocaleReady } = useLocale ( ) ;
2023-07-24 10:25:55 +00:00
const orgBranding = useOrgBranding ( ) ;
const isOrgBrandingDataFetched = orgBranding !== undefined ;
2023-07-19 09:19:53 +00:00
const publicPageUrl = useMemo ( ( ) = > {
if ( ! user ? . organizationId ) return ` ${ process . env . NEXT_PUBLIC_WEBSITE_URL } / ${ user ? . username } ` ;
const publicPageUrl = orgBranding ? . slug ? getOrganizationUrl ( orgBranding ? . slug ) : "" ;
return publicPageUrl ;
} , [ orgBranding ? . slug , user ? . organizationId , user ? . username ] ) ;
2023-06-15 10:42:47 +00:00
const bottomNavItems : NavigationItemType [ ] = [
2023-06-28 13:12:33 +00:00
{
name : "view_public_page" ,
2023-07-19 09:19:53 +00:00
href : publicPageUrl ,
2023-06-28 13:12:33 +00:00
icon : ExternalLink ,
target : "__blank" ,
} ,
{
name : "copy_public_page_link" ,
href : "" ,
onClick : ( e : { preventDefault : ( ) = > void } ) = > {
e . preventDefault ( ) ;
2023-07-19 09:19:53 +00:00
navigator . clipboard . writeText ( publicPageUrl ) ;
2023-06-28 13:12:33 +00:00
showToast ( t ( "link_copied" ) , "success" ) ;
} ,
icon : Copy ,
} ,
2023-06-15 10:42:47 +00:00
{
name : "settings" ,
2023-07-03 08:06:12 +00:00
href : user?.organizationId ? ` /settings/organizations/profile ` : "/settings/my-account/profile" ,
2023-06-15 10:42:47 +00:00
icon : Settings ,
} ,
] ;
2022-08-09 09:21:15 +00:00
return (
2022-12-19 17:37:20 +00:00
< div className = "relative" >
2023-05-30 15:05:46 +00:00
< aside
style = { { maxHeight : ` calc(100vh - ${ bannersHeight } px) ` , top : ` ${ bannersHeight } px ` } }
2023-06-15 10:42:47 +00:00
className = "desktop-transparent bg-muted border-muted fixed left-0 hidden h-full max-h-screen w-14 flex-col overflow-y-auto overflow-x-hidden border-r dark:bg-gradient-to-tr dark:from-[#2a2a2a] dark:to-[#1c1c1c] md:sticky md:flex lg:w-56 lg:px-3" >
2023-06-18 20:54:57 +00:00
< div className = "flex h-full flex-col justify-between py-3 lg:pt-4" >
2022-12-19 17:37:20 +00:00
< header className = "items-center justify-between md:hidden lg:flex" >
2023-07-24 10:25:55 +00:00
{ ! isOrgBrandingDataFetched ? null : orgBranding ? (
2023-06-18 20:54:57 +00:00
< Link href = "/event-types" className = "px-1.5" >
2023-07-03 08:06:12 +00:00
< div className = "flex items-center gap-2 font-medium" >
< Avatar
alt = { ` ${ orgBranding . name } logo ` }
imageSrc = { getPlaceholderAvatar ( orgBranding . logo , orgBranding . name ) }
size = "xsm"
/ >
< p className = "text line-clamp-1 text-sm" >
< span > { orgBranding . name } < / span >
< / p >
< / div >
2023-06-15 10:42:47 +00:00
< / Link >
) : (
< div data - testid = "user-dropdown-trigger" >
< span className = "hidden lg:inline" >
< UserDropdown / >
< / span >
< span className = "hidden md:inline lg:hidden" >
< UserDropdown small / >
< / span >
< / div >
) }
2023-06-18 20:54:57 +00:00
< div className = "flex space-x-0.5 rtl:space-x-reverse" >
2022-12-19 17:37:20 +00:00
< button
color = "minimal"
onClick = { ( ) = > window . history . back ( ) }
2023-04-05 18:14:46 +00:00
className = "desktop-only hover:text-emphasis text-subtle group flex text-sm font-medium" >
2023-04-12 15:26:31 +00:00
< ArrowLeft className = "group-hover:text-emphasis text-subtle h-4 w-4 flex-shrink-0" / >
2022-12-19 17:37:20 +00:00
< / button >
< button
color = "minimal"
onClick = { ( ) = > window . history . forward ( ) }
2023-04-05 18:14:46 +00:00
className = "desktop-only hover:text-emphasis text-subtle group flex text-sm font-medium" >
2023-04-12 15:26:31 +00:00
< ArrowRight className = "group-hover:text-emphasis text-subtle h-4 w-4 flex-shrink-0" / >
2022-12-19 17:37:20 +00:00
< / button >
2023-06-15 10:42:47 +00:00
{ ! ! orgBranding && (
< div data - testid = "user-dropdown-trigger" className = "flex items-center" >
< UserDropdown small / >
< / div >
) }
2022-12-19 17:37:20 +00:00
< KBarTrigger / >
< / div >
< / header >
2023-04-05 18:14:46 +00:00
< hr className = "desktop-only border-subtle absolute -left-3 -right-3 mt-4 block w-full" / >
2022-12-19 17:37:20 +00:00
{ /* logo icon for tablet */ }
2023-01-06 12:13:56 +00:00
< Link href = "/event-types" className = "text-center md:inline lg:hidden" >
< Logo small icon / >
2022-08-09 09:21:15 +00:00
< / Link >
2022-09-07 15:01:33 +00:00
2022-12-19 17:37:20 +00:00
< Navigation / >
< / div >
2022-09-07 15:01:33 +00:00
2023-01-02 10:13:27 +00:00
< div >
2023-01-15 17:54:52 +00:00
< Tips / >
2023-06-18 20:54:57 +00:00
{ bottomNavItems . map ( ( { icon : Icon , . . . item } , index ) = > (
2023-06-15 10:42:47 +00:00
< Tooltip side = "right" content = { t ( item . name ) } className = "lg:hidden" key = { item . name } >
< ButtonOrLink
2023-07-19 09:19:53 +00:00
id = { item . name }
2023-06-15 10:42:47 +00:00
href = { item . href || undefined }
aria - label = { t ( item . name ) }
target = { item . target }
className = { classNames (
"text-left" ,
2023-07-04 17:37:34 +00:00
"[&[aria-current='page']]:bg-emphasis text-default justify-right group flex items-center rounded-md px-2 py-1.5 text-sm font-medium" ,
2023-06-18 20:54:57 +00:00
"[&[aria-current='page']]:text-emphasis mt-0.5 w-full text-sm" ,
isLocaleReady ? "hover:bg-emphasis hover:text-emphasis" : "" ,
index === 0 && "mt-3"
2023-06-15 10:42:47 +00:00
) }
onClick = { item . onClick } >
{ ! ! Icon && (
< Icon
2023-06-18 20:54:57 +00:00
className = { classNames (
"h-4 w-4 flex-shrink-0 [&[aria-current='page']]:text-inherit" ,
2023-07-04 23:41:29 +00:00
"me-3 md:ltr:mr-2 md:rtl:ml-2"
2023-06-18 20:54:57 +00:00
) }
2023-06-15 10:42:47 +00:00
aria - hidden = "true"
/ >
) }
{ isLocaleReady ? (
< span className = "hidden w-full justify-between lg:flex" >
< div className = "flex" > { t ( item . name ) } < / div >
< / span >
) : (
< SkeletonText style = { { width : ` ${ item . name . length * 10 } px ` } } className = "h-[20px]" / >
) }
< / ButtonOrLink >
< / Tooltip >
) ) }
2023-01-02 19:44:51 +00:00
< Credits / >
2022-12-19 17:37:20 +00:00
< / div >
< / aside >
< / div >
2022-08-09 09:21:15 +00:00
) ;
}
2022-09-02 19:00:41 +00:00
export function ShellMain ( props : LayoutProps ) {
const router = useRouter ( ) ;
2022-09-05 19:06:34 +00:00
const { isLocaleReady } = useLocale ( ) ;
2023-02-02 08:24:31 +00:00
2022-08-09 09:21:15 +00:00
return (
2022-09-02 19:00:41 +00:00
< >
2023-07-04 20:07:45 +00:00
{ ( props . heading || ! ! props . backPath ) && (
< div
className = { classNames (
"flex items-center md:mb-6 md:mt-0" ,
props . smallHeading ? "lg:mb-7" : "lg:mb-8" ,
props . hideHeadingOnMobile ? "mb-0" : "mb-6"
) } >
{ ! ! props . backPath && (
< Button
variant = "icon"
size = "sm"
color = "minimal"
onClick = { ( ) = >
typeof props . backPath === "string" ? router . push ( props . backPath as string ) : router . back ( )
}
StartIcon = { ArrowLeft }
aria - label = "Go Back"
className = "rounded-md ltr:mr-2 rtl:ml-2"
/ >
) }
{ props . heading && (
< header
className = { classNames ( props . large && "py-8" , "flex w-full max-w-full items-center truncate" ) } >
{ props . HeadingLeftIcon && < div className = "ltr:mr-4" > { props . HeadingLeftIcon } < / div > }
< div
className = { classNames ( "w-full truncate ltr:mr-4 rtl:ml-4 md:block" , props . headerClassName ) } >
{ props . heading && (
< h3
className = { classNames (
"font-cal max-w-28 sm:max-w-72 md:max-w-80 text-emphasis inline truncate text-lg font-semibold tracking-wide sm:text-xl md:block xl:max-w-full" ,
props . smallHeading ? "text-base" : "text-xl" ,
props . hideHeadingOnMobile && "hidden"
) } >
{ ! isLocaleReady ? < SkeletonText invisible / > : props . heading }
< / h3 >
) }
{ props . subtitle && (
< p className = "text-default hidden text-sm md:block" >
{ ! isLocaleReady ? < SkeletonText invisible / > : props . subtitle }
< / p >
) }
< / div >
{ props . beforeCTAactions }
{ props . CTA && (
< div
2023-01-29 09:38:31 +00:00
className = { classNames (
2023-07-04 20:07:45 +00:00
props . backPath
? "relative"
: "pwa:bottom-24 fixed bottom-20 z-40 ltr:right-4 rtl:left-4 md:z-auto md:ltr:right-0 md:rtl:left-0" ,
"flex-shrink-0 md:relative md:bottom-auto md:right-auto"
2023-01-29 09:38:31 +00:00
) } >
2023-07-04 20:07:45 +00:00
{ props . CTA }
< / div >
2023-01-31 22:31:04 +00:00
) }
2023-07-04 20:07:45 +00:00
{ props . actions && props . actions }
< / header >
) }
< / div >
) }
feat: Organizations (#8993)
* Initial commit
* Adding feature flag
* feat: Orgs Schema Changing `scopedMembers` to `orgUsers` (#9209)
* Change scopedMembers to orgMembers
* Change to orgUsers
* Letting duplicate slugs for teams to support orgs
* Covering null on unique clauses
* Supporting having the orgId in the session cookie
* feat: organization event type filter (#9253)
Signed-off-by: Udit Takkar <udit.07814802719@cse.mait.ac.in>
* Missing changes to support orgs schema changes
* feat: Onboarding process to create an organization (#9184)
* Desktop first banner, mobile pending
* Removing dead code and img
* WIP
* Adds Email verification template+translations for organizations (#9202)
* First step done
* Merge branch 'feat/organizations-onboarding' of github.com:calcom/cal.com into feat/organizations-onboarding
* Step 2 done, avatar not working
* Covering null on unique clauses
* Onboarding admins step
* Last step to create teams
* Moving change password handler, improving verifying code flow
* Clearing error before submitting
* Reverting email testing api changes
* Reverting having the banner for now
* Consistent exported components
* Remove unneeded files from banner
* Removing uneeded code
* Fixing avatar selector
* Using meta component for head/descr
* Missing i18n strings
* Feedback
* Making an org avatar (temp)
* Check for subteams slug clashes with usernames
* Fixing create teams onsuccess
* feedback
* Making sure we check requestedSlug now
---------
Co-authored-by: sean-brydon <55134778+sean-brydon@users.noreply.github.com>
* feat: [CAL-1816] Organization subdomain support (#9345)
* Desktop first banner, mobile pending
* Removing dead code and img
* WIP
* Adds Email verification template+translations for organizations (#9202)
* First step done
* Merge branch 'feat/organizations-onboarding' of github.com:calcom/cal.com into feat/organizations-onboarding
* Step 2 done, avatar not working
* Covering null on unique clauses
* Onboarding admins step
* Last step to create teams
* Moving change password handler, improving verifying code flow
* Clearing error before submitting
* Reverting email testing api changes
* Reverting having the banner for now
* Consistent exported components
* Remove unneeded files from banner
* Removing uneeded code
* Fixing avatar selector
* Using meta component for head/descr
* Missing i18n strings
* Feedback
* Making an org avatar (temp)
* Check for subteams slug clashes with usernames
* Fixing create teams onsuccess
* Covering users and subteams, excluding non-org users
* Unpublished teams shows correctly
* Create subdomain in Vercel
* feedback
* Renaming Vercel env vars
* Vercel domain check before creation
* Supporting cal-staging.com
* Change to have vercel detect it
* vercel domain check data message error
* Remove check domain
* Making sure we check requestedSlug now
* Feedback and unneeded code
* Reverting unneeded changes
* Unneeded changes
---------
Co-authored-by: sean-brydon <55134778+sean-brydon@users.noreply.github.com>
* Vercel subdomain creation in PROD only
* Making sure we let localhost still work
* Feedback
* Type check fixes
* feat: Organization branding in side menu (#9279)
* Desktop first banner, mobile pending
* Removing dead code and img
* WIP
* Adds Email verification template+translations for organizations (#9202)
* First step done
* Merge branch 'feat/organizations-onboarding' of github.com:calcom/cal.com into feat/organizations-onboarding
* Step 2 done, avatar not working
* Covering null on unique clauses
* Onboarding admins step
* Last step to create teams
* Moving change password handler, improving verifying code flow
* Clearing error before submitting
* Reverting email testing api changes
* Reverting having the banner for now
* Consistent exported components
* Remove unneeded files from banner
* Removing uneeded code
* Fixing avatar selector
* Org branding provider used in shell sidebar
* Using meta component for head/descr
* Missing i18n strings
* Feedback
* Making an org avatar (temp)
* Using org avatar (temp)
* Not showing org logo if not set
* User onboarding with org branding (slug)
* Check for subteams slug clashes with usernames
* Fixing create teams onsuccess
* feedback
* Feedback
* Org public profile
* Public profiles for team event types
* Added setup profile alert
* Using org avatar on subteams avatar
* Making sure we show the set up profile on org only
* Profile username availability rely on org hook
* Update apps/web/pages/team/[slug].tsx
Co-authored-by: sean-brydon <55134778+sean-brydon@users.noreply.github.com>
* Update apps/web/pages/team/[slug].tsx
Co-authored-by: sean-brydon <55134778+sean-brydon@users.noreply.github.com>
---------
Co-authored-by: sean-brydon <55134778+sean-brydon@users.noreply.github.com>
* feat: Organization support for event types page (#9449)
* Desktop first banner, mobile pending
* Removing dead code and img
* WIP
* Adds Email verification template+translations for organizations (#9202)
* First step done
* Merge branch 'feat/organizations-onboarding' of github.com:calcom/cal.com into feat/organizations-onboarding
* Step 2 done, avatar not working
* Covering null on unique clauses
* Onboarding admins step
* Last step to create teams
* Moving change password handler, improving verifying code flow
* Clearing error before submitting
* Reverting email testing api changes
* Reverting having the banner for now
* Consistent exported components
* Remove unneeded files from banner
* Removing uneeded code
* Fixing avatar selector
* Org branding provider used in shell sidebar
* Using meta component for head/descr
* Missing i18n strings
* Feedback
* Making an org avatar (temp)
* Using org avatar (temp)
* Not showing org logo if not set
* User onboarding with org branding (slug)
* Check for subteams slug clashes with usernames
* Fixing create teams onsuccess
* feedback
* Feedback
* Org public profile
* Public profiles for team event types
* Added setup profile alert
* Using org avatar on subteams avatar
* Processing orgs and children as profile options
* Reverting change not belonging to this PR
* Making sure we show the set up profile on org only
* Removing console.log
* Comparing memberships to choose the highest one
---------
Co-authored-by: sean-brydon <55134778+sean-brydon@users.noreply.github.com>
* Type errors
* Refactor and type fixes
* Update orgDomains.ts
* Feedback
* Reverting
* NIT
* fix issue getting org slug from domain
* Improving orgDomains util
* Host comes with port
* Update useRouterQuery.ts
* Feedback
* Feedback
* Feedback
* Feedback: SSR for user event-types to have org context
* chore: Cache node_modules (#9492)
* Adding check for cache hit
* Adding a separate install step first
* Put the restore cache steps back
* Revert the uses type for restoring cache
* Added step to restore nm cache
* Removed the cache-hit check
* Comments and naming
* Removed extra install command
* Updated the name of the linting step to be more clear
* Removes the need for useEffect here
* Feedback
* Feedback
* Cookie domain needs a dot
* Type fix
* Update apps/web/public/static/locales/en/common.json
Co-authored-by: Omar López <zomars@me.com>
* Update packages/emails/src/templates/OrganizationAccountVerifyEmail.tsx
* Feedback
---------
Signed-off-by: Udit Takkar <udit.07814802719@cse.mait.ac.in>
Co-authored-by: Joe Au-Yeung <65426560+joeauyeung@users.noreply.github.com>
Co-authored-by: Udit Takkar <53316345+Udit-takkar@users.noreply.github.com>
Co-authored-by: sean-brydon <55134778+sean-brydon@users.noreply.github.com>
Co-authored-by: zomars <zomars@me.com>
Co-authored-by: Efraín Rochín <roae.85@gmail.com>
Co-authored-by: Keith Williams <keithwillcode@gmail.com>
2023-06-14 21:40:20 +00:00
{ props . afterHeading && < > { props . afterHeading } < / > }
2023-01-15 17:54:52 +00:00
< div className = { classNames ( props . flexChildrenContainer && "flex flex-1 flex-col" ) } >
2022-09-02 19:00:41 +00:00
{ props . children }
< / div >
< / >
) ;
}
2022-09-07 01:33:50 +00:00
function MainContainer ( {
MobileNavigationContainer : MobileNavigationContainerProp = < MobileNavigationContainer / > ,
TopNavContainer : TopNavContainerProp = < TopNavContainer / > ,
. . . props
} : LayoutProps ) {
2022-09-02 19:00:41 +00:00
return (
2023-04-05 18:14:46 +00:00
< main className = "bg-default relative z-0 flex-1 focus:outline-none" >
2022-09-02 19:00:41 +00:00
{ /* show top navigation for md and smaller (tablet and phones) */ }
2022-09-07 01:33:50 +00:00
{ TopNavContainerProp }
2023-06-19 11:44:47 +00:00
< div className = "max-w-full px-4 py-4 md:py-8 lg:px-12" >
2022-09-06 17:05:16 +00:00
< ErrorBoundary >
{ ! props . withoutMain ? < ShellMain { ...props } > { props . children } < / ShellMain > : props . children }
< / ErrorBoundary >
2022-09-24 11:55:50 +00:00
{ /* show bottom navigation for md and smaller (tablet and phones) on pages where back button doesn't exist */ }
{ ! props . backPath ? MobileNavigationContainerProp : null }
2022-09-06 17:05:16 +00:00
< / div >
2022-08-09 09:21:15 +00:00
< / main >
) ;
}
function TopNavContainer() {
const { status } = useSession ( ) ;
if ( status !== "authenticated" ) return null ;
return < TopNav / > ;
}
function TopNav() {
const isEmbed = useIsEmbed ( ) ;
const { t } = useLocale ( ) ;
return (
2022-09-09 15:02:31 +00:00
< >
< nav
style = { isEmbed ? { display : "none" } : { } }
2023-06-22 22:25:37 +00:00
className = "bg-muted border-subtle sticky top-0 z-40 flex w-full items-center justify-between border-b bg-opacity-50 px-4 py-1.5 backdrop-blur-lg sm:p-4 md:hidden" >
2022-09-09 15:02:31 +00:00
< Link href = "/event-types" >
2023-01-06 12:13:56 +00:00
< Logo / >
2022-09-09 15:02:31 +00:00
< / Link >
< div className = "flex items-center gap-2 self-center" >
2023-04-05 18:14:46 +00:00
< span className = "hover:bg-muted hover:text-emphasis text-default group flex items-center rounded-full text-sm font-medium lg:hidden" >
2022-09-09 15:02:31 +00:00
< KBarTrigger / >
< / span >
2023-04-05 18:14:46 +00:00
< button className = "hover:bg-muted hover:text-subtle text-muted rounded-full p-1 focus:outline-none focus:ring-2 focus:ring-black focus:ring-offset-2" >
2022-09-09 15:02:31 +00:00
< span className = "sr-only" > { t ( "settings" ) } < / span >
2023-02-24 18:39:09 +00:00
< Link href = "/settings/my-account/profile" >
2023-04-12 15:26:31 +00:00
< Settings className = "text-default h-4 w-4" aria - hidden = "true" / >
2022-09-09 15:02:31 +00:00
< / Link >
< / button >
< UserDropdown small / >
< / div >
< / nav >
< / >
2022-08-09 09:21:15 +00:00
) ;
}
2022-09-07 04:13:31 +00:00
export const MobileNavigationMoreItems = ( ) = > (
2023-04-11 15:21:24 +00:00
< ul className = "border-subtle mt-2 rounded-md border" >
2022-09-07 04:13:31 +00:00
{ mobileNavigationMoreItems . map ( ( item ) = > (
< MobileNavigationMoreItem key = { item . name } item = { item } / >
) ) }
< / ul >
) ;