98be3980cb
Tests / frontend-test (push) Successful in 1m24s
Co-authored-by: gorbenko.pavel <gorbenko.pavel@tansu.kz> Reviewed-on: http://git.tnsu.kz/timur.gorodetskiy/request-portal/pulls/22
104 lines
4.0 KiB
TypeScript
104 lines
4.0 KiB
TypeScript
import * as React from 'react';
|
|
import type { WebPartContext } from '@microsoft/sp-webpart-base';
|
|
import { Alert, Select } from '@tnsu/ui-kit';
|
|
import { accessibleAllRequestsTypes, IRequestType } from '../../shared/approval';
|
|
import { RequestsTableView } from './RequestsTableView';
|
|
import { getLinkedTypes } from './myRequests.service';
|
|
import { IMyRequest } from './models/IMyRequest';
|
|
import styles from './AllRequestsFeature.module.scss';
|
|
|
|
export interface IAllRequestsFeatureProps {
|
|
context: WebPartContext;
|
|
/** Тип из маршрута (rpalltype) — сохраняется в адресе, чтобы ссылку можно было передать. */
|
|
selectedTypeId?: number;
|
|
onTypeChange: (typeId: number) => void;
|
|
page: number;
|
|
onPageChange: (page: number) => void;
|
|
query: string;
|
|
onQueryChange: (query: string) => void;
|
|
onOpen: (request: IMyRequest) => void;
|
|
}
|
|
|
|
/**
|
|
* Раздел «Все заявки»: доступен только тем, у кого в админке approval-route
|
|
* настроен RequestTypeAccess хотя бы на один тип заявки (см.
|
|
* shared/approval/requestTypeAccess.ts). Показывает заявки ВСЕХ авторов
|
|
* выбранного типа — в отличие от «Моих заявок», где отбор всегда идёт по
|
|
* текущему пользователю.
|
|
*/
|
|
export const AllRequestsFeature: React.FC<IAllRequestsFeatureProps> = ({
|
|
context,
|
|
selectedTypeId,
|
|
onTypeChange,
|
|
page,
|
|
onPageChange,
|
|
query,
|
|
onQueryChange,
|
|
onOpen,
|
|
}) => {
|
|
const [types, setTypes] = React.useState<IRequestType[] | undefined>(undefined);
|
|
const [error, setError] = React.useState<string>('');
|
|
|
|
React.useEffect(() => {
|
|
let cancelled = false;
|
|
getLinkedTypes(context)
|
|
.then((all) => accessibleAllRequestsTypes(context, all))
|
|
.then((accessible) => {
|
|
if (!cancelled) setTypes(accessible);
|
|
})
|
|
.catch((e) => {
|
|
if (!cancelled) setError((e as Error).message);
|
|
});
|
|
return () => {
|
|
cancelled = true;
|
|
};
|
|
}, [context]);
|
|
|
|
// Тип по умолчанию — из адреса, если он всё ещё доступен, иначе первый
|
|
// доступный. Отдельным эффектом (а не при рендере): смена выбора идёт через
|
|
// navigate() у вызывающей стороны, и до его отработки selectedTypeId ещё
|
|
// хранит предыдущее значение.
|
|
React.useEffect(() => {
|
|
if (!types || types.length === 0) return;
|
|
const stillValid = !!selectedTypeId && types.some((t) => t.id === selectedTypeId);
|
|
if (!stillValid) onTypeChange(types[0].id);
|
|
// eslint-disable-next-line react-hooks/exhaustive-deps -- onTypeChange стабилен по смыслу (см. gotoAllRequestsType в RequestPortal), включение его в deps дало бы лишний повторный запуск на каждый рендер
|
|
}, [types, selectedTypeId]);
|
|
|
|
if (error) {
|
|
return <Alert variant="err">Не удалось загрузить типы заявок: {error}</Alert>;
|
|
}
|
|
if (types === undefined) {
|
|
return <div className={styles.empty}>Загрузка…</div>;
|
|
}
|
|
if (types.length === 0) {
|
|
return <div className={styles.empty}>Вам не выдан доступ ни к одному типу заявок.</div>;
|
|
}
|
|
|
|
const selectedType = types.find((t) => t.id === selectedTypeId) ?? types[0];
|
|
|
|
return (
|
|
<div>
|
|
{types.length > 1 && (
|
|
<div className={styles.typePicker}>
|
|
<Select
|
|
value={String(selectedType.id)}
|
|
onChange={(v) => onTypeChange(Number(v))}
|
|
options={types.map((t) => ({ value: String(t.id), label: t.name }))}
|
|
/>
|
|
</div>
|
|
)}
|
|
<RequestsTableView
|
|
context={context}
|
|
view="all"
|
|
allRequestsType={selectedType}
|
|
page={page}
|
|
onPageChange={onPageChange}
|
|
query={query}
|
|
onQueryChange={onQueryChange}
|
|
onOpen={onOpen}
|
|
/>
|
|
</div>
|
|
);
|
|
};
|