From 8f75349297c3e62975d8dc1fa41c781e0c2af38e Mon Sep 17 00:00:00 2001 From: "nabijonovdavronbek619@gmail.com" Date: Tue, 7 Apr 2026 16:40:28 +0500 Subject: [PATCH] SI detail page cretaed --- src/app/[locale]/si/[id]/page.tsx | 10 + src/widgets/cabinet/ui/tables/SiTable.tsx | 14 +- src/widgets/detail/SiDetailPage.tsx | 356 ++++++++++++++++++ src/widgets/fileUpload/lib/usePlagiraism.ts | 1 + .../fileUpload/ui/Plagiraismcheckform.tsx | 29 +- src/widgets/fileUpload/ui/documentsType.tsx | 53 +++ 6 files changed, 439 insertions(+), 24 deletions(-) create mode 100644 src/app/[locale]/si/[id]/page.tsx create mode 100644 src/widgets/detail/SiDetailPage.tsx create mode 100644 src/widgets/fileUpload/ui/documentsType.tsx diff --git a/src/app/[locale]/si/[id]/page.tsx b/src/app/[locale]/si/[id]/page.tsx new file mode 100644 index 0000000..7ec954b --- /dev/null +++ b/src/app/[locale]/si/[id]/page.tsx @@ -0,0 +1,10 @@ +import SiDetailPage from '@/widgets/detail/SiDetailPage'; + +interface Props { + params: Promise<{ id: string }>; +} + +export default async function SiDetail({ params }: Props) { + const { id } = await params; + return ; +} diff --git a/src/widgets/cabinet/ui/tables/SiTable.tsx b/src/widgets/cabinet/ui/tables/SiTable.tsx index b9be12a..1504db1 100644 --- a/src/widgets/cabinet/ui/tables/SiTable.tsx +++ b/src/widgets/cabinet/ui/tables/SiTable.tsx @@ -1,6 +1,6 @@ 'use client'; import React from 'react'; -import { Download, CreditCard } from 'lucide-react'; +import { Download, CreditCard, Eye } from 'lucide-react'; import { useMutation } from '@tanstack/react-query'; import { useSiHistory } from '../../lib/hooks/useSiHistory'; import { formatDate } from '@/widgets/history/lib/utils'; @@ -9,6 +9,7 @@ import { links } from '@/shared/request/links'; import { toast } from 'react-toastify'; import type { SiDocument } from '../../lib/types'; import { SiButton } from '@/features/modals/siModal/page'; +import { useRouter, useParams } from 'next/navigation'; // ─── State badge ─────────────────────────────────────────────────────────────── @@ -89,6 +90,9 @@ const SiRow: React.FC<{ item: SiDocument; index: number }> = ({ item, index, }) => { + const router = useRouter(); + const { locale } = useParams() as { locale: string }; + const pay = useMutation({ mutationKey: ['si-payment', item.id], mutationFn: () => @@ -168,7 +172,13 @@ const SiRow: React.FC<{ item: SiDocument; index: number }> = ({ {pay.isPending ? '...' : "To'lash"} ) : ( - + )} diff --git a/src/widgets/detail/SiDetailPage.tsx b/src/widgets/detail/SiDetailPage.tsx new file mode 100644 index 0000000..12b83cb --- /dev/null +++ b/src/widgets/detail/SiDetailPage.tsx @@ -0,0 +1,356 @@ +'use client'; + +import React, { useEffect } from 'react'; +import { useQuery } from '@tanstack/react-query'; +import { useParams } from 'next/navigation'; +import { apiRequest } from '@/shared/request/apiRequest'; +import { links } from '@/shared/request/links'; +import { Download, CloudDownload } from 'lucide-react'; + +// ── Types ──────────────────────────────────────────────────────────────────── + +type SiResult = { + original: number; + ai_possible: number; + ai: number; +}; + +type SiDetail = { + id: number; + title: string; + file: string; + created_at: string; + updated_at: string; + state: 'paid' | 'unpaid'; + total_words: number; + si_percantage: number | null; + result: SiResult | null; + file_size?: number; + file_extension?: string; + total_price?: number | string; + user?: { name: string; surname: string }; +}; + +// ── Helpers ─────────────────────────────────────────────────────────────────── + +function formatDate(iso: string): string { + return new Date(iso).toLocaleString('uz-UZ', { + year: 'numeric', + month: '2-digit', + day: '2-digit', + hour: '2-digit', + minute: '2-digit', + second: '2-digit', + }); +} + +function fileExtension(url: string): string { + const name = url.split('/').pop() ?? ''; + const ext = name.split('.').pop(); + return ext ? `.${ext}` : '—'; +} + +function fileName(url: string): string { + return url.split('/').pop() ?? '—'; +} + +function fileSizeMb(bytes?: number): string { + if (!bytes) return '—'; + return `${(bytes / 1024 / 1024).toFixed(2)} MB`; +} + +// ── Sub-components ──────────────────────────────────────────────────────────── + +function InfoRow({ label, value }: { label: string; value: React.ReactNode }) { + return ( +
+ {label} + + {value} + +
+ ); +} + +function SiBar({ + label, + value, + color, +}: { + label: string; + value: number; + color: string; +}) { + return ( +
+
+ {label} + {value}% +
+
+
+
+
+ ); +} + +// ── Skeleton ────────────────────────────────────────────────────────────────── + +function Skeleton({ className }: { className?: string }) { + return ( +
+ ); +} + +function LoadingSkeleton() { + return ( +
+
+
+ +
+ {Array.from({ length: 8 }).map((_, i) => ( +
+ + +
+ ))} +
+
+ {Array.from({ length: 3 }).map((_, i) => ( + + ))} +
+
+
+ ); +} + +// ── Main Page ───────────────────────────────────────────────────────────────── + +export default function SiDetailPage({ id }: { id: number }) { + const { locale } = useParams() as { locale: string }; + useEffect(() => { + console.log(locale); + }, []); + + const { + data: doc, + isLoading, + isError, + } = useQuery({ + queryKey: ['si-detail', id], + queryFn: (): Promise => + apiRequest('GET', links.si_id(id)).then((res) => res.data as SiDetail), + enabled: !!id, + staleTime: 1000 * 60 * 5, + }); + + if (isLoading) return ; + + if (isError || !doc) { + return ( +
+
+

