Редактирование заявок у конкретного пользователя (#14)
Co-authored-by: gorbenko.pavel <gorbenko.pavel@tansu.kz> Reviewed-on: http://git.tnsu.kz/gorbenko.pavel/tnsu-approval-route/pulls/14
This commit was merged in pull request #14.
This commit is contained in:
@@ -1,19 +1,47 @@
|
||||
import * as React from 'react';
|
||||
import styles from './AdminApp.module.scss';
|
||||
import { TopNav } from './TopNav';
|
||||
import '@tnsu/ui-kit/styles.css';
|
||||
import { IconSprite, Sidebar, SidebarToggle } from '@tnsu/ui-kit';
|
||||
import type { ISidebarItem } from '@tnsu/ui-kit';
|
||||
import { ScreenKey } from './types';
|
||||
import { ApprovalRouteApi } from '../../services/api';
|
||||
import { PortalDictionaryClient } from '../../services/portalDictionary';
|
||||
import { SharePointListsClient } from '../../services/sharePointLists';
|
||||
import { RequestManageService } from '../../services/requestManageService';
|
||||
import { RequestType, TemplateRoute } from '../../models';
|
||||
import { navigate, useRoute } from '../../routing';
|
||||
import { navigate, replaceRoute, useRoute } from '../../routing';
|
||||
import { texts } from '../../texts';
|
||||
import { useLocalStorageState } from '../../hooks/useLocalStorageState';
|
||||
import { DashboardScreen } from '../screens/DashboardScreen';
|
||||
import { RequestTypesScreen } from '../screens/RequestTypesScreen';
|
||||
import { RoutesScreen } from '../screens/RoutesScreen';
|
||||
import { RouteStepsScreen } from '../screens/RouteStepsScreen';
|
||||
import { ResolveScreen } from '../screens/ResolveScreen';
|
||||
import { ManageRequestsScreen } from '../screens/ManageRequestsScreen';
|
||||
import { ManageByUserScreen } from '../screens/ManageByUserScreen';
|
||||
|
||||
// Тот же боковой рейл (@tnsu/ui-kit Sidebar), что и в request-portal — единый
|
||||
// стиль навигации во всех веб-частях Tnsu. 'routeSteps' сюда не входит: это не
|
||||
// отдельная вкладка URL, а состояние вкладки 'routes' при открытых шагах
|
||||
// конкретного маршрута (см. routing.ts) — подсвечиваем в этом случае 'routes'.
|
||||
const NAV_ITEMS: ISidebarItem[] = [
|
||||
{ id: 'dashboard', title: texts.nav.dashboard, icon: 'chart' },
|
||||
{ id: 'requestTypes', title: texts.nav.requestTypes, icon: 'document' },
|
||||
{ id: 'routes', title: texts.nav.routes, icon: 'send' },
|
||||
{ id: 'resolve', title: texts.nav.resolve, icon: 'search' },
|
||||
{ id: 'manageRequests', title: texts.nav.manageRequests, icon: 'clipboard' },
|
||||
{ id: 'manageByUser', title: texts.nav.manageByUser, icon: 'user-check' }
|
||||
];
|
||||
|
||||
function sidebarActiveId(tab: ScreenKey): string {
|
||||
return tab === 'routeSteps' ? 'routes' : tab;
|
||||
}
|
||||
|
||||
// Последняя открытая вкладка. В адресе она и так живёт (aatab, см. routing.ts),
|
||||
// но веб-часть часто открывают по «чистой» ссылке на страницу SharePoint, без
|
||||
// query — и тогда пользователь каждый раз приземлялся на дашборд, даже если
|
||||
// работает всегда в одном разделе.
|
||||
const TAB_STORAGE_KEY = 'approvalAdmin.activeTab';
|
||||
|
||||
export interface IAdminAppProps {
|
||||
api: ApprovalRouteApi;
|
||||
@@ -28,8 +56,31 @@ export const AdminApp: React.FC<IAdminAppProps> = ({ api, dictionary, sharePoint
|
||||
const route = useRoute();
|
||||
const [selectedRoute, setSelectedRoute] = React.useState<TemplateRoute | undefined>();
|
||||
const [selectedRequestType, setSelectedRequestType] = React.useState<RequestType | undefined>();
|
||||
const [navCollapsed, setNavCollapsed] = React.useState(false);
|
||||
const [mobileNavOpen, setMobileNavOpen] = React.useState(false);
|
||||
|
||||
const navigateTab = (key: ScreenKey): void => navigate({ tab: key });
|
||||
const [storedTab, setStoredTab] = useLocalStorageState<ScreenKey>(TAB_STORAGE_KEY, 'dashboard');
|
||||
|
||||
// Восстанавливаем последнюю вкладку ТОЛЬКО когда в адресе её нет: глубокая
|
||||
// ссылка (в т.ч. присланная коллегой) всегда важнее запомненного выбора.
|
||||
// Один раз на монтировании — дальше вкладку меняет только сам пользователь.
|
||||
React.useEffect(() => {
|
||||
const explicitTab = new URLSearchParams(window.location.search).get('aatab');
|
||||
if (explicitTab || storedTab === 'dashboard') return;
|
||||
replaceRoute({ tab: storedTab });
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, []);
|
||||
|
||||
// 'routeSteps' сюда не попадёт: useRoute отдаёт только вкладки из TABS, а шаги
|
||||
// маршрута — состояние вкладки 'routes' (см. routing.ts).
|
||||
React.useEffect(() => {
|
||||
setStoredTab(route.tab);
|
||||
}, [route.tab, setStoredTab]);
|
||||
|
||||
const navigateTab = (key: ScreenKey): void => {
|
||||
setMobileNavOpen(false);
|
||||
navigate({ tab: key });
|
||||
};
|
||||
|
||||
const openSteps = (r: TemplateRoute): void => {
|
||||
setSelectedRoute(r);
|
||||
@@ -76,41 +127,61 @@ export const AdminApp: React.FC<IAdminAppProps> = ({ api, dictionary, sharePoint
|
||||
|
||||
return (
|
||||
<div className={styles.shell}>
|
||||
<TopNav active={route.tab} onSelect={navigateTab} />
|
||||
<div className={styles.content}>
|
||||
{route.tab === 'dashboard' && <DashboardScreen api={api} onNavigate={navigateTab} />}
|
||||
{route.tab === 'requestTypes' && <RequestTypesScreen api={api} sharePoint={sharePoint} />}
|
||||
{route.tab === 'routes' && !route.routeId && (
|
||||
<RoutesScreen
|
||||
api={api}
|
||||
dictionary={dictionary}
|
||||
initialFilterRequestTypeId={route.routesFilter}
|
||||
onOpenSteps={openSteps}
|
||||
/>
|
||||
)}
|
||||
{route.tab === 'routes' && route.routeId && selectedRoute && (
|
||||
<RouteStepsScreen
|
||||
api={api}
|
||||
route={selectedRoute}
|
||||
requestType={selectedRequestType}
|
||||
dictionary={dictionary}
|
||||
sharePoint={sharePoint}
|
||||
onBack={() => navigate({ tab: 'routes', routesFilter: route.routesFilter })}
|
||||
/>
|
||||
)}
|
||||
{route.tab === 'resolve' && (
|
||||
<ResolveScreen
|
||||
api={api}
|
||||
dictionary={dictionary}
|
||||
sharePoint={sharePoint}
|
||||
currentUserEmail={currentUserEmail}
|
||||
route={route.resolve}
|
||||
/>
|
||||
)}
|
||||
{route.tab === 'manageRequests' && (
|
||||
<ManageRequestsScreen api={api} dictionary={dictionary} requestManage={requestManage} route={route.manage} />
|
||||
)}
|
||||
<IconSprite />
|
||||
<div className={styles.side}>
|
||||
<Sidebar
|
||||
items={NAV_ITEMS}
|
||||
activeId={sidebarActiveId(route.tab)}
|
||||
onChange={id => navigateTab(id as ScreenKey)}
|
||||
brand={texts.nav.title}
|
||||
collapsed={navCollapsed}
|
||||
onToggleCollapsed={() => setNavCollapsed(v => !v)}
|
||||
mobileOpen={mobileNavOpen}
|
||||
onMobileClose={() => setMobileNavOpen(false)}
|
||||
/>
|
||||
</div>
|
||||
<main className={styles.main}>
|
||||
<div className={styles.mobileNav}>
|
||||
<SidebarToggle onClick={() => setMobileNavOpen(true)} />
|
||||
</div>
|
||||
<div className={styles.content}>
|
||||
{route.tab === 'dashboard' && <DashboardScreen api={api} onNavigate={navigateTab} />}
|
||||
{route.tab === 'requestTypes' && <RequestTypesScreen api={api} sharePoint={sharePoint} />}
|
||||
{route.tab === 'routes' && !route.routeId && (
|
||||
<RoutesScreen
|
||||
api={api}
|
||||
dictionary={dictionary}
|
||||
initialFilterRequestTypeId={route.routesFilter}
|
||||
onOpenSteps={openSteps}
|
||||
/>
|
||||
)}
|
||||
{route.tab === 'routes' && route.routeId && selectedRoute && (
|
||||
<RouteStepsScreen
|
||||
api={api}
|
||||
route={selectedRoute}
|
||||
requestType={selectedRequestType}
|
||||
dictionary={dictionary}
|
||||
sharePoint={sharePoint}
|
||||
onBack={() => navigate({ tab: 'routes', routesFilter: route.routesFilter })}
|
||||
/>
|
||||
)}
|
||||
{route.tab === 'resolve' && (
|
||||
<ResolveScreen
|
||||
api={api}
|
||||
dictionary={dictionary}
|
||||
sharePoint={sharePoint}
|
||||
currentUserEmail={currentUserEmail}
|
||||
route={route.resolve}
|
||||
/>
|
||||
)}
|
||||
{route.tab === 'manageRequests' && (
|
||||
<ManageRequestsScreen api={api} dictionary={dictionary} requestManage={requestManage} route={route.manage} />
|
||||
)}
|
||||
{route.tab === 'manageByUser' && (
|
||||
<ManageByUserScreen api={api} dictionary={dictionary} requestManage={requestManage} route={route.manageByUser} />
|
||||
)}
|
||||
</div>
|
||||
</main>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user