From 03766057eba3c5f0d699b121b52f4bdce6831901 Mon Sep 17 00:00:00 2001 From: smanylov Date: Tue, 2 Jun 2026 17:45:07 +0700 Subject: [PATCH] add status filter for content table --- src/app/actions/contentActions.ts | 13 +- .../react-query/useContentForModeration.ts | 10 +- src/app/styles/global-styles.scss | 134 ++++++++++++++---- src/app/ui/content/content-appeals-table.tsx | 4 - .../ui/content/content-moderation-table.tsx | 122 +++++++++++----- src/i18n/messages/en.json | 4 +- src/i18n/messages/ru.json | 4 +- 7 files changed, 219 insertions(+), 72 deletions(-) diff --git a/src/app/actions/contentActions.ts b/src/app/actions/contentActions.ts index 23412ef..7093dbe 100644 --- a/src/app/actions/contentActions.ts +++ b/src/app/actions/contentActions.ts @@ -3,7 +3,16 @@ import { getSessionData } from '@/app/actions/session'; import { API_BASE_URL } from '@/app/actions/definitions'; -export async function fetchModerationContentList(page?: number, size?: number, sortBy?: string, sortDirection?: 'asc' | 'desc' | string) { +type ModerationStatus = 'BLOCKED' | 'ACTIVE' | 'MODERATION'; + +export async function fetchModerationContentList( + page?: number, + size?: number, + sortBy?: string, + sortDirection?: 'asc' | 'desc' | string, + statuses?: ModerationStatus[], + isAppeal?: boolean +) { const token = await getSessionData('token'); try { @@ -18,6 +27,8 @@ export async function fetchModerationContentList(page?: number, size?: number, s page_size: size, sort_by: sortBy || '', sort_order: sortDirection || 'asc', + statuses: statuses, + is_appeal: isAppeal, } }), headers: { diff --git a/src/app/hooks/react-query/useContentForModeration.ts b/src/app/hooks/react-query/useContentForModeration.ts index 415b17f..74c206b 100644 --- a/src/app/hooks/react-query/useContentForModeration.ts +++ b/src/app/hooks/react-query/useContentForModeration.ts @@ -22,16 +22,20 @@ export interface ContentForModeration { totalCount: number; } +export type ModerationStatus = 'BLOCKED' | 'ACTIVE' | 'MODERATION'; + export const useContentForModeration = ( page?: number, size?: number, sortBy?: string, - sortDirection?: 'asc' | 'desc' | string + sortDirection?: 'asc' | 'desc' | string, + statuses?: ModerationStatus[], + isAppeal?: boolean ) => { return useQuery({ - queryKey: ['contentForModeration', page, size, sortBy, sortDirection], + queryKey: ['contentForModeration', page, size, sortBy, sortDirection, statuses, isAppeal], queryFn: () => { - return fetchModerationContentList(page, size, sortBy, sortDirection); + return fetchModerationContentList(page, size, sortBy, sortDirection, statuses, isAppeal); }, select: (data: ContentForModeration | null) => { if (!data) { diff --git a/src/app/styles/global-styles.scss b/src/app/styles/global-styles.scss index 611fa36..df41408 100644 --- a/src/app/styles/global-styles.scss +++ b/src/app/styles/global-styles.scss @@ -771,39 +771,121 @@ @media (max-width: 768px) { width: auto; } + } - .table-filtres-item { - display: flex; - flex-direction: column; - width: 12.5rem; + .table-filtres-item { + display: flex; + flex-direction: column; + width: 12.5rem; + } + + .table-filtres-label { + font-size: 0.875rem; + font-weight: 500; + margin-bottom: 0.25rem; + } + + + .table-filtres-text-filter { + background-color: #fff; + border: 2px solid v.$border-color-1; + border-radius: 12px; + justify-content: space-between; + align-items: center; + width: 100%; + padding: 8px 16px; + font-size: 14px; + font-weight: 500; + line-height: 1.25; + transition: background-color .2s ease-in-out; + display: flex; + box-shadow: 0 1px 2px #0000000d; + + &:focus { + outline-offset: 2px; + outline: 2px solid v.$black; + box-shadow: 0 0 0 2px #6365f187; } + } - .table-filtres-label { - font-size: 0.875rem; - font-weight: 500; - margin-bottom: 0.25rem; - } + .status-filters { + display: flex; + gap: 10px; + align-items: center; + flex-wrap: wrap; - - .table-filtres-text-filter { - background-color: #fff; - border: 2px solid v.$border-color-1; - border-radius: 12px; - justify-content: space-between; - align-items: center; - width: 100%; - padding: 8px 16px; + .status-btn { + padding: 4px 12px; + border-radius: 16px; + border: 1px solid; + transition: all 0.2s ease; + cursor: pointer; font-size: 14px; font-weight: 500; - line-height: 1.25; - transition: background-color .2s ease-in-out; - display: flex; - box-shadow: 0 1px 2px #0000000d; - &:focus { - outline-offset: 2px; - outline: 2px solid v.$black; - box-shadow: 0 0 0 2px #6365f187; + &:hover { + transform: translateY(-1px); + } + + &:active { + transform: translateY(0); + } + + // BLOCK статус + &--block { + background-color: white; + color: #dc2626; + border-color: #fca5a5; + + &:hover { + background-color: #fef2f2; + border-color: #f87171; + } + + &.active { + background-color: #dc2626; + color: white; + border-color: #b91c1c; + box-shadow: 0 2px 4px rgba(220, 38, 38, 0.2); + } + } + + // ACTIVE статус + &--active { + background-color: white; + color: #16a34a; + border-color: #86efac; + + &:hover { + background-color: #f0fdf4; + border-color: #4ade80; + } + + &.active { + background-color: #16a34a; + color: white; + border-color: #15803d; + box-shadow: 0 2px 4px rgba(22, 163, 74, 0.2); + } + } + + // MODERATION статус + &--moderation { + background-color: white; + color: #ca8a04; + border-color: #fde047; + + &:hover { + background-color: #fefce8; + border-color: #facc15; + } + + &.active { + background-color: #ca8a04; + color: white; + border-color: #a16207; + box-shadow: 0 2px 4px rgba(202, 138, 4, 0.2); + } } } } diff --git a/src/app/ui/content/content-appeals-table.tsx b/src/app/ui/content/content-appeals-table.tsx index 6354bb7..793d9ff 100644 --- a/src/app/ui/content/content-appeals-table.tsx +++ b/src/app/ui/content/content-appeals-table.tsx @@ -116,10 +116,6 @@ export default function ContentAppealsTable({ permission }: { permission: number getSortParams.sortDirection ); - useEffect(() => { - console.log('Appeals data:', appealsData); - }, [appealsData]); - const queryClient = useQueryClient(); const handleViewFile = useCallback((file: AppealsFile) => { diff --git a/src/app/ui/content/content-moderation-table.tsx b/src/app/ui/content/content-moderation-table.tsx index 0995967..0b6b985 100644 --- a/src/app/ui/content/content-moderation-table.tsx +++ b/src/app/ui/content/content-moderation-table.tsx @@ -17,7 +17,7 @@ import DropDownList from '@/app/components/dropDownList'; import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query'; import ModalWindow from '@/app/components/modalWindow'; import { toast } from 'sonner'; -import { useContentForModeration, ModerationFile, ContentForModeration } from '@/app/hooks/react-query/useContentForModeration'; +import { useContentForModeration, ModerationFile, ContentForModeration, ModerationStatus } from '@/app/hooks/react-query/useContentForModeration'; import FileModerationModal from './FileModerationModal'; import { FileTypeIcon } from '@/app/components/FileTypeIcon'; import { getFileType } from '@/app/lib/getFileType'; @@ -59,6 +59,7 @@ const StatusBadge = ({ status }: { status: string }) => { 'BLOCKED': { className: 'bg-red-100 text-red-800', label: 'Заблокировано' }, 'MODERATION': { className: 'bg-yellow-100 text-yellow-800', label: 'На модерации' }, 'APPROVED': { className: 'bg-green-100 text-green-800', label: 'Одобрено' }, + 'ACTIVE': { className: 'bg-green-100 text-green-800', label: 'ACTIVE' }, }; const config = statusConfig[status] || { className: 'bg-gray-100 text-gray-800', label: status }; @@ -82,6 +83,10 @@ export default function ContentModerationTable({ permission }: { permission: num const [selectedFile, setSelectedFile] = useState(null); const [isFileLoading, setIsFileLoading] = useState(false); + // НОВЫЕ СОСТОЯНИЯ ДЛЯ ФИЛЬТРОВ + const [selectedStatuses, setSelectedStatuses] = useState([]); + const [isAppeal, setIsAppeal] = useState(undefined); + const t = useTranslations("Global"); // Получаем параметры сортировки для API @@ -104,6 +109,7 @@ export default function ContentModerationTable({ permission }: { permission: num }; }, [sorting]); + // Используем хук с фильтрами const { data: moderationData, isLoading, @@ -114,11 +120,45 @@ export default function ContentModerationTable({ permission }: { permission: num pagination.pageIndex, pagination.pageSize, getSortParams.sortBy, - getSortParams.sortDirection + getSortParams.sortDirection, + selectedStatuses.length > 0 ? selectedStatuses : undefined, + isAppeal ); const queryClient = useQueryClient(); + useEffect(() => { + console.log(moderationData); + }, [moderationData]) + + const toggleStatus = (status: ModerationStatus) => { + setSelectedStatuses(prev => { + if (prev.includes(status)) { + return prev.filter(s => s !== status); + } else { + return [...prev, status]; + } + }); + setPagination(prev => ({ ...prev, pageIndex: 0 })); + }; + + const clearAllStatuses = () => { + setSelectedStatuses([]); + setPagination(prev => ({ ...prev, pageIndex: 0 })); + }; + + // Обработчик изменения isAppeal + const handleAppealChange = (value: string) => { + if (value === 'all') { + setIsAppeal(undefined); + } else if (value === 'hasAppeal') { + setIsAppeal(true); + } else if (value === 'noAppeal') { + setIsAppeal(false); + } + setPagination(prev => ({ ...prev, pageIndex: 0 })); + }; + const handleViewFile = useCallback((file: ModerationFile) => { console.log('View file:', file); setSelectedFile(file); @@ -270,36 +310,6 @@ export default function ContentModerationTable({ permission }: { permission: num ), }, - /* { - accessorKey: 'moderationInfo.hasActiveAppeal', - header: ({ column }) => ( -
- - Апелляция - - -
- ), - cell: ({ row }) => ( -
- {row.original.moderationInfo.hasActiveAppeal ? ( - Активна - ) : ( - Нет - )} -
- ), - } */ ]; if (permission === 3) { @@ -393,12 +403,52 @@ export default function ContentModerationTable({ permission }: { permission: num - +

+ Таблица модерации контента +

{/* Фильтры */}
-

- Таблица модерации контента -

+ {/* Блок фильтрации по статусам */} +
+
Статусы:
+
+ + + +
+
+ + {/* Блок фильтрации по апелляции */} +
+
Апелляция:
+ +
  • + {t('all')} +
  • +
  • + {t('has-appeal')} +
  • + {/*
  • Без апелляции
  • */} +
    +
    {t('items-per-page')}:
    diff --git a/src/i18n/messages/en.json b/src/i18n/messages/en.json index 142c588..51bd8bf 100644 --- a/src/i18n/messages/en.json +++ b/src/i18n/messages/en.json @@ -223,7 +223,9 @@ "save": "Save", "delete": "Delete", "create-stuff": "Create stuff", - "download": "Download" + "download": "Download", + "all": "All", + "has-appeal": "Has appeal" }, "Login-register-form": { "and": "and", diff --git a/src/i18n/messages/ru.json b/src/i18n/messages/ru.json index 36d1bd2..800a49a 100644 --- a/src/i18n/messages/ru.json +++ b/src/i18n/messages/ru.json @@ -223,7 +223,9 @@ "save": "Сохранить", "delete": "Удалить", "create-stuff": "Создать сотрудника", - "download": "Скачать" + "download": "Скачать", + "all": "Все", + "has-appeal": "Есть апелляция" }, "Login-register-form": { "and": "и",