fix: unify settings layout prep when entering settings from outside (#19373)
## Summary Clicking **Compose** in the emails tab without a connected account redirects to the New Account settings page, but the settings nav drawer was left in its previous (collapsed / "main") state — producing a visibly half-broken transition. ### Root cause The "enter settings" preparation (memorize previous URL + drawer state, expand the desktop drawer, switch the mobile drawer to `'settings'`) was duplicated **inline in three different places**: - `NavigationDrawerOtherSection.handleSettingsClick` - `MultiWorkspaceDropdownDefaultComponents` Settings link - Implicitly expected (but missing) from every `useNavigateSettings` caller Every other entry point — `ComposeEmailButton`, `ComposeEmailCommand`, `AIChatCreditsExhaustedMessage`, several workflow/role components — just called `navigateSettings(...)` and skipped the prep entirely, reproducing the bug. ### Fix - Move the full prep into `useOpenSettingsMenu`, with a `useIsSettingsPage()` short-circuit so internal navigation doesn't clobber the memorized return target. - `useNavigateSettings` delegates to `openSettingsMenu()` before navigating — fixing every caller in one place. - Collapse the duplicated inline logic in `NavigationDrawerOtherSection` and `MultiWorkspaceDropdownDefaultComponents` to a single call. Net **−9 lines**, single source of truth, no behavior change for the existing happy paths. ## Test plan - [x] \`nx typecheck twenty-front\` passes - [x] \`oxlint\` + \`prettier\` clean on all 4 changed files - [x] Existing \`useNavigateSettings\` tests pass (4/4) - [ ] Manual: Compose button on a Person/Company/Opportunity emails tab with no connected account → settings drawer renders fully expanded, "Exit Settings" returns to the record - [ ] Manual: "Settings" entry in the main nav drawer still works (return path memorized) - [ ] Manual: "Settings" entry in the multi-workspace dropdown still works, and right-click → open in new tab still works (kept \`UndecoratedLink\`) - [ ] Manual: Navigating between settings pages does not overwrite the memorized return URL 🤖 Generated with [Claude Code](https://claude.com/claude-code) --------- Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -1,9 +1,11 @@
|
||||
import { useOpenSettingsMenu } from '@/navigation/hooks/useOpenSettings';
|
||||
import { useNavigate } from 'react-router-dom';
|
||||
import { type SettingsPath } from 'twenty-shared/types';
|
||||
import { getSettingsPath } from 'twenty-shared/utils';
|
||||
|
||||
export const useNavigateSettings = () => {
|
||||
const navigate = useNavigate();
|
||||
const { openSettingsMenu } = useOpenSettingsMenu();
|
||||
|
||||
return <T extends SettingsPath>(
|
||||
to: T,
|
||||
@@ -14,6 +16,8 @@ export const useNavigateSettings = () => {
|
||||
state?: any;
|
||||
},
|
||||
) => {
|
||||
openSettingsMenu();
|
||||
|
||||
const path = getSettingsPath(to, params, queryParams);
|
||||
return navigate(path, options);
|
||||
};
|
||||
|
||||
+3
-25
@@ -1,19 +1,11 @@
|
||||
import { useLingui } from '@lingui/react/macro';
|
||||
import { useLocation, useNavigate } from 'react-router-dom';
|
||||
import { SettingsPath } from 'twenty-shared/types';
|
||||
import { getSettingsPath } from 'twenty-shared/utils';
|
||||
import { IconHelpCircle, IconSettings } from 'twenty-ui/display';
|
||||
import { AnimatedExpandableContainer } from 'twenty-ui/layout';
|
||||
|
||||
import { currentWorkspaceMemberState } from '@/auth/states/currentWorkspaceMemberState';
|
||||
import { useOpenSettingsMenu } from '@/navigation/hooks/useOpenSettings';
|
||||
import { getDocumentationUrl } from '@/support/utils/getDocumentationUrl';
|
||||
import { isNavigationDrawerExpandedState } from '@/ui/navigation/states/isNavigationDrawerExpanded';
|
||||
import { navigationDrawerExpandedMemorizedState } from '@/ui/navigation/states/navigationDrawerExpandedMemorizedState';
|
||||
import { navigationMemorizedUrlState } from '@/ui/navigation/states/navigationMemorizedUrlState';
|
||||
import { useAtomState } from '@/ui/utilities/state/jotai/hooks/useAtomState';
|
||||
import { useAtomStateValue } from '@/ui/utilities/state/jotai/hooks/useAtomStateValue';
|
||||
import { useSetAtomState } from '@/ui/utilities/state/jotai/hooks/useSetAtomState';
|
||||
|
||||
import { NavigationDrawerAnimatedCollapseWrapper } from '@/ui/navigation/navigation-drawer/components/NavigationDrawerAnimatedCollapseWrapper';
|
||||
import { NavigationDrawerItem } from '@/ui/navigation/navigation-drawer/components/NavigationDrawerItem';
|
||||
@@ -22,22 +14,12 @@ import { NavigationDrawerSectionTitle } from '@/ui/navigation/navigation-drawer/
|
||||
import { useNavigationSection } from '@/ui/navigation/navigation-drawer/hooks/useNavigationSection';
|
||||
import { isNavigationSectionOpenFamilyState } from '@/ui/navigation/navigation-drawer/states/isNavigationSectionOpenFamilyState';
|
||||
import { useAtomFamilyStateValue } from '@/ui/utilities/state/jotai/hooks/useAtomFamilyStateValue';
|
||||
import { useNavigateSettings } from '~/hooks/useNavigateSettings';
|
||||
|
||||
export const NavigationDrawerOtherSection = () => {
|
||||
const { t } = useLingui();
|
||||
const location = useLocation();
|
||||
const navigate = useNavigate();
|
||||
const navigateSettings = useNavigateSettings();
|
||||
const currentWorkspaceMember = useAtomStateValue(currentWorkspaceMemberState);
|
||||
const [isNavigationDrawerExpanded, setIsNavigationDrawerExpanded] =
|
||||
useAtomState(isNavigationDrawerExpandedState);
|
||||
const setNavigationDrawerExpandedMemorized = useSetAtomState(
|
||||
navigationDrawerExpandedMemorizedState,
|
||||
);
|
||||
const setNavigationMemorizedUrl = useSetAtomState(
|
||||
navigationMemorizedUrlState,
|
||||
);
|
||||
|
||||
const { openSettingsMenu } = useOpenSettingsMenu();
|
||||
|
||||
const { toggleNavigationSection } = useNavigationSection('Other');
|
||||
const isNavigationSectionOpen = useAtomFamilyStateValue(
|
||||
@@ -46,11 +28,7 @@ export const NavigationDrawerOtherSection = () => {
|
||||
);
|
||||
|
||||
const handleSettingsClick = () => {
|
||||
setNavigationDrawerExpandedMemorized(isNavigationDrawerExpanded);
|
||||
setIsNavigationDrawerExpanded(true);
|
||||
setNavigationMemorizedUrl(location.pathname + location.search);
|
||||
openSettingsMenu();
|
||||
navigate(getSettingsPath(SettingsPath.ProfilePage));
|
||||
navigateSettings(SettingsPath.ProfilePage);
|
||||
};
|
||||
|
||||
return (
|
||||
|
||||
@@ -1,17 +1,35 @@
|
||||
import { useIsSettingsPage } from '@/navigation/hooks/useIsSettingsPage';
|
||||
import { currentMobileNavigationDrawerState } from '@/navigation/states/currentMobileNavigationDrawerState';
|
||||
import { isNavigationDrawerExpandedState } from '@/ui/navigation/states/isNavigationDrawerExpanded';
|
||||
import { navigationDrawerExpandedMemorizedState } from '@/ui/navigation/states/navigationDrawerExpandedMemorizedState';
|
||||
import { navigationMemorizedUrlState } from '@/ui/navigation/states/navigationMemorizedUrlState';
|
||||
import { useAtomState } from '@/ui/utilities/state/jotai/hooks/useAtomState';
|
||||
import { useSetAtomState } from '@/ui/utilities/state/jotai/hooks/useSetAtomState';
|
||||
import { useLocation } from 'react-router-dom';
|
||||
|
||||
export const useOpenSettingsMenu = () => {
|
||||
const setIsNavigationDrawerExpanded = useSetAtomState(
|
||||
isNavigationDrawerExpandedState,
|
||||
const location = useLocation();
|
||||
const isSettingsPage = useIsSettingsPage();
|
||||
const [isNavigationDrawerExpanded, setIsNavigationDrawerExpanded] =
|
||||
useAtomState(isNavigationDrawerExpandedState);
|
||||
const setNavigationDrawerExpandedMemorized = useSetAtomState(
|
||||
navigationDrawerExpandedMemorizedState,
|
||||
);
|
||||
const setNavigationMemorizedUrl = useSetAtomState(
|
||||
navigationMemorizedUrlState,
|
||||
);
|
||||
const setCurrentMobileNavigationDrawer = useSetAtomState(
|
||||
currentMobileNavigationDrawerState,
|
||||
);
|
||||
|
||||
const openSettingsMenu = () => {
|
||||
if (isSettingsPage) {
|
||||
return;
|
||||
}
|
||||
|
||||
setNavigationDrawerExpandedMemorized(isNavigationDrawerExpanded);
|
||||
setIsNavigationDrawerExpanded(true);
|
||||
setNavigationMemorizedUrl(location.pathname + location.search);
|
||||
setCurrentMobileNavigationDrawer('settings');
|
||||
};
|
||||
|
||||
|
||||
+3
-17
@@ -15,13 +15,10 @@ import { DropdownMenuHeaderLeftComponent } from '@/ui/layout/dropdown/components
|
||||
import { DropdownMenuItemsContainer } from '@/ui/layout/dropdown/components/DropdownMenuItemsContainer';
|
||||
import { DropdownMenuSeparator } from '@/ui/layout/dropdown/components/DropdownMenuSeparator';
|
||||
import { useCloseDropdown } from '@/ui/layout/dropdown/hooks/useCloseDropdown';
|
||||
import { useOpenSettingsMenu } from '@/navigation/hooks/useOpenSettings';
|
||||
import { MULTI_WORKSPACE_DROPDOWN_ID } from '@/ui/navigation/navigation-drawer/constants/MultiWorkspaceDropdownId';
|
||||
import { multiWorkspaceDropdownState } from '@/ui/navigation/navigation-drawer/states/multiWorkspaceDropdownState';
|
||||
import { isNavigationDrawerExpandedState } from '@/ui/navigation/states/isNavigationDrawerExpanded';
|
||||
import { navigationDrawerExpandedMemorizedState } from '@/ui/navigation/states/navigationDrawerExpandedMemorizedState';
|
||||
import { navigationMemorizedUrlState } from '@/ui/navigation/states/navigationMemorizedUrlState';
|
||||
import { useColorScheme } from '@/ui/theme/hooks/useColorScheme';
|
||||
import { useAtomState } from '@/ui/utilities/state/jotai/hooks/useAtomState';
|
||||
import { useAtomStateValue } from '@/ui/utilities/state/jotai/hooks/useAtomStateValue';
|
||||
import { useSetAtomState } from '@/ui/utilities/state/jotai/hooks/useSetAtomState';
|
||||
import { CombinedGraphQLErrors } from '@apollo/client/errors';
|
||||
@@ -29,7 +26,6 @@ import { styled } from '@linaria/react';
|
||||
import { useLingui } from '@lingui/react/macro';
|
||||
import { themeCssVariables } from 'twenty-ui/theme-constants';
|
||||
import { isNonEmptyString } from '@sniptt/guards';
|
||||
import { useLocation } from 'react-router-dom';
|
||||
import { AppPath, SettingsPath } from 'twenty-shared/types';
|
||||
import { getSettingsPath } from 'twenty-shared/utils';
|
||||
import {
|
||||
@@ -85,15 +81,7 @@ export const MultiWorkspaceDropdownDefaultComponents = () => {
|
||||
multiWorkspaceDropdownState,
|
||||
);
|
||||
|
||||
const location = useLocation();
|
||||
const [isNavigationDrawerExpanded, setIsNavigationDrawerExpanded] =
|
||||
useAtomState(isNavigationDrawerExpandedState);
|
||||
const setNavigationDrawerExpandedMemorized = useSetAtomState(
|
||||
navigationDrawerExpandedMemorizedState,
|
||||
);
|
||||
const setNavigationMemorizedUrl = useSetAtomState(
|
||||
navigationMemorizedUrlState,
|
||||
);
|
||||
const { openSettingsMenu } = useOpenSettingsMenu();
|
||||
|
||||
const handleSupport = () => {
|
||||
window.FrontChat?.('show');
|
||||
@@ -239,9 +227,7 @@ export const MultiWorkspaceDropdownDefaultComponents = () => {
|
||||
<UndecoratedLink
|
||||
to={getSettingsPath(SettingsPath.ProfilePage)}
|
||||
onClick={() => {
|
||||
setNavigationDrawerExpandedMemorized(isNavigationDrawerExpanded);
|
||||
setIsNavigationDrawerExpanded(true);
|
||||
setNavigationMemorizedUrl(location.pathname + location.search);
|
||||
openSettingsMenu();
|
||||
closeDropdown(MULTI_WORKSPACE_DROPDOWN_ID);
|
||||
}}
|
||||
>
|
||||
|
||||
Reference in New Issue
Block a user