+ Ma'lumot topilmadi +

+ +
+
+ ); + } + + // Derive SI percentages + const original = doc.result?.original ?? 100 - (doc.si_percantage ?? 0); + const aiPossible = doc.result?.ai_possible ?? 0; + const ai = doc.result?.ai ?? doc.si_percantage ?? 0; + + return ( +
+ {/* ── Header ── */} +
+
+ +

+ {doc.title || 'SI tekshiruv'} +

+
+
+ +
+ {/* ── Section 1: Asosiy ma'lumotlar ── */} +
+ {/* Section header */} +
+

+ Asosiy ma'lumotlar +

+
+
+ +
+ {/* Sub-header */} +

+ Hujjat haqida ma'lumotlar +

+ + + {doc.user && ( + + )} + + + 0 + ? doc.total_words.toLocaleString('uz-UZ') + : '—' + } + /> + + {doc.file_size !== undefined && ( + + )} + {doc.total_price !== undefined && ( + + )} + + {/* Download button */} + {doc.file && ( + + )} +
+
+ + {/* ── Section 2: SI detektor natijalari ── */} +
+ {/* Header row */} +
+
+ {/* PDF icon */} +
+ + + + PDF + + +
+
+

+ Hujjatning SI detektori natijalari +

+

+ Ushbu oynada foydalanuvchi tomonidan yuklangan matn + sun'iy intellekt (SI) yordamida yozilgan bo'lish + ehtimoli bo'yicha tahlil natijalari aks etirilgan. + Detektor matnning stilistik, grammatik va semantik + xususiyatlarini baholab, uning qanchalik darajada sun'iy + intellekt tomonidan generatsiya qilingan bo'lishi + mumkinligini foizlik ko'rinishida ko'rsatadi. +

+
+
+ + {doc.file && ( + + + Yuklab olish + + )} +
+ + {/* Bars */} +
+ + + +
+
+
+
+ ); +} diff --git a/src/widgets/fileUpload/lib/usePlagiraism.ts b/src/widgets/fileUpload/lib/usePlagiraism.ts index 02c8152..d520bbd 100644 --- a/src/widgets/fileUpload/lib/usePlagiraism.ts +++ b/src/widgets/fileUpload/lib/usePlagiraism.ts @@ -140,6 +140,7 @@ export function usePlagiarismForm() { fd.append('file', form.file!); // File object — multipart/form-data fd.append('certificate', String(form.certificate)); fd.append('total_price', '41200'); + fd.append('document_type', form.document_type); checkdocumentRequest.mutate(fd); }, [form], diff --git a/src/widgets/fileUpload/ui/Plagiraismcheckform.tsx b/src/widgets/fileUpload/ui/Plagiraismcheckform.tsx index 21de95b..7e202b8 100644 --- a/src/widgets/fileUpload/ui/Plagiraismcheckform.tsx +++ b/src/widgets/fileUpload/ui/Plagiraismcheckform.tsx @@ -11,10 +11,10 @@ import { } from './Plagiraismui'; import { usePlagiarismForm } from '../lib/usePlagiraism'; import { useTranslations } from 'next-intl'; -import { DOCUMENT_TYPES } from '@/features/modals/sertificateModal/types'; import { PaymentModal } from '@/features/modals/paymentModal/ui/Paymentmodal'; +import DocumentsTypes from './documentsType'; -const inputCls = ` +export const inputCls = ` w-full px-3.5 py-3.5 text-[14px] text-slate-800 bg-blue-50 border border-blue-200 rounded-xl placeholder:text-blue-400 @@ -177,26 +177,11 @@ export function PlagiarismCheckForm() {
{/* Document type */} - - - + {/* Submit */} void; + disabled?: boolean; +} + +export default function DocumentsTypes({ + value, + onChange, + disabled, +}: DocumentsTypesProps) { + const { data, isLoading } = useQuery({ + queryKey: ['document_types'], + queryFn: (): Promise => + apiRequest('GET', links.document_types).then( + (res) => res.data as DocumentType[], + ), + }); + + return ( + + + + ); +}