Migrate to a monorepo structure (#2909)
This commit is contained in:
@ -0,0 +1,74 @@
|
||||
import { useEffect } from 'react';
|
||||
import { useRecoilValue, useSetRecoilState } from 'recoil';
|
||||
|
||||
import { currentWorkspaceState } from '@/auth/states/currentWorkspaceState';
|
||||
import { SettingsNavigationDrawerItems } from '@/settings/components/SettingsNavigationDrawerItems';
|
||||
import { SupportChat } from '@/support/components/SupportChat';
|
||||
import { GithubVersionLink } from '@/ui/navigation/link/components/GithubVersionLink';
|
||||
import {
|
||||
NavigationDrawer,
|
||||
NavigationDrawerProps,
|
||||
} from '@/ui/navigation/navigation-drawer/components/NavigationDrawer';
|
||||
import { isNavigationDrawerOpenState } from '@/ui/navigation/states/isNavigationDrawerOpenState';
|
||||
import { useIsMobile } from '@/ui/utilities/responsive/hooks/useIsMobile';
|
||||
import { getImageAbsoluteURIOrBase64 } from '@/users/utils/getProfilePictureAbsoluteURI';
|
||||
|
||||
import { useIsSettingsPage } from '../hooks/useIsSettingsPage';
|
||||
import { currentMobileNavigationDrawerState } from '../states/currentMobileNavigationDrawerState';
|
||||
|
||||
import { MainNavigationDrawerItems } from './MainNavigationDrawerItems';
|
||||
|
||||
export type AppNavigationDrawerProps = {
|
||||
className?: string;
|
||||
};
|
||||
|
||||
export const AppNavigationDrawer = ({
|
||||
className,
|
||||
}: AppNavigationDrawerProps) => {
|
||||
const isMobile = useIsMobile();
|
||||
const isSettingsPage = useIsSettingsPage();
|
||||
const currentMobileNavigationDrawer = useRecoilValue(
|
||||
currentMobileNavigationDrawerState,
|
||||
);
|
||||
const setIsNavigationDrawerOpen = useSetRecoilState(
|
||||
isNavigationDrawerOpenState,
|
||||
);
|
||||
const currentWorkspace = useRecoilValue(currentWorkspaceState);
|
||||
|
||||
const isSettingsDrawer = isMobile
|
||||
? currentMobileNavigationDrawer === 'settings'
|
||||
: isSettingsPage;
|
||||
|
||||
const drawerProps: NavigationDrawerProps = isSettingsDrawer
|
||||
? {
|
||||
isSubMenu: true,
|
||||
title: 'Settings',
|
||||
children: <SettingsNavigationDrawerItems />,
|
||||
footer: <GithubVersionLink />,
|
||||
}
|
||||
: {
|
||||
logo:
|
||||
(currentWorkspace?.logo &&
|
||||
getImageAbsoluteURIOrBase64(currentWorkspace.logo)) ??
|
||||
undefined,
|
||||
title: currentWorkspace?.displayName ?? undefined,
|
||||
children: <MainNavigationDrawerItems />,
|
||||
footer: <SupportChat />,
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
setIsNavigationDrawerOpen(!isMobile);
|
||||
}, [isMobile, setIsNavigationDrawerOpen]);
|
||||
|
||||
return (
|
||||
<NavigationDrawer
|
||||
className={className}
|
||||
isSubMenu={drawerProps.isSubMenu}
|
||||
logo={drawerProps.logo}
|
||||
title={drawerProps.title}
|
||||
footer={drawerProps.footer}
|
||||
>
|
||||
{drawerProps.children}
|
||||
</NavigationDrawer>
|
||||
);
|
||||
};
|
||||
@ -0,0 +1,82 @@
|
||||
import { useLocation, useNavigate } from 'react-router-dom';
|
||||
import { useSetRecoilState } from 'recoil';
|
||||
|
||||
import { useCurrentUserTaskCount } from '@/activities/tasks/hooks/useCurrentUserDueTaskCount';
|
||||
import { useCommandMenu } from '@/command-menu/hooks/useCommandMenu';
|
||||
import { Favorites } from '@/favorites/components/Favorites';
|
||||
import { ObjectMetadataNavItems } from '@/object-metadata/components/ObjectMetadataNavItems';
|
||||
import {
|
||||
IconBell,
|
||||
IconCheckbox,
|
||||
IconSearch,
|
||||
IconSettings,
|
||||
IconTargetArrow,
|
||||
} from '@/ui/display/icon';
|
||||
import { NavigationDrawerItem } from '@/ui/navigation/navigation-drawer/components/NavigationDrawerItem';
|
||||
import { NavigationDrawerSection } from '@/ui/navigation/navigation-drawer/components/NavigationDrawerSection';
|
||||
import { NavigationDrawerSectionTitle } from '@/ui/navigation/navigation-drawer/components/NavigationDrawerSectionTitle';
|
||||
import { navigationMemorizedUrlState } from '@/ui/navigation/states/navigationMemorizedUrlState';
|
||||
import { useIsMobile } from '@/ui/utilities/responsive/hooks/useIsMobile';
|
||||
|
||||
import { useIsTasksPage } from '../hooks/useIsTasksPage';
|
||||
|
||||
export const MainNavigationDrawerItems = () => {
|
||||
const isMobile = useIsMobile();
|
||||
const { toggleCommandMenu } = useCommandMenu();
|
||||
const isTasksPage = useIsTasksPage();
|
||||
const { currentUserDueTaskCount } = useCurrentUserTaskCount();
|
||||
const navigate = useNavigate();
|
||||
const location = useLocation();
|
||||
const setNavigationMemorizedUrl = useSetRecoilState(
|
||||
navigationMemorizedUrlState,
|
||||
);
|
||||
|
||||
return (
|
||||
<>
|
||||
{!isMobile && (
|
||||
<NavigationDrawerSection>
|
||||
<NavigationDrawerItem
|
||||
label="Search"
|
||||
Icon={IconSearch}
|
||||
onClick={toggleCommandMenu}
|
||||
keyboard={['⌘', 'K']}
|
||||
/>
|
||||
<NavigationDrawerItem
|
||||
label="Notifications"
|
||||
to="/inbox"
|
||||
Icon={IconBell}
|
||||
soon
|
||||
/>
|
||||
<NavigationDrawerItem
|
||||
label="Settings"
|
||||
onClick={() => {
|
||||
setNavigationMemorizedUrl(location.pathname + location.search);
|
||||
navigate('/settings/profile');
|
||||
}}
|
||||
Icon={IconSettings}
|
||||
/>
|
||||
<NavigationDrawerItem
|
||||
label="Tasks"
|
||||
to="/tasks"
|
||||
active={isTasksPage}
|
||||
Icon={IconCheckbox}
|
||||
count={currentUserDueTaskCount}
|
||||
/>
|
||||
</NavigationDrawerSection>
|
||||
)}
|
||||
|
||||
<Favorites />
|
||||
|
||||
<NavigationDrawerSection>
|
||||
<NavigationDrawerSectionTitle label="Workspace" />
|
||||
<ObjectMetadataNavItems />
|
||||
<NavigationDrawerItem
|
||||
label="Opportunities"
|
||||
to="/objects/opportunities"
|
||||
active={location.pathname === '/objects/opportunities'}
|
||||
Icon={IconTargetArrow}
|
||||
/>
|
||||
</NavigationDrawerSection>
|
||||
</>
|
||||
);
|
||||
};
|
||||
@ -0,0 +1,91 @@
|
||||
import { useNavigate } from 'react-router-dom';
|
||||
import { useRecoilState } from 'recoil';
|
||||
|
||||
import { useCommandMenu } from '@/command-menu/hooks/useCommandMenu';
|
||||
import { isCommandMenuOpenedState } from '@/command-menu/states/isCommandMenuOpenedState';
|
||||
import {
|
||||
IconCheckbox,
|
||||
IconList,
|
||||
IconSearch,
|
||||
IconSettings,
|
||||
} from '@/ui/display/icon';
|
||||
import { IconComponent } from '@/ui/display/icon/types/IconComponent';
|
||||
import { NavigationBar } from '@/ui/navigation/navigation-bar/components/NavigationBar';
|
||||
import { isNavigationDrawerOpenState } from '@/ui/navigation/states/isNavigationDrawerOpenState';
|
||||
|
||||
import { useIsSettingsPage } from '../hooks/useIsSettingsPage';
|
||||
import { useIsTasksPage } from '../hooks/useIsTasksPage';
|
||||
import { currentMobileNavigationDrawerState } from '../states/currentMobileNavigationDrawerState';
|
||||
|
||||
type NavigationBarItemName = 'main' | 'search' | 'tasks' | 'settings';
|
||||
|
||||
export const MobileNavigationBar = () => {
|
||||
const [isCommandMenuOpened] = useRecoilState(isCommandMenuOpenedState);
|
||||
const { closeCommandMenu, toggleCommandMenu } = useCommandMenu();
|
||||
const isTasksPage = useIsTasksPage();
|
||||
const isSettingsPage = useIsSettingsPage();
|
||||
const navigate = useNavigate();
|
||||
const [isNavigationDrawerOpen, setIsNavigationDrawerOpen] = useRecoilState(
|
||||
isNavigationDrawerOpenState,
|
||||
);
|
||||
const [currentMobileNavigationDrawer, setCurrentMobileNavigationDrawer] =
|
||||
useRecoilState(currentMobileNavigationDrawerState);
|
||||
|
||||
const activeItemName = isNavigationDrawerOpen
|
||||
? currentMobileNavigationDrawer
|
||||
: isCommandMenuOpened
|
||||
? 'search'
|
||||
: isTasksPage
|
||||
? 'tasks'
|
||||
: isSettingsPage
|
||||
? 'settings'
|
||||
: 'main';
|
||||
|
||||
const items: {
|
||||
name: NavigationBarItemName;
|
||||
Icon: IconComponent;
|
||||
onClick: () => void;
|
||||
}[] = [
|
||||
{
|
||||
name: 'main',
|
||||
Icon: IconList,
|
||||
onClick: () => {
|
||||
closeCommandMenu();
|
||||
setIsNavigationDrawerOpen(
|
||||
(previousIsOpen) => activeItemName !== 'main' || !previousIsOpen,
|
||||
);
|
||||
setCurrentMobileNavigationDrawer('main');
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'search',
|
||||
Icon: IconSearch,
|
||||
onClick: () => {
|
||||
setIsNavigationDrawerOpen(false);
|
||||
toggleCommandMenu();
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'tasks',
|
||||
Icon: IconCheckbox,
|
||||
onClick: () => {
|
||||
closeCommandMenu();
|
||||
setIsNavigationDrawerOpen(false);
|
||||
navigate('/tasks');
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'settings',
|
||||
Icon: IconSettings,
|
||||
onClick: () => {
|
||||
closeCommandMenu();
|
||||
setIsNavigationDrawerOpen(
|
||||
(previousIsOpen) => activeItemName !== 'settings' || !previousIsOpen,
|
||||
);
|
||||
setCurrentMobileNavigationDrawer('settings');
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
return <NavigationBar activeItemName={activeItemName} items={items} />;
|
||||
};
|
||||
@ -0,0 +1,77 @@
|
||||
import { useEffect } from 'react';
|
||||
import { MemoryRouter } from 'react-router-dom';
|
||||
import { Meta, StoryObj } from '@storybook/react';
|
||||
import { useSetRecoilState } from 'recoil';
|
||||
|
||||
import { currentMobileNavigationDrawerState } from '@/navigation/states/currentMobileNavigationDrawerState';
|
||||
import { AppPath } from '@/types/AppPath';
|
||||
import { isNavigationDrawerOpenState } from '@/ui/navigation/states/isNavigationDrawerOpenState';
|
||||
import { useIsMobile } from '@/ui/utilities/responsive/hooks/useIsMobile';
|
||||
import { SnackBarDecorator } from '~/testing/decorators/SnackBarDecorator';
|
||||
|
||||
import {
|
||||
AppNavigationDrawer,
|
||||
AppNavigationDrawerProps,
|
||||
} from '../AppNavigationDrawer';
|
||||
|
||||
const MobileNavigationDrawerStateSetterEffect = ({
|
||||
mobileNavigationDrawer = 'main',
|
||||
}: {
|
||||
mobileNavigationDrawer?: 'main' | 'settings';
|
||||
}) => {
|
||||
const isMobile = useIsMobile();
|
||||
const setIsNavigationDrawerOpen = useSetRecoilState(
|
||||
isNavigationDrawerOpenState,
|
||||
);
|
||||
const setCurrentMobileNavigationDrawer = useSetRecoilState(
|
||||
currentMobileNavigationDrawerState,
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
if (!isMobile) return;
|
||||
|
||||
setIsNavigationDrawerOpen(true);
|
||||
setCurrentMobileNavigationDrawer(mobileNavigationDrawer);
|
||||
}, [
|
||||
isMobile,
|
||||
mobileNavigationDrawer,
|
||||
setCurrentMobileNavigationDrawer,
|
||||
setIsNavigationDrawerOpen,
|
||||
]);
|
||||
|
||||
return null;
|
||||
};
|
||||
|
||||
type StoryArgs = AppNavigationDrawerProps & {
|
||||
mobileNavigationDrawer?: 'main' | 'settings';
|
||||
routePath: string;
|
||||
};
|
||||
|
||||
const meta: Meta<StoryArgs> = {
|
||||
title: 'Modules/Navigation/AppNavigationDrawer',
|
||||
decorators: [
|
||||
(Story, { args }) => (
|
||||
<MemoryRouter initialEntries={[args.routePath]}>
|
||||
<Story />
|
||||
<MobileNavigationDrawerStateSetterEffect
|
||||
mobileNavigationDrawer={args.mobileNavigationDrawer}
|
||||
/>
|
||||
</MemoryRouter>
|
||||
),
|
||||
SnackBarDecorator,
|
||||
],
|
||||
component: AppNavigationDrawer,
|
||||
args: { routePath: AppPath.Index },
|
||||
};
|
||||
|
||||
export default meta;
|
||||
type Story = StoryObj<StoryArgs>;
|
||||
|
||||
export const Main: Story = {};
|
||||
|
||||
export const Settings: Story = {
|
||||
args: {
|
||||
mobileNavigationDrawer: 'settings',
|
||||
routePath: '/settings/appearance',
|
||||
},
|
||||
};
|
||||
@ -0,0 +1,4 @@
|
||||
import { useLocation } from 'react-router-dom';
|
||||
|
||||
export const useIsSettingsPage = () =>
|
||||
useLocation().pathname.match(/\/settings\//g) !== null;
|
||||
@ -0,0 +1,3 @@
|
||||
import { useLocation } from 'react-router-dom';
|
||||
|
||||
export const useIsTasksPage = () => useLocation().pathname === '/tasks';
|
||||
@ -0,0 +1,6 @@
|
||||
import { atom } from 'recoil';
|
||||
|
||||
export const currentMobileNavigationDrawerState = atom<'main' | 'settings'>({
|
||||
key: 'currentMobileNavigationDrawerState',
|
||||
default: 'main',
|
||||
});
|
||||
Reference in New Issue
Block a user