Compare commits
58
Commits
d419c1c2cb
..
main
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
6696cc1027 | ||
|
|
98cb5ab09b | ||
|
|
c501c2bbbf | ||
|
|
a74ea966ad | ||
|
|
0a7d29419f | ||
|
|
a9599d8a1f | ||
|
|
cbc1311e9d | ||
|
|
587d7ceead | ||
|
|
ac8ef8caa2 | ||
|
|
7d0fb265d4 | ||
|
|
743db57bb3 | ||
|
|
d7d2e36573 | ||
|
|
8b157b8e87 | ||
|
|
0935e8cbc7 | ||
|
|
f04ce348ae | ||
|
|
508e0d182c | ||
|
|
dbd5d43d65 | ||
|
|
7d8a725e34 | ||
|
|
491adb4090 | ||
|
|
1a3f5277d9 | ||
|
|
ffcd5fc535 | ||
|
|
65e0c2ed62 | ||
|
|
36b4a3b481 | ||
|
|
e0455b200a | ||
|
|
348a5398d0 | ||
|
|
af87bfc7b6 | ||
|
|
beefe86ffd | ||
|
|
3a7c609588 | ||
|
|
aeeee04166 | ||
|
|
288d6782a4 | ||
|
|
55915af9df | ||
|
|
bfc457470c | ||
|
|
210145f5ca | ||
|
|
d0793a281e | ||
|
|
6994edd216 | ||
|
|
3a0ae93846 | ||
|
|
13a5db6313 | ||
|
|
9c011b6416 | ||
|
|
294e16e1a6 | ||
|
|
71f7120239 | ||
|
|
0e28986dc7 | ||
|
|
51a3ed7d18 | ||
|
|
c15867a41c | ||
|
|
c4e4d775f5 | ||
|
|
cd07502128 | ||
|
|
1ef2cc227a | ||
|
|
7226285746 | ||
|
|
dd93cd302c | ||
|
|
37b7ccb52e | ||
|
|
b8a76bd6a9 | ||
|
|
07e1237f05 | ||
|
|
29546740c7 | ||
|
|
42cc96a28a | ||
|
|
84b07af246 | ||
|
|
8a72dbaf68 | ||
|
|
af6b997ceb | ||
|
|
e97dd392c0 | ||
|
|
ae0526a58a |
+1
-1
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "no-copy-frontend",
|
"name": "no-copy-frontend",
|
||||||
"version": "0.107.0",
|
"version": "0.122.0",
|
||||||
"private": true,
|
"private": true,
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"dev": "next dev -p 2999",
|
"dev": "next dev -p 2999",
|
||||||
|
|||||||
@@ -1,9 +1,10 @@
|
|||||||
import Providers from '@/app/providers/getQueryServer'
|
|
||||||
import type { Metadata } from "next";
|
import type { Metadata } from "next";
|
||||||
import { NextIntlClientProvider, hasLocale } from 'next-intl';
|
import { NextIntlClientProvider, hasLocale } from 'next-intl';
|
||||||
import { notFound } from 'next/navigation';
|
import { notFound } from 'next/navigation';
|
||||||
import { routing } from '@/i18n/routing';
|
import { routing } from '@/i18n/routing';
|
||||||
import { ToastProvider } from '@/app/providers/ToastProvider';
|
import { ToastProvider } from '@/app/providers/ToastProvider';
|
||||||
|
import Providers from '@/app/providers/getQueryServer';
|
||||||
|
import { Suspense } from 'react';
|
||||||
|
|
||||||
import "../styles/globals.css";
|
import "../styles/globals.css";
|
||||||
import "../styles/global-styles.scss";
|
import "../styles/global-styles.scss";
|
||||||
@@ -30,9 +31,9 @@ export default async function RootLayout({
|
|||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<html lang={locale}>
|
<html>
|
||||||
<body>
|
<body>
|
||||||
<NextIntlClientProvider>
|
<NextIntlClientProvider locale={locale}>
|
||||||
<Providers>
|
<Providers>
|
||||||
{children}
|
{children}
|
||||||
<ToastProvider />
|
<ToastProvider />
|
||||||
|
|||||||
@@ -48,7 +48,7 @@ export interface FileDetails {
|
|||||||
|
|
||||||
interface PageProps {
|
interface PageProps {
|
||||||
params: Promise<{ id: string }>;
|
params: Promise<{ id: string }>;
|
||||||
searchParams: Promise<{ page?: string, status?: string , violationId?: string, caseType?: 'complaint' | 'claim'}>;
|
searchParams: Promise<{ page?: string, status?: string, violationId?: string, caseType?: 'complaint' | 'claim', startDate: string, endDate: string }>;
|
||||||
}
|
}
|
||||||
|
|
||||||
export default async function Page({
|
export default async function Page({
|
||||||
@@ -56,7 +56,7 @@ export default async function Page({
|
|||||||
searchParams
|
searchParams
|
||||||
}: PageProps) {
|
}: PageProps) {
|
||||||
const { id } = await params;
|
const { id } = await params;
|
||||||
const { page, status, violationId, caseType } = await searchParams;
|
const { page, status, violationId, caseType, startDate, endDate } = await searchParams;
|
||||||
const currentPage = Number(page) || 1;
|
const currentPage = Number(page) || 1;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
@@ -71,7 +71,7 @@ export default async function Page({
|
|||||||
>
|
>
|
||||||
<FilePageFileInfo fileInfo={fileInfo} />
|
<FilePageFileInfo fileInfo={fileInfo} />
|
||||||
{/* <FilePageActions /> */}
|
{/* <FilePageActions /> */}
|
||||||
<ViolationPpageFileStatistic />
|
<ViolationPpageFileStatistic id={id} />
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<FilePageViolationsList
|
<FilePageViolationsList
|
||||||
@@ -80,6 +80,8 @@ export default async function Page({
|
|||||||
fileId={id}
|
fileId={id}
|
||||||
violationId={violationId}
|
violationId={violationId}
|
||||||
caseType={caseType}
|
caseType={caseType}
|
||||||
|
startDate={startDate}
|
||||||
|
endDate={endDate}
|
||||||
/>
|
/>
|
||||||
{/* <FilePageNote /> */}
|
{/* <FilePageNote /> */}
|
||||||
{/* <FilePageViolationInfo /> */}
|
{/* <FilePageViolationInfo /> */}
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
import { TrackingStatistic } from '@/app/ui/tracking-page/tracking-statistic';
|
import { TrackingStatistic } from '@/app/ui/tracking-page/tracking-statistic';
|
||||||
import FilesTable from '@/app/ui/dashboard/files-table';
|
import FilesTable from '@/app/ui/dashboard/files-table';
|
||||||
|
import { TrackingHistoryView } from '@/app/ui/tracking-page/tracking-history-view';
|
||||||
|
|
||||||
export default async function Page() {
|
export default async function Page() {
|
||||||
const FILE_TYPE = "document";
|
const FILE_TYPE = "document";
|
||||||
@@ -12,6 +13,7 @@ export default async function Page() {
|
|||||||
>
|
>
|
||||||
<TrackingStatistic />
|
<TrackingStatistic />
|
||||||
<FilesTable fileType={FILE_TYPE} showFileLink={true} />
|
<FilesTable fileType={FILE_TYPE} showFileLink={true} />
|
||||||
|
<TrackingHistoryView />
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -20,7 +20,7 @@ export default function Page() {
|
|||||||
<ViolationsStatistic />
|
<ViolationsStatistic />
|
||||||
<ViolationsCheckAllSection />
|
<ViolationsCheckAllSection />
|
||||||
<ViolationsTable />
|
<ViolationsTable />
|
||||||
<ViolationsLastCombinedCases />
|
{/* <ViolationsLastCombinedCases /> */}
|
||||||
{/* <ViolationsMyComplaint />
|
{/* <ViolationsMyComplaint />
|
||||||
<ViolationsMyClaims /> */}
|
<ViolationsMyClaims /> */}
|
||||||
<div className="analytics-grid">
|
<div className="analytics-grid">
|
||||||
|
|||||||
@@ -1,9 +1,14 @@
|
|||||||
|
'use client'
|
||||||
|
|
||||||
import { PdfProvider } from '@/app/contexts/PdfContext';
|
import { PdfProvider } from '@/app/contexts/PdfContext';
|
||||||
|
import { WatchDocProviders } from '@/app/providers/WatchDocProviders';
|
||||||
|
|
||||||
export default function RootLayout({ children }: { children: React.ReactNode }) {
|
export default function RootLayout({ children }: { children: React.ReactNode }) {
|
||||||
return (
|
return (
|
||||||
<PdfProvider>
|
<WatchDocProviders>
|
||||||
{children}
|
<PdfProvider>
|
||||||
</PdfProvider>
|
{children}
|
||||||
|
</PdfProvider>
|
||||||
|
</WatchDocProviders>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -43,6 +43,7 @@ interface DocumentInfo {
|
|||||||
updatedAt?: string;
|
updatedAt?: string;
|
||||||
uploadSessionId?: string;
|
uploadSessionId?: string;
|
||||||
userId?: number;
|
userId?: number;
|
||||||
|
appealInfos?: any[]; //Не знаю что тут будет
|
||||||
}
|
}
|
||||||
|
|
||||||
export default async function Page({ searchParams }: PageProps) {
|
export default async function Page({ searchParams }: PageProps) {
|
||||||
@@ -57,7 +58,7 @@ export default async function Page({ searchParams }: PageProps) {
|
|||||||
error = 'Не удалось загрузить информацию о документе';
|
error = 'Не удалось загрузить информацию о документе';
|
||||||
}
|
}
|
||||||
|
|
||||||
const documentTitle = title || 'FileName';
|
const documentTitle = response?.fileName || 'FileName';
|
||||||
|
|
||||||
if (error || !response) {
|
if (error || !response) {
|
||||||
return (
|
return (
|
||||||
@@ -119,7 +120,7 @@ export default async function Page({ searchParams }: PageProps) {
|
|||||||
|
|
||||||
<div className="watch-doc-actions">
|
<div className="watch-doc-actions">
|
||||||
{response?.permissions?.DOWNLOAD && (
|
{response?.permissions?.DOWNLOAD && (
|
||||||
<DownloadButton />
|
<DownloadButton fileId={docid} fileName={response?.fileName}/>
|
||||||
)}
|
)}
|
||||||
<CopyLinkButton />
|
<CopyLinkButton />
|
||||||
</div>
|
</div>
|
||||||
@@ -132,6 +133,7 @@ export default async function Page({ searchParams }: PageProps) {
|
|||||||
<PdfViewer
|
<PdfViewer
|
||||||
fileId={docid}
|
fileId={docid}
|
||||||
fileName={documentTitle}
|
fileName={documentTitle}
|
||||||
|
showDownload={response.permissions?.DOWNLOAD}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -44,12 +44,12 @@ export async function getUserFilesInfo() {
|
|||||||
msg_id: 20005,
|
msg_id: 20005,
|
||||||
message_body: {
|
message_body: {
|
||||||
action: 'user_files_info',
|
action: 'user_files_info',
|
||||||
token: token
|
|
||||||
}
|
}
|
||||||
}),
|
}),
|
||||||
headers: {
|
headers: {
|
||||||
'Content-Type': 'application/json',
|
'Content-Type': 'application/json',
|
||||||
'Accept': 'application/json'
|
'Accept': 'application/json',
|
||||||
|
'Authorization': `Bearer ${token}`
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -81,13 +81,13 @@ export async function fetchTariffs(tariffTerm: 'MONTHLY' | 'YEAR') {
|
|||||||
msg_id: 30001,
|
msg_id: 30001,
|
||||||
message_body: {
|
message_body: {
|
||||||
action: 'get',
|
action: 'get',
|
||||||
user_token: token,
|
|
||||||
tariff_term: tariffTerm
|
tariff_term: tariffTerm
|
||||||
}
|
}
|
||||||
}),
|
}),
|
||||||
headers: {
|
headers: {
|
||||||
'Content-Type': 'application/json',
|
'Content-Type': 'application/json',
|
||||||
'Accept': 'application/json'
|
'Accept': 'application/json',
|
||||||
|
'Authorization': `Bearer ${token}`
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -108,6 +108,7 @@ export async function fetchTariffs(tariffTerm: 'MONTHLY' | 'YEAR') {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export async function fetchTokensBundle() {
|
export async function fetchTokensBundle() {
|
||||||
|
const token = await getSessionData('token');
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const response = await fetch(`${API_BASE_URL}/api/v1/data`, {
|
const response = await fetch(`${API_BASE_URL}/api/v1/data`, {
|
||||||
@@ -122,7 +123,8 @@ export async function fetchTokensBundle() {
|
|||||||
}),
|
}),
|
||||||
headers: {
|
headers: {
|
||||||
'Content-Type': 'application/json',
|
'Content-Type': 'application/json',
|
||||||
'Accept': 'application/json'
|
'Accept': 'application/json',
|
||||||
|
'Authorization': `Bearer ${token}`
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -143,6 +145,7 @@ export async function fetchTokensBundle() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export async function getBuildData() {
|
export async function getBuildData() {
|
||||||
|
const token = await getSessionData('token');
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const response = await fetch(`${API_BASE_URL}/check/api/build`, {
|
const response = await fetch(`${API_BASE_URL}/check/api/build`, {
|
||||||
@@ -150,6 +153,7 @@ export async function getBuildData() {
|
|||||||
headers: {
|
headers: {
|
||||||
'Content-Type': 'application/json',
|
'Content-Type': 'application/json',
|
||||||
'Accept': 'application/json',
|
'Accept': 'application/json',
|
||||||
|
'Authorization': `Bearer ${token}`
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -165,7 +169,7 @@ export async function getBuildData() {
|
|||||||
|
|
||||||
export async function fetchINN(inn: string) {
|
export async function fetchINN(inn: string) {
|
||||||
try {
|
try {
|
||||||
const response = await fetch(`${API_BASE_URL}/api/v1/data`, {
|
const response = await fetch(`${API_BASE_URL}/api/auth`, {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
body: JSON.stringify({
|
body: JSON.stringify({
|
||||||
version: 1,
|
version: 1,
|
||||||
|
|||||||
+9
-12
@@ -72,7 +72,7 @@ export async function authorization(
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
const { email, password } = validatedFields.data;
|
const { email, password } = validatedFields.data;
|
||||||
const response = await fetch(`${API_BASE_URL}/api/v1/data`, {
|
const response = await fetch(`${API_BASE_URL}/api/auth`, {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
body: JSON.stringify({
|
body: JSON.stringify({
|
||||||
version: 1,
|
version: 1,
|
||||||
@@ -89,6 +89,7 @@ export async function authorization(
|
|||||||
});
|
});
|
||||||
if (response.ok) {
|
if (response.ok) {
|
||||||
let parsed = await response.json();
|
let parsed = await response.json();
|
||||||
|
|
||||||
if (parsed.message_code === 0) {
|
if (parsed.message_code === 0) {
|
||||||
await createSession(parsed.message_body.token, email);
|
await createSession(parsed.message_body.token, email);
|
||||||
} else {
|
} else {
|
||||||
@@ -234,7 +235,7 @@ export async function registration(
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
const { fullName, email, password, phone } = validatedFields.data;
|
const { fullName, email, password, phone } = validatedFields.data;
|
||||||
const response = await fetch(`${API_BASE_URL}/api/v1/data`, {
|
const response = await fetch(`${API_BASE_URL}/api/auth`, {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
body: JSON.stringify({
|
body: JSON.stringify({
|
||||||
version: 1,
|
version: 1,
|
||||||
@@ -400,13 +401,11 @@ export async function tokenLifeExtension() {
|
|||||||
headers: {
|
headers: {
|
||||||
'Content-Type': 'application/json',
|
'Content-Type': 'application/json',
|
||||||
'Accept': 'application/json',
|
'Accept': 'application/json',
|
||||||
|
'Authorization': `Bearer ${token}`,
|
||||||
},
|
},
|
||||||
body: JSON.stringify({
|
body: JSON.stringify({
|
||||||
version: 1,
|
version: 1,
|
||||||
msg_id: 20008,
|
msg_id: 20008
|
||||||
message_body: {
|
|
||||||
token: token
|
|
||||||
}
|
|
||||||
}),
|
}),
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -431,14 +430,14 @@ export async function confirmEmail(userId: number, verifyToken: string) {
|
|||||||
headers: {
|
headers: {
|
||||||
"Content-Type": "application/json",
|
"Content-Type": "application/json",
|
||||||
"Accept": "application/json",
|
"Accept": "application/json",
|
||||||
|
'Authorization': `Bearer ${verifyToken}`,
|
||||||
},
|
},
|
||||||
body: JSON.stringify({
|
body: JSON.stringify({
|
||||||
version: 1,
|
version: 1,
|
||||||
msg_id: 20009,
|
msg_id: 20009,
|
||||||
message_body: {
|
message_body: {
|
||||||
resend: 0,
|
resend: 0,
|
||||||
user_id: userId,
|
user_id: userId
|
||||||
verify_token: verifyToken
|
|
||||||
}
|
}
|
||||||
}),
|
}),
|
||||||
});
|
});
|
||||||
@@ -474,7 +473,6 @@ export async function confirmEmail(userId: number, verifyToken: string) {
|
|||||||
export async function resendConfirmEmail(userId: number) {
|
export async function resendConfirmEmail(userId: number) {
|
||||||
console.log('resendConfirmEmail');
|
console.log('resendConfirmEmail');
|
||||||
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const response = await fetch(`${API_BASE_URL}/api/v1/data`, {
|
const response = await fetch(`${API_BASE_URL}/api/v1/data`, {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
@@ -524,10 +522,9 @@ export async function resetPassword(
|
|||||||
formData: FormData,
|
formData: FormData,
|
||||||
) {
|
) {
|
||||||
const email = formData.get('email');
|
const email = formData.get('email');
|
||||||
console.log('resetPassword');
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const response = await fetch(`${API_BASE_URL}/api/v1/data`, {
|
const response = await fetch(`${API_BASE_URL}/api/auth`, {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
headers: {
|
headers: {
|
||||||
'Content-Type': 'application/json',
|
'Content-Type': 'application/json',
|
||||||
@@ -611,6 +608,7 @@ export async function confirmPassword(
|
|||||||
headers: {
|
headers: {
|
||||||
'Content-Type': 'application/json',
|
'Content-Type': 'application/json',
|
||||||
'Accept': 'application/json',
|
'Accept': 'application/json',
|
||||||
|
'Authorization': `Bearer ${verifyToken}`
|
||||||
},
|
},
|
||||||
body: JSON.stringify({
|
body: JSON.stringify({
|
||||||
version: 1,
|
version: 1,
|
||||||
@@ -618,7 +616,6 @@ export async function confirmPassword(
|
|||||||
message_body: {
|
message_body: {
|
||||||
email: email,
|
email: email,
|
||||||
password: password,
|
password: password,
|
||||||
verifyToken: verifyToken,
|
|
||||||
action: "confirmVerification"
|
action: "confirmVerification"
|
||||||
}
|
}
|
||||||
}),
|
}),
|
||||||
|
|||||||
@@ -95,7 +95,6 @@ export async function companyUserRegistration(
|
|||||||
phone: phone,
|
phone: phone,
|
||||||
password,
|
password,
|
||||||
accountType: 'b2b',
|
accountType: 'b2b',
|
||||||
authToken: token,
|
|
||||||
mail_verified: false,
|
mail_verified: false,
|
||||||
ip: ip,
|
ip: ip,
|
||||||
user_agent: userAgent,
|
user_agent: userAgent,
|
||||||
@@ -103,7 +102,8 @@ export async function companyUserRegistration(
|
|||||||
}),
|
}),
|
||||||
headers: {
|
headers: {
|
||||||
'Content-Type': 'application/json',
|
'Content-Type': 'application/json',
|
||||||
'Accept': 'application/json'
|
'Accept': 'application/json',
|
||||||
|
'Authorization': `Bearer ${token}`
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -113,14 +113,6 @@ export async function companyUserRegistration(
|
|||||||
message_body: { token: string },
|
message_body: { token: string },
|
||||||
message_code: number
|
message_code: number
|
||||||
};
|
};
|
||||||
console.log({
|
|
||||||
fullName: fullName,
|
|
||||||
email,
|
|
||||||
phone: phone,
|
|
||||||
password,
|
|
||||||
accountType: 'b2b',
|
|
||||||
authToken: token
|
|
||||||
});
|
|
||||||
|
|
||||||
if (parsed.message_code === 0) {
|
if (parsed.message_code === 0) {
|
||||||
console.log(`registration - ${email}`);
|
console.log(`registration - ${email}`);
|
||||||
|
|||||||
@@ -31,7 +31,6 @@ export async function getUserFilesData({
|
|||||||
msg_id: 20005,
|
msg_id: 20005,
|
||||||
message_body: {
|
message_body: {
|
||||||
action: 'search_files',
|
action: 'search_files',
|
||||||
token: token,
|
|
||||||
page: page,
|
page: page,
|
||||||
page_size: pageSize,
|
page_size: pageSize,
|
||||||
query: query,
|
query: query,
|
||||||
@@ -43,7 +42,8 @@ export async function getUserFilesData({
|
|||||||
}),
|
}),
|
||||||
headers: {
|
headers: {
|
||||||
'Content-Type': 'application/json',
|
'Content-Type': 'application/json',
|
||||||
'Accept': 'application/json'
|
'Accept': 'application/json',
|
||||||
|
'Authorization': `Bearer ${token}`
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -77,12 +77,12 @@ export async function removeUserFile(fileId: string, fullDelete: number) {
|
|||||||
action: 'delete_file',
|
action: 'delete_file',
|
||||||
file_id: fileId,
|
file_id: fileId,
|
||||||
full_delete: fullDelete,
|
full_delete: fullDelete,
|
||||||
token: token
|
|
||||||
}
|
}
|
||||||
}),
|
}),
|
||||||
headers: {
|
headers: {
|
||||||
'Content-Type': 'application/json',
|
'Content-Type': 'application/json',
|
||||||
'Accept': 'application/json'
|
'Accept': 'application/json',
|
||||||
|
'Authorization': `Bearer ${token}`
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -114,13 +114,13 @@ export async function viewFileInfo(fileId: string) {
|
|||||||
msg_id: 20005,
|
msg_id: 20005,
|
||||||
message_body: {
|
message_body: {
|
||||||
action: 'file_info',
|
action: 'file_info',
|
||||||
file_id: fileId,
|
file_id: fileId
|
||||||
token: token
|
|
||||||
}
|
}
|
||||||
}),
|
}),
|
||||||
headers: {
|
headers: {
|
||||||
'Content-Type': 'application/json',
|
'Content-Type': 'application/json',
|
||||||
'Accept': 'application/json'
|
'Accept': 'application/json',
|
||||||
|
'Authorization': `Bearer ${token}`
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -163,3 +163,43 @@ export async function downloadFile(fileId: string, fileName: string) {
|
|||||||
fileName: fileName
|
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,
|
||||||
|
appeal_reason: appealReason,
|
||||||
|
additional_info: additionalInfo
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
'Accept': 'application/json',
|
||||||
|
'Authorization': `Bearer ${token}`
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
if (response.ok) {
|
||||||
|
let parsed = await response.json();
|
||||||
|
|
||||||
|
if (parsed.message_code === 0) {
|
||||||
|
return parsed;
|
||||||
|
} else {
|
||||||
|
throw parsed;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
throw (`${response.status}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
} catch (error) {
|
||||||
|
return error
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -2,8 +2,6 @@
|
|||||||
|
|
||||||
import { API_BASE_URL } from '@/app/actions/definitions';
|
import { API_BASE_URL } from '@/app/actions/definitions';
|
||||||
import { getSessionData } from '@/app/actions/session';
|
import { getSessionData } from '@/app/actions/session';
|
||||||
import { FormState } from '@/app/actions/auth';
|
|
||||||
import { unknown } from 'zod';
|
|
||||||
|
|
||||||
interface initMessageBody {
|
interface initMessageBody {
|
||||||
file_name: string,
|
file_name: string,
|
||||||
@@ -22,7 +20,6 @@ export async function fileUpload(messageBody: initMessageBody, convertTo?: strin
|
|||||||
}
|
}
|
||||||
const message = messageBody;
|
const message = messageBody;
|
||||||
message.action = 'init';
|
message.action = 'init';
|
||||||
message.token = token;
|
|
||||||
|
|
||||||
if (convertTo && convertTo !== 'reject') {
|
if (convertTo && convertTo !== 'reject') {
|
||||||
message.convertTo = convertTo;
|
message.convertTo = convertTo;
|
||||||
@@ -38,7 +35,8 @@ export async function fileUpload(messageBody: initMessageBody, convertTo?: strin
|
|||||||
}),
|
}),
|
||||||
headers: {
|
headers: {
|
||||||
'Content-Type': 'application/json',
|
'Content-Type': 'application/json',
|
||||||
'Accept': 'application/json'
|
'Accept': 'application/json',
|
||||||
|
'Authorization': `Bearer ${token}`
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -68,6 +66,8 @@ export async function fileUpload(messageBody: initMessageBody, convertTo?: strin
|
|||||||
}
|
}
|
||||||
|
|
||||||
export async function cancelUpload(udloadId: string) {
|
export async function cancelUpload(udloadId: string) {
|
||||||
|
const token = await getSessionData('token');
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const response = await fetch(`${API_BASE_URL}/api/v1/data`, {
|
const response = await fetch(`${API_BASE_URL}/api/v1/data`, {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
@@ -81,7 +81,8 @@ export async function cancelUpload(udloadId: string) {
|
|||||||
}),
|
}),
|
||||||
headers: {
|
headers: {
|
||||||
'Content-Type': 'application/json',
|
'Content-Type': 'application/json',
|
||||||
'Accept': 'application/json'
|
'Accept': 'application/json',
|
||||||
|
'Authorization': `Bearer ${token}`
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -114,7 +115,6 @@ export type ChunkResponse = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export async function chunkUpload(formData: FormData, itPrivate?: boolean): Promise<ChunkResponse> {
|
export async function chunkUpload(formData: FormData, itPrivate?: boolean): Promise<ChunkResponse> {
|
||||||
console.log('chunkUpload');
|
|
||||||
const token = await getSessionData('token');
|
const token = await getSessionData('token');
|
||||||
|
|
||||||
try {
|
try {
|
||||||
@@ -123,19 +123,21 @@ export async function chunkUpload(formData: FormData, itPrivate?: boolean): Prom
|
|||||||
: `${API_BASE_URL}/api/v1/files/chunk`;
|
: `${API_BASE_URL}/api/v1/files/chunk`;
|
||||||
|
|
||||||
|
|
||||||
if (token && itPrivate) {
|
/* if (token && itPrivate) {
|
||||||
formData.append('token', token);
|
formData.append('token', token);
|
||||||
}
|
} */
|
||||||
|
|
||||||
const response = await fetch(url, {
|
const response = await fetch(url, {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
body: formData
|
body: formData,
|
||||||
|
headers: {
|
||||||
|
'Authorization': `Bearer ${token}`
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
/* ...(token && itPrivate && { 'Authorization': `Bearer ${token}` }) возможно нужно будет условно отправлять токен*/
|
||||||
|
|
||||||
if (response.ok) {
|
if (response.ok) {
|
||||||
let parsed = await response.json();
|
let parsed = await response.json();
|
||||||
console.log(formData);
|
|
||||||
console.log(parsed);
|
|
||||||
|
|
||||||
if (parsed.message_code === 0) {
|
if (parsed.message_code === 0) {
|
||||||
return {
|
return {
|
||||||
@@ -171,6 +173,8 @@ export async function chunkUpload(formData: FormData, itPrivate?: boolean): Prom
|
|||||||
}
|
}
|
||||||
|
|
||||||
export async function checkChunkStatus(upload_id: string) {
|
export async function checkChunkStatus(upload_id: string) {
|
||||||
|
const token = await getSessionData('token');
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const response = await fetch(`${API_BASE_URL}/api/v1/data`, {
|
const response = await fetch(`${API_BASE_URL}/api/v1/data`, {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
@@ -184,7 +188,8 @@ export async function checkChunkStatus(upload_id: string) {
|
|||||||
}),
|
}),
|
||||||
headers: {
|
headers: {
|
||||||
'Content-Type': 'application/json',
|
'Content-Type': 'application/json',
|
||||||
'Accept': 'application/json'
|
'Accept': 'application/json',
|
||||||
|
'Authorization': `Bearer ${token}`
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -206,6 +211,8 @@ export async function checkChunkStatus(upload_id: string) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export async function getAllowedFilesExtensions(type: string) {
|
export async function getAllowedFilesExtensions(type: string) {
|
||||||
|
const token = await getSessionData('token');
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const response = await fetch(`${API_BASE_URL}/api/v1/data`, {
|
const response = await fetch(`${API_BASE_URL}/api/v1/data`, {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
@@ -219,7 +226,8 @@ export async function getAllowedFilesExtensions(type: string) {
|
|||||||
}),
|
}),
|
||||||
headers: {
|
headers: {
|
||||||
'Content-Type': 'application/json',
|
'Content-Type': 'application/json',
|
||||||
'Accept': 'application/json'
|
'Accept': 'application/json',
|
||||||
|
'Authorization': `Bearer ${token}`
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -250,7 +258,6 @@ export async function checkOperationPrice(action: string, filesCount: number, fi
|
|||||||
version: 1,
|
version: 1,
|
||||||
msg_id: 30008,
|
msg_id: 30008,
|
||||||
message_body: {
|
message_body: {
|
||||||
auth_token: token,
|
|
||||||
action: action,
|
action: action,
|
||||||
file_type: fileType,
|
file_type: fileType,
|
||||||
count_files: filesCount
|
count_files: filesCount
|
||||||
@@ -258,7 +265,8 @@ export async function checkOperationPrice(action: string, filesCount: number, fi
|
|||||||
}),
|
}),
|
||||||
headers: {
|
headers: {
|
||||||
'Content-Type': 'application/json',
|
'Content-Type': 'application/json',
|
||||||
'Accept': 'application/json'
|
'Accept': 'application/json',
|
||||||
|
'Authorization': `Bearer ${token}`
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -14,13 +14,13 @@ export async function setMonitoring(fileId: string, monitoringType: string) {
|
|||||||
msg_id: 30007,
|
msg_id: 30007,
|
||||||
message_body: {
|
message_body: {
|
||||||
monitoring_type: monitoringType,
|
monitoring_type: monitoringType,
|
||||||
file_id: fileId,
|
file_id: fileId
|
||||||
auth_token: token
|
|
||||||
}
|
}
|
||||||
}),
|
}),
|
||||||
headers: {
|
headers: {
|
||||||
'Content-Type': 'application/json',
|
'Content-Type': 'application/json',
|
||||||
'Accept': 'application/json'
|
'Accept': 'application/json',
|
||||||
|
'Authorization': `Bearer ${token}`
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -65,14 +65,12 @@ export async function fetchMonitoringStats(): Promise<MonitoringStats | null> {
|
|||||||
method: 'POST',
|
method: 'POST',
|
||||||
body: JSON.stringify({
|
body: JSON.stringify({
|
||||||
version: 1,
|
version: 1,
|
||||||
msg_id: 30011,
|
msg_id: 30011
|
||||||
message_body: {
|
|
||||||
token: token
|
|
||||||
}
|
|
||||||
}),
|
}),
|
||||||
headers: {
|
headers: {
|
||||||
'Content-Type': 'application/json',
|
'Content-Type': 'application/json',
|
||||||
'Accept': 'application/json'
|
'Accept': 'application/json',
|
||||||
|
'Authorization': `Bearer ${token}`
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -99,13 +97,13 @@ export async function fetchLastMonitoringCheck() {
|
|||||||
version: 1,
|
version: 1,
|
||||||
msg_id: 30011,
|
msg_id: 30011,
|
||||||
message_body: {
|
message_body: {
|
||||||
token: token,
|
|
||||||
limit: 1
|
limit: 1
|
||||||
}
|
}
|
||||||
}),
|
}),
|
||||||
headers: {
|
headers: {
|
||||||
'Content-Type': 'application/json',
|
'Content-Type': 'application/json',
|
||||||
'Accept': 'application/json'
|
'Accept': 'application/json',
|
||||||
|
'Authorization': `Bearer ${token}`
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -114,6 +112,8 @@ export async function fetchLastMonitoringCheck() {
|
|||||||
|
|
||||||
if (parsed?.message_body?.searches_by_status) {
|
if (parsed?.message_body?.searches_by_status) {
|
||||||
return parsed.message_body;
|
return parsed.message_body;
|
||||||
|
} else {
|
||||||
|
return null
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
@@ -129,14 +129,12 @@ export async function fetchMonitoringInfo() {
|
|||||||
method: 'POST',
|
method: 'POST',
|
||||||
body: JSON.stringify({
|
body: JSON.stringify({
|
||||||
version: 1,
|
version: 1,
|
||||||
msg_id: 30027,
|
msg_id: 30027
|
||||||
message_body: {
|
|
||||||
authToken: token
|
|
||||||
}
|
|
||||||
}),
|
}),
|
||||||
headers: {
|
headers: {
|
||||||
'Content-Type': 'application/json',
|
'Content-Type': 'application/json',
|
||||||
'Accept': 'application/json'
|
'Accept': 'application/json',
|
||||||
|
'Authorization': `Bearer ${token}`
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -8,7 +8,8 @@ export interface NotificationBody {
|
|||||||
id: number,
|
id: number,
|
||||||
message: string,
|
message: string,
|
||||||
status: string | null,
|
status: string | null,
|
||||||
type: string
|
type: string,
|
||||||
|
context: Record<string, string>
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function fetchActiveNotifications() {
|
export async function fetchActiveNotifications() {
|
||||||
@@ -21,13 +22,13 @@ export async function fetchActiveNotifications() {
|
|||||||
version: 1,
|
version: 1,
|
||||||
msg_id: 30015,
|
msg_id: 30015,
|
||||||
message_body: {
|
message_body: {
|
||||||
action: 'active',
|
action: 'active'
|
||||||
authToken: token,
|
|
||||||
}
|
}
|
||||||
}),
|
}),
|
||||||
headers: {
|
headers: {
|
||||||
'Content-Type': 'application/json',
|
'Content-Type': 'application/json',
|
||||||
'Accept': 'application/json'
|
'Accept': 'application/json',
|
||||||
|
'Authorization': `Bearer ${token}`
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -58,7 +59,6 @@ export async function fetchAllNotifications(page: number = 0, size: number = 10)
|
|||||||
msg_id: 30015,
|
msg_id: 30015,
|
||||||
message_body: {
|
message_body: {
|
||||||
action: 'list',
|
action: 'list',
|
||||||
authToken: token,
|
|
||||||
page: page,
|
page: page,
|
||||||
size: size,
|
size: size,
|
||||||
sortBy: "createdAt",
|
sortBy: "createdAt",
|
||||||
@@ -69,7 +69,8 @@ export async function fetchAllNotifications(page: number = 0, size: number = 10)
|
|||||||
}),
|
}),
|
||||||
headers: {
|
headers: {
|
||||||
'Content-Type': 'application/json',
|
'Content-Type': 'application/json',
|
||||||
'Accept': 'application/json'
|
'Accept': 'application/json',
|
||||||
|
'Authorization': `Bearer ${token}`
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -100,13 +101,13 @@ export async function notificationsMarkAsRead(ids: number[]) {
|
|||||||
msg_id: 30015,
|
msg_id: 30015,
|
||||||
message_body: {
|
message_body: {
|
||||||
action: 'markRead',
|
action: 'markRead',
|
||||||
authToken: token,
|
|
||||||
notificationIds: ids
|
notificationIds: ids
|
||||||
}
|
}
|
||||||
}),
|
}),
|
||||||
headers: {
|
headers: {
|
||||||
'Content-Type': 'application/json',
|
'Content-Type': 'application/json',
|
||||||
'Accept': 'application/json'
|
'Accept': 'application/json',
|
||||||
|
'Authorization': `Bearer ${token}`
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -131,7 +132,6 @@ export async function notificationsMarkAsRead(ids: number[]) {
|
|||||||
|
|
||||||
export async function notificationsDelete(ids: number[]) {
|
export async function notificationsDelete(ids: number[]) {
|
||||||
const token = await getSessionData('token');
|
const token = await getSessionData('token');
|
||||||
console.log('notificationsDelete');
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const response = await fetch(`${API_BASE_URL}/api/v1/data`, {
|
const response = await fetch(`${API_BASE_URL}/api/v1/data`, {
|
||||||
@@ -141,13 +141,13 @@ export async function notificationsDelete(ids: number[]) {
|
|||||||
msg_id: 30015,
|
msg_id: 30015,
|
||||||
message_body: {
|
message_body: {
|
||||||
action: 'delete',
|
action: 'delete',
|
||||||
authToken: token,
|
|
||||||
notificationIds: ids
|
notificationIds: ids
|
||||||
}
|
}
|
||||||
}),
|
}),
|
||||||
headers: {
|
headers: {
|
||||||
'Content-Type': 'application/json',
|
'Content-Type': 'application/json',
|
||||||
'Accept': 'application/json'
|
'Accept': 'application/json',
|
||||||
|
'Authorization': `Bearer ${token}`
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -14,12 +14,12 @@ export async function fetchReferralsLevels() {
|
|||||||
msg_id: 30003,
|
msg_id: 30003,
|
||||||
message_body: {
|
message_body: {
|
||||||
action: 'levels',
|
action: 'levels',
|
||||||
token: token,
|
|
||||||
}
|
}
|
||||||
}),
|
}),
|
||||||
headers: {
|
headers: {
|
||||||
'Content-Type': 'application/json',
|
'Content-Type': 'application/json',
|
||||||
'Accept': 'application/json'
|
'Accept': 'application/json',
|
||||||
|
'Authorization': `Bearer ${token}`
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -57,12 +57,12 @@ export async function fetchReferralUserStats() {
|
|||||||
msg_id: 30003,
|
msg_id: 30003,
|
||||||
message_body: {
|
message_body: {
|
||||||
action: 'userStats',
|
action: 'userStats',
|
||||||
token: token,
|
|
||||||
}
|
}
|
||||||
}),
|
}),
|
||||||
headers: {
|
headers: {
|
||||||
'Content-Type': 'application/json',
|
'Content-Type': 'application/json',
|
||||||
'Accept': 'application/json'
|
'Accept': 'application/json',
|
||||||
|
'Authorization': `Bearer ${token}`
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -96,14 +96,14 @@ export async function fetchReferralInvitees() {
|
|||||||
msg_id: 30003,
|
msg_id: 30003,
|
||||||
message_body: {
|
message_body: {
|
||||||
action: 'invitees',
|
action: 'invitees',
|
||||||
token: token,
|
|
||||||
pageSize: 100,
|
pageSize: 100,
|
||||||
pageNumber: 0
|
pageNumber: 0
|
||||||
}
|
}
|
||||||
}),
|
}),
|
||||||
headers: {
|
headers: {
|
||||||
'Content-Type': 'application/json',
|
'Content-Type': 'application/json',
|
||||||
'Accept': 'application/json'
|
'Accept': 'application/json',
|
||||||
|
'Authorization': `Bearer ${token}`
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -137,25 +137,18 @@ export async function referralRefill() {
|
|||||||
msg_id: 30003,
|
msg_id: 30003,
|
||||||
message_body: {
|
message_body: {
|
||||||
action: 'refill',
|
action: 'refill',
|
||||||
token: token,
|
|
||||||
amount: 2000,
|
amount: 2000,
|
||||||
}
|
}
|
||||||
}),
|
}),
|
||||||
headers: {
|
headers: {
|
||||||
'Content-Type': 'application/json',
|
'Content-Type': 'application/json',
|
||||||
'Accept': 'application/json'
|
'Accept': 'application/json',
|
||||||
|
'Authorization': `Bearer ${token}`
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
if (response.ok) {
|
if (response.ok) {
|
||||||
console.log('referralRefill');
|
|
||||||
console.log({
|
|
||||||
action: 'refill',
|
|
||||||
token: token,
|
|
||||||
amount: 2000,
|
|
||||||
})
|
|
||||||
let parsed = await response.json();
|
let parsed = await response.json();
|
||||||
console.log(parsed);
|
|
||||||
|
|
||||||
if (parsed.message_code === 0) {
|
if (parsed.message_code === 0) {
|
||||||
return parsed.message_body;
|
return parsed.message_body;
|
||||||
@@ -366,8 +359,8 @@ export async function createPayoutRequest(
|
|||||||
const response = await fetch(`${API_BASE_URL}/api/payouts/create-request`, {
|
const response = await fetch(`${API_BASE_URL}/api/payouts/create-request`, {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
body: JSON.stringify({
|
body: JSON.stringify({
|
||||||
"amount": amount,
|
'amount': amount,
|
||||||
"payoutMethodId": payoutMethodId
|
'payoutMethodId': payoutMethodId
|
||||||
}),
|
}),
|
||||||
headers: {
|
headers: {
|
||||||
'Content-Type': 'application/json',
|
'Content-Type': 'application/json',
|
||||||
|
|||||||
@@ -7,8 +7,11 @@ export async function searchUserFiles(fileId: string) {
|
|||||||
const token = await getSessionData('token');
|
const token = await getSessionData('token');
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const response = await fetch(`${API_BASE_URL}/api/v1/files/${fileId}/similar?similarityLevels=DUPLICATE,SIMILARITY&auth_token=${token}`, {
|
const response = await fetch(`${API_BASE_URL}/api/v1/files/${fileId}/similar?similarityLevels=DUPLICATE,SIMILARITY`, {
|
||||||
method: 'GET'
|
method: 'GET',
|
||||||
|
headers: {
|
||||||
|
'Authorization': `Bearer ${token}`
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
if (response.ok) {
|
if (response.ok) {
|
||||||
@@ -40,8 +43,6 @@ export async function searchUserFiles(fileId: string) {
|
|||||||
export async function searchGlobalFiles(fileId: string, currentPage: number) {
|
export async function searchGlobalFiles(fileId: string, currentPage: number) {
|
||||||
const token = await getSessionData('token');
|
const token = await getSessionData('token');
|
||||||
|
|
||||||
//удалить когда поиск будет нормально работать
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const response = await fetch(`${API_BASE_URL}/api/v1/data`, {
|
const response = await fetch(`${API_BASE_URL}/api/v1/data`, {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
@@ -56,7 +57,8 @@ export async function searchGlobalFiles(fileId: string, currentPage: number) {
|
|||||||
}),
|
}),
|
||||||
headers: {
|
headers: {
|
||||||
'Content-Type': 'application/json',
|
'Content-Type': 'application/json',
|
||||||
'Accept': 'application/json'
|
'Accept': 'application/json',
|
||||||
|
'Authorization': `Bearer ${token}`
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -112,6 +114,7 @@ export async function getSearchStats() {
|
|||||||
|
|
||||||
if (response.ok) {
|
if (response.ok) {
|
||||||
let parsed = await response.json();
|
let parsed = await response.json();
|
||||||
|
|
||||||
return parsed;
|
return parsed;
|
||||||
} else {
|
} else {
|
||||||
return null;
|
return null;
|
||||||
|
|||||||
@@ -37,7 +37,7 @@ export async function createSession(token: string, email: string) {
|
|||||||
});
|
});
|
||||||
const cookieStore = await cookies();
|
const cookieStore = await cookies();
|
||||||
|
|
||||||
cookieStore.set('session', session, {
|
cookieStore.set('session_nc_db', session, {
|
||||||
httpOnly: true,
|
httpOnly: true,
|
||||||
secure: false,
|
secure: false,
|
||||||
expires: expiresAt,
|
expires: expiresAt,
|
||||||
@@ -48,7 +48,7 @@ export async function createSession(token: string, email: string) {
|
|||||||
|
|
||||||
export async function updateSession(newToken: string) {
|
export async function updateSession(newToken: string) {
|
||||||
const cookieStore = await cookies();
|
const cookieStore = await cookies();
|
||||||
const session = cookieStore.get('session')?.value;
|
const session = cookieStore.get('session_nc_db')?.value;
|
||||||
|
|
||||||
if (!session) {
|
if (!session) {
|
||||||
return null;
|
return null;
|
||||||
@@ -68,7 +68,7 @@ export async function updateSession(newToken: string) {
|
|||||||
|
|
||||||
const updatedSession = await encrypt(updatedPayload);
|
const updatedSession = await encrypt(updatedPayload);
|
||||||
|
|
||||||
cookieStore.set('session', updatedSession, {
|
cookieStore.set('session_nc_db', updatedSession, {
|
||||||
httpOnly: true,
|
httpOnly: true,
|
||||||
secure: false,
|
secure: false,
|
||||||
expires: updatedPayload.expiresAt,
|
expires: updatedPayload.expiresAt,
|
||||||
@@ -79,7 +79,7 @@ export async function updateSession(newToken: string) {
|
|||||||
|
|
||||||
export async function getSessionData(type: 'token' | 'email'): Promise<string | null> {
|
export async function getSessionData(type: 'token' | 'email'): Promise<string | null> {
|
||||||
const cookieStore = await cookies();
|
const cookieStore = await cookies();
|
||||||
const sessionCookie = cookieStore.get('session')?.value;
|
const sessionCookie = cookieStore.get('session_nc_db')?.value;
|
||||||
|
|
||||||
if (!sessionCookie) {
|
if (!sessionCookie) {
|
||||||
return null;
|
return null;
|
||||||
@@ -99,7 +99,7 @@ export async function deleteSession() {
|
|||||||
console.log('delete session')
|
console.log('delete session')
|
||||||
try {
|
try {
|
||||||
const cookieStore = await cookies()
|
const cookieStore = await cookies()
|
||||||
cookieStore.delete('session');
|
cookieStore.delete('session_nc_db');
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
|
||||||
} finally {
|
} finally {
|
||||||
|
|||||||
@@ -17,12 +17,12 @@ export async function requestFileWithTracking(fileId: string) {
|
|||||||
method: 'POST',
|
method: 'POST',
|
||||||
body: JSON.stringify({
|
body: JSON.stringify({
|
||||||
file_id: fileId,
|
file_id: fileId,
|
||||||
token: token,
|
|
||||||
ip: ip,
|
ip: ip,
|
||||||
user_agent: userAgent
|
user_agent: userAgent
|
||||||
}),
|
}),
|
||||||
headers: {
|
headers: {
|
||||||
'Content-Type': 'application/json'
|
'Content-Type': 'application/json',
|
||||||
|
'Authorization': `Bearer ${token}`
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -57,12 +57,12 @@ export async function requestFileAsBuffer(fileId: string): Promise<ArrayBuffer |
|
|||||||
method: 'POST',
|
method: 'POST',
|
||||||
body: JSON.stringify({
|
body: JSON.stringify({
|
||||||
file_id: fileId,
|
file_id: fileId,
|
||||||
token: token,
|
|
||||||
ip: ip,
|
ip: ip,
|
||||||
user_agent: userAgent
|
user_agent: userAgent
|
||||||
}),
|
}),
|
||||||
headers: {
|
headers: {
|
||||||
'Content-Type': 'application/json'
|
'Content-Type': 'application/json',
|
||||||
|
'Authorization': `Bearer ${token}`
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -91,6 +91,30 @@ export async function requestFileAsBuffer(fileId: string): Promise<ArrayBuffer |
|
|||||||
|
|
||||||
export async function fetchDocumentInfo(fileId: string) {
|
export async function fetchDocumentInfo(fileId: string) {
|
||||||
const token = await getSessionData('token');
|
const token = await getSessionData('token');
|
||||||
|
console.log('fetchDocumentInfo');
|
||||||
|
|
||||||
|
try {
|
||||||
|
const response = await fetch(`${API_BASE_URL}/api/files/public/file-info/${fileId}`, {
|
||||||
|
method: 'GET',
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
'Authorization': `Bearer ${token}`
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
if (response.ok) {
|
||||||
|
const parsed = await response.json();
|
||||||
|
return parsed;
|
||||||
|
} else {
|
||||||
|
throw new Error(`${response.status}`);
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function filePermisionChange(fileId: string, permissions: boolean) {
|
||||||
|
const token = await getSessionData('token');
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const response = await fetch(`${API_BASE_URL}/api/v1/data`, {
|
const response = await fetch(`${API_BASE_URL}/api/v1/data`, {
|
||||||
@@ -100,12 +124,62 @@ export async function fetchDocumentInfo(fileId: string) {
|
|||||||
msg_id: 20005,
|
msg_id: 20005,
|
||||||
message_body: {
|
message_body: {
|
||||||
file_id: fileId,
|
file_id: fileId,
|
||||||
token: token,
|
action: 'change_permission',
|
||||||
action: 'file_info'
|
permissions: {
|
||||||
|
DOWNLOAD: permissions
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}),
|
}),
|
||||||
headers: {
|
headers: {
|
||||||
'Content-Type': 'application/json'
|
'Content-Type': 'application/json',
|
||||||
|
'Authorization': `Bearer ${token}`
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
if (response.ok) {
|
||||||
|
const parsed = await response.json();
|
||||||
|
|
||||||
|
if (parsed.message_code === 0) {
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
throw new Error(`${response.status}`);
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function fetchHistoryView(
|
||||||
|
page: number,
|
||||||
|
size: number,
|
||||||
|
locale: string,
|
||||||
|
sortDirection?: 'asc' | 'desc',
|
||||||
|
sortBy?: 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: 30028,
|
||||||
|
message_body: {
|
||||||
|
action: 'history_view',
|
||||||
|
page: page,
|
||||||
|
size: size,
|
||||||
|
locale: locale,
|
||||||
|
sort_direction: sortDirection,
|
||||||
|
sort_by: sortBy
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
'Authorization': `Bearer ${token}`
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -126,7 +200,7 @@ export async function fetchDocumentInfo(fileId: string) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function filePermisionChange(fileId: string, permissions: boolean) {
|
export async function fetchTrackingStats() {
|
||||||
const token = await getSessionData('token');
|
const token = await getSessionData('token');
|
||||||
|
|
||||||
try {
|
try {
|
||||||
@@ -134,18 +208,14 @@ export async function filePermisionChange(fileId: string, permissions: boolean)
|
|||||||
method: 'POST',
|
method: 'POST',
|
||||||
body: JSON.stringify({
|
body: JSON.stringify({
|
||||||
version: 1,
|
version: 1,
|
||||||
msg_id: 20005,
|
msg_id: 30028,
|
||||||
message_body: {
|
message_body: {
|
||||||
file_id: fileId,
|
action: 'view_stats'
|
||||||
token: token,
|
|
||||||
action: 'change_permission',
|
|
||||||
permissions: {
|
|
||||||
DOWNLOAD: permissions
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}),
|
}),
|
||||||
headers: {
|
headers: {
|
||||||
'Content-Type': 'application/json'
|
'Content-Type': 'application/json',
|
||||||
|
'Authorization': `Bearer ${token}`
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -153,9 +223,9 @@ export async function filePermisionChange(fileId: string, permissions: boolean)
|
|||||||
const parsed = await response.json();
|
const parsed = await response.json();
|
||||||
|
|
||||||
if (parsed.message_code === 0) {
|
if (parsed.message_code === 0) {
|
||||||
return true;
|
return parsed.message_body;
|
||||||
} else {
|
} else {
|
||||||
return false;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
@@ -165,3 +235,31 @@ export async function filePermisionChange(fileId: string, permissions: boolean)
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export async function downloadTrackingFile(fileId: string, fileName?: string) {
|
||||||
|
const token = await getSessionData('token');
|
||||||
|
|
||||||
|
try {
|
||||||
|
const response = await fetch(`${API_BASE_URL}/api/v1/files/public-download/${fileId}`, {
|
||||||
|
method: 'GET',
|
||||||
|
headers: {
|
||||||
|
'Authorization': `Bearer ${token}`
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!response.ok) {
|
||||||
|
throw 'failed-to-download-file';
|
||||||
|
}
|
||||||
|
|
||||||
|
const arrayBuffer = await response.arrayBuffer()
|
||||||
|
const base64 = Buffer.from(arrayBuffer).toString('base64')
|
||||||
|
|
||||||
|
return {
|
||||||
|
data: base64,
|
||||||
|
contentType: response.headers.get('content-type') || 'application/octet-stream',
|
||||||
|
fileName: fileName ? fileName : 'fileName'
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -88,13 +88,10 @@ export async function getViolationFilesArray(props: {
|
|||||||
file_name?: string
|
file_name?: string
|
||||||
}) {
|
}) {
|
||||||
const token = await getSessionData('token');
|
const token = await getSessionData('token');
|
||||||
console.log('getViolationFilesArray');
|
|
||||||
const { page, size, start_date, end_date, file_name } = props;
|
const { page, size, start_date, end_date, file_name } = props;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const body: Record<string, any> = {
|
const body: Record<string, any> = {};
|
||||||
token: token
|
|
||||||
};
|
|
||||||
|
|
||||||
if (page !== undefined) body.page = page;
|
if (page !== undefined) body.page = page;
|
||||||
if (size !== undefined) body.size = size;
|
if (size !== undefined) body.size = size;
|
||||||
@@ -107,6 +104,7 @@ export async function getViolationFilesArray(props: {
|
|||||||
headers: {
|
headers: {
|
||||||
'Content-Type': 'application/json',
|
'Content-Type': 'application/json',
|
||||||
'Accept': 'application/json',
|
'Accept': 'application/json',
|
||||||
|
'Authorization': `Bearer ${token}`
|
||||||
},
|
},
|
||||||
body: JSON.stringify(body),
|
body: JSON.stringify(body),
|
||||||
});
|
});
|
||||||
@@ -128,42 +126,7 @@ export async function getViolationFilesArray(props: {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* статистика нурешений */
|
export async function getFileMatches(fileId: string, page: number, status?: string, violationId?: string, startDate?: string, endDate?: string) {
|
||||||
export async function fetchViolationStats() {
|
|
||||||
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: 30010,
|
|
||||||
message_body: {
|
|
||||||
token: token
|
|
||||||
}
|
|
||||||
}),
|
|
||||||
headers: {
|
|
||||||
'Content-Type': 'application/json',
|
|
||||||
'Accept': 'application/json'
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
if (response.ok) {
|
|
||||||
let parsed = await response.json();
|
|
||||||
if (parsed) {
|
|
||||||
return parsed;
|
|
||||||
} else {
|
|
||||||
throw null;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
throw (`${response.status}`);
|
|
||||||
}
|
|
||||||
} catch (error) {
|
|
||||||
return null
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export async function getFileViolations(fileId: string, page: number, status?: string, violationId?: string) {
|
|
||||||
const token = await getSessionData('token');
|
const token = await getSessionData('token');
|
||||||
|
|
||||||
try {
|
try {
|
||||||
@@ -174,18 +137,19 @@ export async function getFileViolations(fileId: string, page: number, status?: s
|
|||||||
msg_id: 30009,
|
msg_id: 30009,
|
||||||
message_body: {
|
message_body: {
|
||||||
file_id: fileId,
|
file_id: fileId,
|
||||||
page: page,
|
page: (page > 0 ? page - 1 : 0),
|
||||||
size: 5,
|
size: 5,
|
||||||
sort_direction: 'desc',
|
sort_direction: 'desc',
|
||||||
token: token,
|
|
||||||
status: status,
|
status: status,
|
||||||
...(violationId && { action: 'getByViolationId' }),
|
...(violationId && { action: 'getByViolationId' }),
|
||||||
...(violationId && { violation_id: violationId })
|
...(violationId && { violation_id: violationId }),
|
||||||
|
...((startDate && endDate) && { start_date: startDate, end_date: endDate })
|
||||||
}
|
}
|
||||||
}),
|
}),
|
||||||
headers: {
|
headers: {
|
||||||
'Content-Type': 'application/json',
|
'Content-Type': 'application/json',
|
||||||
'Accept': 'application/json'
|
'Accept': 'application/json',
|
||||||
|
'Authorization': `Bearer ${token}`
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -218,13 +182,13 @@ export async function fetchViolationAnalyticStatistic(group: 'domain' | 'tld') {
|
|||||||
message_body: {
|
message_body: {
|
||||||
group_by: group,
|
group_by: group,
|
||||||
action: "group",
|
action: "group",
|
||||||
token: token,
|
|
||||||
sort_direction: 'desc'
|
sort_direction: 'desc'
|
||||||
}
|
}
|
||||||
}),
|
}),
|
||||||
headers: {
|
headers: {
|
||||||
'Content-Type': 'application/json',
|
'Content-Type': 'application/json',
|
||||||
'Accept': 'application/json'
|
'Accept': 'application/json',
|
||||||
|
'Authorization': `Bearer ${token}`
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -244,7 +208,7 @@ export async function fetchViolationAnalyticStatistic(group: 'domain' | 'tld') {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function fetchViolationStatistic() {
|
export async function fetchViolationStatistic(id?: string) {
|
||||||
const token = await getSessionData('token');
|
const token = await getSessionData('token');
|
||||||
|
|
||||||
try {
|
try {
|
||||||
@@ -254,12 +218,13 @@ export async function fetchViolationStatistic() {
|
|||||||
version: 1,
|
version: 1,
|
||||||
msg_id: 30010,
|
msg_id: 30010,
|
||||||
message_body: {
|
message_body: {
|
||||||
token: token,
|
...(id && { file_id: id })
|
||||||
}
|
}
|
||||||
}),
|
}),
|
||||||
headers: {
|
headers: {
|
||||||
'Content-Type': 'application/json',
|
'Content-Type': 'application/json',
|
||||||
'Accept': 'application/json'
|
'Accept': 'application/json',
|
||||||
|
'Authorization': `Bearer ${token}`
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -287,20 +252,17 @@ export async function fetchViolationFinalSummaryStatistic() {
|
|||||||
method: 'POST',
|
method: 'POST',
|
||||||
body: JSON.stringify({
|
body: JSON.stringify({
|
||||||
version: 1,
|
version: 1,
|
||||||
msg_id: 30023,
|
msg_id: 30023
|
||||||
message_body: {
|
|
||||||
token: token,
|
|
||||||
}
|
|
||||||
}),
|
}),
|
||||||
headers: {
|
headers: {
|
||||||
'Content-Type': 'application/json',
|
'Content-Type': 'application/json',
|
||||||
'Accept': 'application/json'
|
'Accept': 'application/json',
|
||||||
|
'Authorization': `Bearer ${token}`
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
if (response.ok) {
|
if (response.ok) {
|
||||||
let parsed = await response.json();
|
let parsed = await response.json();
|
||||||
console.log(parsed);
|
|
||||||
|
|
||||||
if (parsed?.message_code === 0) {
|
if (parsed?.message_code === 0) {
|
||||||
return parsed?.message_body;
|
return parsed?.message_body;
|
||||||
@@ -363,7 +325,6 @@ export async function createComplaint(
|
|||||||
version: 1,
|
version: 1,
|
||||||
msg_id: 30013,
|
msg_id: 30013,
|
||||||
message_body: {
|
message_body: {
|
||||||
token: token,
|
|
||||||
action: 'create',
|
action: 'create',
|
||||||
violation_id: violationId,
|
violation_id: violationId,
|
||||||
text: textArea,
|
text: textArea,
|
||||||
@@ -372,7 +333,8 @@ export async function createComplaint(
|
|||||||
}),
|
}),
|
||||||
headers: {
|
headers: {
|
||||||
'Content-Type': 'application/json',
|
'Content-Type': 'application/json',
|
||||||
'Accept': 'application/json'
|
'Accept': 'application/json',
|
||||||
|
'Authorization': `Bearer ${token}`
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -429,13 +391,13 @@ export async function fetchComplainInfo(id: number) {
|
|||||||
msg_id: 30013,
|
msg_id: 30013,
|
||||||
message_body: {
|
message_body: {
|
||||||
action: 'get_by_violation',
|
action: 'get_by_violation',
|
||||||
violation_id: id,
|
violation_id: id
|
||||||
token
|
|
||||||
}
|
}
|
||||||
}),
|
}),
|
||||||
headers: {
|
headers: {
|
||||||
'Content-Type': 'application/json',
|
'Content-Type': 'application/json',
|
||||||
'Accept': 'application/json'
|
'Accept': 'application/json',
|
||||||
|
'Authorization': `Bearer ${token}`
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -473,13 +435,13 @@ export async function updateMatchStatus(id: number, status: MatchStatus) {
|
|||||||
message_body: {
|
message_body: {
|
||||||
action: 'updateStatus',
|
action: 'updateStatus',
|
||||||
violation_id: id,
|
violation_id: id,
|
||||||
status: status,
|
status: status
|
||||||
token: token
|
|
||||||
}
|
}
|
||||||
}),
|
}),
|
||||||
headers: {
|
headers: {
|
||||||
'Content-Type': 'application/json',
|
'Content-Type': 'application/json',
|
||||||
'Accept': 'application/json'
|
'Accept': 'application/json',
|
||||||
|
'Authorization': `Bearer ${token}`
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -499,28 +461,18 @@ export async function updateMatchStatus(id: number, status: MatchStatus) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function fetchCaseInfo(id: number) {
|
export async function fetchClaimInfo(id: number) {
|
||||||
const token = await getSessionData('token');
|
const token = await getSessionData('token');
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const response = await fetch(`${API_BASE_URL}/api/v1/data`, {
|
const response = await fetch(`${API_BASE_URL}/api/v1/data`, {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
/* body: JSON.stringify({
|
|
||||||
version: 1,
|
|
||||||
msg_id: 30017,
|
|
||||||
message_body: {
|
|
||||||
action: 'get_byId',
|
|
||||||
token: token,
|
|
||||||
id: id
|
|
||||||
}
|
|
||||||
}), */
|
|
||||||
body: JSON.stringify({
|
body: JSON.stringify({
|
||||||
version: 1,
|
version: 1,
|
||||||
msg_id: 30017,
|
msg_id: 30017,
|
||||||
message_body: {
|
message_body: {
|
||||||
action: 'get_all',
|
action: 'get_all',
|
||||||
token: token,
|
pageSize: 1,
|
||||||
pageSize: 10,
|
|
||||||
pageNumber: 0,
|
pageNumber: 0,
|
||||||
sortBy: "createdAt",
|
sortBy: "createdAt",
|
||||||
sortDir: "desc",
|
sortDir: "desc",
|
||||||
@@ -529,7 +481,8 @@ export async function fetchCaseInfo(id: number) {
|
|||||||
}),
|
}),
|
||||||
headers: {
|
headers: {
|
||||||
'Content-Type': 'application/json',
|
'Content-Type': 'application/json',
|
||||||
'Accept': 'application/json'
|
'Accept': 'application/json',
|
||||||
|
'Authorization': `Bearer ${token}`
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -566,7 +519,7 @@ interface caseBody {
|
|||||||
errorMessage?: Record<string, string> | null
|
errorMessage?: Record<string, string> | null
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function createCase(
|
export async function createClaim(
|
||||||
state: caseBody | undefined,
|
state: caseBody | undefined,
|
||||||
formData: FormData
|
formData: FormData
|
||||||
): Promise<caseBody> {
|
): Promise<caseBody> {
|
||||||
@@ -616,7 +569,6 @@ export async function createCase(
|
|||||||
violation_id: violationId,
|
violation_id: violationId,
|
||||||
description: textArea,
|
description: textArea,
|
||||||
email: email,
|
email: email,
|
||||||
token: token,
|
|
||||||
name: caseTitle,
|
name: caseTitle,
|
||||||
priority: 'HIGH',
|
priority: 'HIGH',
|
||||||
amount: Number(amount)
|
amount: Number(amount)
|
||||||
@@ -624,7 +576,8 @@ export async function createCase(
|
|||||||
}),
|
}),
|
||||||
headers: {
|
headers: {
|
||||||
'Content-Type': 'application/json',
|
'Content-Type': 'application/json',
|
||||||
'Accept': 'application/json'
|
'Accept': 'application/json',
|
||||||
|
'Authorization': `Bearer ${token}`
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -683,7 +636,7 @@ export interface ComplaintsCaseQueryParams {
|
|||||||
sort_direction?: 'desc' | 'asc'
|
sort_direction?: 'desc' | 'asc'
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function fetchLastCase(params: ComplaintsCaseQueryParams) {
|
export async function fetchLastClaims(params: ComplaintsCaseQueryParams) {
|
||||||
const token = await getSessionData('token');
|
const token = await getSessionData('token');
|
||||||
const { page, size, sort_by, sort_direction } = params;
|
const { page, size, sort_by, sort_direction } = params;
|
||||||
|
|
||||||
@@ -695,8 +648,7 @@ export async function fetchLastCase(params: ComplaintsCaseQueryParams) {
|
|||||||
msg_id: 30017,
|
msg_id: 30017,
|
||||||
message_body: {
|
message_body: {
|
||||||
action: "get_all",
|
action: "get_all",
|
||||||
token: token,
|
pageNumber: page,
|
||||||
page,
|
|
||||||
size,
|
size,
|
||||||
sort_by,
|
sort_by,
|
||||||
sort_direction
|
sort_direction
|
||||||
@@ -704,7 +656,8 @@ export async function fetchLastCase(params: ComplaintsCaseQueryParams) {
|
|||||||
}),
|
}),
|
||||||
headers: {
|
headers: {
|
||||||
'Content-Type': 'application/json',
|
'Content-Type': 'application/json',
|
||||||
'Accept': 'application/json'
|
'Accept': 'application/json',
|
||||||
|
'Authorization': `Bearer ${token}`
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -736,7 +689,6 @@ export async function fetchLastComplaint(params: ComplaintsCaseQueryParams) {
|
|||||||
msg_id: 30013,
|
msg_id: 30013,
|
||||||
message_body: {
|
message_body: {
|
||||||
action: "get_all",
|
action: "get_all",
|
||||||
token: token,
|
|
||||||
page,
|
page,
|
||||||
size,
|
size,
|
||||||
sort_by,
|
sort_by,
|
||||||
@@ -745,7 +697,8 @@ export async function fetchLastComplaint(params: ComplaintsCaseQueryParams) {
|
|||||||
}),
|
}),
|
||||||
headers: {
|
headers: {
|
||||||
'Content-Type': 'application/json',
|
'Content-Type': 'application/json',
|
||||||
'Accept': 'application/json'
|
'Accept': 'application/json',
|
||||||
|
'Authorization': `Bearer ${token}`
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ const checkout = new YooCheckout({ shopId: '1276731', secretKey: 'test_0Yns_0NHV
|
|||||||
|
|
||||||
export async function makePaymentOperation(email: string, tariffId: number, operationUuid: string, operationType: 'TARIFF' | 'TOKEN') {
|
export async function makePaymentOperation(email: string, tariffId: number, operationUuid: string, operationType: 'TARIFF' | 'TOKEN') {
|
||||||
const formData = new FormData();
|
const formData = new FormData();
|
||||||
|
const token = await getSessionData('token');
|
||||||
|
|
||||||
formData.append('email', email);
|
formData.append('email', email);
|
||||||
formData.append('tariffId', tariffId.toString());
|
formData.append('tariffId', tariffId.toString());
|
||||||
@@ -17,7 +18,10 @@ export async function makePaymentOperation(email: string, tariffId: number, oper
|
|||||||
try {
|
try {
|
||||||
const response = await fetch(`${API_BASE_URL}/api/payments/create`, {
|
const response = await fetch(`${API_BASE_URL}/api/payments/create`, {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
body: formData
|
body: formData,
|
||||||
|
headers: {
|
||||||
|
'Authorization': `Bearer ${token}`
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
if (response.ok) {
|
if (response.ok) {
|
||||||
@@ -79,6 +83,7 @@ export async function yooKasaCreatePayment(amount: number, tariff: number, opera
|
|||||||
|
|
||||||
export async function fetchPaymentsHistory() {
|
export async function fetchPaymentsHistory() {
|
||||||
const email = await getSessionData('email');
|
const email = await getSessionData('email');
|
||||||
|
const token = await getSessionData('token');
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const response = await fetch(`${API_BASE_URL}/api/v1/data`, {
|
const response = await fetch(`${API_BASE_URL}/api/v1/data`, {
|
||||||
@@ -93,7 +98,8 @@ export async function fetchPaymentsHistory() {
|
|||||||
}),
|
}),
|
||||||
headers: {
|
headers: {
|
||||||
'Content-Type': 'application/json',
|
'Content-Type': 'application/json',
|
||||||
'Accept': 'application/json'
|
'Accept': 'application/json',
|
||||||
|
'Authorization': `Bearer ${token}`
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -1,38 +0,0 @@
|
|||||||
import { NextResponse } from 'next/server';
|
|
||||||
|
|
||||||
export async function POST(request: Request) {
|
|
||||||
const { code } = await request.json();
|
|
||||||
|
|
||||||
try {
|
|
||||||
const response = await fetch('https://oauth.yandex.ru/token', {
|
|
||||||
method: 'POST',
|
|
||||||
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
|
|
||||||
body: new URLSearchParams({
|
|
||||||
grant_type: 'authorization_code',
|
|
||||||
code,
|
|
||||||
client_id: 'b356a7ceac0f4c50a3b434220f86bce0',
|
|
||||||
client_secret: '0800f7774f7d4e19ad4b434f10afd4ab',
|
|
||||||
})
|
|
||||||
});
|
|
||||||
|
|
||||||
const data = await response.json();
|
|
||||||
|
|
||||||
console.log(data);
|
|
||||||
|
|
||||||
if (data.access_token) {
|
|
||||||
const userInfo = await fetch('https://login.yandex.ru/info?format=json', {
|
|
||||||
headers: { 'Authorization': `OAuth ${data.access_token}` }
|
|
||||||
}).then(r => r.json());
|
|
||||||
|
|
||||||
console.log(userInfo);
|
|
||||||
|
|
||||||
// Тут мне нужно будет отправить сделать запрос в бек с userInfo и там уже редиректить на дешборд
|
|
||||||
|
|
||||||
return NextResponse.json({ success: true });
|
|
||||||
}
|
|
||||||
} catch (error) {
|
|
||||||
console.error('Token exchange failed:', error);
|
|
||||||
}
|
|
||||||
|
|
||||||
return NextResponse.json({ success: false }, { status: 400 });
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,103 @@
|
|||||||
|
'use client'
|
||||||
|
|
||||||
|
import { useTranslations } from 'next-intl'
|
||||||
|
|
||||||
|
interface NotificationTextHandlerProps {
|
||||||
|
notificationType: string
|
||||||
|
notificationMessage: string
|
||||||
|
notificationContext: Record<string, string>
|
||||||
|
}
|
||||||
|
|
||||||
|
export function NotificationTextHandler({
|
||||||
|
notificationType,
|
||||||
|
notificationMessage,
|
||||||
|
notificationContext
|
||||||
|
}: NotificationTextHandlerProps) {
|
||||||
|
const t = useTranslations('Notifications');
|
||||||
|
|
||||||
|
const getNotificationText = () => {
|
||||||
|
if (!notificationType) {
|
||||||
|
return t.has(notificationMessage) ? t(notificationMessage) : notificationMessage
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (notificationType) {
|
||||||
|
case 'USER_VERIFIED':
|
||||||
|
return t('user-verified', {
|
||||||
|
status: notificationContext?.status || t('not-specified'),
|
||||||
|
updateDate: notificationContext?.update_date || t('not-specified-date')
|
||||||
|
});
|
||||||
|
|
||||||
|
case 'MONITORING_RESULT':
|
||||||
|
return t('monitoring-result', {
|
||||||
|
message: notificationContext?.message || t('message-missing')
|
||||||
|
});
|
||||||
|
|
||||||
|
case 'COMPLAINT_STATUS_CHANGED':
|
||||||
|
return t('complaint-status-changed', {
|
||||||
|
newStatus: notificationContext?.new_status || t('not-specified'),
|
||||||
|
oldStatus: notificationContext?.old_status || t('not-specified'),
|
||||||
|
violation: notificationContext?.violation || t('not-specified'),
|
||||||
|
file: notificationContext?.file || t('not-specified')
|
||||||
|
});
|
||||||
|
|
||||||
|
case 'FILE_ADDED_TO_SYSTEM':
|
||||||
|
return t('file-added-to-system', {
|
||||||
|
status: notificationContext?.status || t('not-specified'),
|
||||||
|
fileName: notificationContext?.file_name || t('not-specified-file-name')
|
||||||
|
});
|
||||||
|
|
||||||
|
case 'FILE_MODERATION_EVENT':
|
||||||
|
return t('file-moderation-event', {
|
||||||
|
fileName: notificationContext?.file_name || t('not-specified-file-name'),
|
||||||
|
oldStatus: notificationContext?.old_status || t('not-specified'),
|
||||||
|
newStatus: notificationContext?.new_status || t('not-specified'),
|
||||||
|
comment: notificationContext?.comment || t('no-comment')
|
||||||
|
});
|
||||||
|
|
||||||
|
case 'PAYMENT_RESULT':
|
||||||
|
return t('payment-result', {
|
||||||
|
status: notificationContext?.status || t('not-specified'),
|
||||||
|
amount: notificationContext?.amount || '0'
|
||||||
|
});
|
||||||
|
|
||||||
|
case 'REFERRAL_REGISTERED':
|
||||||
|
return t('referral-registered', {
|
||||||
|
referralUser: notificationContext?.referral_user || t('unknown-user')
|
||||||
|
});
|
||||||
|
|
||||||
|
case 'SEARCH_RESULT':
|
||||||
|
return t('search-result', {
|
||||||
|
startDate: notificationContext?.start_date || t('not-specified-date'),
|
||||||
|
endDate: notificationContext?.end_date || t('not-specified-date'),
|
||||||
|
searchType: notificationContext?.search_type || t('not-specified'),
|
||||||
|
count: notificationContext?.count || '0'
|
||||||
|
});
|
||||||
|
|
||||||
|
case 'SEARCH_OPERATION_FAILED':
|
||||||
|
return t('search-operation-failed', {
|
||||||
|
status: notificationContext?.status || t('not-specified'),
|
||||||
|
errorMessage: notificationContext?.error_message || t('error-not-described'),
|
||||||
|
message: notificationContext?.message || t('message-missing'),
|
||||||
|
reason: notificationContext?.reason || t('reason-not-specified'),
|
||||||
|
nextRun: notificationContext?.next_run || t('not-scheduled')
|
||||||
|
});
|
||||||
|
|
||||||
|
case 'TOKEN_NOT_FOUND':
|
||||||
|
return t('token-not-found', {
|
||||||
|
currentTokens: notificationContext?.current_tokens || '0',
|
||||||
|
needTokens: notificationContext?.need_tokens || t('not-specified'),
|
||||||
|
message: notificationContext?.message || t('message-missing'),
|
||||||
|
nextRun: notificationContext?.next_run || t('not-scheduled')
|
||||||
|
});
|
||||||
|
|
||||||
|
default:
|
||||||
|
return notificationMessage || t('notification-without-text');
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
{getNotificationText()}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -2,13 +2,15 @@
|
|||||||
|
|
||||||
import { useEffect, useRef, useState } from 'react';
|
import { useEffect, useRef, useState } from 'react';
|
||||||
import { usePdf } from '@/app/contexts/PdfContext';
|
import { usePdf } from '@/app/contexts/PdfContext';
|
||||||
|
import { requestFileAsBuffer } from '@/app/actions/trackingActions';
|
||||||
|
|
||||||
interface PdfViewerProps {
|
interface PdfViewerProps {
|
||||||
fileId: string;
|
fileId: string;
|
||||||
fileName?: string;
|
fileName?: string;
|
||||||
|
showDownload?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export default function PdfViewer({ fileId, fileName = 'document.pdf' }: PdfViewerProps) {
|
export default function PdfViewer({ fileId, fileName = 'document.pdf', showDownload }: PdfViewerProps) {
|
||||||
const canvasRef = useRef<HTMLCanvasElement>(null);
|
const canvasRef = useRef<HTMLCanvasElement>(null);
|
||||||
const [currentPage, setCurrentPage] = useState(1);
|
const [currentPage, setCurrentPage] = useState(1);
|
||||||
const [totalPages, setTotalPages] = useState(0);
|
const [totalPages, setTotalPages] = useState(0);
|
||||||
@@ -26,16 +28,17 @@ export default function PdfViewer({ fileId, fileName = 'document.pdf' }: PdfView
|
|||||||
const loadAndDisplayPdf = async () => {
|
const loadAndDisplayPdf = async () => {
|
||||||
try {
|
try {
|
||||||
setLoading(true);
|
setLoading(true);
|
||||||
|
|
||||||
// 1. Получаем данные документа как ArrayBuffer (а не blob URL)
|
|
||||||
const { requestFileAsBuffer } = await import('@/app/actions/trackingActions');
|
|
||||||
const pdfData = await requestFileAsBuffer(fileId);
|
const pdfData = await requestFileAsBuffer(fileId);
|
||||||
|
|
||||||
if (!pdfData) {
|
if (!pdfData) {
|
||||||
throw new Error('Failed to load document');
|
throw new Error('Failed to load document');
|
||||||
}
|
}
|
||||||
|
|
||||||
setPdfData(pdfData, fileName);
|
//это нужно для скачивания так-как иначе pdfData теряется для скачивания
|
||||||
|
if (showDownload) {
|
||||||
|
const pdfDataForDownload = pdfData.slice(0);
|
||||||
|
setPdfData(pdfDataForDownload, fileName);
|
||||||
|
}
|
||||||
|
|
||||||
if (!isMounted) return;
|
if (!isMounted) return;
|
||||||
|
|
||||||
|
|||||||
@@ -1,12 +1,49 @@
|
|||||||
'use client';
|
'use client';
|
||||||
|
|
||||||
import { usePdf } from '@/app/contexts/PdfContext';
|
import { downloadTrackingFile } from '@/app/actions/trackingActions';
|
||||||
|
import { useTranslations } from 'next-intl';
|
||||||
|
import { toast } from 'sonner';
|
||||||
|
interface DownloadButtonProps {
|
||||||
|
fileId: string;
|
||||||
|
fileName?: string;
|
||||||
|
}
|
||||||
|
|
||||||
export function DownloadButton() {
|
export function DownloadButton({ fileId, fileName }: DownloadButtonProps) {
|
||||||
const { downloadPdf } = usePdf();
|
const t = useTranslations('Global');
|
||||||
|
|
||||||
|
const handleDownload = async () => {
|
||||||
|
try {
|
||||||
|
const result = await downloadTrackingFile(fileId, fileName);
|
||||||
|
|
||||||
|
if (!result) {
|
||||||
|
throw 'failed-to-download-file'
|
||||||
|
}
|
||||||
|
|
||||||
|
const byteCharacters = atob(result.data);
|
||||||
|
const byteNumbers = new Array(byteCharacters.length);
|
||||||
|
for (let i = 0; i < byteCharacters.length; i++) {
|
||||||
|
byteNumbers[i] = byteCharacters.charCodeAt(i)
|
||||||
|
}
|
||||||
|
|
||||||
|
const byteArray = new Uint8Array(byteNumbers);
|
||||||
|
const blob = new Blob([byteArray], { type: result.contentType });
|
||||||
|
|
||||||
|
const url = window.URL.createObjectURL(blob);
|
||||||
|
const a = document.createElement('a');
|
||||||
|
a.href = url;
|
||||||
|
a.download = result.fileName;
|
||||||
|
document.body.appendChild(a);
|
||||||
|
a.click();
|
||||||
|
window.URL.revokeObjectURL(url);
|
||||||
|
document.body.removeChild(a);
|
||||||
|
toast.success(`${t('file-is-downloading')} - `);
|
||||||
|
} catch (error) {
|
||||||
|
toast.error(t('failed-to-download-file'));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<button className="btn btn-out" onClick={downloadPdf}>
|
<button className="btn btn-out" onClick={handleDownload}>
|
||||||
Скачать документ
|
Скачать документ
|
||||||
</button>
|
</button>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -33,6 +33,7 @@ import Link from 'next/link';
|
|||||||
import { SelectedFilesAction } from '@/app/components/tanstak-table/SelectedFilesActions';
|
import { SelectedFilesAction } from '@/app/components/tanstak-table/SelectedFilesActions';
|
||||||
import Image from 'next/image';
|
import Image from 'next/image';
|
||||||
import { filePermisionChange } from '@/app/actions/trackingActions';
|
import { filePermisionChange } from '@/app/actions/trackingActions';
|
||||||
|
import { FileAppealModalWindow } from '@/app/ui/modal-windows/file-appeal-modal-window';
|
||||||
|
|
||||||
export type FileItem = {
|
export type FileItem = {
|
||||||
id: string;
|
id: string;
|
||||||
@@ -41,7 +42,7 @@ export type FileItem = {
|
|||||||
violations?: number | undefined;
|
violations?: number | undefined;
|
||||||
size?: number | undefined;
|
size?: number | undefined;
|
||||||
uploadDate?: number;
|
uploadDate?: number;
|
||||||
status?: string;
|
status: string;
|
||||||
monitoring: string;
|
monitoring: string;
|
||||||
protectStatus: string;
|
protectStatus: string;
|
||||||
_original?: ApiFile;
|
_original?: ApiFile;
|
||||||
@@ -67,9 +68,22 @@ type ApiFile = {
|
|||||||
thumbnailFileUrl: string;
|
thumbnailFileUrl: string;
|
||||||
permissions: {
|
permissions: {
|
||||||
DOWNLOAD: boolean;
|
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 = {
|
type ApiResponse = {
|
||||||
files?: ApiFile[];
|
files?: ApiFile[];
|
||||||
total_count: number;
|
total_count: number;
|
||||||
@@ -295,6 +309,32 @@ export default function TanstakFilesTable({ fileType, showFileLink }: { fileType
|
|||||||
});
|
});
|
||||||
}, [apiResponse]);
|
}, [apiResponse]);
|
||||||
|
|
||||||
|
const StatusBadge = ({ status, protectStatus }: { status: string, protectStatus: string }) => {
|
||||||
|
|
||||||
|
switch (status) {
|
||||||
|
case 'ACTIVE':
|
||||||
|
return <span className="table-item-status-badge protected">
|
||||||
|
{protectStatus ? t(protectStatus) : t('error')}
|
||||||
|
</span>;
|
||||||
|
case 'MODERATION':
|
||||||
|
return <span className="table-item-status-badge moderation">
|
||||||
|
{t('pending-moderation')}
|
||||||
|
</span>;
|
||||||
|
case 'BLOCKED':
|
||||||
|
return <span className="table-item-status-badge blocked">
|
||||||
|
{t('blocked')}
|
||||||
|
</span>;
|
||||||
|
case 'REMOVED':
|
||||||
|
return <span className="table-item-status-badge blocked">
|
||||||
|
{t('file-has-been-deleted')}
|
||||||
|
</span>;
|
||||||
|
default:
|
||||||
|
return <span className="table-item-status-badge protected">
|
||||||
|
{protectStatus ? t(protectStatus) : t('error')}
|
||||||
|
</span>;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const isAllSelected = useMemo(() => {
|
const isAllSelected = useMemo(() => {
|
||||||
if (!apiResponse?.items?.length) return false;
|
if (!apiResponse?.items?.length) return false;
|
||||||
const allIds = new Set(apiResponse.items.map(item => item.id));
|
const allIds = new Set(apiResponse.items.map(item => item.id));
|
||||||
@@ -431,9 +471,7 @@ export default function TanstakFilesTable({ fileType, showFileLink }: { fileType
|
|||||||
{cutFileName(row.original.fileName)}
|
{cutFileName(row.original.fileName)}
|
||||||
</span>
|
</span>
|
||||||
<br />
|
<br />
|
||||||
<span className="table-item-extension">{cutFileExtension(row.original.fileName)}</span> <span className="table-item-protected">
|
<span className="table-item-extension">{cutFileExtension(row.original.fileName)}</span> <StatusBadge status={row.original.status} protectStatus={row.original.protectStatus} />
|
||||||
{row.original?.protectStatus ? t(row.original?.protectStatus) : t('error')}
|
|
||||||
</span>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -614,36 +652,53 @@ export default function TanstakFilesTable({ fileType, showFileLink }: { fileType
|
|||||||
</div>
|
</div>
|
||||||
) : (
|
) : (
|
||||||
<>
|
<>
|
||||||
<div className="actions-group">
|
{/* "BLOCKED" "REMOVED" */}
|
||||||
<Link
|
{(row.original.status !== 'BLOCKED' && row.original.status !== 'REMOVED') ? (
|
||||||
href={`/pages/file/${row.original.id}`}
|
<>
|
||||||
className="bg-violet-500 hover:bg-violet-600"
|
<div className="actions-group">
|
||||||
title={t('view')}
|
<Link
|
||||||
>
|
href={`/pages/file/${row.original.id}`}
|
||||||
<IconEye />
|
className="bg-violet-500 hover:bg-violet-600"
|
||||||
</Link>
|
title={t('view')}
|
||||||
</div>
|
>
|
||||||
<div className="actions-group">
|
<IconEye />
|
||||||
{row.original.protectStatus === 'PROTECTED' && (
|
</Link>
|
||||||
|
</div>
|
||||||
|
<div className="actions-group">
|
||||||
|
{row.original.protectStatus === 'PROTECTED' && (
|
||||||
|
<button
|
||||||
|
onClick={() => handleDownload(row.original)}
|
||||||
|
disabled={isFileLoading}
|
||||||
|
className="table-action-download"
|
||||||
|
title={t('download')}
|
||||||
|
>
|
||||||
|
<IconFileDownload />
|
||||||
|
</button>
|
||||||
|
)}
|
||||||
|
<button
|
||||||
|
onClick={() => {
|
||||||
|
handleView(row.original)
|
||||||
|
}}
|
||||||
|
className="table-action-view"
|
||||||
|
title={t('make-check')}
|
||||||
|
>
|
||||||
|
<IconInfo />
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
|
) : (
|
||||||
|
<div className="actions-group">
|
||||||
<button
|
<button
|
||||||
onClick={() => handleDownload(row.original)}
|
onClick={() => {
|
||||||
disabled={isFileLoading}
|
handleAppeal(row.original)
|
||||||
className="table-action-download"
|
}}
|
||||||
title={t('download')}
|
className="table-action-appeal"
|
||||||
|
title={t('file-an-appeal')}
|
||||||
>
|
>
|
||||||
<IconFileDownload />
|
<IconInfo />
|
||||||
</button>
|
</button>
|
||||||
)}
|
</div>
|
||||||
<button
|
)}
|
||||||
onClick={() => {
|
|
||||||
handleView(row.original)
|
|
||||||
}}
|
|
||||||
className="table-action-view"
|
|
||||||
title={t('make-check')}
|
|
||||||
>
|
|
||||||
<IconInfo />
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
@@ -666,6 +721,16 @@ export default function TanstakFilesTable({ fileType, showFileLink }: { fileType
|
|||||||
setOpenWindow(true);
|
setOpenWindow(true);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const handleAppeal = async (file: FileItem) => {
|
||||||
|
|
||||||
|
setOpenWindowChildren(() => {
|
||||||
|
return (
|
||||||
|
<FileAppealModalWindow fileId={file.id} appeal={file._original?.appealInfos} setWindowClose={setOpenWindow} setWindowChildren={setOpenWindowChildren} />
|
||||||
|
)
|
||||||
|
})
|
||||||
|
setOpenWindow(true);
|
||||||
|
};
|
||||||
|
|
||||||
const handleDownload = async (file: FileItem) => {
|
const handleDownload = async (file: FileItem) => {
|
||||||
setIsFileLoading(true)
|
setIsFileLoading(true)
|
||||||
|
|
||||||
@@ -1014,10 +1079,7 @@ export default function TanstakFilesTable({ fileType, showFileLink }: { fileType
|
|||||||
{t('page')}{' '}
|
{t('page')}{' '}
|
||||||
<strong>
|
<strong>
|
||||||
{pagination.pageIndex + 1} {t('out-of')} {totalPages || 1}
|
{pagination.pageIndex + 1} {t('out-of')} {totalPages || 1}
|
||||||
</strong>
|
</strong> | {t('total-files')}: {totalItems}
|
||||||
</span>
|
|
||||||
<span className="pagination-info-files">
|
|
||||||
| {t('shown')} {tableData.length} {t('out-of')} {totalItems} {pluralizeFiles(totalItems)}
|
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { useQuery } from '@tanstack/react-query';
|
import { useQuery } from '@tanstack/react-query';
|
||||||
import { getFileViolations } from '@/app/actions/violationActions';
|
import { getFileMatches } from '@/app/actions/violationActions';
|
||||||
|
|
||||||
export interface ViolationFileDetail {
|
export interface ViolationFileDetail {
|
||||||
id: number;
|
id: number;
|
||||||
@@ -24,11 +24,11 @@ interface ViolationFile {
|
|||||||
has_previous: boolean;
|
has_previous: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const useFileViolations = (id: string, page: number, status?: string, violationId?: string) => {
|
export const useFileViolations = (id: string, page: number, status?: string, violationId?: string, startDate?: string, endDate?: string,) => {
|
||||||
return useQuery({
|
return useQuery({
|
||||||
queryKey: ['fileViolations', id, page, status, violationId],
|
queryKey: ['fileViolations', id, page, status, violationId, startDate, endDate],
|
||||||
queryFn: () => {
|
queryFn: () => {
|
||||||
return getFileViolations(id, page, status, violationId)
|
return getFileMatches(id, page, status, violationId, startDate, endDate)
|
||||||
},
|
},
|
||||||
select: (data: ViolationFile | null) => {
|
select: (data: ViolationFile | null) => {
|
||||||
if (!data) {
|
if (!data) {
|
||||||
|
|||||||
@@ -0,0 +1,44 @@
|
|||||||
|
import { useQuery } from '@tanstack/react-query';
|
||||||
|
import { fetchHistoryView } from '@/app/actions/trackingActions';
|
||||||
|
|
||||||
|
export interface HistoryViewItem {
|
||||||
|
city: string;
|
||||||
|
country: string;
|
||||||
|
viewer: string;
|
||||||
|
document: string;
|
||||||
|
view_date: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface UseHistoryView {
|
||||||
|
documentsCount: number;
|
||||||
|
history: HistoryViewItem[];
|
||||||
|
pageNumber: number;
|
||||||
|
pageSize: number;
|
||||||
|
totalElements: number;
|
||||||
|
totalPages: number;
|
||||||
|
uniqueCityCount: number;
|
||||||
|
uniqueCountryCount: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const useHistoryView = (
|
||||||
|
page: number,
|
||||||
|
size: number,
|
||||||
|
locale: string,
|
||||||
|
sortDirection?: 'asc' | 'desc',
|
||||||
|
sortBy?: string
|
||||||
|
) => {
|
||||||
|
return useQuery({
|
||||||
|
queryKey: ['violationStatistic', page, size, locale, sortDirection, sortBy],
|
||||||
|
queryFn: () => {
|
||||||
|
return fetchHistoryView(page, size, locale, sortDirection, sortBy)
|
||||||
|
},
|
||||||
|
select: (data: UseHistoryView | null) => {
|
||||||
|
if (!data) {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
return data;
|
||||||
|
},
|
||||||
|
retry: false,
|
||||||
|
placeholderData: (previousData) => previousData // для оптимистичных обновлений
|
||||||
|
});
|
||||||
|
};
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
import { useQuery } from '@tanstack/react-query';
|
import { useQuery } from '@tanstack/react-query';
|
||||||
import { fetchLastCase, ComplaintsCaseQueryParams } from '@/app/actions/violationActions';
|
import { fetchLastClaims, ComplaintsCaseQueryParams } from '@/app/actions/violationActions';
|
||||||
|
|
||||||
export interface Case {
|
export interface Case {
|
||||||
amount: number;
|
amount: number;
|
||||||
@@ -31,7 +31,7 @@ export const useLastCases = (params: ComplaintsCaseQueryParams) => {
|
|||||||
return useQuery({
|
return useQuery({
|
||||||
queryKey: ['lastCases', params.page, params.size, params.sort_by, params.sort_direction],
|
queryKey: ['lastCases', params.page, params.size, params.sort_by, params.sort_direction],
|
||||||
queryFn: () => {
|
queryFn: () => {
|
||||||
return fetchLastCase(params)
|
return fetchLastClaims(params)
|
||||||
},
|
},
|
||||||
select: (data: useLastCase | null) => {
|
select: (data: useLastCase | null) => {
|
||||||
if (!data) {
|
if (!data) {
|
||||||
|
|||||||
@@ -0,0 +1,29 @@
|
|||||||
|
import { useQuery } from '@tanstack/react-query';
|
||||||
|
import { fetchTrackingStats } from '@/app/actions/trackingActions';
|
||||||
|
|
||||||
|
export interface useTrackingStats {
|
||||||
|
totalViews: number,
|
||||||
|
uniqueIps: number,
|
||||||
|
uniqueUsers: number,
|
||||||
|
documentsCount: number,
|
||||||
|
uniqueCountryCount: number,
|
||||||
|
uniqueCityCount: number,
|
||||||
|
firstViewDate: string,
|
||||||
|
lastViewDate: string
|
||||||
|
}
|
||||||
|
|
||||||
|
export const useTrackingStats = () => {
|
||||||
|
return useQuery({
|
||||||
|
queryKey: ['trackingStats'],
|
||||||
|
queryFn: () => {
|
||||||
|
return fetchTrackingStats()
|
||||||
|
},
|
||||||
|
select: (data: useTrackingStats | null) => {
|
||||||
|
if (!data) {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
return data;
|
||||||
|
},
|
||||||
|
retry: false
|
||||||
|
});
|
||||||
|
};
|
||||||
@@ -5,14 +5,16 @@ export interface UseViolationStatistic {
|
|||||||
total_violations: number,
|
total_violations: number,
|
||||||
new_violations: number,
|
new_violations: number,
|
||||||
in_progress_violations: number,
|
in_progress_violations: number,
|
||||||
resolved_violations: number
|
resolved_violations: number,
|
||||||
|
total_complaints: number,
|
||||||
|
total_law_cases: number
|
||||||
}
|
}
|
||||||
|
|
||||||
export const useViolationStatistic = () => {
|
export const useViolationStatistic = (id?: string) => {
|
||||||
return useQuery({
|
return useQuery({
|
||||||
queryKey: ['violationStatistic'],
|
queryKey: ['violationStatistic', id],
|
||||||
queryFn: () => {
|
queryFn: () => {
|
||||||
return fetchViolationStatistic()
|
return fetchViolationStatistic(id)
|
||||||
},
|
},
|
||||||
select: (data: UseViolationStatistic | null) => {
|
select: (data: UseViolationStatistic | null) => {
|
||||||
if (!data) {
|
if (!data) {
|
||||||
|
|||||||
@@ -0,0 +1,11 @@
|
|||||||
|
'use client';
|
||||||
|
|
||||||
|
import Providers from './getQueryServer';
|
||||||
|
|
||||||
|
export function WatchDocProviders({ children }: { children: React.ReactNode }) {
|
||||||
|
return (
|
||||||
|
<Providers>
|
||||||
|
{children}
|
||||||
|
</Providers>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -1,34 +1,11 @@
|
|||||||
'use client'
|
'use client'
|
||||||
|
|
||||||
import {
|
import {
|
||||||
isServer,
|
|
||||||
QueryClient,
|
|
||||||
QueryClientProvider,
|
QueryClientProvider,
|
||||||
} from '@tanstack/react-query'
|
} from '@tanstack/react-query'
|
||||||
|
|
||||||
import { getQueryClient } from '@/app/providers/getQueryClient';
|
import { getQueryClient } from '@/app/providers/getQueryClient';
|
||||||
|
|
||||||
/* export function makeQueryClient() {
|
|
||||||
return new QueryClient({
|
|
||||||
defaultOptions: {
|
|
||||||
queries: {
|
|
||||||
staleTime: 60 * 1000,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
let browserQueryClient: QueryClient | undefined = undefined
|
|
||||||
|
|
||||||
function getQueryClient() {
|
|
||||||
if (isServer) {
|
|
||||||
return makeQueryClient()
|
|
||||||
} else {
|
|
||||||
if (!browserQueryClient) browserQueryClient = makeQueryClient()
|
|
||||||
return browserQueryClient
|
|
||||||
}
|
|
||||||
} */
|
|
||||||
|
|
||||||
export default function Providers({ children }: { children: React.ReactNode }) {
|
export default function Providers({ children }: { children: React.ReactNode }) {
|
||||||
const queryClient = getQueryClient();
|
const queryClient = getQueryClient();
|
||||||
|
|
||||||
|
|||||||
@@ -163,7 +163,7 @@
|
|||||||
|
|
||||||
.btn,
|
.btn,
|
||||||
.btn-s,
|
.btn-s,
|
||||||
.btn-m {
|
.btn-l {
|
||||||
border: none;
|
border: none;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
@@ -197,7 +197,8 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.btn-primary {
|
.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;
|
color: v.$white;
|
||||||
border: 2px solid transparent;
|
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 {
|
.btn-outline {
|
||||||
background: transparent;
|
background: transparent;
|
||||||
border: 2px solid v.$p-color;
|
border: 2px solid v.$p-color;
|
||||||
|
|||||||
@@ -270,16 +270,16 @@
|
|||||||
position: absolute;
|
position: absolute;
|
||||||
right: -5px;
|
right: -5px;
|
||||||
bottom: -5px;
|
bottom: -5px;
|
||||||
width: 20px;
|
/* width: 22px;
|
||||||
height: 20px;
|
height: 22px; */
|
||||||
border-radius: 50%;
|
border-radius: 15px;
|
||||||
background: v.$red;
|
background: v.$red;
|
||||||
color: v.$white;
|
color: v.$white;
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
font-size: 12px;
|
font-size: 12px;
|
||||||
padding-top: 1px;
|
padding: 2px 5px;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -650,6 +650,10 @@
|
|||||||
&.text-filter-search {
|
&.text-filter-search {
|
||||||
flex-grow: 1;
|
flex-grow: 1;
|
||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
|
|
||||||
|
&.end {
|
||||||
|
justify-content: end;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@media (max-width: 768px) {
|
@media (max-width: 768px) {
|
||||||
@@ -829,6 +833,10 @@
|
|||||||
padding: 15px 16px;
|
padding: 15px 16px;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
&:has(.column-location) {
|
||||||
|
width: 250px;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.column {
|
.column {
|
||||||
@@ -902,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 {
|
.table-item-file-name-image-wrapper {
|
||||||
width: 40px;
|
width: 40px;
|
||||||
height: 40px;
|
height: 40px;
|
||||||
@@ -926,13 +959,24 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.table-item-protected {
|
.table-item-status-badge {
|
||||||
color: #10b981;
|
|
||||||
font-size: 12px;
|
font-size: 12px;
|
||||||
position: relative;
|
position: relative;
|
||||||
margin-left: 5px;
|
margin-left: 5px;
|
||||||
padding-left: 5px;
|
padding-left: 5px;
|
||||||
|
|
||||||
|
&.protected {
|
||||||
|
color: #10b981;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.moderation {
|
||||||
|
color: v.$color-warning;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.blocked {
|
||||||
|
color: v.$red;
|
||||||
|
}
|
||||||
|
|
||||||
&::before {
|
&::before {
|
||||||
content: '•';
|
content: '•';
|
||||||
color: v.$text-s;
|
color: v.$text-s;
|
||||||
@@ -1012,11 +1056,11 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.table-action-delete {
|
.table-action-appeal {
|
||||||
background-color: #e80a14;
|
background-color: #9f0712;
|
||||||
|
|
||||||
&:hover {
|
&:hover {
|
||||||
background-color: #9f0712;
|
background-color: v.$red;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2799,7 +2843,6 @@
|
|||||||
|
|
||||||
.cases-carousel-track {
|
.cases-carousel-track {
|
||||||
position: relative;
|
position: relative;
|
||||||
margin-bottom: 16px;
|
|
||||||
|
|
||||||
.swiper-slide {
|
.swiper-slide {
|
||||||
height: auto;
|
height: auto;
|
||||||
@@ -2838,6 +2881,14 @@
|
|||||||
.swiper-pagination-bullet-active {
|
.swiper-pagination-bullet-active {
|
||||||
background: #3b82f6 !important;
|
background: #3b82f6 !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.swiper-pagination-fraction,
|
||||||
|
.swiper-pagination-custom,
|
||||||
|
.swiper-horizontal>.swiper-pagination-bullets,
|
||||||
|
.swiper-pagination-bullets.swiper-pagination-horizontal {
|
||||||
|
margin-top: 16px;
|
||||||
|
position: static;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.violation-check-all-section {
|
.violation-check-all-section {
|
||||||
@@ -3783,12 +3834,16 @@
|
|||||||
min-width: 400px;
|
min-width: 400px;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
|
|
||||||
|
&.appeal-info {
|
||||||
|
margin-bottom: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
@media (max-width: 470px) {
|
@media (max-width: 470px) {
|
||||||
min-width: auto;
|
min-width: auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
.info-header {
|
.info-header {
|
||||||
background: linear-gradient(0deg, #6366f1 50%, #8b5cf6 130%);
|
background: #6366f1;
|
||||||
color: white;
|
color: white;
|
||||||
padding: 16px 20px;
|
padding: 16px 20px;
|
||||||
border-bottom: 1px solid v.$border-color-1;
|
border-bottom: 1px solid v.$border-color-1;
|
||||||
@@ -3836,6 +3891,118 @@
|
|||||||
padding: 12px 20px;
|
padding: 12px 20px;
|
||||||
border-bottom: 1px solid #f1f5f9;
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
.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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -3881,48 +4048,6 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.section-add-file {
|
|
||||||
position: relative;
|
|
||||||
|
|
||||||
.section-drop-down-list {
|
|
||||||
position: absolute;
|
|
||||||
left: 80%;
|
|
||||||
top: 50%;
|
|
||||||
max-height: 0;
|
|
||||||
color: v.$text-p;
|
|
||||||
font-size: 16px;
|
|
||||||
border-radius: 20px;
|
|
||||||
padding: 0;
|
|
||||||
border: none;
|
|
||||||
width: fit-content;
|
|
||||||
z-index: 2;
|
|
||||||
font-weight: 500;
|
|
||||||
|
|
||||||
background: #ffffff00;
|
|
||||||
overflow: hidden;
|
|
||||||
transition: all 0.5s ease;
|
|
||||||
transform: translateY(-50%);
|
|
||||||
|
|
||||||
&.opened {
|
|
||||||
max-height: 500px;
|
|
||||||
padding: 15px 10px;
|
|
||||||
box-shadow: 0 4px 20px #00000014;
|
|
||||||
background: v.$white;
|
|
||||||
}
|
|
||||||
|
|
||||||
a {
|
|
||||||
white-space: nowrap;
|
|
||||||
color: v.$p-color;
|
|
||||||
opacity: 0.7;
|
|
||||||
}
|
|
||||||
|
|
||||||
a:hover {
|
|
||||||
transition: all 0.3s ease;
|
|
||||||
opacity: 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.violations-table {
|
.violations-table {
|
||||||
background: white;
|
background: white;
|
||||||
border-radius: 20px;
|
border-radius: 20px;
|
||||||
|
|||||||
@@ -2,11 +2,9 @@
|
|||||||
|
|
||||||
import { useQuery } from '@tanstack/react-query';
|
import { useQuery } from '@tanstack/react-query';
|
||||||
import { getUserFilesData } from '@/app/actions/fileEntity';
|
import { getUserFilesData } from '@/app/actions/fileEntity';
|
||||||
import { useEffect, useState, useRef } from 'react';
|
|
||||||
import { FileTypeIcon } from '@/app/components/FileTypeIcon';
|
import { FileTypeIcon } from '@/app/components/FileTypeIcon';
|
||||||
import { convertBytes } from '@/app/lib/convertBytes';
|
import { convertBytes } from '@/app/lib/convertBytes';
|
||||||
import { useTranslations } from 'next-intl';
|
import { useTranslations } from 'next-intl';
|
||||||
import { useClickOutside } from '@/app/hooks/useClickOutside';
|
|
||||||
import Link from 'next/link';
|
import Link from 'next/link';
|
||||||
|
|
||||||
type FileItem = {
|
type FileItem = {
|
||||||
@@ -71,15 +69,6 @@ export default function DashboardUserFiles() {
|
|||||||
});
|
});
|
||||||
|
|
||||||
const t = useTranslations('Global');
|
const t = useTranslations('Global');
|
||||||
const [openDropDownList, setOpenDropDownList] = useState(false);
|
|
||||||
const dropDownList = useRef(null);
|
|
||||||
useClickOutside(
|
|
||||||
dropDownList,
|
|
||||||
() => {
|
|
||||||
setOpenDropDownList(false)
|
|
||||||
},
|
|
||||||
openDropDownList
|
|
||||||
);
|
|
||||||
|
|
||||||
const formatDate = (timestamp: number) => {
|
const formatDate = (timestamp: number) => {
|
||||||
const date = new Date(timestamp);
|
const date = new Date(timestamp);
|
||||||
@@ -97,30 +86,11 @@ export default function DashboardUserFiles() {
|
|||||||
{t('your-files')}
|
{t('your-files')}
|
||||||
</h3>
|
</h3>
|
||||||
<div
|
<div
|
||||||
className="section-add-file btn view-all-link"
|
className="btn view-all-link"
|
||||||
onClick={() => {
|
|
||||||
setOpenDropDownList(!openDropDownList);
|
|
||||||
}}
|
|
||||||
ref={dropDownList}
|
|
||||||
>
|
>
|
||||||
{t('add')}
|
<Link href='/pages/my-content'>
|
||||||
<div
|
{t('all')}
|
||||||
className={`section-drop-down-list ${openDropDownList ? 'opened' : ''}`}
|
</Link>
|
||||||
>
|
|
||||||
<div
|
|
||||||
className="flex flex-col text-center"
|
|
||||||
>
|
|
||||||
<Link href='/pages/marking-images'>
|
|
||||||
{t('photo-marking')}
|
|
||||||
</Link>
|
|
||||||
<Link href='/pages/marking-video'>
|
|
||||||
{t('video-marking')}
|
|
||||||
</Link>
|
|
||||||
<Link href='/pages/marking-audio'>
|
|
||||||
{t('audio-marking')}
|
|
||||||
</Link>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|||||||
@@ -62,7 +62,7 @@ export default function DashboardUserViolations() {
|
|||||||
{t('violation')}
|
{t('violation')}
|
||||||
</h3>
|
</h3>
|
||||||
<div
|
<div
|
||||||
className="section-add-file btn view-all-link"
|
className="btn view-all-link"
|
||||||
>
|
>
|
||||||
<Link href='/pages/violations'>
|
<Link href='/pages/violations'>
|
||||||
{t('all')}
|
{t('all')}
|
||||||
@@ -82,7 +82,7 @@ export default function DashboardUserViolations() {
|
|||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{violationData?.content.length ? (
|
{violationData?.content?.length ? (
|
||||||
violationData?.content.map((file) => {
|
violationData?.content.map((file) => {
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
|
|||||||
@@ -1,4 +1,10 @@
|
|||||||
export default function FilePpageFileStatistic() {
|
'use client'
|
||||||
|
|
||||||
|
import { useViolationStatistic } from '@/app/hooks/react-query/useViolationStatistic';
|
||||||
|
|
||||||
|
export default function FilePageFileStatistic({ id }: { id: string }) {
|
||||||
|
const { data: violationStatistic } = useViolationStatistic(id);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
className="block-wrapper"
|
className="block-wrapper"
|
||||||
@@ -13,36 +19,36 @@ export default function FilePpageFileStatistic() {
|
|||||||
<div className="stat-mini-card">
|
<div className="stat-mini-card">
|
||||||
<div
|
<div
|
||||||
className="stat-mini-value"
|
className="stat-mini-value"
|
||||||
style={{'color': '#dc2626'}}
|
style={{ 'color': '#dc2626' }}
|
||||||
>
|
>
|
||||||
0
|
{violationStatistic?.new_violations ? violationStatistic?.new_violations : 0}
|
||||||
</div>
|
</div>
|
||||||
<div className="stat-mini-label">Новых</div>
|
<div className="stat-mini-label">Новых</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="stat-mini-card">
|
<div className="stat-mini-card">
|
||||||
<div
|
<div
|
||||||
className="stat-mini-value"
|
className="stat-mini-value"
|
||||||
style={{'color': '#d97706'}}
|
style={{ 'color': '#d97706' }}
|
||||||
>
|
>
|
||||||
0
|
{violationStatistic?.in_progress_violations ? violationStatistic?.in_progress_violations : 0}
|
||||||
</div>
|
</div>
|
||||||
<div className="stat-mini-label">В работе</div>
|
<div className="stat-mini-label">В работе</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="stat-mini-card">
|
<div className="stat-mini-card">
|
||||||
<div
|
<div
|
||||||
className="stat-mini-value"
|
className="stat-mini-value"
|
||||||
style={{'color': '#059669'}}
|
style={{ 'color': '#059669' }}
|
||||||
>
|
>
|
||||||
0
|
{violationStatistic?.resolved_violations ? violationStatistic?.resolved_violations : 0}
|
||||||
</div>
|
</div>
|
||||||
<div className="stat-mini-label">Решено</div>
|
<div className="stat-mini-label">Решено</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="stat-mini-card">
|
<div className="stat-mini-card">
|
||||||
<div
|
<div
|
||||||
className="stat-mini-value"
|
className="stat-mini-value"
|
||||||
style={{'color': '#6366f1'}}
|
style={{ 'color': '#6366f1' }}
|
||||||
>
|
>
|
||||||
0
|
{violationStatistic?.total_violations ? violationStatistic?.total_violations : 0}
|
||||||
</div>
|
</div>
|
||||||
<div className="stat-mini-label">Всего</div>
|
<div className="stat-mini-label">Всего</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
import { ViolationFileDetail } from '@/app/hooks/react-query/useFileViolations';
|
import { ViolationFileDetail } from '@/app/hooks/react-query/useFileViolations';
|
||||||
import { useEffect, useActionState, SetStateAction } from 'react';
|
import { useEffect, useActionState, SetStateAction } from 'react';
|
||||||
import { fetchCaseInfo, createCase, MatchStatus } from '@/app/actions/violationActions';
|
import { fetchClaimInfo, createClaim, MatchStatus } from '@/app/actions/violationActions';
|
||||||
import { useQuery } from '@tanstack/react-query';
|
import { useQuery } from '@tanstack/react-query';
|
||||||
import { useTranslations } from 'next-intl';
|
import { useTranslations } from 'next-intl';
|
||||||
import { toast } from 'sonner';
|
import { toast } from 'sonner';
|
||||||
@@ -37,11 +37,11 @@ export default function CaseViolation({ selectedViolation, updateStatusHandler,
|
|||||||
}
|
}
|
||||||
) {
|
) {
|
||||||
const t = useTranslations('Global');
|
const t = useTranslations('Global');
|
||||||
const [state, formAction, isPending] = useActionState(createCase, undefined);
|
const [state, formAction, isPending] = useActionState(createClaim, undefined);
|
||||||
|
|
||||||
const { data: caseInfo, isLoading: isLoadingCase } = useQuery({
|
const { data: caseInfo, isLoading: isLoadingCase } = useQuery({
|
||||||
queryKey: ['caseInfo', selectedViolation.id],
|
queryKey: ['caseInfo', selectedViolation.id],
|
||||||
queryFn: () => fetchCaseInfo(selectedViolation.id),
|
queryFn: () => fetchClaimInfo(selectedViolation.id),
|
||||||
select: (data) => {
|
select: (data) => {
|
||||||
if (data) {
|
if (data) {
|
||||||
return data
|
return data
|
||||||
@@ -52,7 +52,7 @@ export default function CaseViolation({ selectedViolation, updateStatusHandler,
|
|||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (state?.success) {
|
if (state?.success) {
|
||||||
toast.success(t('the-complaint-has-been-registered'));
|
toast.success(t('the-claims-has-been-registered'));
|
||||||
|
|
||||||
const newStatus = selectedViolation.status === 'COMPLAINT_IN_WORK'
|
const newStatus = selectedViolation.status === 'COMPLAINT_IN_WORK'
|
||||||
? 'COMPLAINT_AND_LEGAL_IN_WORK'
|
? 'COMPLAINT_AND_LEGAL_IN_WORK'
|
||||||
@@ -69,7 +69,7 @@ export default function CaseViolation({ selectedViolation, updateStatusHandler,
|
|||||||
if (state.errorMessage?.server) {
|
if (state.errorMessage?.server) {
|
||||||
toast.warning(t(state.errorMessage.server));
|
toast.warning(t(state.errorMessage.server));
|
||||||
} else {
|
} else {
|
||||||
toast.warning(t('the-complaint-has-not-been-registered'));
|
toast.warning(t('the-claims-has-not-been-registered'));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}, [state, updateStatusHandler, selectedViolation.id]);
|
}, [state, updateStatusHandler, selectedViolation.id]);
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
'use client'
|
'use client'
|
||||||
|
|
||||||
import { ViolationFileDetail } from '@/app/hooks/react-query/useFileViolations';
|
import { ViolationFileDetail } from '@/app/hooks/react-query/useFileViolations';
|
||||||
import {useActionState, useEffect, useState, SetStateAction} from 'react';
|
import { useActionState, useEffect, useState, SetStateAction } from 'react';
|
||||||
import { useTranslations } from 'next-intl';
|
import { useTranslations } from 'next-intl';
|
||||||
import { createComplaint, fetchComplainInfo, MatchStatus } from '@/app/actions/violationActions';
|
import { createComplaint, fetchComplainInfo, MatchStatus } from '@/app/actions/violationActions';
|
||||||
import { toast } from 'sonner';
|
import { toast } from 'sonner';
|
||||||
@@ -158,13 +158,14 @@ export default function CaseComplaint({ selectedViolation, updateStatusHandler,
|
|||||||
<div
|
<div
|
||||||
className="button-actions"
|
className="button-actions"
|
||||||
>
|
>
|
||||||
<button
|
{/* пока скроем интерфейс с шаблонами */}
|
||||||
|
{/* <button
|
||||||
type="button"
|
type="button"
|
||||||
className="btn-s btn-primary-small"
|
className="btn-s btn-primary-small"
|
||||||
onClick={openTemplateSaveModal}
|
onClick={openTemplateSaveModal}
|
||||||
>
|
>
|
||||||
{t('save-template')}
|
{t('save-template')}
|
||||||
</button>
|
</button> */}
|
||||||
|
|
||||||
<button
|
<button
|
||||||
type="submit"
|
type="submit"
|
||||||
@@ -176,7 +177,8 @@ export default function CaseComplaint({ selectedViolation, updateStatusHandler,
|
|||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
<div
|
{/* пока скроем интерфейс с шаблонами */}
|
||||||
|
{/* <div
|
||||||
className="samples-wrapper"
|
className="samples-wrapper"
|
||||||
>
|
>
|
||||||
<h5>Шаблоны</h5>
|
<h5>Шаблоны</h5>
|
||||||
@@ -272,7 +274,7 @@ export default function CaseComplaint({ selectedViolation, updateStatusHandler,
|
|||||||
</div>
|
</div>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div> */}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<ModalWindow
|
<ModalWindow
|
||||||
@@ -350,60 +352,48 @@ export default function CaseComplaint({ selectedViolation, updateStatusHandler,
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="violation-info-case">
|
<div className="violation-info-case">
|
||||||
{complainInfo?.body?.content ? (
|
{complainInfo?.body ? (
|
||||||
<>
|
<div>
|
||||||
{complainInfo.body.content.map((item: complaintInfo) => {
|
<div className="complaint-details">
|
||||||
return (
|
<div className="complaint-details-item">
|
||||||
<div key={item.id}>
|
<div className="complaint-details-header">
|
||||||
<div className="complaint-details">
|
<h5>COM-{complainInfo.body?.id}</h5>
|
||||||
<div className="complaint-details-item">
|
|
||||||
<div className="complaint-details-header">
|
|
||||||
<h5>COM-{item.id}</h5>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className="complaint-details-item">
|
|
||||||
<div className="complaint-details-title">{t('Status')}:</div>
|
|
||||||
<div
|
|
||||||
className="complaint-details-content"
|
|
||||||
>
|
|
||||||
{item.status}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className="complaint-details-item">
|
|
||||||
<div className="complaint-details-title">{t('date-of-creation')}:</div>
|
|
||||||
<div
|
|
||||||
className="complaint-details-content"
|
|
||||||
>
|
|
||||||
{item.created_at ? `${formatDate(item.created_at)}: ${formatDateTime(item.created_at)}` : '---'}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className="complaint-details-item">
|
|
||||||
<div className="complaint-details-title">{t('date-of-update')}:</div>
|
|
||||||
<div
|
|
||||||
className="complaint-details-content"
|
|
||||||
>
|
|
||||||
{item.updated_at ? `${formatDate(item.updated_at)}: ${formatDateTime(item.updated_at)}` : '---'}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className="complaint-details-item">
|
|
||||||
<div className="complaint-details-title">{t('text-of-the-complaint')}:
|
|
||||||
|
|
||||||
</div>
|
|
||||||
<div
|
|
||||||
className="complaint-details-content"
|
|
||||||
>
|
|
||||||
{item.complaint_text}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
);
|
</div>
|
||||||
})}
|
|
||||||
</>
|
<div className="complaint-details-item">
|
||||||
|
<div className="complaint-details-title">{t('Status')}:</div>
|
||||||
|
<div className="complaint-details-content">
|
||||||
|
{complainInfo.body?.status}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="complaint-details-item">
|
||||||
|
<div className="complaint-details-title">{t('date-of-creation')}:</div>
|
||||||
|
<div className="complaint-details-content">
|
||||||
|
{complainInfo.body?.created_at
|
||||||
|
? `${formatDate(complainInfo.body.created_at)}: ${formatDateTime(complainInfo.body.created_at)}`
|
||||||
|
: '---'}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="complaint-details-item">
|
||||||
|
<div className="complaint-details-title">{t('date-of-update')}:</div>
|
||||||
|
<div className="complaint-details-content">
|
||||||
|
{complainInfo.body?.updated_at
|
||||||
|
? `${formatDate(complainInfo.body.updated_at)}: ${formatDateTime(complainInfo.body.updated_at)}`
|
||||||
|
: '---'}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="complaint-details-item">
|
||||||
|
<div className="complaint-details-title">{t('text-of-the-complaint')}:</div>
|
||||||
|
<div className="complaint-details-content">
|
||||||
|
{complainInfo.body?.complaint_text}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
) : (
|
) : (
|
||||||
<div>
|
<div>
|
||||||
{t('no-information-about-the-complaint')}
|
{t('no-information-about-the-complaint')}
|
||||||
|
|||||||
@@ -17,13 +17,17 @@ export default function FilePageViolationsList({
|
|||||||
fileId,
|
fileId,
|
||||||
status,
|
status,
|
||||||
violationId,
|
violationId,
|
||||||
caseType
|
caseType,
|
||||||
|
startDate,
|
||||||
|
endDate
|
||||||
}: {
|
}: {
|
||||||
currentPage: number,
|
currentPage: number,
|
||||||
fileId: string,
|
fileId: string,
|
||||||
status: string | undefined,
|
status: string | undefined,
|
||||||
violationId?: string | undefined
|
violationId?: string | undefined,
|
||||||
caseType?: 'claim' | 'complaint'
|
caseType?: 'claim' | 'complaint',
|
||||||
|
startDate?: string,
|
||||||
|
endDate?: string
|
||||||
}) {
|
}) {
|
||||||
const t = useTranslations('Global');
|
const t = useTranslations('Global');
|
||||||
const tStatus = useTranslations('Match-status');
|
const tStatus = useTranslations('Match-status');
|
||||||
@@ -38,7 +42,7 @@ export default function FilePageViolationsList({
|
|||||||
current_page: number;
|
current_page: number;
|
||||||
} | null>(null);
|
} | null>(null);
|
||||||
|
|
||||||
const { data: fileViolations, error, isPending } = useFileViolations(fileId, currentPage, status, violationId);
|
const { data: fileViolations, error, isPending } = useFileViolations(fileId, currentPage, status, violationId, startDate, endDate);
|
||||||
|
|
||||||
function selectHandler(violation: ViolationFileDetail) {
|
function selectHandler(violation: ViolationFileDetail) {
|
||||||
setSelectedViolation(violation);
|
setSelectedViolation(violation);
|
||||||
@@ -228,7 +232,7 @@ export default function FilePageViolationsList({
|
|||||||
className="sources-list-pagination"
|
className="sources-list-pagination"
|
||||||
>
|
>
|
||||||
<span>
|
<span>
|
||||||
{t('total-violations')}: {fileViolations?.total_elements} | {t('page')} {fileViolations?.current_page} {t('out-of')} {fileViolations?.total_pages}
|
{t('page')} <strong>{fileViolations?.current_page + 1} {t('out-of')} {fileViolations?.total_pages}</strong> | {t('total-violations')}: {fileViolations?.total_elements}
|
||||||
</span>
|
</span>
|
||||||
{fileViolations?.total_pages > 1 && (
|
{fileViolations?.total_pages > 1 && (
|
||||||
<div className="pagination-controls">
|
<div className="pagination-controls">
|
||||||
|
|||||||
@@ -256,9 +256,12 @@ export default function RegisterForm() {
|
|||||||
<ConfirmMailModalWindow userId={state?.userId} email={formState?.previousState?.email} onClose={() => { setShowMailConfirmWindow(false) }} />
|
<ConfirmMailModalWindow userId={state?.userId} email={formState?.previousState?.email} onClose={() => { setShowMailConfirmWindow(false) }} />
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
<form action={(e) => {
|
<form
|
||||||
formAction(e);
|
action={(e) => {
|
||||||
}}>
|
formAction(e);
|
||||||
|
}}
|
||||||
|
autoComplete="off"
|
||||||
|
>
|
||||||
<div className={`${styles['form-switcher']}`}>
|
<div className={`${styles['form-switcher']}`}>
|
||||||
<button
|
<button
|
||||||
className={`${styles['form-switcher-button']} ${accountType === 'b2c' ? styles['active'] : ''}`}
|
className={`${styles['form-switcher-button']} ${accountType === 'b2c' ? styles['active'] : ''}`}
|
||||||
@@ -432,6 +435,7 @@ export default function RegisterForm() {
|
|||||||
e.target.value = e.target.value.toLocaleLowerCase();
|
e.target.value = e.target.value.toLocaleLowerCase();
|
||||||
onChangeHandler(e)
|
onChangeHandler(e)
|
||||||
}}
|
}}
|
||||||
|
autoComplete="off"
|
||||||
/>
|
/>
|
||||||
{formState?.error?.email && (
|
{formState?.error?.email && (
|
||||||
<p className="text-sm text-red-500">
|
<p className="text-sm text-red-500">
|
||||||
@@ -486,6 +490,7 @@ export default function RegisterForm() {
|
|||||||
placeholder={t('password-placeholder')}
|
placeholder={t('password-placeholder')}
|
||||||
defaultValue={formState?.previousState?.password ? formState?.previousState?.password : ''}
|
defaultValue={formState?.previousState?.password ? formState?.previousState?.password : ''}
|
||||||
onChange={onChangeHandler}
|
onChange={onChangeHandler}
|
||||||
|
autoComplete="off"
|
||||||
/>
|
/>
|
||||||
<button
|
<button
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
|
|||||||
@@ -6,9 +6,10 @@ import { useTranslations } from 'next-intl';
|
|||||||
import Link from 'next/link';
|
import Link from 'next/link';
|
||||||
import { IconInfoMessage, IconPolicy, IconFiles, IconAccountBalanceWallet, IconCheckbook, IconGavel } from '@/app/ui/icons/icons';
|
import { IconInfoMessage, IconPolicy, IconFiles, IconAccountBalanceWallet, IconCheckbook, IconGavel } from '@/app/ui/icons/icons';
|
||||||
import { useActiveNotifications } from '@/app/hooks/react-query/useActiveNotificationsList';
|
import { useActiveNotifications } from '@/app/hooks/react-query/useActiveNotificationsList';
|
||||||
import { NotificationBody, notificationsMarkAsRead } from '@/app/actions/notificationActions';
|
import { notificationsMarkAsRead } from '@/app/actions/notificationActions';
|
||||||
import { useQueryClient } from '@tanstack/react-query';
|
import { useQueryClient } from '@tanstack/react-query';
|
||||||
import { formatDate } from '@/app/lib/formatDate';
|
import { formatDate } from '@/app/lib/formatDate';
|
||||||
|
import { NotificationTextHandler } from '@/app/components/NotificationTextHandler';
|
||||||
|
|
||||||
export default function NotificationsButton() {
|
export default function NotificationsButton() {
|
||||||
const t = useTranslations('Global');
|
const t = useTranslations('Global');
|
||||||
@@ -147,12 +148,12 @@ export default function NotificationsButton() {
|
|||||||
<svg viewBox="0 0 24 24" fill="currentColor" style={{ width: "20px", height: "20px" }}>
|
<svg viewBox="0 0 24 24" fill="currentColor" style={{ width: "20px", height: "20px" }}>
|
||||||
<path d="M12 22c1.1 0 2-.9 2-2h-4c0 1.1.89 2 2 2zm6-6v-5c0-3.07-1.64-5.64-4.5-6.32V4c0-.83-.67-1.5-1.5-1.5s-1.5.67-1.5 1.5v.68C7.63 5.36 6 7.92 6 11v5l-2 2v1h16v-1l-2-2z"></path>
|
<path d="M12 22c1.1 0 2-.9 2-2h-4c0 1.1.89 2 2 2zm6-6v-5c0-3.07-1.64-5.64-4.5-6.32V4c0-.83-.67-1.5-1.5-1.5s-1.5.67-1.5 1.5v.68C7.63 5.36 6 7.92 6 11v5l-2 2v1h16v-1l-2-2z"></path>
|
||||||
</svg>
|
</svg>
|
||||||
{notificationList?.unreadCount !== 0 && (
|
{(notificationList?.unreadCount !== 0 && notificationList?.unreadCount !== undefined) && (
|
||||||
<span
|
<span
|
||||||
className="notification-unread-count"
|
className="notification-unread-count"
|
||||||
style={{ fontSize: getFontSizeByCount(notificationList?.unreadCount) }}
|
/* style={{ fontSize: getFontSizeByCount(notificationList?.unreadCount) }} */
|
||||||
>
|
>
|
||||||
{notificationList?.unreadCount ? notificationList?.unreadCount : ''}
|
{notificationList?.unreadCount > 9 ? '9+' : notificationList?.unreadCount}
|
||||||
</span>
|
</span>
|
||||||
)}
|
)}
|
||||||
</button>
|
</button>
|
||||||
@@ -220,7 +221,7 @@ export default function NotificationsButton() {
|
|||||||
className="notification-item-header"
|
className="notification-item-header"
|
||||||
>
|
>
|
||||||
<div className="notification-title">
|
<div className="notification-title">
|
||||||
{norificationTranslate.has(item.type) ? norificationTranslate(item.type) : item.type}
|
{norificationTranslate.has(item.message) ? norificationTranslate(item.message) : item.message}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="notification-data">
|
<div className="notification-data">
|
||||||
@@ -229,7 +230,7 @@ export default function NotificationsButton() {
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="notification-text">
|
<div className="notification-text">
|
||||||
{norificationTranslate.has(item.message) ? norificationTranslate(item.message) : item.message}
|
<NotificationTextHandler notificationType={item.type} notificationMessage={item.message} notificationContext={item.context} />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ import { logout } from '@/app/actions/auth';
|
|||||||
import { useTranslations } from 'next-intl';
|
import { useTranslations } from 'next-intl';
|
||||||
import { useUserProfile } from '@/app/hooks/react-query/useUserDataInfo';
|
import { useUserProfile } from '@/app/hooks/react-query/useUserDataInfo';
|
||||||
import { useQueryClient } from '@tanstack/react-query';
|
import { useQueryClient } from '@tanstack/react-query';
|
||||||
|
import {formatDate} from '@/app/lib/formatDate';
|
||||||
|
|
||||||
export default function UserMenuButton() {
|
export default function UserMenuButton() {
|
||||||
const [isOpen, setIsOpen] = useState(false);
|
const [isOpen, setIsOpen] = useState(false);
|
||||||
@@ -62,14 +63,16 @@ export default function UserMenuButton() {
|
|||||||
<div className="user-email">
|
<div className="user-email">
|
||||||
{userData?.email ?? ''}
|
{userData?.email ?? ''}
|
||||||
</div>
|
</div>
|
||||||
<div className="user-subscription">
|
{userData?.tariffInfo?.tariffName && (
|
||||||
<span className="text-[14px]">{t('rate')}: </span>
|
<div className="user-subscription">
|
||||||
<span className="subscription-badge">
|
<span className="text-[14px]">{t('rate')}: </span>
|
||||||
{userData?.tariffInfo?.tariffName ? userData?.tariffInfo?.tariffName : '---'}
|
<span className="subscription-badge">
|
||||||
</span>
|
{userData?.tariffInfo?.tariffName ? userData?.tariffInfo?.tariffName : '---'}
|
||||||
<br />
|
</span>
|
||||||
<span className="user-subscription-expire">{t('expires')}: 00.00.00</span>
|
<br />
|
||||||
</div>
|
<span className="user-subscription-expire">{t('expires')}: {formatDate(userData?.tariffInfo.endTariff)}</span>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|||||||
@@ -283,3 +283,11 @@ export function IconGlobe() {
|
|||||||
</svg>
|
</svg>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function IconCity() {
|
||||||
|
return (
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 -960 960 960" width="24px" className="icon">
|
||||||
|
<path d="M120-120v-560h240v-80l120-120 120 120v240h240v400H120Zm80-80h80v-80h-80v80Zm0-160h80v-80h-80v80Zm0-160h80v-80h-80v80Zm240 320h80v-80h-80v80Zm0-160h80v-80h-80v80Zm0-160h80v-80h-80v80Zm0-160h80v-80h-80v80Zm240 480h80v-80h-80v80Zm0-160h80v-80h-80v80Z" />
|
||||||
|
</svg>
|
||||||
|
)
|
||||||
|
}
|
||||||
@@ -0,0 +1,184 @@
|
|||||||
|
'use client';
|
||||||
|
|
||||||
|
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, appeal, setWindowClose, setWindowChildren }: {
|
||||||
|
fileId: string,
|
||||||
|
appeal?: AppealInfos[],
|
||||||
|
setWindowClose: any,
|
||||||
|
setWindowChildren: any
|
||||||
|
}) {
|
||||||
|
const t = useTranslations('Global');
|
||||||
|
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()) {
|
||||||
|
toast.error(t('please-enter-appeal-reason'));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
setIsSubmitting(true);
|
||||||
|
|
||||||
|
try {
|
||||||
|
const result = await FileAnAppeal(fileId, appealReason, additionalInfo);
|
||||||
|
|
||||||
|
if (result?.message_desc === 'Appeal submitted successfully') {
|
||||||
|
toast.success(t('appeal-submitted-successfully'));
|
||||||
|
setWindowClose(false);
|
||||||
|
} else if (result?.message_desc === 'Active appeal already exists for this file') {
|
||||||
|
toast.error(t('active-appeal-already-exists-for-this-file'));
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
toast.error(result?.message_desc || t('appeal-submission-failed'));
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Appeal submission error:', error);
|
||||||
|
toast.error(t('appeal-submission-failed'));
|
||||||
|
} finally {
|
||||||
|
setIsSubmitting(false);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
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>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="info-item">
|
||||||
|
<div className="info-label">
|
||||||
|
{t('appeal-reason')} <span className="required">*</span>
|
||||||
|
</div>
|
||||||
|
<div className="info-value">
|
||||||
|
<textarea
|
||||||
|
className="appeal-textarea"
|
||||||
|
value={appealReason}
|
||||||
|
onChange={(e) => setAppealReason(e.target.value)}
|
||||||
|
placeholder={t('enter-appeal-reason')}
|
||||||
|
rows={4}
|
||||||
|
disabled={isSubmitting}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="info-item">
|
||||||
|
<div className="info-label">{t('additional-info')}</div>
|
||||||
|
<div className="info-value">
|
||||||
|
<textarea
|
||||||
|
className="appeal-textarea"
|
||||||
|
value={additionalInfo}
|
||||||
|
onChange={(e) => setAdditionalInfo(e.target.value)}
|
||||||
|
placeholder={t('enter-additional-info')}
|
||||||
|
rows={3}
|
||||||
|
disabled={isSubmitting}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="appeal-actions">
|
||||||
|
<button
|
||||||
|
className="btn btn-cancel"
|
||||||
|
onClick={() => setWindowClose(false)}
|
||||||
|
disabled={isSubmitting}
|
||||||
|
>
|
||||||
|
{t('cancel')}
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
className="btn btn-primary"
|
||||||
|
onClick={handleSubmitAppeal}
|
||||||
|
disabled={isSubmitting}
|
||||||
|
>
|
||||||
|
{isSubmitting ? t('submitting') : t('submit-appeal')}
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -16,7 +16,7 @@ import {
|
|||||||
createColumnHelper,
|
createColumnHelper,
|
||||||
RowSelectionState,
|
RowSelectionState,
|
||||||
} from '@tanstack/react-table';
|
} from '@tanstack/react-table';
|
||||||
|
import { NotificationTextHandler } from '@/app/components/NotificationTextHandler';
|
||||||
|
|
||||||
export function NotificationsList() {
|
export function NotificationsList() {
|
||||||
const t = useTranslations('Global');
|
const t = useTranslations('Global');
|
||||||
@@ -81,28 +81,30 @@ export function NotificationsList() {
|
|||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
<button
|
{allNotifications?.notifications.length !== 0 && (
|
||||||
className="btn btn-primary"
|
<button
|
||||||
onClick={() => {
|
className="btn btn-primary"
|
||||||
if (allNotificationSelectedOnPage) {
|
onClick={() => {
|
||||||
|
if (allNotificationSelectedOnPage) {
|
||||||
|
|
||||||
const newSelection = { ...rowSelection };
|
const newSelection = { ...rowSelection };
|
||||||
currentPageRows.forEach(row => {
|
currentPageRows.forEach(row => {
|
||||||
delete newSelection[row.original.id];
|
delete newSelection[row.original.id];
|
||||||
});
|
});
|
||||||
setRowSelection(newSelection);
|
setRowSelection(newSelection);
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
const newSelection = { ...rowSelection };
|
const newSelection = { ...rowSelection };
|
||||||
currentPageRows.forEach(row => {
|
currentPageRows.forEach(row => {
|
||||||
newSelection[row.original.id] = true;
|
newSelection[row.original.id] = true;
|
||||||
});
|
});
|
||||||
setRowSelection(newSelection);
|
setRowSelection(newSelection);
|
||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{allNotificationSelectedOnPage ? t('deselect') : t('select-all')}
|
{allNotificationSelectedOnPage ? t('deselect') : t('select-all')}
|
||||||
</button>
|
</button>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
@@ -135,18 +137,22 @@ export function NotificationsList() {
|
|||||||
}),
|
}),
|
||||||
columnHelper.accessor('message', {
|
columnHelper.accessor('message', {
|
||||||
id: 'message',
|
id: 'message',
|
||||||
header: () => null, // No header text, using custom header above
|
header: () => null,
|
||||||
cell: ({ row }) => {
|
cell: ({ row }) => {
|
||||||
const item = row.original;
|
const item = row.original;
|
||||||
return (
|
return (
|
||||||
<div className="notification-body">
|
<div className="notification-body">
|
||||||
<div className="notification-header">
|
<div className="notification-header">
|
||||||
{/* Optional header content */}
|
<div
|
||||||
|
className="notification-title"
|
||||||
|
>
|
||||||
|
{norificationTranslate.has(item.message)
|
||||||
|
? norificationTranslate(item.message)
|
||||||
|
: item.message} ({item.id})
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="notification-text">
|
<div className="notification-text">
|
||||||
{norificationTranslate.has(item.message)
|
<NotificationTextHandler notificationType={item.type} notificationMessage={item.message} notificationContext={item.context} />
|
||||||
? norificationTranslate(item.message)
|
|
||||||
: item.message} ({item.id})
|
|
||||||
</div>
|
</div>
|
||||||
<div className="notification-footer">
|
<div className="notification-footer">
|
||||||
<div className="notification-date">
|
<div className="notification-date">
|
||||||
|
|||||||
@@ -429,9 +429,6 @@ export default function PaymentTabTransactionHistory() {
|
|||||||
{table.getState().pagination.pageIndex + 1} {t('out-of')} {table.getPageCount() ? table.getPageCount() : 1}
|
{table.getState().pagination.pageIndex + 1} {t('out-of')} {table.getPageCount() ? table.getPageCount() : 1}
|
||||||
</strong>
|
</strong>
|
||||||
</span>
|
</span>
|
||||||
<span className="pagination-info-files">
|
|
||||||
| {t('shown')} {table.getRowModel().rows.length} {t('out-of')} {filteredData.length}
|
|
||||||
</span>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="pagination-controls">
|
<div className="pagination-controls">
|
||||||
|
|||||||
@@ -397,14 +397,11 @@ export default function InvitationsTable() {
|
|||||||
{/* Пагинация */}
|
{/* Пагинация */}
|
||||||
<div className="tanstak-table-pagination">
|
<div className="tanstak-table-pagination">
|
||||||
<div className="pagination-info">
|
<div className="pagination-info">
|
||||||
{/* <span className="pagination-info-pages">
|
{/* <span className="pagination-info-pages">
|
||||||
{t('page')}{' '}
|
{t('page')}{' '}
|
||||||
<strong>
|
<strong>
|
||||||
{table.getState().pagination.pageIndex + 1} {t('out-of')} {table.getPageCount() ? table.getPageCount() : 1}
|
{table.getState().pagination.pageIndex + 1} {t('out-of')} {table.getPageCount() ? table.getPageCount() : 1}
|
||||||
</strong>
|
</strong>
|
||||||
</span>
|
|
||||||
<span className="pagination-info-files">
|
|
||||||
| {t('shown')} {table.getRowModel().rows.length} {t('out-of')} {filteredData.length} {pluralizeFiles(filteredData.length || 0)}
|
|
||||||
</span> */}
|
</span> */}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|||||||
@@ -425,9 +425,6 @@ export default function PaymentsHistory() {
|
|||||||
<strong>
|
<strong>
|
||||||
{table.getState().pagination.pageIndex + 1} {t('out-of')} {table.getPageCount() ? table.getPageCount() : 1}
|
{table.getState().pagination.pageIndex + 1} {t('out-of')} {table.getPageCount() ? table.getPageCount() : 1}
|
||||||
</strong>
|
</strong>
|
||||||
</span>
|
|
||||||
<span className="pagination-info-files">
|
|
||||||
| {t('shown')} {table.getRowModel().rows.length} {t('out-of')} {filteredData.length} {pluralizeFiles(filteredData.length || 0)}
|
|
||||||
</span> */}
|
</span> */}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|||||||
@@ -3,13 +3,13 @@
|
|||||||
import { useUserFilesInfo } from '@/app/hooks/react-query/useUserFilesInfo';
|
import { useUserFilesInfo } from '@/app/hooks/react-query/useUserFilesInfo';
|
||||||
import { useTranslations } from 'next-intl';
|
import { useTranslations } from 'next-intl';
|
||||||
import { useMonitoringStats } from '@/app/hooks/react-query/useMonitoringStats';
|
import { useMonitoringStats } from '@/app/hooks/react-query/useMonitoringStats';
|
||||||
import { useViolationFinalSummaryStatistic } from '@/app/hooks/react-query/useViolationFinalSummaryStatistic';
|
import { useViolationStatistic } from '@/app/hooks/react-query/useViolationStatistic';
|
||||||
|
|
||||||
export default function FinalSummary() {
|
export default function FinalSummary() {
|
||||||
const t = useTranslations('Global');
|
const t = useTranslations('Global');
|
||||||
const { data: filesInfo, isLoading, isError, error } = useUserFilesInfo();
|
const { data: filesInfo, isLoading, isError, error } = useUserFilesInfo();
|
||||||
const { data: violationStatistic } = useViolationFinalSummaryStatistic();
|
|
||||||
const { data: monitoringStats } = useMonitoringStats();
|
const { data: monitoringStats } = useMonitoringStats();
|
||||||
|
const { data: violationStatistic } = useViolationStatistic();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="final-summary">
|
<div className="final-summary">
|
||||||
|
|||||||
@@ -0,0 +1,462 @@
|
|||||||
|
'use client'
|
||||||
|
|
||||||
|
import { useHistoryView, HistoryViewItem } from '@/app/hooks/react-query/useHistoryView';
|
||||||
|
import { useEffect, useState, useMemo } from 'react';
|
||||||
|
import { IconDoubleArrowRight, IconArrowRight, IconDoubleArrowLeft, IconArrowLeft, IconArrowUp, IconArrowDown, IconFilter } from '@/app/ui/icons/icons';
|
||||||
|
import DropDownList from '@/app/components/DropDownList';
|
||||||
|
import { useReactTable, getCoreRowModel, getSortedRowModel, getPaginationRowModel, SortingState, ColumnDef } from '@tanstack/react-table';
|
||||||
|
import { formatDate, formatDateTime } from '@/app/lib/formatDate';
|
||||||
|
import { useTranslations } from 'next-intl';
|
||||||
|
import { useViewport } from '@/app/hooks/useViewport';
|
||||||
|
import { useLocale } from 'next-intl';
|
||||||
|
|
||||||
|
export function TrackingHistoryView() {
|
||||||
|
const [pagination, setPagination] = useState({
|
||||||
|
pageIndex: 0,
|
||||||
|
pageSize: 10,
|
||||||
|
});
|
||||||
|
const [sorting, setSorting] = useState<SortingState>([]);
|
||||||
|
const t = useTranslations('Global');
|
||||||
|
const locale = useLocale();
|
||||||
|
|
||||||
|
const getSortParams = useMemo(() => {
|
||||||
|
if (sorting.length === 0) {
|
||||||
|
return { sortBy: '', sortOrder: undefined };
|
||||||
|
}
|
||||||
|
|
||||||
|
const sort = sorting[0];
|
||||||
|
const sortByMap: Record<string, string> = {
|
||||||
|
'document': 'docName',
|
||||||
|
'view_date': 'createdAt',
|
||||||
|
'viewer': 'viewerName',
|
||||||
|
'location': locale === 'ru' ? 'geoNameRu' : 'geoNameEn'
|
||||||
|
};
|
||||||
|
|
||||||
|
return {
|
||||||
|
sortBy: sortByMap[sort.id] || sort.id,
|
||||||
|
sortOrder: sort.desc ? 'desc' : 'asc' as 'desc' | 'asc'
|
||||||
|
};
|
||||||
|
}, [sorting]);
|
||||||
|
|
||||||
|
const {
|
||||||
|
data: apiResponse,
|
||||||
|
isLoading,
|
||||||
|
isFetching,
|
||||||
|
isError,
|
||||||
|
error,
|
||||||
|
refetch
|
||||||
|
} = useHistoryView(pagination.pageIndex, pagination.pageSize, locale, getSortParams.sortOrder, getSortParams.sortBy);
|
||||||
|
|
||||||
|
const totalElements = apiResponse?.totalElements || 0
|
||||||
|
const tableData = apiResponse?.history || [];
|
||||||
|
const totalPages = apiResponse?.totalPages || 0;
|
||||||
|
|
||||||
|
const viewport = useViewport();
|
||||||
|
|
||||||
|
const getMaxLengthByWidth = (): number => {
|
||||||
|
if (viewport.device === 'MOBILE') return 22;
|
||||||
|
if (viewport.device === 'TABLET') return 30;
|
||||||
|
if (viewport.device === 'DESKTOP') return 50;
|
||||||
|
return 100;
|
||||||
|
};
|
||||||
|
|
||||||
|
const cutFileName = (fileName: string) => {
|
||||||
|
const MAX_FILE_NAME_LENGTH = getMaxLengthByWidth();
|
||||||
|
const lastDotIndex = fileName.lastIndexOf('.');
|
||||||
|
|
||||||
|
if (lastDotIndex <= 0) {
|
||||||
|
return fileName.length > MAX_FILE_NAME_LENGTH ? fileName.substring(0, MAX_FILE_NAME_LENGTH - 3) + '...' : fileName;
|
||||||
|
}
|
||||||
|
|
||||||
|
const nameWithoutExtension = fileName.substring(0, lastDotIndex);
|
||||||
|
const extension = fileName.substring(lastDotIndex);
|
||||||
|
|
||||||
|
if (fileName.length <= MAX_FILE_NAME_LENGTH) {
|
||||||
|
return fileName;
|
||||||
|
}
|
||||||
|
|
||||||
|
const maxNameLength = MAX_FILE_NAME_LENGTH - extension.length - 3;
|
||||||
|
|
||||||
|
if (maxNameLength <= 0) {
|
||||||
|
return '...';
|
||||||
|
}
|
||||||
|
|
||||||
|
return nameWithoutExtension.substring(0, maxNameLength) + '...';
|
||||||
|
}
|
||||||
|
|
||||||
|
function EditLocationName({ location }: { location: string | undefined | null }) {
|
||||||
|
if (!location) return (
|
||||||
|
<div></div>
|
||||||
|
);
|
||||||
|
|
||||||
|
const [city, country] = location.split('/');
|
||||||
|
|
||||||
|
const translatedCity = city === 'unknow' ? t('not-defined-city') : city;
|
||||||
|
const translatedCountry = country === 'unknow' ? t('not-defined-country') : country;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
{t('city')}: <strong title={translatedCity}>{translatedCity}</strong>
|
||||||
|
<br />
|
||||||
|
{t('country')}: <strong title={translatedCountry}>{translatedCountry}</strong>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
const columns = useMemo<ColumnDef<HistoryViewItem>[]>(
|
||||||
|
() => [
|
||||||
|
{
|
||||||
|
accessorKey: 'document',
|
||||||
|
header: ({ column }) => (
|
||||||
|
<div className="column column-document">
|
||||||
|
<span>
|
||||||
|
{t('document')}
|
||||||
|
</span>
|
||||||
|
<button
|
||||||
|
onClick={() => column.toggleSorting(column.getIsSorted() === 'asc')}
|
||||||
|
className="sort-button"
|
||||||
|
>
|
||||||
|
{
|
||||||
|
column.getIsSorted() === 'asc' ?
|
||||||
|
<span>
|
||||||
|
<IconArrowUp />
|
||||||
|
</span>
|
||||||
|
: column.getIsSorted() === 'desc' ?
|
||||||
|
<span>
|
||||||
|
<IconArrowDown />
|
||||||
|
</span>
|
||||||
|
: <span>
|
||||||
|
<IconFilter />
|
||||||
|
</span>
|
||||||
|
}
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
),
|
||||||
|
cell: ({ row }) => (
|
||||||
|
<div className="text-center table-item column-document">
|
||||||
|
{row.original.document}
|
||||||
|
</div>
|
||||||
|
),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
accessorKey: 'view_date',
|
||||||
|
header: ({ column }) => (
|
||||||
|
<div className="column column-viewer-date">
|
||||||
|
<span>
|
||||||
|
{t('date')} / {t('time')}
|
||||||
|
</span>
|
||||||
|
<button
|
||||||
|
onClick={() => column.toggleSorting(column.getIsSorted() === 'asc')}
|
||||||
|
className="sort-button"
|
||||||
|
>
|
||||||
|
{
|
||||||
|
column.getIsSorted() === 'asc' ?
|
||||||
|
<span>
|
||||||
|
<IconArrowUp />
|
||||||
|
</span>
|
||||||
|
: column.getIsSorted() === 'desc' ?
|
||||||
|
<span>
|
||||||
|
<IconArrowDown />
|
||||||
|
</span>
|
||||||
|
: <span>
|
||||||
|
<IconFilter />
|
||||||
|
</span>
|
||||||
|
}
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
),
|
||||||
|
cell: ({ row }) => {
|
||||||
|
return (
|
||||||
|
<div className="text-center table-item column-viewer-date">
|
||||||
|
{row.original.view_date ? (
|
||||||
|
<>
|
||||||
|
{formatDate(row.original.view_date)}
|
||||||
|
<br />
|
||||||
|
{formatDateTime(row.original.view_date)}
|
||||||
|
<br />
|
||||||
|
</>
|
||||||
|
) : (
|
||||||
|
<div>-</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
},
|
||||||
|
enableColumnFilter: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
accessorKey: 'viewer',
|
||||||
|
header: ({ column }) => (
|
||||||
|
<div className="column column-viewer">
|
||||||
|
<span>
|
||||||
|
{t('who-opened')}
|
||||||
|
</span>
|
||||||
|
<button
|
||||||
|
onClick={() => column.toggleSorting(column.getIsSorted() === 'asc')}
|
||||||
|
className="sort-button"
|
||||||
|
>
|
||||||
|
{
|
||||||
|
column.getIsSorted() === 'asc' ?
|
||||||
|
<span>
|
||||||
|
<IconArrowUp />
|
||||||
|
</span>
|
||||||
|
: column.getIsSorted() === 'desc' ?
|
||||||
|
<span>
|
||||||
|
<IconArrowDown />
|
||||||
|
</span>
|
||||||
|
: <span>
|
||||||
|
<IconFilter />
|
||||||
|
</span>
|
||||||
|
}
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
),
|
||||||
|
cell: ({ row }) => {
|
||||||
|
return (
|
||||||
|
<div className="text-center font-semibold table-item column-viewer">
|
||||||
|
{row.original.viewer}
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
accessorKey: 'location',
|
||||||
|
header: ({ column }) => (
|
||||||
|
<div className="column column-location">
|
||||||
|
<span>
|
||||||
|
{t('location')}
|
||||||
|
</span>
|
||||||
|
<button
|
||||||
|
onClick={() => column.toggleSorting(column.getIsSorted() === 'asc')}
|
||||||
|
className="sort-button"
|
||||||
|
>
|
||||||
|
{
|
||||||
|
column.getIsSorted() === 'asc' ?
|
||||||
|
<span>
|
||||||
|
<IconArrowUp />
|
||||||
|
</span>
|
||||||
|
: column.getIsSorted() === 'desc' ?
|
||||||
|
<span>
|
||||||
|
<IconArrowDown />
|
||||||
|
</span>
|
||||||
|
: <span>
|
||||||
|
<IconFilter />
|
||||||
|
</span>
|
||||||
|
}
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
),
|
||||||
|
cell: ({ row }) => {
|
||||||
|
return (
|
||||||
|
<div className="text-center font-semibold table-item column-location">
|
||||||
|
{row.original.country === 'unknow/unknow' ? (
|
||||||
|
t('not-defined')
|
||||||
|
) : (
|
||||||
|
<EditLocationName location={row.original.country} />
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
},
|
||||||
|
}
|
||||||
|
],
|
||||||
|
[]
|
||||||
|
);
|
||||||
|
|
||||||
|
// Создание таблицы
|
||||||
|
const table = useReactTable({
|
||||||
|
data: tableData,
|
||||||
|
columns,
|
||||||
|
state: {
|
||||||
|
sorting,
|
||||||
|
pagination
|
||||||
|
},
|
||||||
|
pageCount: totalPages,
|
||||||
|
manualPagination: true,
|
||||||
|
manualSorting: true,
|
||||||
|
manualFiltering: true,
|
||||||
|
onPaginationChange: setPagination,
|
||||||
|
onSortingChange: (updater) => {
|
||||||
|
const newSorting = typeof updater === 'function' ? updater(sorting) : updater;
|
||||||
|
setSorting(newSorting);
|
||||||
|
setPagination(prev => ({ ...prev, pageIndex: 0 }));
|
||||||
|
},
|
||||||
|
getCoreRowModel: getCoreRowModel(),
|
||||||
|
getSortedRowModel: getSortedRowModel(),
|
||||||
|
getPaginationRowModel: getPaginationRowModel(),
|
||||||
|
});
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (tableData.length === 0 && pagination.pageIndex > 0 && totalPages > 0) {
|
||||||
|
setPagination(prev => ({ ...prev, pageIndex: Math.max(0, totalPages - 1) }));
|
||||||
|
}
|
||||||
|
}, [tableData, pagination.pageIndex, totalPages]);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
className="block-wrapper"
|
||||||
|
>
|
||||||
|
<div className="tanstak-table-wrapper">
|
||||||
|
|
||||||
|
{/* Фильтры */}
|
||||||
|
<div className="tanstak-table-filtres">
|
||||||
|
<h3
|
||||||
|
className="tanstak-table-title"
|
||||||
|
>
|
||||||
|
{t('history-of-opened')}
|
||||||
|
</h3>
|
||||||
|
<div className="table-filtres-wrapper text-filter-search end">
|
||||||
|
<div className="table-filtres-item">
|
||||||
|
<div className="table-filtres-label">{t('items-per-page')}:</div>
|
||||||
|
<DropDownList
|
||||||
|
value={table.getState().pagination.pageSize}
|
||||||
|
callBack={(newSize: string) => {
|
||||||
|
table.setPageSize(Number(newSize));
|
||||||
|
setPagination(prev => ({ ...prev, pageIndex: 0 }));
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{['5', '10', '20', '50', '100'].map(pageSize => (
|
||||||
|
<li key={pageSize} value={pageSize}>
|
||||||
|
{t('show')} {pageSize}
|
||||||
|
</li>
|
||||||
|
))}
|
||||||
|
</DropDownList>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Таблица */}
|
||||||
|
<div className="tanstak-table-block">
|
||||||
|
<table className="tanstak-table">
|
||||||
|
<thead className="tanstak-table-head">
|
||||||
|
{table.getHeaderGroups().map(headerGroup => (
|
||||||
|
<tr key={headerGroup.id}>
|
||||||
|
{headerGroup.headers.map(header => (
|
||||||
|
<th
|
||||||
|
key={header.id}
|
||||||
|
>
|
||||||
|
{header.isPlaceholder
|
||||||
|
? null
|
||||||
|
: typeof header.column.columnDef.header === 'function'
|
||||||
|
? header.column.columnDef.header(header.getContext())
|
||||||
|
: header.column.columnDef.header as string}
|
||||||
|
</th>
|
||||||
|
))}
|
||||||
|
</tr>
|
||||||
|
))}
|
||||||
|
</thead>
|
||||||
|
<tbody className={`tanstak-table-body ${isFetching ? 'loading' : ''}`}>
|
||||||
|
{isLoading && (
|
||||||
|
<tr>
|
||||||
|
<td colSpan={columns.length} className="text-center relative h-12.5">
|
||||||
|
<div
|
||||||
|
className="loading-animation"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
className="global-spinner"
|
||||||
|
>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{table.getRowModel().rows.length > 0 ? (
|
||||||
|
table.getRowModel().rows.map(row => (
|
||||||
|
<tr key={row.id}>
|
||||||
|
{row.getVisibleCells().map(cell => (
|
||||||
|
<td key={cell.id}>
|
||||||
|
{typeof cell.column.columnDef.cell === 'function'
|
||||||
|
? cell.column.columnDef.cell(cell.getContext())
|
||||||
|
: cell.getValue() as string}
|
||||||
|
</td>
|
||||||
|
))}
|
||||||
|
</tr>
|
||||||
|
))
|
||||||
|
) : (
|
||||||
|
<tr>
|
||||||
|
{!isLoading && (
|
||||||
|
<td colSpan={columns.length} className="text-center">
|
||||||
|
{t('no-data-for-selected-filters')}
|
||||||
|
</td>
|
||||||
|
)}
|
||||||
|
</tr>
|
||||||
|
)}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Пагинация */}
|
||||||
|
<div className="tanstak-table-pagination">
|
||||||
|
<div className="pagination-info">
|
||||||
|
<span className="pagination-info-pages">
|
||||||
|
{t('page')}{' '}
|
||||||
|
<strong>
|
||||||
|
{pagination.pageIndex + 1} {t('out-of')} {totalPages || 1}
|
||||||
|
</strong> | {t('total-document-openings')}: {totalElements}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="pagination-controls">
|
||||||
|
<button
|
||||||
|
className="arrow"
|
||||||
|
onClick={() => table.firstPage()}
|
||||||
|
disabled={!table.getCanPreviousPage() || isLoading}
|
||||||
|
>
|
||||||
|
<IconDoubleArrowLeft />
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
className="arrow"
|
||||||
|
onClick={() => table.previousPage()}
|
||||||
|
disabled={!table.getCanPreviousPage() || isLoading}
|
||||||
|
>
|
||||||
|
<IconArrowLeft />
|
||||||
|
</button>
|
||||||
|
|
||||||
|
<div className="pagination-controls-pages">
|
||||||
|
{Array.from({ length: Math.min(5, totalPages) }, (_, i) => {
|
||||||
|
let pageIndex;
|
||||||
|
if (totalPages <= 5) {
|
||||||
|
pageIndex = i;
|
||||||
|
} else if (pagination.pageIndex <= 2) {
|
||||||
|
pageIndex = i;
|
||||||
|
} else if (pagination.pageIndex >= totalPages - 3) {
|
||||||
|
pageIndex = totalPages - 5 + i;
|
||||||
|
} else {
|
||||||
|
pageIndex = pagination.pageIndex - 2 + i;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pageIndex >= 0 && pageIndex < totalPages) {
|
||||||
|
return (
|
||||||
|
<button
|
||||||
|
key={pageIndex}
|
||||||
|
className={pagination.pageIndex === pageIndex ? 'current' : 'other'}
|
||||||
|
onClick={() => table.setPageIndex(pageIndex)}
|
||||||
|
disabled={isLoading}
|
||||||
|
>
|
||||||
|
{pageIndex + 1}
|
||||||
|
</button>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
})}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<button
|
||||||
|
className="arrow"
|
||||||
|
onClick={() => table.nextPage()}
|
||||||
|
disabled={!table.getCanNextPage() || isLoading}
|
||||||
|
>
|
||||||
|
<IconArrowRight />
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
className="arrow"
|
||||||
|
onClick={() => table.lastPage()}
|
||||||
|
disabled={!table.getCanNextPage() || isLoading}
|
||||||
|
>
|
||||||
|
<IconDoubleArrowRight />
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div >
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
@@ -1,5 +1,11 @@
|
|||||||
import { IconLink, IconDocument, IconCheck, IconPerson, IconGlobe } from '@/app/ui/icons/icons';
|
'use client'
|
||||||
|
|
||||||
|
import { IconLink, IconDocument, IconCheck, IconPerson, IconGlobe, IconCity } from '@/app/ui/icons/icons';
|
||||||
|
import { useTrackingStats } from '@/app/hooks/react-query/useTrackingStats';
|
||||||
|
|
||||||
export function TrackingStatistic() {
|
export function TrackingStatistic() {
|
||||||
|
const { data, isLoading } = useTrackingStats();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
className="general-statistic"
|
className="general-statistic"
|
||||||
@@ -21,7 +27,17 @@ export function TrackingStatistic() {
|
|||||||
<IconDocument />
|
<IconDocument />
|
||||||
</div>
|
</div>
|
||||||
<div className="general-statistic-item-val">
|
<div className="general-statistic-item-val">
|
||||||
33
|
<div
|
||||||
|
className="loading-placeholder start"
|
||||||
|
>
|
||||||
|
{isLoading ? (
|
||||||
|
<div className="loading-animation">
|
||||||
|
<div className="global-spinner" />
|
||||||
|
</div>
|
||||||
|
) : (
|
||||||
|
data?.documentsCount ? data?.documentsCount : 0
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="general-statistic-item-lbl">
|
<div className="general-statistic-item-lbl">
|
||||||
Документов
|
Документов
|
||||||
@@ -30,30 +46,51 @@ export function TrackingStatistic() {
|
|||||||
<div className="general-statistic-item">
|
<div className="general-statistic-item">
|
||||||
<div className="general-statistic-item-ico">
|
<div className="general-statistic-item-ico">
|
||||||
<IconLink />
|
<IconLink />
|
||||||
</div><div className="general-statistic-item-val">
|
</div>
|
||||||
103
|
<div className="general-statistic-item-val">
|
||||||
|
<div
|
||||||
|
className="loading-placeholder start"
|
||||||
|
>
|
||||||
|
{isLoading ? (
|
||||||
|
<div className="loading-animation">
|
||||||
|
<div className="global-spinner" />
|
||||||
|
</div>
|
||||||
|
) : (
|
||||||
|
data?.totalViews ? data?.totalViews : 0
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="general-statistic-item-lbl">
|
<div className="general-statistic-item-lbl">
|
||||||
Открытий
|
Открытий
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="general-statistic-item">
|
{/* <div className="general-statistic-item">
|
||||||
<div className="general-statistic-item-ico">
|
<div className="general-statistic-item-ico">
|
||||||
<IconCheck />
|
<IconCheck />
|
||||||
</div>
|
</div>
|
||||||
<div className="general-statistic-item-val">
|
<div className="general-statistic-item-val">
|
||||||
247
|
{data?.uniqueUsers ? data?.uniqueUsers : 0}
|
||||||
</div>
|
</div>
|
||||||
<div className="general-statistic-item-lbl">
|
<div className="general-statistic-item-lbl">
|
||||||
Верификаций
|
Уникальных пользователей
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div> */}
|
||||||
<div className="general-statistic-item">
|
<div className="general-statistic-item">
|
||||||
<div className="general-statistic-item-ico">
|
<div className="general-statistic-item-ico">
|
||||||
<IconPerson />
|
<IconPerson />
|
||||||
</div>
|
</div>
|
||||||
<div className="general-statistic-item-val">
|
<div className="general-statistic-item-val">
|
||||||
27
|
<div
|
||||||
|
className="loading-placeholder start"
|
||||||
|
>
|
||||||
|
{isLoading ? (
|
||||||
|
<div className="loading-animation">
|
||||||
|
<div className="global-spinner" />
|
||||||
|
</div>
|
||||||
|
) : (
|
||||||
|
data?.uniqueIps ? data?.uniqueIps : 0
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="general-statistic-item-lbl">
|
<div className="general-statistic-item-lbl">
|
||||||
Уникальных IP
|
Уникальных IP
|
||||||
@@ -64,10 +101,41 @@ export function TrackingStatistic() {
|
|||||||
<IconGlobe />
|
<IconGlobe />
|
||||||
</div>
|
</div>
|
||||||
<div className="general-statistic-item-val">
|
<div className="general-statistic-item-val">
|
||||||
7
|
<div
|
||||||
|
className="loading-placeholder start"
|
||||||
|
>
|
||||||
|
{isLoading ? (
|
||||||
|
<div className="loading-animation">
|
||||||
|
<div className="global-spinner" />
|
||||||
|
</div>
|
||||||
|
) : (
|
||||||
|
data?.uniqueCountryCount ? data?.uniqueCountryCount : 0
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="general-statistic-item-lbl">
|
<div className="general-statistic-item-lbl">
|
||||||
Стран
|
Уникальных стран
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className="general-statistic-item">
|
||||||
|
<div className="general-statistic-item-ico">
|
||||||
|
<IconCity />
|
||||||
|
</div>
|
||||||
|
<div className="general-statistic-item-val">
|
||||||
|
<div
|
||||||
|
className="loading-placeholder start"
|
||||||
|
>
|
||||||
|
{isLoading ? (
|
||||||
|
<div className="loading-animation">
|
||||||
|
<div className="global-spinner" />
|
||||||
|
</div>
|
||||||
|
) : (
|
||||||
|
data?.uniqueCountryCount ? data?.uniqueCountryCount : 0
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className="general-statistic-item-lbl">
|
||||||
|
Уникальных городов
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
'use client'
|
'use client'
|
||||||
|
|
||||||
import { useState, useMemo, useCallback } from 'react';
|
import { useState, useMemo } from 'react';
|
||||||
import {
|
import {
|
||||||
useReactTable,
|
useReactTable,
|
||||||
getCoreRowModel,
|
getCoreRowModel,
|
||||||
@@ -51,7 +51,7 @@ export function ViolationsMyClaimsTable() {
|
|||||||
isLoading,
|
isLoading,
|
||||||
isFetching,
|
isFetching,
|
||||||
} = useLastCases({
|
} = useLastCases({
|
||||||
page: pagination.pageIndex + 1,
|
page: pagination.pageIndex,
|
||||||
size: pagination.pageSize,
|
size: pagination.pageSize,
|
||||||
sort_by: getSortParams.sort_by,
|
sort_by: getSortParams.sort_by,
|
||||||
sort_direction: getSortParams.sort_direction ? getSortParams.sort_direction : 'desc',
|
sort_direction: getSortParams.sort_direction ? getSortParams.sort_direction : 'desc',
|
||||||
@@ -270,10 +270,7 @@ export function ViolationsMyClaimsTable() {
|
|||||||
{t('page')}{' '}
|
{t('page')}{' '}
|
||||||
<strong>
|
<strong>
|
||||||
{pagination.pageIndex + 1} {t('out-of')} {totalPages || 1}
|
{pagination.pageIndex + 1} {t('out-of')} {totalPages || 1}
|
||||||
</strong>
|
</strong> | {t('total-claims')}: {totalItems}
|
||||||
</span>
|
|
||||||
<span className="pagination-info-files">
|
|
||||||
| {t('shown')} {tableData.length} {t('out-of')} {totalItems}
|
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|||||||
@@ -52,7 +52,7 @@ export function ViolationsMyComplaintsTable() {
|
|||||||
isLoading,
|
isLoading,
|
||||||
isFetching,
|
isFetching,
|
||||||
} = useLastComplaints({
|
} = useLastComplaints({
|
||||||
page: pagination.pageIndex + 1,
|
page: pagination.pageIndex,
|
||||||
size: pagination.pageSize,
|
size: pagination.pageSize,
|
||||||
sort_by: getSortParams.sort_by,
|
sort_by: getSortParams.sort_by,
|
||||||
sort_direction: getSortParams.sort_direction ? getSortParams.sort_direction : 'desc',
|
sort_direction: getSortParams.sort_direction ? getSortParams.sort_direction : 'desc',
|
||||||
@@ -91,33 +91,33 @@ export function ViolationsMyComplaintsTable() {
|
|||||||
</div>
|
</div>
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
/* {
|
/* {
|
||||||
accessorKey: 'createdAt',
|
accessorKey: 'createdAt',
|
||||||
header: ({ column }) => (
|
header: ({ column }) => (
|
||||||
<div className="column">
|
<div className="column">
|
||||||
<span>{t('date-of-creation')}</span>
|
<span>{t('date-of-creation')}</span>
|
||||||
<button
|
<button
|
||||||
onClick={() => column.toggleSorting(column.getIsSorted() === 'asc')}
|
onClick={() => column.toggleSorting(column.getIsSorted() === 'asc')}
|
||||||
className="sort-button hidden"
|
className="sort-button hidden"
|
||||||
>
|
>
|
||||||
{column.getIsSorted() === 'asc' ? (
|
{column.getIsSorted() === 'asc' ? (
|
||||||
<IconArrowUp />
|
<IconArrowUp />
|
||||||
) : column.getIsSorted() === 'desc' ? (
|
) : column.getIsSorted() === 'desc' ? (
|
||||||
<IconArrowDown />
|
<IconArrowDown />
|
||||||
) : (
|
) : (
|
||||||
<IconFilter />
|
<IconFilter />
|
||||||
)}
|
)}
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
),
|
),
|
||||||
cell: ({ row }) => (
|
cell: ({ row }) => (
|
||||||
<div className="text-center table-item">
|
<div className="text-center table-item">
|
||||||
{formatDate(new Date(row.original.created_at).getTime())}
|
{formatDate(new Date(row.original.created_at).getTime())}
|
||||||
<br />
|
<br />
|
||||||
{formatDateTime(new Date(row.original.created_at).getTime())}
|
{formatDateTime(new Date(row.original.created_at).getTime())}
|
||||||
</div>
|
</div>
|
||||||
),
|
),
|
||||||
}, */
|
}, */
|
||||||
{
|
{
|
||||||
accessorKey: 'updatedAt',
|
accessorKey: 'updatedAt',
|
||||||
header: ({ column }) => (
|
header: ({ column }) => (
|
||||||
@@ -270,10 +270,7 @@ export function ViolationsMyComplaintsTable() {
|
|||||||
{t('page')}{' '}
|
{t('page')}{' '}
|
||||||
<strong>
|
<strong>
|
||||||
{pagination.pageIndex + 1} {t('out-of')} {totalPages || 1}
|
{pagination.pageIndex + 1} {t('out-of')} {totalPages || 1}
|
||||||
</strong>
|
</strong> | {t('total-complaints')}: {totalItems}
|
||||||
</span>
|
|
||||||
<span className="pagination-info-files">
|
|
||||||
| {t('shown')} {tableData.length} {t('out-of')} {totalItems}
|
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|||||||
@@ -125,9 +125,13 @@ export default function ViolationsLastCombinedCases() {
|
|||||||
},
|
},
|
||||||
loop: filteredItems.length > 3,
|
loop: filteredItems.length > 3,
|
||||||
pagination: {
|
pagination: {
|
||||||
|
clickable: true,
|
||||||
|
dynamicBullets: false,
|
||||||
|
},
|
||||||
|
/* pagination: {
|
||||||
el: '.custom-pagination-container', // Кастомный контейнер для пагинации
|
el: '.custom-pagination-container', // Кастомный контейнер для пагинации
|
||||||
clickable: true,
|
clickable: true,
|
||||||
},
|
}, */
|
||||||
onSwiper: (swiper: any) => {
|
onSwiper: (swiper: any) => {
|
||||||
swiperRef.current = swiper;
|
swiperRef.current = swiper;
|
||||||
}
|
}
|
||||||
@@ -235,7 +239,7 @@ export default function ViolationsLastCombinedCases() {
|
|||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
{!isNothingSelected && filteredItems.length > 0 && (
|
{!isNothingSelected && filteredItems.length > 0 && (
|
||||||
<div className="custom-pagination-container text-center"></div>
|
<div className="swiper-pagination-custom-wrapper"></div>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -68,12 +68,6 @@ export default function ViolationsTable() {
|
|||||||
monthAgo.setHours(0, 0, 0, 0);
|
monthAgo.setHours(0, 0, 0, 0);
|
||||||
return { start_date: formatDateTimeForAPI(monthAgo), end_date };
|
return { start_date: formatDateTimeForAPI(monthAgo), end_date };
|
||||||
}
|
}
|
||||||
case 'older': {
|
|
||||||
const monthAgo = new Date(now);
|
|
||||||
monthAgo.setMonth(monthAgo.getMonth() - 1);
|
|
||||||
monthAgo.setHours(0, 0, 0, 0);
|
|
||||||
return { end_date: formatDateTimeForAPI(monthAgo) };
|
|
||||||
}
|
|
||||||
default:
|
default:
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
@@ -108,7 +102,6 @@ export default function ViolationsTable() {
|
|||||||
end_date: dateRange.end_date,
|
end_date: dateRange.end_date,
|
||||||
}),
|
}),
|
||||||
select: (data) => {
|
select: (data) => {
|
||||||
console.log(data);
|
|
||||||
return data;
|
return data;
|
||||||
},
|
},
|
||||||
placeholderData: (previousData) => previousData,
|
placeholderData: (previousData) => previousData,
|
||||||
@@ -154,7 +147,7 @@ export default function ViolationsTable() {
|
|||||||
return nameWithoutExtension.substring(0, maxNameLength) + '...';
|
return nameWithoutExtension.substring(0, maxNameLength) + '...';
|
||||||
};
|
};
|
||||||
|
|
||||||
const columns = useMemo<ColumnDef<FileViolation>[]>(
|
const baseColumns = useMemo<ColumnDef<FileViolation>[]>(
|
||||||
() => [
|
() => [
|
||||||
{
|
{
|
||||||
accessorKey: 'supportId',
|
accessorKey: 'supportId',
|
||||||
@@ -283,32 +276,38 @@ export default function ViolationsTable() {
|
|||||||
{row.original.countLawCase}
|
{row.original.countLawCase}
|
||||||
</div>
|
</div>
|
||||||
),
|
),
|
||||||
},
|
}
|
||||||
{
|
|
||||||
accessorKey: 'actions',
|
|
||||||
header: () => (
|
|
||||||
<div className="column">
|
|
||||||
<span>{t('actions')}</span>
|
|
||||||
</div>
|
|
||||||
),
|
|
||||||
cell: ({ row }) => (
|
|
||||||
<div className="actions">
|
|
||||||
<div className="actions-group">
|
|
||||||
<Link
|
|
||||||
href={`/pages/file/${row.original.fileId}`}
|
|
||||||
className="bg-violet-500 hover:bg-violet-600"
|
|
||||||
title={t('view')}
|
|
||||||
>
|
|
||||||
<IconEye />
|
|
||||||
</Link>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
),
|
|
||||||
},
|
|
||||||
],
|
],
|
||||||
[t, viewport]
|
[t, viewport]
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const actionsColumn = useMemo<ColumnDef<FileViolation>>(
|
||||||
|
() => ({
|
||||||
|
accessorKey: 'actions',
|
||||||
|
header: () => (
|
||||||
|
<div className="column">
|
||||||
|
<span>{t('actions')}</span>
|
||||||
|
</div>
|
||||||
|
),
|
||||||
|
cell: ({ row }) => (
|
||||||
|
<div className="actions">
|
||||||
|
<div className="actions-group">
|
||||||
|
<Link
|
||||||
|
href={`/pages/file/${row.original.fileId}?startDate=${dateRange.start_date || ''}&endDate=${dateRange.end_date || ''}`}
|
||||||
|
className="bg-violet-500 hover:bg-violet-600"
|
||||||
|
title={t('view')}
|
||||||
|
>
|
||||||
|
<IconEye />
|
||||||
|
</Link>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
),
|
||||||
|
}),
|
||||||
|
[t, dateRange.start_date, dateRange.end_date]
|
||||||
|
);
|
||||||
|
|
||||||
|
const columns = useMemo(() => [...baseColumns, actionsColumn], [baseColumns, actionsColumn]);
|
||||||
|
|
||||||
const table = useReactTable({
|
const table = useReactTable({
|
||||||
data: violationData?.content || [],
|
data: violationData?.content || [],
|
||||||
columns,
|
columns,
|
||||||
@@ -366,8 +365,6 @@ export default function ViolationsTable() {
|
|||||||
return t('for-a-week');
|
return t('for-a-week');
|
||||||
case 'month':
|
case 'month':
|
||||||
return t('for-a-month');
|
return t('for-a-month');
|
||||||
case 'older':
|
|
||||||
return t('older-than-a-month');
|
|
||||||
default:
|
default:
|
||||||
return t('today');
|
return t('today');
|
||||||
}
|
}
|
||||||
@@ -378,7 +375,6 @@ export default function ViolationsTable() {
|
|||||||
<li value="today">{t('today')}</li>
|
<li value="today">{t('today')}</li>
|
||||||
<li value="week">{t('for-a-week')}</li>
|
<li value="week">{t('for-a-week')}</li>
|
||||||
<li value="month">{t('for-a-month')}</li>
|
<li value="month">{t('for-a-month')}</li>
|
||||||
<li value="older">{t('older-than-a-month')}</li>
|
|
||||||
</DropDownList>
|
</DropDownList>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -481,10 +477,7 @@ export default function ViolationsTable() {
|
|||||||
{t('page')}{' '}
|
{t('page')}{' '}
|
||||||
<strong>
|
<strong>
|
||||||
{table.getState().pagination.pageIndex + 1} {t('out-of')} {violationData?.totalPages || 1}
|
{table.getState().pagination.pageIndex + 1} {t('out-of')} {violationData?.totalPages || 1}
|
||||||
</strong>
|
</strong> | {t('total-matches')}: {violationData?.totalElements}
|
||||||
</span>
|
|
||||||
<span className="pagination-info-files">
|
|
||||||
| {t('shown')} {violationData?.content?.length || 0} {t('out-of')} {violationData?.totalElements || 0}
|
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|||||||
@@ -385,7 +385,9 @@
|
|||||||
"violation-id": "Violation ID",
|
"violation-id": "Violation ID",
|
||||||
"no-information-about-the-complaint": "No information about the complaint",
|
"no-information-about-the-complaint": "No information about the complaint",
|
||||||
"the-complaint-has-not-been-registered": "The complaint has not been registered",
|
"the-complaint-has-not-been-registered": "The complaint has not been registered",
|
||||||
|
"the-claims-has-not-been-registered": "The claims has not been registered",
|
||||||
"the-complaint-has-been-registered": "The complaint has been registered",
|
"the-complaint-has-been-registered": "The complaint has been registered",
|
||||||
|
"the-claims-has-been-registered": "The claims has been registered",
|
||||||
"all-statuses": "All statuses",
|
"all-statuses": "All statuses",
|
||||||
"all": "All",
|
"all": "All",
|
||||||
"mark-all-as-read": "Mark all as read",
|
"mark-all-as-read": "Mark all as read",
|
||||||
@@ -464,7 +466,42 @@
|
|||||||
"please-enter-complaint-text-first": "Please enter complaint text first",
|
"please-enter-complaint-text-first": "Please enter complaint text first",
|
||||||
"please-enter-template-name": "Please enter template name",
|
"please-enter-template-name": "Please enter template name",
|
||||||
"template-saved-successfully": "Template saved successfully",
|
"template-saved-successfully": "Template saved successfully",
|
||||||
"no-claims-complaints-found": "No complaints/claims found"
|
"no-claims-complaints-found": "No complaints/claims found",
|
||||||
|
"no-notifications": "No notifications",
|
||||||
|
"who-opened": "Who opened",
|
||||||
|
"time": "Time",
|
||||||
|
"location": "Location",
|
||||||
|
"history-of-opened": "History of opened",
|
||||||
|
"not-defined": "Not defined",
|
||||||
|
"not-defined-city": "Not defined",
|
||||||
|
"not-defined-country": "Not defined",
|
||||||
|
"total-document-openings": "Total document openings",
|
||||||
|
"total-matches": "Total matches",
|
||||||
|
"total-complaints": "Total complaints",
|
||||||
|
"total-claims": "Total claims",
|
||||||
|
"city": "City",
|
||||||
|
"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...",
|
||||||
|
"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": {
|
"Login-register-form": {
|
||||||
"and": "and",
|
"and": "and",
|
||||||
@@ -595,7 +632,27 @@
|
|||||||
"notification-token-not-found": "Token not found",
|
"notification-token-not-found": "Token not found",
|
||||||
"notification-file-moderation": "File moderation event",
|
"notification-file-moderation": "File moderation event",
|
||||||
"notification-file-added": "File added to system",
|
"notification-file-added": "File added to system",
|
||||||
"notification-search-operation-filed": "Search operation failed"
|
"notification-search-operation-filed": "Search operation failed",
|
||||||
|
"not-specified": "not specified",
|
||||||
|
"not-specified-date": "not specified",
|
||||||
|
"not-specified-file-name": "not specified",
|
||||||
|
"message-missing": "message missing",
|
||||||
|
"reason-not-specified": "reason not specified",
|
||||||
|
"no-comment": "no comment",
|
||||||
|
"unknown-user": "unknown user",
|
||||||
|
"error-not-described": "error not described",
|
||||||
|
"not-scheduled": "not scheduled",
|
||||||
|
"notification-without-text": "Notification without text",
|
||||||
|
"user-verified": "Status: {status}. Update date: {updateDate}",
|
||||||
|
"monitoring-result": "Monitoring result: {message}",
|
||||||
|
"complaint-status-changed": "Complaint status changed from {oldStatus} to {newStatus}. Violation: {violation}. File: {file}",
|
||||||
|
"file-added-to-system": "Status: {status}. File name: {fileName}",
|
||||||
|
"file-moderation-event": "File moderation for '{fileName}'. Status changed from {oldStatus} to {newStatus}. Comment: {comment}",
|
||||||
|
"payment-result": "Payment result: {status}. Amount: {amount}",
|
||||||
|
"referral-registered": "Referral registered: {referralUser}",
|
||||||
|
"search-result": "Search results from {startDate} to {endDate}. Type: {searchType}. Files found: {count}",
|
||||||
|
"search-operation-failed": "Status: {status}. Message: {message}. Reason: {reason}. Next run: {nextRun}",
|
||||||
|
"token-not-found": "Current: {currentTokens}, needed: {needTokens}. Message: {message}. Next run: {nextRun}"
|
||||||
},
|
},
|
||||||
"User-status": {
|
"User-status": {
|
||||||
"under-moderation": "Under moderation",
|
"under-moderation": "Under moderation",
|
||||||
|
|||||||
@@ -204,8 +204,8 @@
|
|||||||
"document-occupy": "Занимают документы",
|
"document-occupy": "Занимают документы",
|
||||||
"violations-found": "Найдено нарушений",
|
"violations-found": "Найдено нарушений",
|
||||||
"total-violations": "Всего нарушений",
|
"total-violations": "Всего нарушений",
|
||||||
"violations-registered": "Жалоб зарегистрированно",
|
"violations-registered": "Жалоб зарегистрировано",
|
||||||
"claims-registered": "Претензий зарегистрированно",
|
"claims-registered": "Претензий зарегистрировано",
|
||||||
"new": "Новые",
|
"new": "Новые",
|
||||||
"in-progress": "В работе",
|
"in-progress": "В работе",
|
||||||
"it-decided": "Решено",
|
"it-decided": "Решено",
|
||||||
@@ -385,7 +385,9 @@
|
|||||||
"violation-id": "ID нарушения",
|
"violation-id": "ID нарушения",
|
||||||
"no-information-about-the-complaint": "Нет информации о жалобе",
|
"no-information-about-the-complaint": "Нет информации о жалобе",
|
||||||
"the-complaint-has-not-been-registered": "Жалоба не зарегистрирована",
|
"the-complaint-has-not-been-registered": "Жалоба не зарегистрирована",
|
||||||
|
"the-claims-has-not-been-registered": "Претензия не зарегистрирована",
|
||||||
"the-complaint-has-been-registered": "Жалоба зарегистрирована",
|
"the-complaint-has-been-registered": "Жалоба зарегистрирована",
|
||||||
|
"the-claims-has-been-registered": "Претензия зарегистрирована",
|
||||||
"all-statuses": "Все статусы",
|
"all-statuses": "Все статусы",
|
||||||
"all": "Все",
|
"all": "Все",
|
||||||
"mark-all-as-read": "Отметить все как прочитанные",
|
"mark-all-as-read": "Отметить все как прочитанные",
|
||||||
@@ -464,7 +466,42 @@
|
|||||||
"please-enter-complaint-text-first": "Пожалуйста, сначала введите текст жалобы",
|
"please-enter-complaint-text-first": "Пожалуйста, сначала введите текст жалобы",
|
||||||
"please-enter-template-name": "Пожалуйста, введите название шаблона",
|
"please-enter-template-name": "Пожалуйста, введите название шаблона",
|
||||||
"template-saved-successfully": "Шаблон успешно сохранен",
|
"template-saved-successfully": "Шаблон успешно сохранен",
|
||||||
"no-claims-complaints-found": "Жалобы/претензии не найдены"
|
"no-claims-complaints-found": "Жалобы / претензии не найдены",
|
||||||
|
"no-notifications": "Нет уведомлений",
|
||||||
|
"who-opened": "Кто открыл",
|
||||||
|
"time": "Время",
|
||||||
|
"location": "Местоположение",
|
||||||
|
"history-of-opened": "История открытий",
|
||||||
|
"not-defined": "Не определено",
|
||||||
|
"not-defined-city": "Не определен",
|
||||||
|
"not-defined-country": "Не определена",
|
||||||
|
"total-document-openings": "Всего открытий документов",
|
||||||
|
"total-matches": "Всего совпадений",
|
||||||
|
"total-complaints": "Всего нарушений",
|
||||||
|
"total-claims": "Всего претензий",
|
||||||
|
"city": "Город",
|
||||||
|
"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": "Отправка...",
|
||||||
|
"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": {
|
"Login-register-form": {
|
||||||
"and": "и",
|
"and": "и",
|
||||||
@@ -595,7 +632,27 @@
|
|||||||
"notification-token-not-found": "Токен не найден",
|
"notification-token-not-found": "Токен не найден",
|
||||||
"notification-file-moderation": "Модерация файла",
|
"notification-file-moderation": "Модерация файла",
|
||||||
"notification-file-added": "Файл добавлен в систему",
|
"notification-file-added": "Файл добавлен в систему",
|
||||||
"notification-search-operation-filed": "Ошибка операции поиска"
|
"notification-search-operation-filed": "Ошибка операции поиска",
|
||||||
|
"not-specified": "не указан",
|
||||||
|
"not-specified-date": "не указана",
|
||||||
|
"not-specified-file-name": "не указано",
|
||||||
|
"message-missing": "сообщение отсутствует",
|
||||||
|
"reason-not-specified": "причина не указана",
|
||||||
|
"no-comment": "без комментария",
|
||||||
|
"unknown-user": "неизвестный пользователь",
|
||||||
|
"error-not-described": "ошибка не описана",
|
||||||
|
"not-scheduled": "не запланирован",
|
||||||
|
"notification-without-text": "Уведомление без текста",
|
||||||
|
"user-verified": "Статус: {status}. Дата обновления: {updateDate}",
|
||||||
|
"monitoring-result": "Результат мониторинга: {message}",
|
||||||
|
"complaint-status-changed": "Статус жалобы изменён с {oldStatus} на {newStatus}. Нарушение: {violation}. Файл: {file}",
|
||||||
|
"file-added-to-system": "Статус: {status}. Имя файла: {fileName}",
|
||||||
|
"file-moderation-event": "Модерация файла '{fileName}'. Статус изменён с {oldStatus} на {newStatus}. Комментарий: {comment}",
|
||||||
|
"payment-result": "Результат платежа: {status}. Сумма: {amount}",
|
||||||
|
"referral-registered": "Зарегистрирован реферал: {referralUser}",
|
||||||
|
"search-result": "Результаты поиска с {startDate} по {endDate}. Тип: {searchType}. Найдено файлов: {count}",
|
||||||
|
"search-operation-failed": "Статус: {status}. Сообщение: {message}. Причина: {reason}. Следующий запуск: {nextRun}",
|
||||||
|
"token-not-found": "Текущие: {currentTokens}, необходимо: {needTokens}. Сообщение: {message}. Следующий запуск: {nextRun}"
|
||||||
},
|
},
|
||||||
"User-status": {
|
"User-status": {
|
||||||
"under-moderation": "На модерации",
|
"under-moderation": "На модерации",
|
||||||
@@ -606,7 +663,5 @@
|
|||||||
"user-verification": "Верификация пользователя",
|
"user-verification": "Верификация пользователя",
|
||||||
"Status": "Статус"
|
"Status": "Статус"
|
||||||
},
|
},
|
||||||
"Countryes": {
|
"Countryes": {}
|
||||||
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
+1
-1
@@ -37,7 +37,7 @@ export default async function proxy(request: NextRequest) {
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
const cookie = (await cookies()).get('session')?.value;
|
const cookie = (await cookies()).get('session_nc_db')?.value;
|
||||||
const session = await decrypt(cookie);
|
const session = await decrypt(cookie);
|
||||||
|
|
||||||
if (isProtectedRoute && !session?.token) {
|
if (isProtectedRoute && !session?.token) {
|
||||||
|
|||||||
Reference in New Issue
Block a user