diff --git a/package.json b/package.json
index fd22a55..a048211 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "no-copy-admin-panel-frontend",
- "version": "0.16.0",
+ "version": "0.17.0",
"private": true,
"scripts": {
"dev": "next dev -p 2996",
diff --git a/src/app/hooks/react-query/useContentForModeration.ts b/src/app/hooks/react-query/useContentForModeration.ts
index 74c206b..881374b 100644
--- a/src/app/hooks/react-query/useContentForModeration.ts
+++ b/src/app/hooks/react-query/useContentForModeration.ts
@@ -1,10 +1,21 @@
import { useQuery } from '@tanstack/react-query';
import { fetchModerationContentList } from '@/app/actions/contentActions';
+export interface AppealInfo {
+ additionalInfo: string | null;
+ adminComment: null;
+ appealId: string | null;
+ appealReason: string | null;
+ createdAt: string | null;
+ fileId: string | null;
+ fileName: string | null;
+ resolvedAt: string | null;
+ status: string;
+}
export interface ModerationFile {
fileName: string;
moderationInfo: {
- appealInfo: null | any;
+ appealInfo: null | AppealInfo;
hasActiveAppeal: boolean;
};
userId: number;
diff --git a/src/app/styles/file-moderation-modal.scss b/src/app/styles/file-moderation-modal.scss
index 0a1b1fc..716ad52 100644
--- a/src/app/styles/file-moderation-modal.scss
+++ b/src/app/styles/file-moderation-modal.scss
@@ -125,6 +125,62 @@
cursor: not-allowed;
}
}
+
+ .tabs-modal__header {
+ display: flex;
+ flex-direction: column;
+ gap: 1rem;
+ }
+
+ .tabs-modal__tabs {
+ display: flex;
+ gap: 0.5rem;
+ border-bottom: 1px solid #e2e8f0;
+ padding-bottom: 0.5rem;
+ justify-content: space-between;
+ }
+
+ .tabs-modal__tab {
+ padding: 0.5rem 1rem;
+ background: transparent;
+ border: none;
+ border-radius: 0.375rem;
+ cursor: pointer;
+ font-size: 0.875rem;
+ font-weight: 500;
+ color: #64748b;
+ transition: all 0.2s;
+ position: relative;
+ }
+
+ .tabs-modal__tab:hover:not(:disabled) {
+ color: #3b82f6;
+ background: #f1f5f9;
+ }
+
+ .tabs-modal__tab--active {
+ color: #3b82f6;
+ background: #eff6ff;
+ }
+
+ .tabs-modal__tab--disabled {
+ opacity: 0.5;
+ cursor: not-allowed;
+ }
+
+ .tabs-modal__tab-badge {
+ display: inline-block;
+ margin-left: 0.5rem;
+ padding: 0.125rem 0.375rem;
+ background: #e2e8f0;
+ border-radius: 9999px;
+ font-size: 0.75rem;
+ font-weight: normal;
+ }
+
+ .tabs-modal__content {
+ margin-top: 1rem;
+ }
}
.status-badge {
diff --git a/src/app/styles/global-styles.scss b/src/app/styles/global-styles.scss
index df41408..60223cd 100644
--- a/src/app/styles/global-styles.scss
+++ b/src/app/styles/global-styles.scss
@@ -1035,6 +1035,14 @@
}
}
+ .table-status {
+ display: flex;
+ flex-direction: column;
+ justify-content: center;
+ align-items: center;
+ gap: 5px;
+ }
+
.table-item-protected {
color: #10b981;
font-size: 12px;
diff --git a/src/app/ui/content/AppealModerationModal.tsx b/src/app/ui/content/AppealModerationModal.tsx
index 0a4f2c6..fb2c273 100644
--- a/src/app/ui/content/AppealModerationModal.tsx
+++ b/src/app/ui/content/AppealModerationModal.tsx
@@ -7,9 +7,10 @@ import DropDownList from '@/app/components/dropDownList';
import { AppealsFile } from '@/app/hooks/react-query/useContentForAppeals';
import { changeAppealContentStatus } from '@/app/actions/contentActions';
import { formatDate, formatDateTime } from '@/app/lib/formatDate';
+import { AppealInfo } from '@/app/hooks/react-query/useContentForModeration';
interface AppealModerationModalProps {
- file: AppealsFile | null;
+ file: AppealInfo | AppealsFile | null;
onClose: () => void;
}
@@ -100,96 +101,93 @@ export default function AppealModerationModal({ file, onClose }: AppealModeratio
if (!file) return null;
return (
-
-
Управление апелляцией
+ <>
+ {/* Информация о файле */}
+
+
+
{file?.fileName ? file?.fileName : '---'}
+
-
- {/* Информация о файле */}
-
-
-
{file?.fileName ? file?.fileName : '---'}
-
+
+
+ {/* @ts-ignore сейчас нету айди юзера возможно нужно будет удалить или добавить*/}
+
{file?.userId ? file?.userId : '---'}
+
-
-
- {/* @ts-ignore сейчас нету айди юзера возможно нужно будет удалить или добавить*/}
-
{file?.userId ? file?.userId : '---'}
-
+
+
+
{file.appealReason}
+
-
-
-
{file.appealReason}
-
+
+
+
{file.additionalInfo || '—'}
+
-
-
-
{file.additionalInfo || '—'}
-
+
+
+
+ {file.createdAt && (
+ `${formatDate(file.createdAt)}, ${formatDateTime(file.createdAt)}`
+ )}
+
+
+ {file.resolvedAt && (
-
+
- {formatDate(file.createdAt)}, {formatDateTime(file.createdAt)}
+ {formatDate(file.resolvedAt)}, {formatDateTime(file.resolvedAt)}
+ )}
- {file.resolvedAt && (
-
-
-
- {formatDate(file.resolvedAt)}, {formatDateTime(file.resolvedAt)}
-
-
- )}
-
-
-
-
-
-
- {/* Комментарий администратора */}
-
-
-
-
- {/* Смена статуса */}
-
-
- setSelectedStatus(value)}
- >
- {/* На модерации */}
- Заблокировано
- Одобрено
-
-
-
- {/* Кнопки действий */}
-
-
-
-
+
+
+
-
+
+ {/* Комментарий администратора */}
+
+
+
+
+ {/* Смена статуса */}
+
+
+ setSelectedStatus(value)}
+ >
+ Заблокировано
+ Одобрено
+
+
+
+ {/* Кнопки действий */}
+
+
+
+
+ >
);
}
\ No newline at end of file
diff --git a/src/app/ui/content/FileModerationModal.tsx b/src/app/ui/content/FileModerationModal.tsx
index 7e1c791..7aa9cfe 100644
--- a/src/app/ui/content/FileModerationModal.tsx
+++ b/src/app/ui/content/FileModerationModal.tsx
@@ -82,56 +82,52 @@ export default function FileModerationModal({ file, onClose }: FileModerationMod
if (!file) return null;
return (
-
-
Управление файлом
+
+ {/* Информация о файле */}
+
+
+
{file.fileName}
+
-
- {/* Информация о файле */}
-
-
-
{file.fileName}
-
+
+
+
{file.userId}
+
-
-
-
{file.userId}
-
+
+
+
+
-
-
-
-
+ {/* Смена статуса */}
+
+
+ setSelectedStatus(value)}
+ >
+ На модерации
+ Заблокировано
+ Одобрено
+
+
- {/* Смена статуса */}
-
-
- setSelectedStatus(value)}
- >
- На модерации
- Заблокировано
- Одобрено
-
-
-
- {/* Кнопки действий */}
-
-
-
-
+ {/* Кнопки действий */}
+
+
+
);
diff --git a/src/app/ui/content/FileWithAppealModerationModal.tsx b/src/app/ui/content/FileWithAppealModerationModal.tsx
new file mode 100644
index 0000000..7200107
--- /dev/null
+++ b/src/app/ui/content/FileWithAppealModerationModal.tsx
@@ -0,0 +1,62 @@
+'use client';
+
+import { useState } from 'react';
+import { ModerationFile } from '@/app/hooks/react-query/useContentForModeration';
+import FileModerationModal from './FileModerationModal';
+import AppealModerationModal from './AppealModerationModal';
+
+interface FileWithAppealModerationModalProps {
+ file: ModerationFile | null;
+ onClose: () => void;
+}
+
+type TabType = 'file' | 'appeal';
+
+export default function FileWithAppealModerationModal({ file, onClose }: FileWithAppealModerationModalProps) {
+ const [activeTab, setActiveTab] = useState
('file');
+
+ if (!file) return null;
+
+ const hasAppeal = !!file.moderationInfo?.appealInfo;
+
+ return (
+
+
+
+ Модерация контента
+
+
+
+
+
+
+
+
+
+
+ {activeTab === 'file' && (
+
+ )}
+
+ {activeTab === 'appeal' && hasAppeal && (
+
+ )}
+
+
+ );
+}
\ No newline at end of file
diff --git a/src/app/ui/content/content-appeals-table.tsx b/src/app/ui/content/content-appeals-table.tsx
index 793d9ff..0a36616 100644
--- a/src/app/ui/content/content-appeals-table.tsx
+++ b/src/app/ui/content/content-appeals-table.tsx
@@ -22,6 +22,7 @@ import { downloadFile } from '@/app/actions/contentActions';
import { useContentForAppeals, AppealsFile } from '@/app/hooks/react-query/useContentForAppeals';
import AppealModerationModal from '@/app/ui/content/AppealModerationModal';
import { formatDate, formatDateTime } from '@/app/lib/formatDate';
+import {AppealInfo} from '@/app/hooks/react-query/useContentForModeration';
const cutFileExtension = (fileName: string) => {
const lastDotIndex = fileName.lastIndexOf('.');
@@ -79,7 +80,7 @@ export default function ContentAppealsTable({ permission }: { permission: number
pageSize: 10,
});
const [openWindow, setOpenWindow] = useState(false);
- const [selectedFile, setSelectedFile] = useState(null);
+ const [selectedFile, setSelectedFile] = useState(null);
const [isFileLoading, setIsFileLoading] = useState(false);
const t = useTranslations("Global");
diff --git a/src/app/ui/content/content-moderation-table.tsx b/src/app/ui/content/content-moderation-table.tsx
index 0b6b985..b8f0656 100644
--- a/src/app/ui/content/content-moderation-table.tsx
+++ b/src/app/ui/content/content-moderation-table.tsx
@@ -1,6 +1,6 @@
'use client';
-import { useState, useMemo, useEffect, ReactNode, useCallback } from 'react';
+import { useState, useMemo, useEffect, useCallback } from 'react';
import {
useReactTable,
getCoreRowModel,
@@ -17,12 +17,12 @@ 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, ModerationStatus } from '@/app/hooks/react-query/useContentForModeration';
-import FileModerationModal from './FileModerationModal';
+import { useContentForModeration, ModerationFile, ModerationStatus } from '@/app/hooks/react-query/useContentForModeration';
import { FileTypeIcon } from '@/app/components/FileTypeIcon';
import { getFileType } from '@/app/lib/getFileType';
import Image from 'next/image';
import { downloadFile } from '@/app/actions/contentActions';
+import FileWithAppealModerationModal from './FileWithAppealModerationModal';
const cutFileExtension = (fileName: string) => {
const lastDotIndex = fileName.lastIndexOf('.');
@@ -71,6 +71,23 @@ const StatusBadge = ({ status }: { status: string }) => {
);
};
+const AppealStatusBadge = ({ status }: { status: string }) => {
+ const statusConfig: Record = {
+ 'REJECTED': { 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: 'Одобрено' },
+ 'PENDING': { className: 'bg-gray-100 text-gray-800', label: 'На рассмотрении' }
+ };
+
+ const config = statusConfig[status] || { className: 'bg-gray-100 text-gray-800', label: status };
+
+ return (
+
+ {config.label}
+
+ );
+};
+
export default function ContentModerationTable({ permission }: { permission: number }) {
// Состояния
const [sorting, setSorting] = useState([]);
@@ -127,10 +144,6 @@ export default function ContentModerationTable({ permission }: { permission: num
const queryClient = useQueryClient();
- useEffect(() => {
- console.log(moderationData);
- }, [moderationData])
-
const toggleStatus = (status: ModerationStatus) => {
setSelectedStatuses(prev => {
if (prev.includes(status)) {
@@ -305,8 +318,15 @@ export default function ContentModerationTable({ permission }: { permission: num
),
cell: ({ row }) => (
-
-
+
+
+
+
+ {row.original.moderationInfo.appealInfo?.status && (
+
+ )}
),
},
@@ -401,7 +421,7 @@ export default function ContentModerationTable({ permission }: { permission: num
return (
-
+
Таблица модерации контента
diff --git a/src/i18n/messages/en.json b/src/i18n/messages/en.json
index 51bd8bf..af45809 100644
--- a/src/i18n/messages/en.json
+++ b/src/i18n/messages/en.json
@@ -225,7 +225,8 @@
"create-stuff": "Create stuff",
"download": "Download",
"all": "All",
- "has-appeal": "Has appeal"
+ "has-appeal": "Has appeal",
+ "appeal": "Appeal"
},
"Login-register-form": {
"and": "and",
diff --git a/src/i18n/messages/ru.json b/src/i18n/messages/ru.json
index 800a49a..79ffa07 100644
--- a/src/i18n/messages/ru.json
+++ b/src/i18n/messages/ru.json
@@ -225,7 +225,8 @@
"create-stuff": "Создать сотрудника",
"download": "Скачать",
"all": "Все",
- "has-appeal": "Есть апелляция"
+ "has-appeal": "Есть апелляция",
+ "appeal": "Апелляция"
},
"Login-register-form": {
"and": "и",