роутинг пагинации
This commit is contained in:
@@ -118,6 +118,14 @@ export interface IRequestsTableViewProps {
|
||||
/** Фильтр по статусу заявки; только для view='own:created'. '' — все статусы. */
|
||||
statusFilter?: string;
|
||||
onStatusFilterChange?: (status: string) => void;
|
||||
/**
|
||||
* Текущая страница (1-based) и её смена. Страница живёт в маршруте, а не
|
||||
* внутри компонента: так она попадает в адрес (ссылку можно передать),
|
||||
* переживает открытие/закрытие заявки и запоминается для этой таблицы
|
||||
* (см. persistPage в shared/routing.ts).
|
||||
*/
|
||||
page: number;
|
||||
onPageChange: (page: number) => void;
|
||||
/** Клик по строке — открыть заявку (в выезжающей панели). */
|
||||
onOpen: (request: IMyRequest) => void;
|
||||
}
|
||||
@@ -230,12 +238,13 @@ export const RequestsTableView: React.FC<IRequestsTableViewProps> = ({
|
||||
view,
|
||||
statusFilter = '',
|
||||
onStatusFilterChange,
|
||||
page,
|
||||
onPageChange,
|
||||
onOpen,
|
||||
}) => {
|
||||
const [types, setTypes] = React.useState<IRequestType[] | undefined>(undefined);
|
||||
const [rows, setRows] = React.useState<IMyRequest[] | undefined>(undefined);
|
||||
const [totalRows, setTotalRows] = React.useState<number>(0);
|
||||
const [page, setPage] = React.useState<number>(1);
|
||||
const [query, setQuery] = usePersistedQuery(view);
|
||||
const [error, setError] = React.useState<string>('');
|
||||
// query — то, что в поле ввода (меняется сразу); debouncedQuery — то, что
|
||||
@@ -243,7 +252,18 @@ export const RequestsTableView: React.FC<IRequestsTableViewProps> = ({
|
||||
// иначе поиск бил бы запросом по каждой набранной букве.
|
||||
const debouncedQuery = useDebouncedQuery(query);
|
||||
|
||||
React.useEffect(() => setPage(1), [debouncedQuery, view, statusFilter]);
|
||||
// Смена ЗАПРОСА сбрасывает страницу: набор результатов другой, и «страница 3»
|
||||
// от прошлого запроса к нему отношения не имеет. Смену вкладки/фильтра здесь
|
||||
// НЕ обрабатываем — там страница приходит уже правильной из маршрута
|
||||
// (см. RequestPortal: gotoOwnTab/setOwnStatus). Сравниваем с предыдущим
|
||||
// значением, а не просто вешаемся на изменение: иначе эффект сбрасывал бы
|
||||
// страницу и на первом рендере, затирая ту, что пришла из адреса.
|
||||
const prevQuery = React.useRef<string>(debouncedQuery);
|
||||
React.useEffect(() => {
|
||||
if (prevQuery.current === debouncedQuery) return;
|
||||
prevQuery.current = debouncedQuery;
|
||||
if (page !== 1) onPageChange(1);
|
||||
}, [debouncedQuery, page, onPageChange]);
|
||||
|
||||
React.useEffect(() => {
|
||||
let cancelled = false;
|
||||
@@ -348,6 +368,14 @@ export const RequestsTableView: React.FC<IRequestsTableViewProps> = ({
|
||||
const visible = rows || [];
|
||||
const totalPages = Math.max(1, Math.ceil(total / PAGE_SIZE));
|
||||
|
||||
// Страница может оказаться за пределами набора: пришла из старой ссылки или
|
||||
// из запомненной, а заявок с тех пор стало меньше (часть согласовали, и они
|
||||
// ушли из этой очереди). Показывать пустую таблицу с непустым счётчиком —
|
||||
// выглядит как поломка, поэтому возвращаемся на последнюю существующую.
|
||||
React.useEffect(() => {
|
||||
if (rows && page > totalPages) onPageChange(totalPages);
|
||||
}, [rows, page, totalPages, onPageChange]);
|
||||
|
||||
return (
|
||||
<section className={styles.view}>
|
||||
<div className={styles.head}>
|
||||
@@ -392,7 +420,7 @@ export const RequestsTableView: React.FC<IRequestsTableViewProps> = ({
|
||||
{!error && rows && total > 0 && (
|
||||
<>
|
||||
<Table rows={visible} view={view} onOpen={onOpen} />
|
||||
<Pager page={page} totalPages={totalPages} onChange={setPage} />
|
||||
<Pager page={page} totalPages={totalPages} onChange={onPageChange} />
|
||||
</>
|
||||
)}
|
||||
</section>
|
||||
|
||||
@@ -20,6 +20,12 @@ const AUTO_REFRESH_MS = 10 * 60 * 1000;
|
||||
|
||||
export interface ISearchViewProps {
|
||||
context: WebPartContext;
|
||||
/**
|
||||
* Текущая страница (1-based) и её смена — как и в RequestsTableView, страница
|
||||
* живёт в маршруте, а не внутри компонента (см. shared/routing.ts).
|
||||
*/
|
||||
page: number;
|
||||
onPageChange: (page: number) => void;
|
||||
/** Клик по строке — открыть заявку (в выезжающей панели). */
|
||||
onOpen: (request: IMyRequest) => void;
|
||||
}
|
||||
@@ -94,11 +100,10 @@ const Table: React.FC<{ rows: IMyRequest[]; onOpen: (request: IMyRequest) => voi
|
||||
// после решения согласующего) — но т.к. это по большей части Search, свежая
|
||||
// правка может проявиться не мгновенно (частично компенсируется довеском
|
||||
// последних 10 минут через REST — см. myRequests.service.ts).
|
||||
export const SearchView: React.FC<ISearchViewProps> = ({ context, onOpen }) => {
|
||||
export const SearchView: React.FC<ISearchViewProps> = ({ context, page, onPageChange, onOpen }) => {
|
||||
const [types, setTypes] = React.useState<IRequestType[] | undefined>(undefined);
|
||||
const [rows, setRows] = React.useState<IMyRequest[] | undefined>(undefined);
|
||||
const [totalRows, setTotalRows] = React.useState<number>(0);
|
||||
const [page, setPage] = React.useState<number>(1);
|
||||
const [query, setQuery] = usePersistedQuery('search');
|
||||
// query — то, что в поле ввода (меняется сразу); debouncedQuery — то, что
|
||||
// уходит в запрос (после паузы в наборе). Здесь это особенно важно: поиск
|
||||
@@ -107,7 +112,15 @@ export const SearchView: React.FC<ISearchViewProps> = ({ context, onOpen }) => {
|
||||
const debouncedQuery = useDebouncedQuery(query);
|
||||
const [error, setError] = React.useState<string>('');
|
||||
|
||||
React.useEffect(() => setPage(1), [debouncedQuery]);
|
||||
// Новый запрос — новый набор результатов, страница от прошлого к нему не
|
||||
// относится. Сравниваем с предыдущим значением, чтобы не сбросить страницу,
|
||||
// пришедшую из адреса, на первом же рендере (см. RequestsTableView).
|
||||
const prevQuery = React.useRef<string>(debouncedQuery);
|
||||
React.useEffect(() => {
|
||||
if (prevQuery.current === debouncedQuery) return;
|
||||
prevQuery.current = debouncedQuery;
|
||||
if (page !== 1) onPageChange(1);
|
||||
}, [debouncedQuery, page, onPageChange]);
|
||||
|
||||
React.useEffect(() => {
|
||||
let cancelled = false;
|
||||
@@ -198,7 +211,7 @@ export const SearchView: React.FC<ISearchViewProps> = ({ context, onOpen }) => {
|
||||
{!error && hasQuery && rows && totalRows > 0 && (
|
||||
<>
|
||||
<Table rows={rows} onOpen={onOpen} />
|
||||
<Pager page={page} totalPages={totalPages} onChange={setPage} />
|
||||
<Pager page={page} totalPages={totalPages} onChange={onPageChange} />
|
||||
</>
|
||||
)}
|
||||
</section>
|
||||
|
||||
Reference in New Issue
Block a user