1 import { type FC, useMemo } from 'react';
2 import { useSelector } from 'react-redux';
4 import { AccountSwitcherTooltip } from 'proton-pass-web/app/Auth/AccountSwitcher';
5 import { useAuthService } from 'proton-pass-web/app/Auth/AuthServiceProvider';
6 import { checkAuthSwitch, useAvailableSessions } from 'proton-pass-web/app/Auth/AuthSwitchProvider';
7 import { c } from 'ttag';
9 import { Button, ButtonLike, Scroll } from '@proton/atoms';
10 import { Icon } from '@proton/components';
11 import { UserPanel } from '@proton/pass/components/Account/UserPanel';
12 import { DropdownMenuButton } from '@proton/pass/components/Layout/Dropdown/DropdownMenuButton';
13 import { AdminPanelButton } from '@proton/pass/components/Menu/B2B/AdminPanelButton';
14 import { OnboardingButton } from '@proton/pass/components/Menu/B2B/OnboardingButton';
15 import { MonitorButton } from '@proton/pass/components/Menu/Monitor/MonitorButton';
16 import { SecureLinkButton } from '@proton/pass/components/Menu/SecureLink/SecureLinkButton';
17 import { Submenu } from '@proton/pass/components/Menu/Submenu';
18 import { VaultMenu } from '@proton/pass/components/Menu/Vault/VaultMenu';
19 import { useNavigation } from '@proton/pass/components/Navigation/NavigationProvider';
20 import { getLocalPath } from '@proton/pass/components/Navigation/routing';
21 import { useOnboarding } from '@proton/pass/components/Onboarding/OnboardingProvider';
22 import { OnboardingType } from '@proton/pass/components/Onboarding/Provider/OnboardingContext';
23 import { useOrganization } from '@proton/pass/components/Organization/OrganizationProvider';
24 import { useVaultActions } from '@proton/pass/components/Vault/VaultActionsProvider';
25 import { useFeatureFlag } from '@proton/pass/hooks/useFeatureFlag';
26 import { useMenuItems } from '@proton/pass/hooks/useMenuItems';
27 import { LockMode } from '@proton/pass/lib/auth/lock/types';
28 import { selectLockMode, selectPassPlan, selectPlanDisplayName, selectUser } from '@proton/pass/store/selectors';
29 import { PassFeature } from '@proton/pass/types/api/features';
30 import { PASS_APP_NAME } from '@proton/shared/lib/constants';
31 import clsx from '@proton/utils/clsx';
33 import { MenuActions } from './MenuActions';
35 export const Menu: FC<{ onToggle: () => void }> = ({ onToggle }) => {
36 const authService = useAuthService();
37 const onboarding = useOnboarding();
38 const org = useOrganization();
40 const menu = useMenuItems({ onAction: onToggle });
41 const vaultActions = useVaultActions();
43 const accountSwitchEnabled = useFeatureFlag(PassFeature.PassAccountSwitchV1);
44 const authSwitchEnabled = useMemo(() => accountSwitchEnabled || checkAuthSwitch(), [accountSwitchEnabled]);
45 const sessions = useAvailableSessions();
47 const { navigate, filters, matchTrash } = useNavigation();
48 const { selectedShareId } = filters;
50 const user = useSelector(selectUser);
51 const lockMode = useSelector(selectLockMode);
52 const passPlan = useSelector(selectPassPlan);
53 const planDisplayName = useSelector(selectPlanDisplayName);
55 const canLock = lockMode !== LockMode.NONE;
58 <div className="flex flex-column flex-nowrap justify-space-between flex-1 overflow-auto gap-2">
63 onClick={vaultActions.create}
65 title={c('Action').t`Create a new vault`}
66 className="flex items-center justify-space-between flex-nowrap py-2 pl-3 px-2 mx-3"
68 <div className="flex text-ellipsis">{c('Label').t`Vaults`}</div>
69 <Icon name="plus" alt={c('Action').t`Create a new vault`} />
72 <Scroll className="flex flex-1 h-1/2 min-h-custom" style={{ '--min-h-custom': '5em' }}>
73 <div className="flex mx-3">
74 <VaultMenu selectedShareId={selectedShareId} inTrash={matchTrash} onSelect={vaultActions.select} />
78 <div className="flex flex-column flex-nowrap pb-2">
79 {onboarding.type === OnboardingType.B2B && onboarding.enabled && <OnboardingButton />}
82 activeClassName="sidebar-item-selected"
83 parentClassName="mx-3"
84 onClick={() => navigate(getLocalPath('secure-links'))}
89 authService.lock(lockMode, {
95 label={c('Action').t`Lock ${PASS_APP_NAME}`}
97 parentClassName="mx-3"
101 {org && org.b2bAdmin && <AdminPanelButton {...org.organization} />}
102 <hr className="my-2 mx-4" aria-hidden="true" />
106 label={c('Action').t`Advanced`}
107 items={menu.advanced}
108 headerClassname="mx-3 pr-2 py-1"
109 contentClassname="mx-3"
113 label={c('Action').t`Feedback`}
114 items={menu.feedback}
115 headerClassname="mx-3 pr-2 py-1"
116 contentClassname="mx-3"
120 label={c('Action').t`Get mobile apps`}
121 items={menu.download}
122 headerClassname="mx-3 pr-2 py-1"
123 contentClassname="mx-3"
125 <hr className="my-2 mx-4" aria-hidden="true" />
127 <div className="flex justify-space-between items-center flex-nowrap gap-1 pl-3 pr-5">
128 <AccountSwitcherTooltip sessions={authSwitchEnabled ? sessions : []}>
129 {({ anchorRef, toggle }) => (
134 className={clsx('flex-1', !authSwitchEnabled && 'pointer-events-none')}
138 email={user?.Email ?? ''}
139 name={user?.DisplayName ?? user?.Name ?? ''}
141 planName={planDisplayName}
145 </AccountSwitcherTooltip>