import { LeftOutlined, PlusOutlined, RightOutlined } from '@ant-design/icons'; import { Button, Divider, Layout, Tooltip, message } from 'antd'; import { Archive, Building2, ScrollText, UserCog2, Users2 } from 'lucide-react'; import { type ReactNode, memo, useState } from 'react'; import { NavLink, useNavigate } from 'react-router-dom'; import { USERS_ADMIN } from '../../auth/permissions'; import { Logo } from '../../components/Logo'; import { createConsolidation } from '../../services/api/consolidations'; import { getConsolidationsListThunk } from '../../store/slices/consolidations/thunks'; import { useAppDispatch } from '../../store/store'; import { quarterLabel } from '../../utils/labels'; import { NewConsolidationModal } from '../NewConsoleModal/NewConsoleModal'; import styles from './styles.module.css'; type CollapsedIconProps = { icon: ReactNode; onClick?: () => void; title: string; to: string | null; cn?: string; }; function CollapsedIcon({ icon, onClick, title, to, cn = '' }: CollapsedIconProps) { if (to === null) { return ( ); } return ( cn || `${styles.iconBtn} ${isActive ? styles.iconBtnActive : styles.iconBtnNav}`}> {icon} ); } type NavItem = { link: string; label: string; icon?: ReactNode; /** Право из `/me`, без которого пункт не показывается; нет — пункт виден всем. */ permission?: string; }; type Group = { title: string; key: string; children: NavItem[]; }; const config: Group[] = [ { title: 'Отчётность', key: 'reporting', children: [ { link: '/groups', label: 'Группы компаний', }, { link: '/groups/monozaemchiki', label: 'Монозаемщики', }, ], }, { title: 'Справочники', key: 'catalogues', children: [ { link: '/catalogue/groups', icon: , label: 'ГК и организации', }, { link: '/catalogue/jur_l', icon: , label: 'ЮЛ вне ГК', }, ], }, { title: 'Документы', key: 'docs', children: [ { link: '/docstorage', icon: , label: 'Единое хранилище', }, ], }, { title: 'Система', key: 'system', children: [ { link: '/logging', icon: , label: 'Журнал действий', }, { link: '/admin', icon: , label: 'Пользователи и роли', permission: USERS_ADMIN, }, ], }, ]; function NavLinkStyled({ to, children }: { to: string; children: ReactNode }) { return ( { return `${styles.linkBase} ${isActive ? styles.linkActive : ''}`; }} to={to} end> {children} ); } const Section = memo(function Section({ isCollapsed, group }: { isCollapsed: boolean; group: Group }) { return !isCollapsed ? (
{group.title}
{group.children.map((i) => ( {i.icon} {i.label} ))}
) : ( <> {group.children.map((i) => ( ))} ); }); export function Sidebar() { const navigate = useNavigate(); const dispatch = useAppDispatch(); const [modalOpen, setModalOpen] = useState(false); const [isCollapsed, setIsCollapsed] = useState(false); return (
{!isCollapsed && }
{isCollapsed ? (
} cn={`${styles.iconBtn} ${styles.iconBtnAction}`} to={null} title='Новая консолидация' onClick={() => { setModalOpen(true); }} />
) : ( <> )} {config.map((g) => (
))}
{ setModalOpen(false); }} onOk={async (values) => { const card = await createConsolidation(values); // перечитываем список: на странице группы он сам не обновится, и новая консолидация не станет текущей // in_work_only: false — переход ниже открывает список без ?in_work_only (флажок выключен) await dispatch(getConsolidationsListThunk({ company_group_id: values.company_group_id, in_work_only: false })); setModalOpen(false); message.success(`Создана консолидация ${values.year}, ${quarterLabel(values.quarter)}`); navigate(`/groups/${values.company_group_id}?version=${card.id}`); }} />
); }