fix(tables): сохранение размера страницы и showSizeChanger
Размер таблицы сохраняется в localStorage, опции 10/20/50/100 на всех list-страницах. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -5,10 +5,13 @@ import { useNavigate } from 'react-router-dom';
|
|||||||
import { useAdmins, useCreateAdmin, useUpdateAdmin, useDeleteAdmin, useAdmin } from '../../hooks/useAdmins';
|
import { useAdmins, useCreateAdmin, useUpdateAdmin, useDeleteAdmin, useAdmin } from '../../hooks/useAdmins';
|
||||||
import { Admin, AdminListParams } from '../../types/api';
|
import { Admin, AdminListParams } from '../../types/api';
|
||||||
import type { ColumnsType, SorterResult } from 'antd/es/table/interface';
|
import type { ColumnsType, SorterResult } from 'antd/es/table/interface';
|
||||||
|
import { getSavedPageSize, getTablePagination, mergeTablePagination } from '../../utils/tablePagination';
|
||||||
|
|
||||||
|
const TABLE_KEY = 'admins';
|
||||||
|
|
||||||
const AdminListPage: React.FC = () => {
|
const AdminListPage: React.FC = () => {
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
const [params, setParams] = useState<AdminListParams>({ limit: 20, offset: 0, sort: 'email', order: 'asc' });
|
const [params, setParams] = useState<AdminListParams>({ limit: getSavedPageSize(TABLE_KEY), offset: 0, sort: 'email', order: 'asc' });
|
||||||
const { data, isLoading } = useAdmins(params);
|
const { data, isLoading } = useAdmins(params);
|
||||||
const createAdmin = useCreateAdmin();
|
const createAdmin = useCreateAdmin();
|
||||||
const updateAdmin = useUpdateAdmin();
|
const updateAdmin = useUpdateAdmin();
|
||||||
@@ -91,13 +94,11 @@ const AdminListPage: React.FC = () => {
|
|||||||
sorter: SorterResult<Admin> | SorterResult<Admin>[]
|
sorter: SorterResult<Admin> | SorterResult<Admin>[]
|
||||||
) => {
|
) => {
|
||||||
const s = Array.isArray(sorter) ? sorter[0] : sorter;
|
const s = Array.isArray(sorter) ? sorter[0] : sorter;
|
||||||
setParams(prev => ({
|
setParams(prev => mergeTablePagination({
|
||||||
...prev,
|
...prev,
|
||||||
sort: s.field as string,
|
sort: s.field as string,
|
||||||
order: s.order === 'ascend' ? 'asc' : s.order === 'descend' ? 'desc' : undefined,
|
order: s.order === 'ascend' ? 'asc' : s.order === 'descend' ? 'desc' : undefined,
|
||||||
offset: ((pagination.current - 1) * pagination.pageSize) || 0,
|
}, pagination, TABLE_KEY));
|
||||||
limit: pagination.pageSize || prev.limit,
|
|
||||||
}));
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const roleColors: Record<string, string> = {
|
const roleColors: Record<string, string> = {
|
||||||
@@ -207,12 +208,7 @@ const AdminListPage: React.FC = () => {
|
|||||||
rowKey="id"
|
rowKey="id"
|
||||||
loading={isLoading}
|
loading={isLoading}
|
||||||
onChange={handleTableChange}
|
onChange={handleTableChange}
|
||||||
pagination={{
|
pagination={getTablePagination(params, data?.total)}
|
||||||
total: data?.total,
|
|
||||||
current: (params.offset || 0) / (params.limit || 20) + 1,
|
|
||||||
pageSize: params.limit || 20,
|
|
||||||
showSizeChanger: false,
|
|
||||||
}}
|
|
||||||
/>
|
/>
|
||||||
|
|
||||||
{/* Модальное окно создания */}
|
{/* Модальное окно создания */}
|
||||||
|
|||||||
@@ -7,11 +7,14 @@ import { useUser } from '../../hooks/useUsers';
|
|||||||
import { useEvent } from '../../hooks/useEvents';
|
import { useEvent } from '../../hooks/useEvents';
|
||||||
import { AuditRecord, AuditListParams } from '../../types/api';
|
import { AuditRecord, AuditListParams } from '../../types/api';
|
||||||
import type { ColumnsType, SorterResult } from 'antd/es/table/interface';
|
import type { ColumnsType, SorterResult } from 'antd/es/table/interface';
|
||||||
|
import { getSavedPageSize, getTablePagination, mergeTablePagination } from '../../utils/tablePagination';
|
||||||
|
|
||||||
const { RangePicker } = DatePicker;
|
const { RangePicker } = DatePicker;
|
||||||
|
|
||||||
|
const TABLE_KEY = 'audit';
|
||||||
|
|
||||||
const AuditPage: React.FC = () => {
|
const AuditPage: React.FC = () => {
|
||||||
const [params, setParams] = useState<AuditListParams>({ limit: 20, offset: 0, sort: 'timestamp', order: 'desc' });
|
const [params, setParams] = useState<AuditListParams>({ limit: getSavedPageSize(TABLE_KEY), offset: 0, sort: 'timestamp', order: 'desc' });
|
||||||
const { data, isLoading } = useAudit(params);
|
const { data, isLoading } = useAudit(params);
|
||||||
|
|
||||||
const { data: admins, isLoading: loadingAdmins } = useAdmins({ limit: 1000, offset: 0 });
|
const { data: admins, isLoading: loadingAdmins } = useAdmins({ limit: 1000, offset: 0 });
|
||||||
@@ -71,13 +74,11 @@ const AuditPage: React.FC = () => {
|
|||||||
sorter: SorterResult<AuditRecord> | SorterResult<AuditRecord>[]
|
sorter: SorterResult<AuditRecord> | SorterResult<AuditRecord>[]
|
||||||
) => {
|
) => {
|
||||||
const s = Array.isArray(sorter) ? sorter[0] : sorter;
|
const s = Array.isArray(sorter) ? sorter[0] : sorter;
|
||||||
setParams(prev => ({
|
setParams(prev => mergeTablePagination({
|
||||||
...prev,
|
...prev,
|
||||||
sort: s.field as string,
|
sort: s.field as string,
|
||||||
order: s.order === 'ascend' ? 'asc' : s.order === 'descend' ? 'desc' : undefined,
|
order: s.order === 'ascend' ? 'asc' : s.order === 'descend' ? 'desc' : undefined,
|
||||||
offset: ((pagination.current - 1) * pagination.pageSize) || 0,
|
}, pagination, TABLE_KEY));
|
||||||
limit: pagination.pageSize || prev.limit,
|
|
||||||
}));
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleDateChange = (dates: any) => {
|
const handleDateChange = (dates: any) => {
|
||||||
@@ -226,12 +227,7 @@ const AuditPage: React.FC = () => {
|
|||||||
rowKey="id"
|
rowKey="id"
|
||||||
loading={isLoading}
|
loading={isLoading}
|
||||||
onChange={handleTableChange}
|
onChange={handleTableChange}
|
||||||
pagination={{
|
pagination={getTablePagination(params, data?.total)}
|
||||||
total: data?.total,
|
|
||||||
current: (params.offset || 0) / (params.limit || 20) + 1,
|
|
||||||
pageSize: params.limit || 20,
|
|
||||||
showSizeChanger: false,
|
|
||||||
}}
|
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -8,9 +8,12 @@ import { useAdmin } from '../../hooks/useAdmins';
|
|||||||
import { BannedWord } from '../../types/api';
|
import { BannedWord } from '../../types/api';
|
||||||
import type { ColumnsType, SorterResult } from 'antd/es/table/interface';
|
import type { ColumnsType, SorterResult } from 'antd/es/table/interface';
|
||||||
import dayjs from 'dayjs';
|
import dayjs from 'dayjs';
|
||||||
|
import { getSavedPageSize, getTablePagination, mergeTablePagination } from '../../utils/tablePagination';
|
||||||
|
|
||||||
|
const TABLE_KEY = 'banned-words';
|
||||||
|
|
||||||
const BannedWordsPage: React.FC = () => {
|
const BannedWordsPage: React.FC = () => {
|
||||||
const [params, setParams] = useState<BannedWordListParams>({ limit: 20, offset: 0 });
|
const [params, setParams] = useState<BannedWordListParams>({ limit: getSavedPageSize(TABLE_KEY), offset: 0 });
|
||||||
const { data, isLoading } = useBannedWords(params);
|
const { data, isLoading } = useBannedWords(params);
|
||||||
const addWord = useAddBannedWord();
|
const addWord = useAddBannedWord();
|
||||||
const removeWord = useRemoveBannedWord();
|
const removeWord = useRemoveBannedWord();
|
||||||
@@ -31,13 +34,11 @@ const BannedWordsPage: React.FC = () => {
|
|||||||
sorter: SorterResult<BannedWord> | SorterResult<BannedWord>[]
|
sorter: SorterResult<BannedWord> | SorterResult<BannedWord>[]
|
||||||
) => {
|
) => {
|
||||||
const s = Array.isArray(sorter) ? sorter[0] : sorter;
|
const s = Array.isArray(sorter) ? sorter[0] : sorter;
|
||||||
setParams(prev => ({
|
setParams(prev => mergeTablePagination({
|
||||||
...prev,
|
...prev,
|
||||||
sort: s.field as string,
|
sort: s.field as string,
|
||||||
order: s.order === 'ascend' ? 'asc' : s.order === 'descend' ? 'desc' : undefined,
|
order: s.order === 'ascend' ? 'asc' : s.order === 'descend' ? 'desc' : undefined,
|
||||||
offset: ((pagination.current - 1) * pagination.pageSize) || 0,
|
}, pagination, TABLE_KEY));
|
||||||
limit: pagination.pageSize || prev.limit,
|
|
||||||
}));
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// Обработчик поиска
|
// Обработчик поиска
|
||||||
@@ -126,12 +127,7 @@ const BannedWordsPage: React.FC = () => {
|
|||||||
rowKey="id"
|
rowKey="id"
|
||||||
loading={isLoading}
|
loading={isLoading}
|
||||||
onChange={handleTableChange}
|
onChange={handleTableChange}
|
||||||
pagination={{
|
pagination={getTablePagination(params, data?.total)}
|
||||||
total: data?.total,
|
|
||||||
current: (params.offset || 0) / (params.limit || 20) + 1,
|
|
||||||
pageSize: params.limit || 20,
|
|
||||||
showSizeChanger: false,
|
|
||||||
}}
|
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -5,10 +5,13 @@ import { Link, useNavigate } from 'react-router-dom';
|
|||||||
import { useCalendars, useUpdateCalendar, useDeleteCalendar, useCalendar, useCalendarStats } from '../../hooks/useCalendars';
|
import { useCalendars, useUpdateCalendar, useDeleteCalendar, useCalendar, useCalendarStats } from '../../hooks/useCalendars';
|
||||||
import { Calendar, CalendarListParams } from '../../types/api';
|
import { Calendar, CalendarListParams } from '../../types/api';
|
||||||
import type { ColumnsType, SorterResult } from 'antd/es/table/interface';
|
import type { ColumnsType, SorterResult } from 'antd/es/table/interface';
|
||||||
|
import { getSavedPageSize, getTablePagination, mergeTablePagination } from '../../utils/tablePagination';
|
||||||
|
|
||||||
|
const TABLE_KEY = 'calendars';
|
||||||
|
|
||||||
const CalendarListPage: React.FC = () => {
|
const CalendarListPage: React.FC = () => {
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
const [params, setParams] = useState<CalendarListParams>({ limit: 20, offset: 0, sort: 'created_at', order: 'desc' });
|
const [params, setParams] = useState<CalendarListParams>({ limit: getSavedPageSize(TABLE_KEY), offset: 0, sort: 'created_at', order: 'desc' });
|
||||||
const { data, isLoading } = useCalendars(params);
|
const { data, isLoading } = useCalendars(params);
|
||||||
const { data: stats } = useCalendarStats();
|
const { data: stats } = useCalendarStats();
|
||||||
const updateCalendar = useUpdateCalendar();
|
const updateCalendar = useUpdateCalendar();
|
||||||
@@ -101,13 +104,11 @@ const CalendarListPage: React.FC = () => {
|
|||||||
sorter: SorterResult<Calendar> | SorterResult<Calendar>[]
|
sorter: SorterResult<Calendar> | SorterResult<Calendar>[]
|
||||||
) => {
|
) => {
|
||||||
const s = Array.isArray(sorter) ? sorter[0] : sorter;
|
const s = Array.isArray(sorter) ? sorter[0] : sorter;
|
||||||
setParams(prev => ({
|
setParams(prev => mergeTablePagination({
|
||||||
...prev,
|
...prev,
|
||||||
sort: s.field as string,
|
sort: s.field as string,
|
||||||
order: s.order === 'ascend' ? 'asc' : s.order === 'descend' ? 'desc' : undefined,
|
order: s.order === 'ascend' ? 'asc' : s.order === 'descend' ? 'desc' : undefined,
|
||||||
offset: ((pagination.current || 1) - 1) * (pagination.pageSize || prev.limit || 20),
|
}, pagination, TABLE_KEY));
|
||||||
limit: pagination.pageSize || prev.limit,
|
|
||||||
}));
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const columns: ColumnsType<Calendar> = [
|
const columns: ColumnsType<Calendar> = [
|
||||||
@@ -270,12 +271,7 @@ const CalendarListPage: React.FC = () => {
|
|||||||
rowKey="id"
|
rowKey="id"
|
||||||
loading={isLoading}
|
loading={isLoading}
|
||||||
onChange={handleTableChange}
|
onChange={handleTableChange}
|
||||||
pagination={{
|
pagination={getTablePagination(params, data?.total)}
|
||||||
total: data?.total,
|
|
||||||
current: (params.offset || 0) / (params.limit || 20) + 1,
|
|
||||||
pageSize: params.limit || 20,
|
|
||||||
showSizeChanger: false,
|
|
||||||
}}
|
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<Modal
|
<Modal
|
||||||
|
|||||||
@@ -6,10 +6,13 @@ import { useEvents, useUpdateEvent, useDeleteEvent, useEvent, useEventStats } fr
|
|||||||
import { Event, EventListParams } from '../../types/api';
|
import { Event, EventListParams } from '../../types/api';
|
||||||
import type { ColumnsType, SorterResult } from 'antd/es/table/interface';
|
import type { ColumnsType, SorterResult } from 'antd/es/table/interface';
|
||||||
import dayjs from 'dayjs';
|
import dayjs from 'dayjs';
|
||||||
|
import { getSavedPageSize, getTablePagination, mergeTablePagination } from '../../utils/tablePagination';
|
||||||
|
|
||||||
|
const TABLE_KEY = 'events';
|
||||||
|
|
||||||
const EventListPage: React.FC = () => {
|
const EventListPage: React.FC = () => {
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
const [params, setParams] = useState<EventListParams>({ limit: 20, offset: 0, sort: 'id', order: 'asc' });
|
const [params, setParams] = useState<EventListParams>({ limit: getSavedPageSize(TABLE_KEY), offset: 0, sort: 'id', order: 'asc' });
|
||||||
const { data, isLoading } = useEvents(params);
|
const { data, isLoading } = useEvents(params);
|
||||||
const { data: stats } = useEventStats();
|
const { data: stats } = useEventStats();
|
||||||
const updateEvent = useUpdateEvent();
|
const updateEvent = useUpdateEvent();
|
||||||
@@ -111,13 +114,11 @@ const EventListPage: React.FC = () => {
|
|||||||
sorter: SorterResult<Event> | SorterResult<Event>[]
|
sorter: SorterResult<Event> | SorterResult<Event>[]
|
||||||
) => {
|
) => {
|
||||||
const s = Array.isArray(sorter) ? sorter[0] : sorter;
|
const s = Array.isArray(sorter) ? sorter[0] : sorter;
|
||||||
setParams(prev => ({
|
setParams(prev => mergeTablePagination({
|
||||||
...prev,
|
...prev,
|
||||||
sort: s.field as string,
|
sort: s.field as string,
|
||||||
order: s.order === 'ascend' ? 'asc' : s.order === 'descend' ? 'desc' : undefined,
|
order: s.order === 'ascend' ? 'asc' : s.order === 'descend' ? 'desc' : undefined,
|
||||||
offset: ((pagination.current - 1) * pagination.pageSize) || 0,
|
}, pagination, TABLE_KEY));
|
||||||
limit: pagination.pageSize || prev.limit,
|
|
||||||
}));
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const typeColors: Record<string, string> = {
|
const typeColors: Record<string, string> = {
|
||||||
@@ -265,12 +266,7 @@ const EventListPage: React.FC = () => {
|
|||||||
rowKey="id"
|
rowKey="id"
|
||||||
loading={isLoading}
|
loading={isLoading}
|
||||||
onChange={handleTableChange}
|
onChange={handleTableChange}
|
||||||
pagination={{
|
pagination={getTablePagination(params, data?.total)}
|
||||||
total: data?.total,
|
|
||||||
current: (params.offset || 0) / (params.limit || 20) + 1,
|
|
||||||
pageSize: params.limit || 20,
|
|
||||||
showSizeChanger: false,
|
|
||||||
}}
|
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<Modal
|
<Modal
|
||||||
|
|||||||
@@ -8,10 +8,14 @@ import { useEvent } from '../../hooks/useEvents';
|
|||||||
import { useAdmin } from '../../hooks/useAdmins';
|
import { useAdmin } from '../../hooks/useAdmins';
|
||||||
import { Report, ReportListParams } from '../../types/api';
|
import { Report, ReportListParams } from '../../types/api';
|
||||||
import type { ColumnsType, SorterResult } from 'antd/es/table/interface';
|
import type { ColumnsType, SorterResult } from 'antd/es/table/interface';
|
||||||
|
import { getSavedPageSize, getTablePagination, mergeTablePagination } from '../../utils/tablePagination';
|
||||||
|
import { formatStatusLabel } from '../../utils/statusLabels';
|
||||||
|
|
||||||
|
const TABLE_KEY = 'reports';
|
||||||
|
|
||||||
const ReportListPage: React.FC = () => {
|
const ReportListPage: React.FC = () => {
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
const [params, setParams] = useState<ReportListParams>({ limit: 20, offset: 0, sort: 'created_at', order: 'desc' });
|
const [params, setParams] = useState<ReportListParams>({ limit: getSavedPageSize(TABLE_KEY), offset: 0, sort: 'created_at', order: 'desc' });
|
||||||
const { data, isLoading } = useReports(params);
|
const { data, isLoading } = useReports(params);
|
||||||
const { data: stats } = useReportStats();
|
const { data: stats } = useReportStats();
|
||||||
const updateReport = useUpdateReport();
|
const updateReport = useUpdateReport();
|
||||||
@@ -40,13 +44,11 @@ const ReportListPage: React.FC = () => {
|
|||||||
sorter: SorterResult<Report> | SorterResult<Report>[]
|
sorter: SorterResult<Report> | SorterResult<Report>[]
|
||||||
) => {
|
) => {
|
||||||
const s = Array.isArray(sorter) ? sorter[0] : sorter;
|
const s = Array.isArray(sorter) ? sorter[0] : sorter;
|
||||||
setParams(prev => ({
|
setParams(prev => mergeTablePagination({
|
||||||
...prev,
|
...prev,
|
||||||
sort: s.field as string,
|
sort: s.field as string,
|
||||||
order: s.order === 'ascend' ? 'asc' : s.order === 'descend' ? 'desc' : undefined,
|
order: s.order === 'ascend' ? 'asc' : s.order === 'descend' ? 'desc' : undefined,
|
||||||
offset: ((pagination.current - 1) * pagination.pageSize) || 0,
|
}, pagination, TABLE_KEY));
|
||||||
limit: pagination.pageSize || prev.limit,
|
|
||||||
}));
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// Цвета для типа цели
|
// Цвета для типа цели
|
||||||
@@ -141,7 +143,7 @@ const ReportListPage: React.FC = () => {
|
|||||||
sorter: true,
|
sorter: true,
|
||||||
render: (status: string) => (
|
render: (status: string) => (
|
||||||
<Tag color={status === 'pending' ? 'orange' : status === 'reviewed' ? 'green' : 'default'}>
|
<Tag color={status === 'pending' ? 'orange' : status === 'reviewed' ? 'green' : 'default'}>
|
||||||
{status}
|
{formatStatusLabel(status)}
|
||||||
</Tag>
|
</Tag>
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
@@ -256,12 +258,7 @@ const ReportListPage: React.FC = () => {
|
|||||||
rowKey="id"
|
rowKey="id"
|
||||||
loading={isLoading}
|
loading={isLoading}
|
||||||
onChange={handleTableChange}
|
onChange={handleTableChange}
|
||||||
pagination={{
|
pagination={getTablePagination(params, data?.total)}
|
||||||
total: data?.total,
|
|
||||||
current: (params.offset || 0) / (params.limit || 20) + 1,
|
|
||||||
pageSize: params.limit || 20,
|
|
||||||
showSizeChanger: false,
|
|
||||||
}}
|
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<Modal
|
<Modal
|
||||||
|
|||||||
@@ -7,10 +7,14 @@ import { useUser } from '../../hooks/useUsers';
|
|||||||
import { useEvent } from '../../hooks/useEvents';
|
import { useEvent } from '../../hooks/useEvents';
|
||||||
import { Review, ReviewListParams } from '../../types/api';
|
import { Review, ReviewListParams } from '../../types/api';
|
||||||
import type { ColumnsType, SorterResult } from 'antd/es/table/interface';
|
import type { ColumnsType, SorterResult } from 'antd/es/table/interface';
|
||||||
|
import { getSavedPageSize, getTablePagination, mergeTablePagination } from '../../utils/tablePagination';
|
||||||
|
import { formatStatusLabel } from '../../utils/statusLabels';
|
||||||
|
|
||||||
|
const TABLE_KEY = 'reviews';
|
||||||
|
|
||||||
const ReviewListPage: React.FC = () => {
|
const ReviewListPage: React.FC = () => {
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
const [params, setParams] = useState<ReviewListParams>({ limit: 20, offset: 0, sort: 'created_at', order: 'desc' });
|
const [params, setParams] = useState<ReviewListParams>({ limit: getSavedPageSize(TABLE_KEY), offset: 0, sort: 'created_at', order: 'desc' });
|
||||||
const { data, isLoading } = useReviews(params);
|
const { data, isLoading } = useReviews(params);
|
||||||
const { data: stats } = useReviewStats();
|
const { data: stats } = useReviewStats();
|
||||||
const updateReview = useUpdateReview();
|
const updateReview = useUpdateReview();
|
||||||
@@ -97,13 +101,11 @@ const ReviewListPage: React.FC = () => {
|
|||||||
sorter: SorterResult<Review> | SorterResult<Review>[]
|
sorter: SorterResult<Review> | SorterResult<Review>[]
|
||||||
) => {
|
) => {
|
||||||
const s = Array.isArray(sorter) ? sorter[0] : sorter;
|
const s = Array.isArray(sorter) ? sorter[0] : sorter;
|
||||||
setParams(prev => ({
|
setParams(prev => mergeTablePagination({
|
||||||
...prev,
|
...prev,
|
||||||
sort: s.field as string,
|
sort: s.field as string,
|
||||||
order: s.order === 'ascend' ? 'asc' : s.order === 'descend' ? 'desc' : undefined,
|
order: s.order === 'ascend' ? 'asc' : s.order === 'descend' ? 'desc' : undefined,
|
||||||
offset: ((pagination.current - 1) * pagination.pageSize) || 0,
|
}, pagination, TABLE_KEY));
|
||||||
limit: pagination.pageSize || prev.limit,
|
|
||||||
}));
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const isBadValue = (val: any) => val === '-' || val === 'undefined' || val === '' || val === null || val === undefined;
|
const isBadValue = (val: any) => val === '-' || val === 'undefined' || val === '' || val === null || val === undefined;
|
||||||
@@ -205,7 +207,7 @@ const ReviewListPage: React.FC = () => {
|
|||||||
sorter: true,
|
sorter: true,
|
||||||
render: (status: string) => (
|
render: (status: string) => (
|
||||||
<Tag color={status === 'visible' ? 'green' : status === 'hidden' ? 'orange' : 'red'}>
|
<Tag color={status === 'visible' ? 'green' : status === 'hidden' ? 'orange' : 'red'}>
|
||||||
{status}
|
{formatStatusLabel(status)}
|
||||||
</Tag>
|
</Tag>
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
@@ -305,12 +307,7 @@ const ReviewListPage: React.FC = () => {
|
|||||||
rowKey="id"
|
rowKey="id"
|
||||||
loading={isLoading}
|
loading={isLoading}
|
||||||
onChange={handleTableChange}
|
onChange={handleTableChange}
|
||||||
pagination={{
|
pagination={getTablePagination(params, data?.total)}
|
||||||
total: data?.total,
|
|
||||||
current: (params.offset || 0) / (params.limit || 20) + 1,
|
|
||||||
pageSize: params.limit || 20,
|
|
||||||
showSizeChanger: false,
|
|
||||||
}}
|
|
||||||
/>
|
/>
|
||||||
|
|
||||||
{/* Модальное окно индивидуального редактирования */}
|
{/* Модальное окно индивидуального редактирования */}
|
||||||
|
|||||||
@@ -7,9 +7,12 @@ import { useUser } from '../../hooks/useUsers';
|
|||||||
import { Subscription, SubscriptionListParams } from '../../types/api';
|
import { Subscription, SubscriptionListParams } from '../../types/api';
|
||||||
import type { ColumnsType, SorterResult } from 'antd/es/table/interface';
|
import type { ColumnsType, SorterResult } from 'antd/es/table/interface';
|
||||||
import dayjs from 'dayjs';
|
import dayjs from 'dayjs';
|
||||||
|
import { getSavedPageSize, getTablePagination, mergeTablePagination } from '../../utils/tablePagination';
|
||||||
|
|
||||||
|
const TABLE_KEY = 'subscriptions';
|
||||||
|
|
||||||
const SubscriptionListPage: React.FC = () => {
|
const SubscriptionListPage: React.FC = () => {
|
||||||
const [params, setParams] = useState<SubscriptionListParams>({ limit: 20, offset: 0 });
|
const [params, setParams] = useState<SubscriptionListParams>({ limit: getSavedPageSize(TABLE_KEY), offset: 0 });
|
||||||
const { data, isLoading } = useSubscriptions(params);
|
const { data, isLoading } = useSubscriptions(params);
|
||||||
const { data: stats } = useSubscriptionStats();
|
const { data: stats } = useSubscriptionStats();
|
||||||
const updateSubscription = useUpdateSubscription();
|
const updateSubscription = useUpdateSubscription();
|
||||||
@@ -77,13 +80,11 @@ const SubscriptionListPage: React.FC = () => {
|
|||||||
sorter: SorterResult<Subscription> | SorterResult<Subscription>[]
|
sorter: SorterResult<Subscription> | SorterResult<Subscription>[]
|
||||||
) => {
|
) => {
|
||||||
const s = Array.isArray(sorter) ? sorter[0] : sorter;
|
const s = Array.isArray(sorter) ? sorter[0] : sorter;
|
||||||
setParams(prev => ({
|
setParams(prev => mergeTablePagination({
|
||||||
...prev,
|
...prev,
|
||||||
sort: s.field as string,
|
sort: s.field as string,
|
||||||
order: s.order === 'ascend' ? 'asc' : s.order === 'descend' ? 'desc' : undefined,
|
order: s.order === 'ascend' ? 'asc' : s.order === 'descend' ? 'desc' : undefined,
|
||||||
offset: ((pagination.current - 1) * pagination.pageSize) || 0,
|
}, pagination, TABLE_KEY));
|
||||||
limit: pagination.pageSize || prev.limit,
|
|
||||||
}));
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const isBadValue = (val: any) => val === '-' || val === 'undefined' || val === '' || val === null || val === undefined;
|
const isBadValue = (val: any) => val === '-' || val === 'undefined' || val === '' || val === null || val === undefined;
|
||||||
@@ -253,12 +254,7 @@ const SubscriptionListPage: React.FC = () => {
|
|||||||
rowKey="id"
|
rowKey="id"
|
||||||
loading={isLoading}
|
loading={isLoading}
|
||||||
onChange={handleTableChange}
|
onChange={handleTableChange}
|
||||||
pagination={{
|
pagination={getTablePagination(params, data?.total)}
|
||||||
total: data?.total,
|
|
||||||
current: (params.offset || 0) / (params.limit || 20) + 1,
|
|
||||||
pageSize: params.limit || 20,
|
|
||||||
showSizeChanger: false,
|
|
||||||
}}
|
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<Modal
|
<Modal
|
||||||
|
|||||||
@@ -6,10 +6,14 @@ import { useTickets, useDeleteTicket, useTicketStats } from '../../hooks/useTick
|
|||||||
import { useAdmin } from '../../hooks/useAdmins';
|
import { useAdmin } from '../../hooks/useAdmins';
|
||||||
import { Ticket, TicketListParams } from '../../types/api';
|
import { Ticket, TicketListParams } from '../../types/api';
|
||||||
import type { ColumnsType, SorterResult } from 'antd/es/table/interface';
|
import type { ColumnsType, SorterResult } from 'antd/es/table/interface';
|
||||||
|
import { getSavedPageSize, getTablePagination, mergeTablePagination } from '../../utils/tablePagination';
|
||||||
|
import { formatStatusLabel } from '../../utils/statusLabels';
|
||||||
|
|
||||||
|
const TABLE_KEY = 'tickets';
|
||||||
|
|
||||||
const TicketListPage: React.FC = () => {
|
const TicketListPage: React.FC = () => {
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
const [params, setParams] = useState<TicketListParams>({ limit: 20, offset: 0, sort: 'last_seen', order: 'desc' });
|
const [params, setParams] = useState<TicketListParams>({ limit: getSavedPageSize(TABLE_KEY), offset: 0, sort: 'last_seen', order: 'desc' });
|
||||||
const { data, isLoading } = useTickets(params);
|
const { data, isLoading } = useTickets(params);
|
||||||
const deleteTicket = useDeleteTicket();
|
const deleteTicket = useDeleteTicket();
|
||||||
const { data: stats } = useTicketStats();
|
const { data: stats } = useTicketStats();
|
||||||
@@ -33,13 +37,11 @@ const TicketListPage: React.FC = () => {
|
|||||||
sorter: SorterResult<Ticket> | SorterResult<Ticket>[]
|
sorter: SorterResult<Ticket> | SorterResult<Ticket>[]
|
||||||
) => {
|
) => {
|
||||||
const s = Array.isArray(sorter) ? sorter[0] : sorter;
|
const s = Array.isArray(sorter) ? sorter[0] : sorter;
|
||||||
setParams(prev => ({
|
setParams(prev => mergeTablePagination({
|
||||||
...prev,
|
...prev,
|
||||||
sort: s.field as string,
|
sort: s.field as string,
|
||||||
order: s.order === 'ascend' ? 'asc' : s.order === 'descend' ? 'desc' : undefined,
|
order: s.order === 'ascend' ? 'asc' : s.order === 'descend' ? 'desc' : undefined,
|
||||||
offset: ((pagination.current - 1) * pagination.pageSize) || 0,
|
}, pagination, TABLE_KEY));
|
||||||
limit: pagination.pageSize || prev.limit,
|
|
||||||
}));
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const columns: ColumnsType<Ticket> = [
|
const columns: ColumnsType<Ticket> = [
|
||||||
@@ -78,7 +80,7 @@ const TicketListPage: React.FC = () => {
|
|||||||
status === 'open' ? 'red' :
|
status === 'open' ? 'red' :
|
||||||
status === 'in_progress' ? 'blue' :
|
status === 'in_progress' ? 'blue' :
|
||||||
status === 'resolved' ? 'green' : 'default';
|
status === 'resolved' ? 'green' : 'default';
|
||||||
return <Tag color={color}>{status}</Tag>;
|
return <Tag color={color}>{formatStatusLabel(status)}</Tag>;
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -154,12 +156,7 @@ const TicketListPage: React.FC = () => {
|
|||||||
rowKey="id"
|
rowKey="id"
|
||||||
loading={isLoading}
|
loading={isLoading}
|
||||||
onChange={handleTableChange}
|
onChange={handleTableChange}
|
||||||
pagination={{
|
pagination={getTablePagination(params, data?.total)}
|
||||||
total: data?.total,
|
|
||||||
current: (params.offset || 0) / (params.limit || 20) + 1,
|
|
||||||
pageSize: params.limit || 20,
|
|
||||||
showSizeChanger: false,
|
|
||||||
}}
|
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -5,10 +5,14 @@ import { useNavigate } from 'react-router-dom';
|
|||||||
import { useUsers, useUpdateUser, useDeleteUser, useUser, useUserStats } from '../../hooks/useUsers';
|
import { useUsers, useUpdateUser, useDeleteUser, useUser, useUserStats } from '../../hooks/useUsers';
|
||||||
import { User, UserListParams } from '../../types/api';
|
import { User, UserListParams } from '../../types/api';
|
||||||
import type { ColumnsType, SorterResult } from 'antd/es/table/interface';
|
import type { ColumnsType, SorterResult } from 'antd/es/table/interface';
|
||||||
|
import { getSavedPageSize, getTablePagination, mergeTablePagination } from '../../utils/tablePagination';
|
||||||
|
import { formatStatusLabel } from '../../utils/statusLabels';
|
||||||
|
|
||||||
|
const TABLE_KEY = 'users';
|
||||||
|
|
||||||
const UserListPage: React.FC = () => {
|
const UserListPage: React.FC = () => {
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
const [params, setParams] = useState<UserListParams>({ limit: 20, offset: 0, sort: 'id', order: 'asc' });
|
const [params, setParams] = useState<UserListParams>({ limit: getSavedPageSize(TABLE_KEY), offset: 0, sort: 'id', order: 'asc' });
|
||||||
const { data, isLoading } = useUsers(params);
|
const { data, isLoading } = useUsers(params);
|
||||||
const { data: stats } = useUserStats();
|
const { data: stats } = useUserStats();
|
||||||
const updateUser = useUpdateUser();
|
const updateUser = useUpdateUser();
|
||||||
@@ -155,13 +159,11 @@ const UserListPage: React.FC = () => {
|
|||||||
sorter: SorterResult<User> | SorterResult<User>[]
|
sorter: SorterResult<User> | SorterResult<User>[]
|
||||||
) => {
|
) => {
|
||||||
const s = Array.isArray(sorter) ? sorter[0] : sorter;
|
const s = Array.isArray(sorter) ? sorter[0] : sorter;
|
||||||
setParams(prev => ({
|
setParams(prev => mergeTablePagination({
|
||||||
...prev,
|
...prev,
|
||||||
sort: s.field as string,
|
sort: s.field as string,
|
||||||
order: s.order === 'ascend' ? 'asc' : s.order === 'descend' ? 'desc' : undefined,
|
order: s.order === 'ascend' ? 'asc' : s.order === 'descend' ? 'desc' : undefined,
|
||||||
offset: ((pagination.current - 1) * pagination.pageSize) || 0,
|
}, pagination, TABLE_KEY));
|
||||||
limit: pagination.pageSize || prev.limit,
|
|
||||||
}));
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const columns: ColumnsType<User> = [
|
const columns: ColumnsType<User> = [
|
||||||
@@ -202,7 +204,7 @@ const UserListPage: React.FC = () => {
|
|||||||
sorter: true,
|
sorter: true,
|
||||||
render: (status: string) => (
|
render: (status: string) => (
|
||||||
<Tag color={status === 'active' ? 'green' : status === 'frozen' ? 'orange' : 'red'}>
|
<Tag color={status === 'active' ? 'green' : status === 'frozen' ? 'orange' : 'red'}>
|
||||||
{status}
|
{formatStatusLabel(status)}
|
||||||
</Tag>
|
</Tag>
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
@@ -282,12 +284,7 @@ const UserListPage: React.FC = () => {
|
|||||||
rowKey="id"
|
rowKey="id"
|
||||||
loading={isLoading}
|
loading={isLoading}
|
||||||
onChange={handleTableChange}
|
onChange={handleTableChange}
|
||||||
pagination={{
|
pagination={getTablePagination(params, data?.total)}
|
||||||
total: data?.total,
|
|
||||||
current: (params.offset || 0) / (params.limit || 20) + 1,
|
|
||||||
pageSize: params.limit || 20,
|
|
||||||
showSizeChanger: false,
|
|
||||||
}}
|
|
||||||
/>
|
/>
|
||||||
|
|
||||||
{/* Модальное окно редактирования */}
|
{/* Модальное окно редактирования */}
|
||||||
|
|||||||
@@ -0,0 +1,44 @@
|
|||||||
|
export const TABLE_PAGE_SIZE_OPTIONS = [10, 20, 50, 100] as const;
|
||||||
|
export const DEFAULT_TABLE_PAGE_SIZE = 20;
|
||||||
|
|
||||||
|
const STORAGE_PREFIX = 'admin.table.';
|
||||||
|
|
||||||
|
export function getSavedPageSize(tableKey: string, fallback = DEFAULT_TABLE_PAGE_SIZE): number {
|
||||||
|
const raw = localStorage.getItem(`${STORAGE_PREFIX}${tableKey}.pageSize`);
|
||||||
|
const size = raw ? Number(raw) : fallback;
|
||||||
|
return (TABLE_PAGE_SIZE_OPTIONS as readonly number[]).includes(size) ? size : fallback;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function savePageSize(tableKey: string, size: number): void {
|
||||||
|
localStorage.setItem(`${STORAGE_PREFIX}${tableKey}.pageSize`, String(size));
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getTablePagination(
|
||||||
|
params: { offset?: number; limit?: number },
|
||||||
|
total?: number
|
||||||
|
) {
|
||||||
|
const pageSize = params.limit || DEFAULT_TABLE_PAGE_SIZE;
|
||||||
|
return {
|
||||||
|
total,
|
||||||
|
current: Math.floor((params.offset || 0) / pageSize) + 1,
|
||||||
|
pageSize,
|
||||||
|
showSizeChanger: true,
|
||||||
|
pageSizeOptions: [...TABLE_PAGE_SIZE_OPTIONS],
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export function mergeTablePagination<T extends { offset?: number; limit?: number }>(
|
||||||
|
prev: T,
|
||||||
|
pagination: { current?: number; pageSize?: number },
|
||||||
|
tableKey: string
|
||||||
|
): T {
|
||||||
|
const pageSize = pagination.pageSize || prev.limit || DEFAULT_TABLE_PAGE_SIZE;
|
||||||
|
if (pagination.pageSize && pagination.pageSize !== prev.limit) {
|
||||||
|
savePageSize(tableKey, pageSize);
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
...prev,
|
||||||
|
offset: ((pagination.current ?? 1) - 1) * pageSize,
|
||||||
|
limit: pageSize,
|
||||||
|
};
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user