Feat: Navbar customization (#17728)
Co-authored-by: Copilot Autofix powered by AI <223894421+github-code-quality[bot]@users.noreply.github.com> Co-authored-by: Devessier <baptiste@devessier.fr>
This commit is contained in:
+169
-7
@@ -1,26 +1,188 @@
|
||||
import styled from '@emotion/styled';
|
||||
import { useLingui } from '@lingui/react/macro';
|
||||
import {
|
||||
useRecoilCallback,
|
||||
useRecoilState,
|
||||
useRecoilValue,
|
||||
useSetRecoilState,
|
||||
} from 'recoil';
|
||||
import {
|
||||
IconFolder,
|
||||
IconLink,
|
||||
IconPlus,
|
||||
IconTool,
|
||||
useIcons,
|
||||
} from 'twenty-ui/display';
|
||||
import { LightIconButton } from 'twenty-ui/input';
|
||||
import { FeatureFlagKey } from '~/generated-metadata/graphql';
|
||||
|
||||
import { useWorkspaceNavigationMenuItems } from '@/navigation-menu-item/hooks/useWorkspaceNavigationMenuItems';
|
||||
import { NavigationDrawerSectionForObjectMetadataItems } from '@/object-metadata/components/NavigationDrawerSectionForObjectMetadataItems';
|
||||
import { useNavigateCommandMenu } from '@/command-menu/hooks/useNavigateCommandMenu';
|
||||
import { CommandMenuPages } from '@/command-menu/types/CommandMenuPages';
|
||||
import { useOpenNavigationMenuItemInCommandMenu } from '@/navigation-menu-item/hooks/useOpenNavigationMenuItemInCommandMenu';
|
||||
import {
|
||||
type NavigationMenuItemClickParams,
|
||||
useWorkspaceSectionItems,
|
||||
} from '@/navigation-menu-item/hooks/useWorkspaceSectionItems';
|
||||
import { isNavigationMenuInEditModeState } from '@/navigation-menu-item/states/isNavigationMenuInEditModeState';
|
||||
import { NAVIGATION_MENU_ITEM_TYPE } from '@/navigation-menu-item/types/navigation-menu-item-type';
|
||||
import { navigationMenuItemsDraftState } from '@/navigation-menu-item/states/navigationMenuItemsDraftState';
|
||||
import { filterWorkspaceNavigationMenuItems } from '@/navigation-menu-item/utils/filterWorkspaceNavigationMenuItems';
|
||||
import { openNavigationMenuItemFolderIdsState } from '@/navigation-menu-item/states/openNavigationMenuItemFolderIdsState';
|
||||
import { selectedNavigationMenuItemInEditModeState } from '@/navigation-menu-item/states/selectedNavigationMenuItemInEditModeState';
|
||||
import { NavigationDrawerSectionForObjectMetadataItemsSkeletonLoader } from '@/object-metadata/components/NavigationDrawerSectionForObjectMetadataItemsSkeletonLoader';
|
||||
import { NavigationDrawerSectionForWorkspaceItems } from '@/object-metadata/components/NavigationDrawerSectionForWorkspaceItems';
|
||||
import { type ObjectMetadataItem } from '@/object-metadata/types/ObjectMetadataItem';
|
||||
import { useIsPrefetchLoading } from '@/prefetch/hooks/useIsPrefetchLoading';
|
||||
import { prefetchNavigationMenuItemsState } from '@/prefetch/states/prefetchNavigationMenuItemsState';
|
||||
import { useIsFeatureEnabled } from '@/workspace/hooks/useIsFeatureEnabled';
|
||||
import { isDefined } from 'twenty-shared/utils';
|
||||
|
||||
const StyledRightIconsContainer = styled.div`
|
||||
align-items: center;
|
||||
display: flex;
|
||||
gap: ${({ theme }) => theme.spacing(1)};
|
||||
`;
|
||||
|
||||
export const WorkspaceNavigationMenuItems = () => {
|
||||
const { workspaceNavigationMenuItemsObjectMetadataItems } =
|
||||
useWorkspaceNavigationMenuItems();
|
||||
const items = useWorkspaceSectionItems();
|
||||
const enterEditMode = useRecoilCallback(
|
||||
({ set, snapshot }) =>
|
||||
() => {
|
||||
const prefetchNavigationMenuItems = snapshot
|
||||
.getLoadable(prefetchNavigationMenuItemsState)
|
||||
.getValue();
|
||||
const workspaceNavigationMenuItems = filterWorkspaceNavigationMenuItems(
|
||||
prefetchNavigationMenuItems,
|
||||
);
|
||||
set(navigationMenuItemsDraftState, workspaceNavigationMenuItems);
|
||||
set(isNavigationMenuInEditModeState, true);
|
||||
},
|
||||
[],
|
||||
);
|
||||
const isNavigationMenuItemEditingEnabled = useIsFeatureEnabled(
|
||||
FeatureFlagKey.IS_NAVIGATION_MENU_ITEM_EDITING_ENABLED,
|
||||
);
|
||||
const isNavigationMenuInEditMode = useRecoilValue(
|
||||
isNavigationMenuInEditModeState,
|
||||
);
|
||||
const [
|
||||
selectedNavigationMenuItemInEditMode,
|
||||
setSelectedNavigationMenuItemInEditMode,
|
||||
] = useRecoilState(selectedNavigationMenuItemInEditModeState);
|
||||
const setOpenNavigationMenuItemFolderIds = useSetRecoilState(
|
||||
openNavigationMenuItemFolderIdsState,
|
||||
);
|
||||
const { navigateCommandMenu } = useNavigateCommandMenu();
|
||||
const { openNavigationMenuItemInCommandMenu } =
|
||||
useOpenNavigationMenuItemInCommandMenu();
|
||||
const { getIcon } = useIcons();
|
||||
|
||||
const loading = useIsPrefetchLoading();
|
||||
const { t } = useLingui();
|
||||
|
||||
const handleEditClick = (event: React.MouseEvent) => {
|
||||
event.stopPropagation();
|
||||
enterEditMode();
|
||||
};
|
||||
|
||||
const handleNavigationMenuItemClick = (
|
||||
params: NavigationMenuItemClickParams,
|
||||
) => {
|
||||
const { item, objectMetadataItem } = params;
|
||||
const id = item.id;
|
||||
setSelectedNavigationMenuItemInEditMode(id);
|
||||
if (item.itemType === NAVIGATION_MENU_ITEM_TYPE.FOLDER) {
|
||||
setOpenNavigationMenuItemFolderIds((currentOpenFolders) =>
|
||||
currentOpenFolders.includes(id)
|
||||
? currentOpenFolders
|
||||
: [...currentOpenFolders, id],
|
||||
);
|
||||
openNavigationMenuItemInCommandMenu({
|
||||
pageTitle: t`Edit folder`,
|
||||
pageIcon: IconFolder,
|
||||
});
|
||||
} else if (item.itemType === NAVIGATION_MENU_ITEM_TYPE.LINK) {
|
||||
openNavigationMenuItemInCommandMenu({
|
||||
pageTitle: t`Edit link`,
|
||||
pageIcon: IconLink,
|
||||
});
|
||||
} else if (isDefined(objectMetadataItem)) {
|
||||
openNavigationMenuItemInCommandMenu({
|
||||
pageTitle: objectMetadataItem.labelPlural,
|
||||
pageIcon: getIcon(objectMetadataItem.icon),
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
const handleActiveObjectMetadataItemClick = (
|
||||
objectMetadataItem: ObjectMetadataItem,
|
||||
navigationMenuItemId: string,
|
||||
) => {
|
||||
enterEditMode();
|
||||
setSelectedNavigationMenuItemInEditMode(navigationMenuItemId);
|
||||
openNavigationMenuItemInCommandMenu({
|
||||
pageTitle: objectMetadataItem.labelPlural,
|
||||
pageIcon: getIcon(objectMetadataItem.icon),
|
||||
});
|
||||
};
|
||||
|
||||
const handleAddMenuItem = (event?: React.MouseEvent) => {
|
||||
event?.stopPropagation();
|
||||
navigateCommandMenu({
|
||||
page: CommandMenuPages.NavigationMenuAddItem,
|
||||
pageTitle: t`New sidebar item`,
|
||||
pageIcon: IconPlus,
|
||||
resetNavigationStack: true,
|
||||
});
|
||||
};
|
||||
|
||||
const isEditMode =
|
||||
isNavigationMenuItemEditingEnabled && isNavigationMenuInEditMode;
|
||||
|
||||
if (loading) {
|
||||
return <NavigationDrawerSectionForObjectMetadataItemsSkeletonLoader />;
|
||||
}
|
||||
|
||||
return (
|
||||
<NavigationDrawerSectionForObjectMetadataItems
|
||||
<NavigationDrawerSectionForWorkspaceItems
|
||||
sectionTitle={t`Workspace`}
|
||||
objectMetadataItems={workspaceNavigationMenuItemsObjectMetadataItems}
|
||||
isRemote={false}
|
||||
items={items}
|
||||
rightIcon={
|
||||
isNavigationMenuItemEditingEnabled ? (
|
||||
<StyledRightIconsContainer>
|
||||
{isEditMode ? (
|
||||
<LightIconButton
|
||||
Icon={IconPlus}
|
||||
accent="tertiary"
|
||||
size="small"
|
||||
onClick={handleAddMenuItem}
|
||||
/>
|
||||
) : (
|
||||
<LightIconButton
|
||||
Icon={IconTool}
|
||||
accent="tertiary"
|
||||
size="small"
|
||||
onClick={handleEditClick}
|
||||
/>
|
||||
)}
|
||||
</StyledRightIconsContainer>
|
||||
) : undefined
|
||||
}
|
||||
onAddMenuItem={
|
||||
isNavigationMenuItemEditingEnabled && isEditMode
|
||||
? handleAddMenuItem
|
||||
: undefined
|
||||
}
|
||||
isEditMode={isEditMode}
|
||||
selectedNavigationMenuItemId={selectedNavigationMenuItemInEditMode}
|
||||
onNavigationMenuItemClick={
|
||||
isEditMode ? handleNavigationMenuItemClick : undefined
|
||||
}
|
||||
onActiveObjectMetadataItemClick={
|
||||
isNavigationMenuItemEditingEnabled
|
||||
? handleActiveObjectMetadataItemClick
|
||||
: undefined
|
||||
}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user