Compare commits

...
6 Commits
Author SHA1 Message Date
smanylov 6696cc1027 set fixed width for document view table 2026-06-08 15:16:08 +07:00
smanylov 98cb5ab09b set location column width 2026-06-08 14:37:02 +07:00
smanylov c501c2bbbf hide template interface 2026-06-08 13:27:30 +07:00
smanylov a74ea966ad hide ViolationsLastCombinedCases 2026-06-08 13:23:13 +07:00
smanylov 0a7d29419f update watch dock info endpoint 2026-06-08 13:17:23 +07:00
smanylov a9599d8a1f add more appeal information for modal window 2026-06-04 14:56:03 +07:00
11 changed files with 234 additions and 72 deletions
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "no-copy-frontend",
"version": "0.120.0",
"version": "0.122.0",
"private": true,
"scripts": {
"dev": "next dev -p 2999",
+1 -1
View File
@@ -20,7 +20,7 @@ export default function Page() {
<ViolationsStatistic />
<ViolationsCheckAllSection />
<ViolationsTable />
<ViolationsLastCombinedCases />
{/* <ViolationsLastCombinedCases /> */}
{/* <ViolationsMyComplaint />
<ViolationsMyClaims /> */}
<div className="analytics-grid">
+1
View File
@@ -43,6 +43,7 @@ interface DocumentInfo {
updatedAt?: string;
uploadSessionId?: string;
userId?: number;
appealInfos?: any[]; //Не знаю что тут будет
}
export default async function Page({ searchParams }: PageProps) {
+4 -17
View File
@@ -91,18 +91,11 @@ export async function requestFileAsBuffer(fileId: string): Promise<ArrayBuffer |
export async function fetchDocumentInfo(fileId: string) {
const token = await getSessionData('token');
console.log('fetchDocumentInfo');
try {
const response = await fetch(`${API_BASE_URL}/api/v1/data`, {
method: 'POST',
body: JSON.stringify({
version: 1,
msg_id: 20005,
message_body: {
file_id: fileId,
action: 'file_info'
}
}),
const response = await fetch(`${API_BASE_URL}/api/files/public/file-info/${fileId}`, {
method: 'GET',
headers: {
'Content-Type': 'application/json',
'Authorization': `Bearer ${token}`
@@ -111,13 +104,7 @@ export async function fetchDocumentInfo(fileId: string) {
if (response.ok) {
const parsed = await response.json();
if (parsed.message_code === 0) {
return parsed.message_body;
} else {
return null;
}
return parsed;
} else {
throw new Error(`${response.status}`);
}
@@ -68,9 +68,22 @@ type ApiFile = {
thumbnailFileUrl: string;
permissions: {
DOWNLOAD: boolean;
}
},
appealInfos: AppealInfos[];
};
export type AppealInfos = {
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;
}
type ApiResponse = {
files?: ApiFile[];
total_count: number;
@@ -709,11 +722,10 @@ export default function TanstakFilesTable({ fileType, showFileLink }: { fileType
};
const handleAppeal = async (file: FileItem) => {
console.log(file);
setOpenWindowChildren(() => {
return (
<FileAppealModalWindow fileId={file.id} setWindowClose={setOpenWindow} setWindowChildren={setOpenWindowChildren} />
<FileAppealModalWindow fileId={file.id} appeal={file._original?.appealInfos} setWindowClose={setOpenWindow} setWindowChildren={setOpenWindowChildren} />
)
})
setOpenWindow(true);
+67
View File
@@ -833,6 +833,10 @@
padding: 15px 16px;
}
}
&:has(.column-location) {
width: 250px;
}
}
.column {
@@ -906,6 +910,31 @@
}
}
&:has(.column-document) {
width: 35%;
}
&:has(.column-viewer-date) {
width: 15%;
}
&:has(.column-viewer) {
width: 25%;
}
&:has(.column-location) {
width: 25%;
}
.column-document,
.column-viewer-date,
.column-viewer,
.column-location {
/* width: 250px;
margin: 0 auto; */
overflow: hidden;
}
.table-item-file-name-image-wrapper {
width: 40px;
height: 40px;
@@ -3805,6 +3834,10 @@
min-width: 400px;
width: 100%;
&.appeal-info {
margin-bottom: 20px;
}
@media (max-width: 470px) {
min-width: auto;
}
@@ -3936,6 +3969,40 @@
opacity: 0.5;
cursor: not-allowed;
}
.appeal-info {
margin-bottom: 20px;
}
.appeal-status {
display: inline-block;
background-color: #f9fafb;
padding: 4px 12px;
border-radius: 20px;
font-size: 12px;
font-weight: 500;
}
.appeal-reason-text,
.appeal-additional-text,
.admin-comment-text {
background-color: #f9fafb;
padding: 12px;
border-radius: 6px;
line-height: 1.5;
white-space: pre-wrap;
word-wrap: break-word;
}
.appeal-warning {
margin-top: 15px;
padding: 12px;
background-color: #fef3c7;
border-left: 4px solid #d97706;
border-radius: 6px;
color: #78350f;
font-size: 14px;
}
}
}
}
@@ -158,13 +158,14 @@ export default function CaseComplaint({ selectedViolation, updateStatusHandler,
<div
className="button-actions"
>
<button
{/* пока скроем интерфейс с шаблонами */}
{/* <button
type="button"
className="btn-s btn-primary-small"
onClick={openTemplateSaveModal}
>
{t('save-template')}
</button>
</button> */}
<button
type="submit"
@@ -176,7 +177,8 @@ export default function CaseComplaint({ selectedViolation, updateStatusHandler,
</div>
</form>
</div>
<div
{/* пока скроем интерфейс с шаблонами */}
{/* <div
className="samples-wrapper"
>
<h5>Шаблоны</h5>
@@ -272,7 +274,7 @@ export default function CaseComplaint({ selectedViolation, updateStatusHandler,
</div>
</li>
</ul>
</div>
</div> */}
</div>
<ModalWindow
@@ -1,15 +1,16 @@
'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';
import { AppealInfos } from '@/app/components/tanstak-table/TanstakTable';
export function FileAppealModalWindow({ fileId, setWindowClose, setWindowChildren }: {
export function FileAppealModalWindow({ fileId, appeal, setWindowClose, setWindowChildren }: {
fileId: string,
appeal?: AppealInfos[],
setWindowClose: any,
setWindowChildren: any
}) {
@@ -17,6 +18,8 @@ export function FileAppealModalWindow({ fileId, setWindowClose, setWindowChildre
const [appealReason, setAppealReason] = useState('');
const [additionalInfo, setAdditionalInfo] = useState('');
const [isSubmitting, setIsSubmitting] = useState(false);
const existingAppeal = appeal && appeal.length > 0 ? appeal[0] : null;
const hasActiveAppeal = existingAppeal && existingAppeal.status === 'pending';
const handleSubmitAppeal = async () => {
if (!appealReason.trim()) {
@@ -49,7 +52,79 @@ export function FileAppealModalWindow({ fileId, setWindowClose, setWindowChildre
return (
<div className="modal-window-view-file">
<div className="modal-window-view-file-content">
{/* Форма подачи апелляции */}
{existingAppeal && (
<div className="file-info-card appeal-info">
<div className="info-header">
<h4>{t('appeal-information')}</h4>
</div>
<div className="info-item">
<div className="info-label">{t('appeal-status')}</div>
<div className="info-value">
<span className="appeal-status">
{existingAppeal.status}
</span>
</div>
</div>
<div className="info-item">
<div className="info-label">{t('appeal-reason')}</div>
<div className="info-value">
<div className="appeal-reason-text">
{existingAppeal.appealReason || t('not-provided')}
</div>
</div>
</div>
{existingAppeal.additionalInfo && (
<div className="info-item">
<div className="info-label">{t('additional-info')}</div>
<div className="info-value">
<div className="appeal-additional-text">
{existingAppeal.additionalInfo}
</div>
</div>
</div>
)}
{existingAppeal.createdAt && (
<div className="info-item">
<div className="info-label">{t('appeal-created-at')}</div>
<div className="info-value">
{formatDate(existingAppeal.createdAt)} {formatDateTime(existingAppeal.createdAt)}
</div>
</div>
)}
{existingAppeal.adminComment && (
<div className="info-item">
<div className="info-label">{t('admin-comment')}</div>
<div className="info-value">
<div className="admin-comment-text">
{existingAppeal.adminComment}
</div>
</div>
</div>
)}
{existingAppeal.resolvedAt && (
<div className="info-item">
<div className="info-label">{t('resolved-at')}</div>
<div className="info-value">
{formatDateTime(existingAppeal.resolvedAt)}
</div>
</div>
)}
{hasActiveAppeal && (
<div className="appeal-warning">
{t('active-appeal-pending-message')}
</div>
)}
</div>
)}
{!hasActiveAppeal && (
<div className="file-info-card appeal-form">
<div className="info-header">
<h4>{t('file-an-appeal')}</h4>
@@ -83,6 +158,8 @@ export function FileAppealModalWindow({ fileId, setWindowClose, setWindowChildre
disabled={isSubmitting}
/>
</div>
</div>
<div className="appeal-actions">
<button
className="btn btn-cancel"
@@ -100,7 +177,7 @@ export function FileAppealModalWindow({ fileId, setWindowClose, setWindowChildre
</button>
</div>
</div>
</div>
)}
</div>
</div>
);
@@ -96,9 +96,9 @@ export function TrackingHistoryView() {
return (
<div>
{t('city')}: <strong>{translatedCity}</strong>
{t('city')}: <strong title={translatedCity}>{translatedCity}</strong>
<br />
{t('country')}: <strong>{translatedCountry}</strong>
{t('country')}: <strong title={translatedCountry}>{translatedCountry}</strong>
</div>
);
}
@@ -108,7 +108,7 @@ export function TrackingHistoryView() {
{
accessorKey: 'document',
header: ({ column }) => (
<div className="column">
<div className="column column-document">
<span>
{t('document')}
</span>
@@ -133,7 +133,7 @@ export function TrackingHistoryView() {
</div>
),
cell: ({ row }) => (
<div className="text-center table-item">
<div className="text-center table-item column-document">
{row.original.document}
</div>
),
@@ -141,7 +141,7 @@ export function TrackingHistoryView() {
{
accessorKey: 'view_date',
header: ({ column }) => (
<div className="column">
<div className="column column-viewer-date">
<span>
{t('date')} / {t('time')}
</span>
@@ -167,7 +167,7 @@ export function TrackingHistoryView() {
),
cell: ({ row }) => {
return (
<div className="text-center table-item">
<div className="text-center table-item column-viewer-date">
{row.original.view_date ? (
<>
{formatDate(row.original.view_date)}
@@ -186,7 +186,7 @@ export function TrackingHistoryView() {
{
accessorKey: 'viewer',
header: ({ column }) => (
<div className="column">
<div className="column column-viewer">
<span>
{t('who-opened')}
</span>
@@ -212,7 +212,7 @@ export function TrackingHistoryView() {
),
cell: ({ row }) => {
return (
<div className="text-center font-semibold table-item">
<div className="text-center font-semibold table-item column-viewer">
{row.original.viewer}
</div>
)
@@ -247,7 +247,7 @@ export function TrackingHistoryView() {
),
cell: ({ row }) => {
return (
<div className="text-center font-semibold table-item">
<div className="text-center font-semibold table-item column-location">
{row.original.country === 'unknow/unknow' ? (
t('not-defined')
) : (
@@ -260,7 +260,7 @@ export function TrackingHistoryView() {
],
[]
);
/* `${editLocationName(row.original.country)}` */
// Создание таблицы
const table = useReactTable({
data: tableData,
+9 -1
View File
@@ -493,7 +493,15 @@
"enter-additional-info": "Any additional information that may help...",
"submit-appeal": "Submit appeal",
"submitting": "Submitting...",
"active-appeal-already-exists-for-this-file": "Active appeal already exists for this file"
"active-appeal-already-exists-for-this-file": "Active appeal already exists for this file",
"appeal-information": "Appeal Information",
"appeal-status": "Status",
"appeal-created-at": "Created at",
"appeal-resolution": "Appeal Resolution",
"not-provided": "Not provided",
"admin-comment": "Admin Comment",
"resolved-at": "Resolved at",
"active-appeal-pending-message": "You have an active appeal pending review. Please wait for the admin to respond."
},
"Login-register-form": {
"and": "and",
+9 -1
View File
@@ -493,7 +493,15 @@
"enter-additional-info": "Любая дополнительная информация, которая может помочь...",
"submit-appeal": "Отправить апелляцию",
"submitting": "Отправка...",
"active-appeal-already-exists-for-this-file": "По данному делу уже подана активная апелляция"
"active-appeal-already-exists-for-this-file": "По данному делу уже подана активная апелляция",
"appeal-information": "Информация об апелляции",
"appeal-status": "Статус",
"appeal-created-at": "Дата создания",
"appeal-resolution": "Результат апелляции",
"not-provided": "Не указано",
"admin-comment": "Комментарий администратора",
"resolved-at": "Дата решения",
"active-appeal-pending-message": "У вас есть активная апелляция на рассмотрении. Пожалуйста, дождитесь ответа администратора."
},
"Login-register-form": {
"and": "и",