diff --git a/package.json b/package.json
index ce1a404..fc366d7 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "no-copy-frontend",
- "version": "0.118.0",
+ "version": "0.119.0",
"private": true,
"scripts": {
"dev": "next dev -p 2999",
diff --git a/src/app/actions/fileEntity.ts b/src/app/actions/fileEntity.ts
index b3578c2..e51fb39 100644
--- a/src/app/actions/fileEntity.ts
+++ b/src/app/actions/fileEntity.ts
@@ -162,4 +162,44 @@ export async function downloadFile(fileId: string, fileName: string) {
contentType: response.headers.get('content-type') || 'application/octet-stream',
fileName: fileName
}
+}
+
+export async function FileAnAppeal(fileId: string, appealReason: string, additionalInfo: string) {
+ const token = await getSessionData('token');
+
+ try {
+ const response = await fetch(`${API_BASE_URL}/api/v1/data`, {
+ method: 'POST',
+ body: JSON.stringify({
+ version: 1,
+ msg_id: 20005,
+ message_body: {
+ action: 'submit_appeal',
+ file_id: fileId,
+ token: token,
+ appeal_reason: appealReason,
+ additional_info: additionalInfo
+ }
+ }),
+ headers: {
+ 'Content-Type': 'application/json',
+ 'Accept': 'application/json'
+ }
+ });
+
+ if (response.ok) {
+ let parsed = await response.json();
+
+ if (parsed.message_code === 0) {
+ return parsed.message_body;
+ } else {
+ throw parsed;
+ }
+ } else {
+ throw (`${response.status}`);
+ }
+
+ } catch (error) {
+ return error
+ }
}
\ No newline at end of file
diff --git a/src/app/components/tanstak-table/TanstakTable.tsx b/src/app/components/tanstak-table/TanstakTable.tsx
index 2cfb77d..97e522d 100644
--- a/src/app/components/tanstak-table/TanstakTable.tsx
+++ b/src/app/components/tanstak-table/TanstakTable.tsx
@@ -33,6 +33,7 @@ import Link from 'next/link';
import { SelectedFilesAction } from '@/app/components/tanstak-table/SelectedFilesActions';
import Image from 'next/image';
import { filePermisionChange } from '@/app/actions/trackingActions';
+import {FileAppealModalWindow} from '@/app/ui/modal-windows/file-appeal-modal-window';
export type FileItem = {
id: string;
@@ -41,7 +42,7 @@ export type FileItem = {
violations?: number | undefined;
size?: number | undefined;
uploadDate?: number;
- status?: string;
+ status: string;
monitoring: string;
protectStatus: string;
_original?: ApiFile;
@@ -295,6 +296,32 @@ export default function TanstakFilesTable({ fileType, showFileLink }: { fileType
});
}, [apiResponse]);
+ const StatusBadge = ({ status, protectStatus }: { status: string, protectStatus: string }) => {
+
+ switch (status) {
+ case 'ACTIVE':
+ return
+ {protectStatus ? t(protectStatus) : t('error')}
+ ;
+ case 'MODERATION':
+ return
+ {t('pending-moderation')}
+ ;
+ case 'BLOCKED':
+ return
+ {t('blocked')}
+ ;
+ case 'REMOVED':
+ return
+ {t('file-has-been-deleted')}
+ ;
+ default:
+ return
+ {protectStatus ? t(protectStatus) : t('error')}
+ ;
+ }
+ }
+
const isAllSelected = useMemo(() => {
if (!apiResponse?.items?.length) return false;
const allIds = new Set(apiResponse.items.map(item => item.id));
@@ -431,9 +458,7 @@ export default function TanstakFilesTable({ fileType, showFileLink }: { fileType
{cutFileName(row.original.fileName)}
- {cutFileExtension(row.original.fileName)}
- {row.original?.protectStatus ? t(row.original?.protectStatus) : t('error')}
-
+ {cutFileExtension(row.original.fileName)}
@@ -614,36 +639,53 @@ export default function TanstakFilesTable({ fileType, showFileLink }: { fileType
) : (
<>
-
-
-
-
-
-
- {row.original.protectStatus === 'PROTECTED' && (
+ {/* "BLOCKED" "REMOVED" */}
+ {(row.original.status !== 'BLOCKED' && row.original.status !== 'REMOVED') ? (
+ <>
+
+
+
+
+
+
+ {row.original.protectStatus === 'PROTECTED' && (
+
+ )}
+
+
+ >
+ ) : (
+
- )}
-
-
+
+ )}
>
)}
@@ -666,6 +708,16 @@ export default function TanstakFilesTable({ fileType, showFileLink }: { fileType
setOpenWindow(true);
};
+ const handleAppeal = async (file: FileItem) => {
+
+ setOpenWindowChildren(() => {
+ return (
+
+ )
+ })
+ setOpenWindow(true);
+ };
+
const handleDownload = async (file: FileItem) => {
setIsFileLoading(true)
diff --git a/src/app/styles/global-styles.scss b/src/app/styles/global-styles.scss
index 5f71437..0016e92 100644
--- a/src/app/styles/global-styles.scss
+++ b/src/app/styles/global-styles.scss
@@ -163,7 +163,7 @@
.btn,
.btn-s,
-.btn-m {
+.btn-l {
border: none;
cursor: pointer;
font-weight: 600;
@@ -197,7 +197,8 @@
}
.btn-primary {
- background: linear-gradient(135deg, v.$p-color, v.$s-color);
+ /* background: linear-gradient(135deg, v.$p-color, v.$s-color); */
+ background: #6366f1;
color: v.$white;
border: 2px solid transparent;
@@ -222,6 +223,16 @@
}
}
+.btn-cancel {
+ background: v.$bg-hover;
+ color: v.$text-p;
+ border: 2px solid v.$border-color-1;
+
+ &:hover {
+ transform: translateY(-2px);
+ }
+}
+
.btn-outline {
background: transparent;
border: 2px solid v.$p-color;
diff --git a/src/app/styles/pages-styles.scss b/src/app/styles/pages-styles.scss
index 9ab4bb7..720c77f 100644
--- a/src/app/styles/pages-styles.scss
+++ b/src/app/styles/pages-styles.scss
@@ -930,13 +930,24 @@
}
}
- .table-item-protected {
- color: #10b981;
+ .table-item-status-badge {
font-size: 12px;
position: relative;
margin-left: 5px;
padding-left: 5px;
+ &.protected {
+ color: #10b981;
+ }
+
+ &.moderation {
+ color: v.$color-warning;
+ }
+
+ &.blocked {
+ color: v.$red;
+ }
+
&::before {
content: '•';
color: v.$text-s;
@@ -1016,11 +1027,11 @@
}
}
- .table-action-delete {
- background-color: #e80a14;
+ .table-action-appeal {
+ background-color: #9f0712;
&:hover {
- background-color: #9f0712;
+ background-color: v.$red;
}
}
@@ -3799,7 +3810,7 @@
}
.info-header {
- background: linear-gradient(0deg, #6366f1 50%, #8b5cf6 130%);
+ background: #6366f1;
color: white;
padding: 16px 20px;
border-bottom: 1px solid v.$border-color-1;
@@ -3847,6 +3858,84 @@
padding: 12px 20px;
border-bottom: 1px solid #f1f5f9;
}
+
+ .appeal-form {
+ margin-top: 20px;
+ }
+
+ .appeal-textarea {
+ width: 100%;
+ padding: 10px;
+ border: 1px solid #ddd;
+ border-radius: 6px;
+ font-family: inherit;
+ font-size: 14px;
+ resize: vertical;
+ }
+
+ .appeal-textarea:focus {
+ outline: none;
+ border-color: #6366f1;
+ box-shadow: 0 0 0 2px rgba(99, 102, 241, 0.1);
+ }
+
+ .appeal-textarea:disabled {
+ background-color: #f3f4f6;
+ cursor: not-allowed;
+ }
+
+ .required {
+ color: #ef4444;
+ }
+
+ .appeal-actions {
+ display: flex;
+ gap: 12px;
+ justify-content: center;
+ margin: 10px 0;
+ }
+
+ .appeal-submit-btn {
+ padding: 8px 20px;
+ background-color: #6366f1;
+ color: white;
+ border: none;
+ border-radius: 6px;
+ cursor: pointer;
+ font-size: 14px;
+ font-weight: 500;
+ transition: background-color 0.2s;
+ }
+
+ .appeal-submit-btn:hover:not(:disabled) {
+ background-color: #4f46e5;
+ }
+
+ .appeal-submit-btn:disabled {
+ background-color: #9ca3af;
+ cursor: not-allowed;
+ }
+
+ .appeal-cancel-btn {
+ padding: 8px 20px;
+ background-color: #f3f4f6;
+ color: #374151;
+ border: 1px solid #d1d5db;
+ border-radius: 6px;
+ cursor: pointer;
+ font-size: 14px;
+ font-weight: 500;
+ transition: all 0.2s;
+ }
+
+ .appeal-cancel-btn:hover:not(:disabled) {
+ background-color: #e5e7eb;
+ }
+
+ .appeal-cancel-btn:disabled {
+ opacity: 0.5;
+ cursor: not-allowed;
+ }
}
}
}
diff --git a/src/app/ui/modal-windows/file-appeal-modal-window.tsx b/src/app/ui/modal-windows/file-appeal-modal-window.tsx
new file mode 100644
index 0000000..fd548d0
--- /dev/null
+++ b/src/app/ui/modal-windows/file-appeal-modal-window.tsx
@@ -0,0 +1,104 @@
+'use client';
+
+import { convertBytes } from '@/app/lib/convertBytes';
+import { formatDate, formatDateTime } from '@/app/lib/formatDate';
+import { useTranslations } from 'next-intl';
+import { FileDetails } from '@/app/[locale]/pages/file/[id]/page';
+import { FileAnAppeal } from '@/app/actions/fileEntity';
+import { useState } from 'react';
+import { toast } from 'sonner';
+
+export function FileAppealModalWindow({ fileId, setWindowClose, setWindowChildren }: {
+ fileId: string,
+ setWindowClose: any,
+ setWindowChildren: any
+}) {
+ const t = useTranslations('Global');
+ const [appealReason, setAppealReason] = useState('');
+ const [additionalInfo, setAdditionalInfo] = useState('');
+ const [isSubmitting, setIsSubmitting] = useState(false);
+
+ const handleSubmitAppeal = async () => {
+ if (!appealReason.trim()) {
+ toast.error(t('please-enter-appeal-reason'));
+ return;
+ }
+
+ setIsSubmitting(true);
+
+ try {
+ const result = await FileAnAppeal(fileId, appealReason, additionalInfo);
+
+ if (result && result.status === 'success') {
+ toast.success(t('appeal-submitted-successfully'));
+ setWindowClose(false);
+ } else {
+ toast.error(result?.message || t('appeal-submission-failed'));
+ }
+ } catch (error) {
+ console.error('Appeal submission error:', error);
+ toast.error(t('appeal-submission-failed'));
+ } finally {
+ setIsSubmitting(false);
+ }
+ };
+
+ return (
+
+
+ {/* Форма подачи апелляции */}
+
+
+
{t('file-an-appeal')}
+
+
+
+
+ {t('appeal-reason')} *
+
+
+
+
+
+
+
{t('additional-info')}
+
+
+
+
+
+
+
+
+
+
+ );
+}
\ No newline at end of file
diff --git a/src/i18n/messages/en.json b/src/i18n/messages/en.json
index 8f12c66..166ebcf 100644
--- a/src/i18n/messages/en.json
+++ b/src/i18n/messages/en.json
@@ -480,7 +480,19 @@
"total-complaints": "Total complaints",
"total-claims": "Total claims",
"city": "City",
- "closed": "Closed"
+ "closed": "Closed",
+ "blocked": "Blocked",
+ "pending-moderation": "Pending moderation",
+ "file-an-appeal": "File an appeal",
+ "please-enter-appeal-reason": "Please enter the reason for appeal",
+ "appeal-submitted-successfully": "Appeal submitted successfully",
+ "appeal-submission-failed": "Failed to submit appeal",
+ "appeal-reason": "Reason for appeal",
+ "enter-appeal-reason": "Describe the reason for your appeal...",
+ "additional-info": "Additional information",
+ "enter-additional-info": "Any additional information that may help...",
+ "submit-appeal": "Submit appeal",
+ "submitting": "Submitting..."
},
"Login-register-form": {
"and": "and",
diff --git a/src/i18n/messages/ru.json b/src/i18n/messages/ru.json
index d310ceb..35e640b 100644
--- a/src/i18n/messages/ru.json
+++ b/src/i18n/messages/ru.json
@@ -480,7 +480,19 @@
"total-complaints": "Всего нарушений",
"total-claims": "Всего претензий",
"city": "Город",
- "closed": "Закрыта"
+ "closed": "Закрыта",
+ "blocked": "Заблокирован",
+ "pending-moderation": "На модерации",
+ "file-an-appeal": "Подать апелляцию",
+ "please-enter-appeal-reason": "Пожалуйста, укажите причину апелляции",
+ "appeal-submitted-successfully": "Апелляция успешно отправлена",
+ "appeal-submission-failed": "Не удалось отправить апелляцию",
+ "appeal-reason": "Причина апелляции",
+ "enter-appeal-reason": "Опишите причину вашей апелляции...",
+ "additional-info": "Дополнительная информация",
+ "enter-additional-info": "Любая дополнительная информация, которая может помочь...",
+ "submit-appeal": "Отправить апелляцию",
+ "submitting": "Отправка..."
},
"Login-register-form": {
"and": "и",