From 43316883c575e89668464bc1129b26ad7dfa89ee Mon Sep 17 00:00:00 2001 From: Stefanos Anagnostou Date: Fri, 13 Oct 2023 14:59:49 +0300 Subject: [PATCH] refactor(clerk-react,types): Resolve PR comments --- .changeset/proud-ways-lie.md | 34 ++++++++++++++++- .../OrganizationProfileRoutes.tsx | 5 ++- .../UserProfile/UserProfileRoutes.tsx | 5 ++- packages/clerk-js/src/ui/constants.ts | 9 +++++ .../src/ui/utils/createCustomPages.tsx | 38 ++++++++++--------- .../react/src/components/uiComponents.tsx | 3 +- packages/react/src/utils/index.ts | 1 - packages/react/src/utils/useCustomPages.tsx | 2 +- packages/shared/src/utils/index.ts | 1 + .../src/utils/logErrorInDevMode.ts | 2 +- 10 files changed, 74 insertions(+), 26 deletions(-) create mode 100644 packages/clerk-js/src/ui/constants.ts rename packages/{react => shared}/src/utils/logErrorInDevMode.ts (66%) diff --git a/.changeset/proud-ways-lie.md b/.changeset/proud-ways-lie.md index a659759959..d099191bd3 100644 --- a/.changeset/proud-ways-lie.md +++ b/.changeset/proud-ways-lie.md @@ -4,4 +4,36 @@ '@clerk/types': minor --- -Introduce Custom Pages in UserProfile and OrganizationProfile +Introduce customization in `UserProfile` and `OrganizationProfile` + +The `` component now allows the addition of custom pages and external links to the navigation sidebar. Custom pages can be created using the `` component, and external links can be added using the `` component. The default routes, such as `Account` and `Security`, can be reordered. + +Example React API usage: + +```tsx + + }> + + + } /> + + + +``` +Custom pages and links should be provided as children using the `` and `` components when using the `UserButton` component. + +The `` component now supports the addition of custom pages and external links to the navigation sidebar. Custom pages can be created using the `` component, and external links can be added using the `` component. The default routes, such as `Members` and `Settings`, can be reordered. + +Example React API usage: + +```tsx + + }> + + + } /> + + + +``` +Custom pages and links should be provided as children using the `` and `` components when using the `OrganizationSwitcher` component. diff --git a/packages/clerk-js/src/ui/components/OrganizationProfile/OrganizationProfileRoutes.tsx b/packages/clerk-js/src/ui/components/OrganizationProfile/OrganizationProfileRoutes.tsx index 8a145de4d9..9c4461392c 100644 --- a/packages/clerk-js/src/ui/components/OrganizationProfile/OrganizationProfileRoutes.tsx +++ b/packages/clerk-js/src/ui/components/OrganizationProfile/OrganizationProfileRoutes.tsx @@ -1,4 +1,5 @@ import { CustomPageContentContainer } from '../../common/CustomPageContentContainer'; +import { ORGANIZATION_PROFILE_NAVBAR_ROUTE_ID } from '../../constants'; import { Gate } from '../../common/Gate'; import { useOrganizationProfileContext } from '../../contexts'; import { ProfileCardContent } from '../../elements'; @@ -16,8 +17,8 @@ import { VerifyDomainPage } from './VerifyDomainPage'; export const OrganizationProfileRoutes = (props: PropsOfComponent) => { const { pages } = useOrganizationProfileContext(); - const isMembersPageRoot = pages.routes[0].id === 'members'; - const isSettingsPageRoot = pages.routes[0].id === 'settings'; + const isMembersPageRoot = pages.routes[0].id === ORGANIZATION_PROFILE_NAVBAR_ROUTE_ID.MEMBERS; + const isSettingsPageRoot = pages.routes[0].id === ORGANIZATION_PROFILE_NAVBAR_ROUTE_ID.SETTINGS; const customPageRoutesWithContents = pages.contents?.map((customPage, index) => { const shouldFirstCustomItemBeOnRoot = !isSettingsPageRoot && !isMembersPageRoot && index === 0; diff --git a/packages/clerk-js/src/ui/components/UserProfile/UserProfileRoutes.tsx b/packages/clerk-js/src/ui/components/UserProfile/UserProfileRoutes.tsx index 3f3c41fef9..a9b293e3a3 100644 --- a/packages/clerk-js/src/ui/components/UserProfile/UserProfileRoutes.tsx +++ b/packages/clerk-js/src/ui/components/UserProfile/UserProfileRoutes.tsx @@ -1,4 +1,5 @@ import { CustomPageContentContainer } from '../../common/CustomPageContentContainer'; +import { USER_PROFILE_NAVBAR_ROUTE_ID } from '../../constants'; import { useUserProfileContext } from '../../contexts'; import { ProfileCardContent } from '../../elements'; import { Route, Switch } from '../../router'; @@ -25,7 +26,9 @@ import { Web3Page } from './Web3Page'; export const UserProfileRoutes = (props: PropsOfComponent) => { const { pages } = useUserProfileContext(); - const isAccountPageRoot = pages.routes[0].id === 'account' || pages.routes[0].id === 'security'; + const isAccountPageRoot = + pages.routes[0].id === USER_PROFILE_NAVBAR_ROUTE_ID.ACCOUNT || + pages.routes[0].id === USER_PROFILE_NAVBAR_ROUTE_ID.SECURITY; const customPageRoutesWithContents = pages.contents?.map((customPage, index) => { const shouldFirstCustomItemBeOnRoot = !isAccountPageRoot && index === 0; diff --git a/packages/clerk-js/src/ui/constants.ts b/packages/clerk-js/src/ui/constants.ts new file mode 100644 index 0000000000..17d1dea512 --- /dev/null +++ b/packages/clerk-js/src/ui/constants.ts @@ -0,0 +1,9 @@ +export const USER_PROFILE_NAVBAR_ROUTE_ID = { + ACCOUNT: 'account', + SECURITY: 'security', +}; + +export const ORGANIZATION_PROFILE_NAVBAR_ROUTE_ID = { + MEMBERS: 'members', + SETTINGS: 'settings', +}; diff --git a/packages/clerk-js/src/ui/utils/createCustomPages.tsx b/packages/clerk-js/src/ui/utils/createCustomPages.tsx index e72a909846..1f50917783 100644 --- a/packages/clerk-js/src/ui/utils/createCustomPages.tsx +++ b/packages/clerk-js/src/ui/utils/createCustomPages.tsx @@ -2,6 +2,7 @@ import { isDevelopmentEnvironment } from '@clerk/shared'; import type { CustomPage } from '@clerk/types'; import { isValidUrl } from '../../utils'; +import { ORGANIZATION_PROFILE_NAVBAR_ROUTE_ID, USER_PROFILE_NAVBAR_ROUTE_ID } from '../constants'; import type { NavbarRoute } from '../elements'; import { CogFilled, TickShield, User } from '../icons'; import { localizationKeys } from '../localization'; @@ -14,7 +15,7 @@ export type CustomPageContent = { }; type ProfileReorderItem = { - label: 'account' | 'security'; + label: 'account' | 'security' | 'members' | 'settings'; }; type ProfileCustomPage = { @@ -184,6 +185,7 @@ const checkForDuplicateUsageOfReorderingItems = (customPages: CustomPage[], vali return [...acc, cp.label]; }, [] as string[]); }; + //path !== '/' && path !== 'account' const warnForDuplicatePaths = (routes: NavbarRoute[], pathsToFilter: string[]) => { const paths = routes @@ -243,27 +245,27 @@ const getUserProfileDefaultRoutes = (): GetDefaultRoutesReturnType => { const INITIAL_ROUTES: NavbarRoute[] = [ { name: localizationKeys('userProfile.start.headerTitle__account'), - id: 'account', + id: USER_PROFILE_NAVBAR_ROUTE_ID.ACCOUNT, icon: User, path: 'account', }, { name: localizationKeys('userProfile.start.headerTitle__security'), - id: 'security', + id: USER_PROFILE_NAVBAR_ROUTE_ID.SECURITY, icon: TickShield, path: 'account', }, ]; const pageToRootNavbarRouteMap: Record = { - profile: INITIAL_ROUTES.find(r => r.id === 'account') as NavbarRoute, - 'email-address': INITIAL_ROUTES.find(r => r.id === 'account') as NavbarRoute, - 'phone-number': INITIAL_ROUTES.find(r => r.id === 'account') as NavbarRoute, - 'connected-account': INITIAL_ROUTES.find(r => r.id === 'account') as NavbarRoute, - 'web3-wallet': INITIAL_ROUTES.find(r => r.id === 'account') as NavbarRoute, - username: INITIAL_ROUTES.find(r => r.id === 'account') as NavbarRoute, - 'multi-factor': INITIAL_ROUTES.find(r => r.id === 'security') as NavbarRoute, - password: INITIAL_ROUTES.find(r => r.id === 'security') as NavbarRoute, + profile: INITIAL_ROUTES.find(r => r.id === USER_PROFILE_NAVBAR_ROUTE_ID.ACCOUNT) as NavbarRoute, + 'email-address': INITIAL_ROUTES.find(r => r.id === USER_PROFILE_NAVBAR_ROUTE_ID.ACCOUNT) as NavbarRoute, + 'phone-number': INITIAL_ROUTES.find(r => r.id === USER_PROFILE_NAVBAR_ROUTE_ID.ACCOUNT) as NavbarRoute, + 'connected-account': INITIAL_ROUTES.find(r => r.id === USER_PROFILE_NAVBAR_ROUTE_ID.ACCOUNT) as NavbarRoute, + 'web3-wallet': INITIAL_ROUTES.find(r => r.id === USER_PROFILE_NAVBAR_ROUTE_ID.ACCOUNT) as NavbarRoute, + username: INITIAL_ROUTES.find(r => r.id === USER_PROFILE_NAVBAR_ROUTE_ID.ACCOUNT) as NavbarRoute, + 'multi-factor': INITIAL_ROUTES.find(r => r.id === USER_PROFILE_NAVBAR_ROUTE_ID.SECURITY) as NavbarRoute, + password: INITIAL_ROUTES.find(r => r.id === USER_PROFILE_NAVBAR_ROUTE_ID.SECURITY) as NavbarRoute, }; const validReorderItemLabels: string[] = INITIAL_ROUTES.map(r => r.id); @@ -275,24 +277,24 @@ const getOrganizationProfileDefaultRoutes = (): GetDefaultRoutesReturnType => { const INITIAL_ROUTES: NavbarRoute[] = [ { name: localizationKeys('organizationProfile.start.headerTitle__members'), - id: 'members', + id: ORGANIZATION_PROFILE_NAVBAR_ROUTE_ID.MEMBERS, icon: User, path: 'organization-members', }, { name: localizationKeys('organizationProfile.start.headerTitle__settings'), - id: 'settings', + id: ORGANIZATION_PROFILE_NAVBAR_ROUTE_ID.SETTINGS, icon: CogFilled, path: 'organization-settings', }, ]; const pageToRootNavbarRouteMap: Record = { - 'invite-members': INITIAL_ROUTES.find(r => r.id === 'members') as NavbarRoute, - domain: INITIAL_ROUTES.find(r => r.id === 'settings') as NavbarRoute, - profile: INITIAL_ROUTES.find(r => r.id === 'settings') as NavbarRoute, - leave: INITIAL_ROUTES.find(r => r.id === 'settings') as NavbarRoute, - delete: INITIAL_ROUTES.find(r => r.id === 'settings') as NavbarRoute, + 'invite-members': INITIAL_ROUTES.find(r => r.id === ORGANIZATION_PROFILE_NAVBAR_ROUTE_ID.MEMBERS) as NavbarRoute, + domain: INITIAL_ROUTES.find(r => r.id === ORGANIZATION_PROFILE_NAVBAR_ROUTE_ID.SETTINGS) as NavbarRoute, + profile: INITIAL_ROUTES.find(r => r.id === ORGANIZATION_PROFILE_NAVBAR_ROUTE_ID.SETTINGS) as NavbarRoute, + leave: INITIAL_ROUTES.find(r => r.id === ORGANIZATION_PROFILE_NAVBAR_ROUTE_ID.SETTINGS) as NavbarRoute, + delete: INITIAL_ROUTES.find(r => r.id === ORGANIZATION_PROFILE_NAVBAR_ROUTE_ID.SETTINGS) as NavbarRoute, }; const validReorderItemLabels: string[] = INITIAL_ROUTES.map(r => r.id); diff --git a/packages/react/src/components/uiComponents.tsx b/packages/react/src/components/uiComponents.tsx index 58650f3d59..42edc8f1ff 100644 --- a/packages/react/src/components/uiComponents.tsx +++ b/packages/react/src/components/uiComponents.tsx @@ -1,3 +1,4 @@ +import { logErrorInDevMode } from '@clerk/shared'; import type { CreateOrganizationProps, OrganizationListProps, @@ -25,7 +26,7 @@ import type { UserProfilePageProps, WithClerkProp, } from '../types'; -import { logErrorInDevMode, useOrganizationProfileCustomPages, useUserProfileCustomPages } from '../utils'; +import { useOrganizationProfileCustomPages, useUserProfileCustomPages } from '../utils'; import { withClerk } from './withClerk'; type UserProfileExportType = typeof _UserProfile & { diff --git a/packages/react/src/utils/index.ts b/packages/react/src/utils/index.ts index 816d275a5c..04a02b3085 100644 --- a/packages/react/src/utils/index.ts +++ b/packages/react/src/utils/index.ts @@ -5,4 +5,3 @@ export { loadClerkJsScript } from './loadClerkJsScript'; export * from './useMaxAllowedInstancesGuard'; export * from './useCustomElementPortal'; export * from './useCustomPages'; -export * from './logErrorInDevMode'; diff --git a/packages/react/src/utils/useCustomPages.tsx b/packages/react/src/utils/useCustomPages.tsx index 97352e03ac..7037a4751c 100644 --- a/packages/react/src/utils/useCustomPages.tsx +++ b/packages/react/src/utils/useCustomPages.tsx @@ -1,3 +1,4 @@ +import { logErrorInDevMode } from '@clerk/shared'; import type { CustomPage } from '@clerk/types'; import type { ReactElement } from 'react'; import React from 'react'; @@ -10,7 +11,6 @@ import { } from '../components/uiComponents'; import { customLinkWrongProps, customPagesIgnoredComponent, customPageWrongProps } from '../errors'; import type { UserProfilePageProps } from '../types'; -import { logErrorInDevMode } from './logErrorInDevMode'; import type { UseCustomElementPortalParams, UseCustomElementPortalReturn } from './useCustomElementPortal'; import { useCustomElementPortal } from './useCustomElementPortal'; diff --git a/packages/shared/src/utils/index.ts b/packages/shared/src/utils/index.ts index 7e6dcec81b..8838c7ed4b 100644 --- a/packages/shared/src/utils/index.ts +++ b/packages/shared/src/utils/index.ts @@ -3,3 +3,4 @@ export { isStaging } from './instance'; export { noop } from './noop'; export * from './runtimeEnvironment'; export * from './runWithExponentialBackOff'; +export { logErrorInDevMode } from './logErrorInDevMode'; diff --git a/packages/react/src/utils/logErrorInDevMode.ts b/packages/shared/src/utils/logErrorInDevMode.ts similarity index 66% rename from packages/react/src/utils/logErrorInDevMode.ts rename to packages/shared/src/utils/logErrorInDevMode.ts index 8992e997d3..ea299ba832 100644 --- a/packages/react/src/utils/logErrorInDevMode.ts +++ b/packages/shared/src/utils/logErrorInDevMode.ts @@ -1,4 +1,4 @@ -import { isDevelopmentEnvironment } from '@clerk/shared'; +import { isDevelopmentEnvironment } from './runtimeEnvironment'; export const logErrorInDevMode = (message: string) => { if (isDevelopmentEnvironment()) {