Pull request #71: feat(TEAMMSBMOB-15864): добавлен дродаун для профиля
Merge in MCB_FE/mcb-platform-monorepo from story/TEAMMSBMOB-15365 to develop * commit '7899c9bdbae229812553003a7dba0afad2d35551':
This commit is contained in:
@@ -0,0 +1,2 @@
|
||||
export * from './localization';
|
||||
export * from './paths';
|
||||
@@ -0,0 +1,10 @@
|
||||
const LOCALIZATION = {
|
||||
USER_PROFILE: 'Профиль пользователя',
|
||||
ORGANIZATION: 'Организация',
|
||||
ORGANIZATIONS: 'Организации',
|
||||
AGREEMENTS: 'Соглашения',
|
||||
EXIT: 'Выйти',
|
||||
SETTINGS: 'Настройки',
|
||||
};
|
||||
|
||||
export { LOCALIZATION };
|
||||
@@ -0,0 +1,6 @@
|
||||
enum PATHS {
|
||||
PROFILE = '/profile',
|
||||
ORGANIZATIONS = '/organizations',
|
||||
}
|
||||
|
||||
export { PATHS };
|
||||
@@ -0,0 +1 @@
|
||||
export { ProfileDropdown } from './ui';
|
||||
@@ -0,0 +1,73 @@
|
||||
import styled from '@emotion/styled';
|
||||
import { Dropdown } from '@fractal-ui/composites';
|
||||
import { Divider } from '@fractal-ui/core';
|
||||
import { Avatar } from '@fractal-ui/extended';
|
||||
import { ExitIcon } from '@fractal-ui/library';
|
||||
import { DEFAULT_ANIMATION_DURATION_MS, MEDIA } from '@msb/shared';
|
||||
|
||||
const ProfileDropdown = styled(Dropdown)`
|
||||
padding: 24px;
|
||||
min-width: 280px;
|
||||
max-width: 320px;
|
||||
border-radius: 16px;
|
||||
`;
|
||||
|
||||
const Body = styled.div`
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 16px;
|
||||
align-items: start;
|
||||
|
||||
@media ${MEDIA.mobile} {
|
||||
padding-top: 24px;
|
||||
}
|
||||
`;
|
||||
|
||||
const Wrapper = styled.div`
|
||||
position: relative;
|
||||
`;
|
||||
|
||||
const ChildrenWrapper = styled.div<{ $isDropdownOpened: boolean }>(({ theme, $isDropdownOpened }) => ({
|
||||
cursor: 'pointer',
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
|
||||
svg: {
|
||||
transition: `${DEFAULT_ANIMATION_DURATION_MS}ms`,
|
||||
color: $isDropdownOpened && theme.colors.text.primary,
|
||||
},
|
||||
}));
|
||||
|
||||
const Button = styled.div`
|
||||
display: flex;
|
||||
gap: 4px;
|
||||
align-items: center;
|
||||
cursor: pointer;
|
||||
|
||||
svg {
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
}
|
||||
`;
|
||||
|
||||
const ButtonsGroup = styled.div`
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 24px;
|
||||
`;
|
||||
|
||||
const LogoutIcon = styled(ExitIcon)(({ theme }) => ({
|
||||
'&&&': {
|
||||
color: theme.colors.text.error,
|
||||
},
|
||||
}));
|
||||
|
||||
const ProfileInfo = styled(Avatar)`
|
||||
cursor: pointer;
|
||||
`;
|
||||
|
||||
const ProfileDivider = styled(Divider)(({ theme }) => ({
|
||||
borderColor: theme.colors.bg.four,
|
||||
}));
|
||||
|
||||
export { ProfileDropdown, Body, Wrapper, ChildrenWrapper, Button, ButtonsGroup, LogoutIcon, ProfileInfo, ProfileDivider };
|
||||
@@ -0,0 +1,86 @@
|
||||
import { useRef, useState, type ReactNode } from 'react';
|
||||
import { BriefcaseIcon, DocEditIcon, SettingsIcon } from '@fractal-ui/library';
|
||||
import { Drawer, PopupContainer } from '@fractal-ui/overlays';
|
||||
import { Text } from '@fractal-ui/styling';
|
||||
import { MEDIA, useMediaQuery } from '@msb/shared';
|
||||
import { useHistory } from 'react-router-dom';
|
||||
import { LOCALIZATION, PATHS } from '../constants';
|
||||
import * as S from './ProfileDropdown.styles';
|
||||
|
||||
interface Props {
|
||||
children: ReactNode;
|
||||
}
|
||||
|
||||
const ProfileDropdown = ({ children }: Props) => {
|
||||
const history = useHistory();
|
||||
|
||||
const handleOpenPage = (url: string) => {
|
||||
history.push(url);
|
||||
};
|
||||
|
||||
const [isDropdownOpened, setIsDropdownOpened] = useState(false);
|
||||
|
||||
const handleOpenDropdown = () => {
|
||||
setIsDropdownOpened(true);
|
||||
};
|
||||
|
||||
const handleCloseDropdown = () => {
|
||||
setIsDropdownOpened(false);
|
||||
};
|
||||
const dropdownRef = useRef<HTMLDivElement>(null);
|
||||
|
||||
const isDesktop = useMediaQuery(MEDIA.desktop);
|
||||
|
||||
const DropdownContent = (
|
||||
<S.Body>
|
||||
<S.ProfileInfo showCaption alt="Иванов С.В." src="" variant="cyan" onClick={() => handleOpenPage(PATHS.PROFILE)} />
|
||||
<S.ProfileDivider width="100%" />
|
||||
<S.ButtonsGroup>
|
||||
<S.Button onClick={() => handleOpenPage(PATHS.ORGANIZATIONS)}>
|
||||
<BriefcaseIcon size="S" />
|
||||
<Text.P2>{LOCALIZATION.ORGANIZATION}</Text.P2>
|
||||
</S.Button>
|
||||
<S.Button>
|
||||
<DocEditIcon size="S" />
|
||||
<Text.P2>{LOCALIZATION.AGREEMENTS}</Text.P2>
|
||||
</S.Button>
|
||||
<S.Button>
|
||||
<SettingsIcon size="S" />
|
||||
<Text.P2>{LOCALIZATION.SETTINGS}</Text.P2>
|
||||
</S.Button>
|
||||
</S.ButtonsGroup>
|
||||
<S.ProfileDivider width="100%" />
|
||||
<S.Button>
|
||||
<S.LogoutIcon size="S" />
|
||||
<Text.P2 color="text.error">{LOCALIZATION.EXIT}</Text.P2>
|
||||
</S.Button>
|
||||
</S.Body>
|
||||
);
|
||||
|
||||
return (
|
||||
<S.Wrapper ref={dropdownRef}>
|
||||
<S.ChildrenWrapper $isDropdownOpened={isDropdownOpened} onClick={handleOpenDropdown}>
|
||||
{children}
|
||||
</S.ChildrenWrapper>
|
||||
{isDesktop ? (
|
||||
<PopupContainer
|
||||
disableAutowidth
|
||||
anchorEl={dropdownRef}
|
||||
isOpen={isDropdownOpened}
|
||||
offsetX={8}
|
||||
offsetY={12}
|
||||
position="bottom left"
|
||||
onClose={handleCloseDropdown}
|
||||
>
|
||||
<S.ProfileDropdown dataName="profile-dropdown">{DropdownContent}</S.ProfileDropdown>
|
||||
</PopupContainer>
|
||||
) : (
|
||||
<Drawer header={LOCALIZATION.USER_PROFILE} isOpen={isDropdownOpened} onClose={handleCloseDropdown}>
|
||||
{DropdownContent}
|
||||
</Drawer>
|
||||
)}
|
||||
</S.Wrapper>
|
||||
);
|
||||
};
|
||||
|
||||
export { ProfileDropdown };
|
||||
@@ -0,0 +1 @@
|
||||
export { ProfileDropdown } from './ProfileDropdown';
|
||||
@@ -1 +1,2 @@
|
||||
export { PageNavigation } from './PageNavigation';
|
||||
export { ProfileDropdown } from './ProfileDropdown';
|
||||
|
||||
@@ -5,6 +5,7 @@ import { NotificationIcon, SearchIcon, UserProfileIcon } from '@fractal-ui/libra
|
||||
import gpbIcon from '@msb/shared/assets/gpb_flavor.png';
|
||||
import gpbMsbLogo from '../../../assets/logo_pic_out.svg';
|
||||
import * as S from './HeaderMenu.styles';
|
||||
import { ProfileDropdown } from '@/features/ProfileDropdown/ui';
|
||||
|
||||
interface Props {
|
||||
organizationsSlot: ReactNode;
|
||||
@@ -23,7 +24,10 @@ const HeaderMenu = ({ organizationsSlot }: Props): ReactElement => (
|
||||
<S.ProfileGroup>
|
||||
{organizationsSlot}
|
||||
<NotificationIcon />
|
||||
<UserProfileIcon />
|
||||
|
||||
<ProfileDropdown>
|
||||
<UserProfileIcon />
|
||||
</ProfileDropdown>
|
||||
</S.ProfileGroup>
|
||||
</S.Box>
|
||||
</S.Header>
|
||||
|
||||
@@ -2,6 +2,7 @@ import type { ReactNode, ReactElement } from 'react';
|
||||
import { InputSearch } from '@fractal-ui/composites';
|
||||
import { UserProfileIcon } from '@fractal-ui/library';
|
||||
import * as S from './HeaderMenu.styles';
|
||||
import { ProfileDropdown } from '@/features/ProfileDropdown';
|
||||
|
||||
interface Props {
|
||||
organizationsSlot: ReactNode;
|
||||
@@ -10,9 +11,9 @@ interface Props {
|
||||
const HeaderMobileMenu = ({ organizationsSlot }: Props): ReactElement => (
|
||||
<S.Header>
|
||||
<S.MobileBox>
|
||||
<div>
|
||||
<ProfileDropdown>
|
||||
<UserProfileIcon />
|
||||
</div>
|
||||
</ProfileDropdown>
|
||||
<S.SearchInputBox>
|
||||
<InputSearch name="search" options={[]} placeholder="Поиск" />
|
||||
</S.SearchInputBox>
|
||||
|
||||
Reference in New Issue
Block a user