diff --git a/packages/twenty-front/src/modules/app/components/AppRouterProviders.tsx b/packages/twenty-front/src/modules/app/components/AppRouterProviders.tsx index 5ba248a56a..43ce095f4a 100644 --- a/packages/twenty-front/src/modules/app/components/AppRouterProviders.tsx +++ b/packages/twenty-front/src/modules/app/components/AppRouterProviders.tsx @@ -8,6 +8,7 @@ import { ClientConfigProvider } from '@/client-config/components/ClientConfigPro import { ClientConfigProviderEffect } from '@/client-config/components/ClientConfigProviderEffect'; import { PromiseRejectionEffect } from '@/error-handler/components/PromiseRejectionEffect'; import { ApolloMetadataClientProvider } from '@/object-metadata/components/ApolloMetadataClientProvider'; +import { ObjectMetadataItemsGater } from '@/object-metadata/components/ObjectMetadataItemsGater'; import { ObjectMetadataItemsProvider } from '@/object-metadata/components/ObjectMetadataItemsProvider'; import { PrefetchDataProvider } from '@/prefetch/components/PrefetchDataProvider'; import { DialogManager } from '@/ui/feedback/dialog-manager/components/DialogManager'; @@ -15,6 +16,7 @@ import { DialogManagerScope } from '@/ui/feedback/dialog-manager/scopes/DialogMa import { SnackBarProvider } from '@/ui/feedback/snack-bar-manager/components/SnackBarProvider'; import { UserThemeProviderEffect } from '@/ui/theme/components/AppThemeProvider'; import { BaseThemeProvider } from '@/ui/theme/components/BaseThemeProvider'; +import { PageFavicon } from '@/ui/utilities/page-favicon/components/PageFavicon'; import { PageTitle } from '@/ui/utilities/page-title/components/PageTitle'; import { UserProvider } from '@/users/components/UserProvider'; import { UserProviderEffect } from '@/users/components/UserProviderEffect'; @@ -22,7 +24,6 @@ import { WorkspaceProviderEffect } from '@/workspace/components/WorkspaceProvide import { StrictMode } from 'react'; import { Outlet, useLocation } from 'react-router-dom'; import { getPageTitleFromPath } from '~/utils/title-utils'; -import { PageFavicon } from '@/ui/utilities/page-favicon/components/PageFavicon'; export const AppRouterProviders = () => { const { pathname } = useLocation(); @@ -41,22 +42,24 @@ export const AppRouterProviders = () => { - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + diff --git a/packages/twenty-front/src/modules/app/effect-components/PageChangeEffect.tsx b/packages/twenty-front/src/modules/app/effect-components/PageChangeEffect.tsx index 3934d9040d..b9f692e0eb 100644 --- a/packages/twenty-front/src/modules/app/effect-components/PageChangeEffect.tsx +++ b/packages/twenty-front/src/modules/app/effect-components/PageChangeEffect.tsx @@ -1,6 +1,6 @@ import { useEffect, useState } from 'react'; import { useLocation, useNavigate } from 'react-router-dom'; -import { useRecoilValue } from 'recoil'; +import { useRecoilValue, useSetRecoilState } from 'recoil'; import { setSessionId, @@ -8,12 +8,14 @@ import { } from '@/analytics/hooks/useEventTracker'; import { useRequestFreshCaptchaToken } from '@/captcha/hooks/useRequestFreshCaptchaToken'; import { isCaptchaScriptLoadedState } from '@/captcha/states/isCaptchaScriptLoadedState'; +import { isAppWaitingForFreshObjectMetadataState } from '@/object-metadata/states/isAppWaitingForFreshObjectMetadataState'; import { TableHotkeyScope } from '@/object-record/record-table/types/TableHotkeyScope'; import { AppBasePath } from '@/types/AppBasePath'; import { AppPath } from '@/types/AppPath'; import { PageHotkeyScope } from '@/types/PageHotkeyScope'; import { SettingsPath } from '@/types/SettingsPath'; import { useSetHotkeyScope } from '@/ui/utilities/hotkey/hooks/useSetHotkeyScope'; +import { useDebouncedCallback } from 'use-debounce'; import { useCleanRecoilState } from '~/hooks/useCleanRecoilState'; import { useIsMatchingLocation } from '~/hooks/useIsMatchingLocation'; import { usePageChangeEffectNavigateLocation } from '~/hooks/usePageChangeEffectNavigateLocation'; @@ -50,11 +52,27 @@ export const PageChangeEffect = () => { } }, [location, previousLocation]); + const setIsAppWaitingForFreshObjectMetadata = useSetRecoilState( + isAppWaitingForFreshObjectMetadataState, + ); + + const setIsAppWaitingForFreshObjectMetadataDebounced = useDebouncedCallback( + () => { + setIsAppWaitingForFreshObjectMetadata(false); + }, + 100, + ); + useEffect(() => { if (isDefined(pageChangeEffectNavigateLocation)) { navigate(pageChangeEffectNavigateLocation); + setIsAppWaitingForFreshObjectMetadataDebounced(); } - }, [navigate, pageChangeEffectNavigateLocation]); + }, [ + navigate, + pageChangeEffectNavigateLocation, + setIsAppWaitingForFreshObjectMetadataDebounced, + ]); useEffect(() => { switch (true) { diff --git a/packages/twenty-front/src/modules/auth/components/VerifyEffect.tsx b/packages/twenty-front/src/modules/auth/components/VerifyEffect.tsx index a066ddf7ed..e650104f01 100644 --- a/packages/twenty-front/src/modules/auth/components/VerifyEffect.tsx +++ b/packages/twenty-front/src/modules/auth/components/VerifyEffect.tsx @@ -3,7 +3,9 @@ import { useNavigate, useSearchParams } from 'react-router-dom'; import { useAuth } from '@/auth/hooks/useAuth'; import { useIsLogged } from '@/auth/hooks/useIsLogged'; +import { isAppWaitingForFreshObjectMetadataState } from '@/object-metadata/states/isAppWaitingForFreshObjectMetadataState'; import { AppPath } from '@/types/AppPath'; +import { useSetRecoilState } from 'recoil'; export const VerifyEffect = () => { const [searchParams] = useSearchParams(); @@ -14,11 +16,16 @@ export const VerifyEffect = () => { const { verify } = useAuth(); + const setIsAppWaitingForFreshObjectMetadata = useSetRecoilState( + isAppWaitingForFreshObjectMetadataState, + ); + useEffect(() => { const getTokens = async () => { if (!loginToken) { navigate(AppPath.SignInUp); } else { + setIsAppWaitingForFreshObjectMetadata(true); await verify(loginToken); } }; diff --git a/packages/twenty-front/src/modules/auth/hooks/useAuth.ts b/packages/twenty-front/src/modules/auth/hooks/useAuth.ts index 3129976d43..dc9c51dce9 100644 --- a/packages/twenty-front/src/modules/auth/hooks/useAuth.ts +++ b/packages/twenty-front/src/modules/auth/hooks/useAuth.ts @@ -47,6 +47,7 @@ import { useIsCurrentLocationOnAWorkspaceSubdomain } from '@/domain-manager/hook import { useLastAuthenticatedWorkspaceDomain } from '@/domain-manager/hooks/useLastAuthenticatedWorkspaceDomain'; import { useReadWorkspaceSubdomainFromCurrentLocation } from '@/domain-manager/hooks/useReadWorkspaceSubdomainFromCurrentLocation'; import { domainConfigurationState } from '@/domain-manager/states/domainConfigurationState'; +import { isAppWaitingForFreshObjectMetadataState } from '@/object-metadata/states/isAppWaitingForFreshObjectMetadataState'; export const useAuth = () => { const setTokenPair = useSetRecoilState(tokenPairState); @@ -54,6 +55,9 @@ export const useAuth = () => { const setCurrentWorkspaceMember = useSetRecoilState( currentWorkspaceMemberState, ); + const setIsAppWaitingForFreshObjectMetadataState = useSetRecoilState( + isAppWaitingForFreshObjectMetadataState, + ); const setCurrentWorkspaceMembers = useSetRecoilState( currentWorkspaceMembersState, ); @@ -240,6 +244,7 @@ export const useAuth = () => { setWorkspaces(validWorkspaces); } + setIsAppWaitingForFreshObjectMetadataState(true); return { user, @@ -254,6 +259,7 @@ export const useAuth = () => { setCurrentUser, setCurrentWorkspace, isOnAWorkspaceSubdomain, + setIsAppWaitingForFreshObjectMetadataState, setCurrentWorkspaceMembers, setCurrentWorkspaceMember, setDateTimeFormat, diff --git a/packages/twenty-front/src/modules/object-metadata/components/ObjectMetadataItemsGater.tsx b/packages/twenty-front/src/modules/object-metadata/components/ObjectMetadataItemsGater.tsx new file mode 100644 index 0000000000..4ab14ba953 --- /dev/null +++ b/packages/twenty-front/src/modules/object-metadata/components/ObjectMetadataItemsGater.tsx @@ -0,0 +1,19 @@ +import React from 'react'; +import { useRecoilValue } from 'recoil'; + +import { isAppWaitingForFreshObjectMetadataState } from '@/object-metadata/states/isAppWaitingForFreshObjectMetadataState'; +import { UserOrMetadataLoader } from '~/loading/components/UserOrMetadataLoader'; + +export const ObjectMetadataItemsGater = ({ + children, +}: React.PropsWithChildren) => { + const isAppWaitingForFreshObjectMetadata = useRecoilValue( + isAppWaitingForFreshObjectMetadataState, + ); + + const shouldDisplayChildren = !isAppWaitingForFreshObjectMetadata; + + return ( + <>{shouldDisplayChildren ? <>{children} : } + ); +}; diff --git a/packages/twenty-front/src/modules/object-metadata/states/isAppWaitingForFreshObjectMetadataState.ts b/packages/twenty-front/src/modules/object-metadata/states/isAppWaitingForFreshObjectMetadataState.ts new file mode 100644 index 0000000000..2cbe59765f --- /dev/null +++ b/packages/twenty-front/src/modules/object-metadata/states/isAppWaitingForFreshObjectMetadataState.ts @@ -0,0 +1,6 @@ +import { createState } from 'twenty-ui'; + +export const isAppWaitingForFreshObjectMetadataState = createState({ + key: 'isAppWaitingForFreshObjectMetadataState', + defaultValue: false, +}); diff --git a/packages/twenty-front/src/modules/ui/layout/hooks/useShowAuthModal.ts b/packages/twenty-front/src/modules/ui/layout/hooks/useShowAuthModal.ts index f81f545362..a12dbf5905 100644 --- a/packages/twenty-front/src/modules/ui/layout/hooks/useShowAuthModal.ts +++ b/packages/twenty-front/src/modules/ui/layout/hooks/useShowAuthModal.ts @@ -21,17 +21,14 @@ export const useShowAuthModal = () => { ); return useMemo(() => { - if (isMatchingLocation(AppPath.SignInUp)) { - return true; - } - if (isMatchingLocation(AppPath.Verify)) { return false; } if ( isMatchingLocation(AppPath.Invite) || - isMatchingLocation(AppPath.ResetPassword) + isMatchingLocation(AppPath.ResetPassword) || + isMatchingLocation(AppPath.SignInUp) ) { return isDefaultLayoutAuthModalVisible; } diff --git a/packages/twenty-front/src/modules/ui/layout/states/isDefaultLayoutAuthModalVisibleState.ts b/packages/twenty-front/src/modules/ui/layout/states/isDefaultLayoutAuthModalVisibleState.ts index 95c4198694..c181a6a7d5 100644 --- a/packages/twenty-front/src/modules/ui/layout/states/isDefaultLayoutAuthModalVisibleState.ts +++ b/packages/twenty-front/src/modules/ui/layout/states/isDefaultLayoutAuthModalVisibleState.ts @@ -2,5 +2,5 @@ import { createState } from 'twenty-ui'; export const isDefaultLayoutAuthModalVisibleState = createState({ key: 'isDefaultLayoutAuthModalVisibleState', - defaultValue: false, + defaultValue: true, }); diff --git a/packages/twenty-front/src/pages/auth/SignInUp.tsx b/packages/twenty-front/src/pages/auth/SignInUp.tsx index 20b76a3ee0..2c8a1f6b84 100644 --- a/packages/twenty-front/src/pages/auth/SignInUp.tsx +++ b/packages/twenty-front/src/pages/auth/SignInUp.tsx @@ -5,21 +5,21 @@ import { useSignInUpForm } from '@/auth/sign-in-up/hooks/useSignInUpForm'; import { SignInUpStep } from '@/auth/states/signInUpStepState'; import { workspacePublicDataState } from '@/auth/states/workspacePublicDataState'; -import { SignInUpGlobalScopeForm } from '@/auth/sign-in-up/components/SignInUpGlobalScopeForm'; -import { FooterNote } from '@/auth/sign-in-up/components/FooterNote'; -import { AnimatedEaseIn } from 'twenty-ui'; import { Logo } from '@/auth/components/Logo'; import { Title } from '@/auth/components/Title'; -import { SignInUpWorkspaceScopeForm } from '@/auth/sign-in-up/components/SignInUpWorkspaceScopeForm'; -import { DEFAULT_WORKSPACE_NAME } from '@/ui/navigation/navigation-drawer/constants/DefaultWorkspaceName'; +import { FooterNote } from '@/auth/sign-in-up/components/FooterNote'; +import { SignInUpGlobalScopeForm } from '@/auth/sign-in-up/components/SignInUpGlobalScopeForm'; import { SignInUpSSOIdentityProviderSelection } from '@/auth/sign-in-up/components/SignInUpSSOIdentityProviderSelection'; -import { isMultiWorkspaceEnabledState } from '@/client-config/states/isMultiWorkspaceEnabledState'; -import { useMemo } from 'react'; -import { isDefined } from '~/utils/isDefined'; +import { SignInUpWorkspaceScopeForm } from '@/auth/sign-in-up/components/SignInUpWorkspaceScopeForm'; import { SignInUpWorkspaceScopeFormEffect } from '@/auth/sign-in-up/components/SignInUpWorkspaceScopeFormEffect'; +import { isMultiWorkspaceEnabledState } from '@/client-config/states/isMultiWorkspaceEnabledState'; import { useGetPublicWorkspaceDataBySubdomain } from '@/domain-manager/hooks/useGetPublicWorkspaceDataBySubdomain'; import { useIsCurrentLocationOnAWorkspaceSubdomain } from '@/domain-manager/hooks/useIsCurrentLocationOnAWorkspaceSubdomain'; import { useIsCurrentLocationOnDefaultDomain } from '@/domain-manager/hooks/useIsCurrentLocationOnDefaultDomain'; +import { DEFAULT_WORKSPACE_NAME } from '@/ui/navigation/navigation-drawer/constants/DefaultWorkspaceName'; +import { useMemo } from 'react'; +import { AnimatedEaseIn } from 'twenty-ui'; +import { isDefined } from '~/utils/isDefined'; export const SignInUp = () => { const { form } = useSignInUpForm();