diff --git a/src/features/modals/sertificateModal/sertificateModal.tsx b/src/features/modals/sertificateModal/sertificateModal.tsx index d32c6b9..8d888f8 100644 --- a/src/features/modals/sertificateModal/sertificateModal.tsx +++ b/src/features/modals/sertificateModal/sertificateModal.tsx @@ -9,7 +9,7 @@ import { Loader2, CheckCircle2, } from 'lucide-react'; - +import { useTranslations } from 'next-intl'; import { useCertificateModal } from './useSertificateModal'; import { Field, inputCls } from './modalField'; import { SertificateModalProps } from './types'; @@ -20,6 +20,7 @@ export default function SertificateModal({ open, setOpen, }: SertificateModalProps) { + const t = useTranslations('CertificateModal'); const { form, updateField, @@ -44,7 +45,7 @@ export default function SertificateModal({ onKeyDown={handleKeyDown} role="dialog" aria-modal="true" - aria-label="Sertifikat yaratish" + aria-label={t('title')} > {/* Backdrop */}

- Sertifikat yaratish + {t('title')}

@@ -101,7 +102,7 @@ export default function SertificateModal({ icon={ } - label="Muallifning to'liq ismi" + label={t('authorName')} > updateField('fullname', e.target.value)} disabled={loading || success} - placeholder="Ismingizni kiriting..." + placeholder={t('namePlaceholder')} className={inputCls} /> @@ -124,7 +125,7 @@ export default function SertificateModal({ strokeWidth={2} /> } - label="Hujjat mavzusi" + label={t('documentTheme')} > updateField('document_theme', e.target.value)} disabled={loading || success} - placeholder="Mavzuni kiriting..." + placeholder={t('themePlaceholder')} className={inputCls} /> {/* Document type */} updateField('document_type', val)} + value={form.type} + onChange={(val) => updateField('type', val)} disabled={loading || success} /> @@ -151,7 +152,9 @@ export default function SertificateModal({ strokeWidth={1.8} />
- Hujjat ID + + {t('documentId')} + #{document_id} @@ -177,15 +180,15 @@ export default function SertificateModal({ {loading ? ( <> - Yaratilmoqda... + {t('creating')} ) : success ? ( <> - Sertifikat yaratildi! + {t('created')} ) : ( - Sertifikat yaratish + {t('create')} )}
diff --git a/src/features/modals/sertificateModal/types.ts b/src/features/modals/sertificateModal/types.ts index 2721456..0238e90 100644 --- a/src/features/modals/sertificateModal/types.ts +++ b/src/features/modals/sertificateModal/types.ts @@ -1,7 +1,7 @@ export interface CertificateFormData { fullname: string; document_theme: string; - document_type: string | number; + type: number; document_id: number; } diff --git a/src/features/modals/sertificateModal/useSertificateModal.ts b/src/features/modals/sertificateModal/useSertificateModal.ts index 6a2a432..751ee22 100644 --- a/src/features/modals/sertificateModal/useSertificateModal.ts +++ b/src/features/modals/sertificateModal/useSertificateModal.ts @@ -1,8 +1,10 @@ import React, { useState, useEffect, useRef } from 'react'; import { useMutation } from '@tanstack/react-query'; +import { AxiosError } from 'axios'; import { apiRequest } from '@/shared/request/apiRequest'; import { links } from '@/shared/request/links'; import { CertificateFormData } from './types'; +import { SIPaymentResponse } from '../siModal/utils/useFileUpload'; interface UseCertificateModalProps { document_id: number; @@ -24,13 +26,21 @@ export function useCertificateModal({ const [form, setForm] = useState({ fullname: '', document_theme: '', - document_type: '', + type: 0, document_id, }); const [success, setSuccess] = useState(false); const [visible, setVisible] = useState(false); const inputRef = useRef(null); + const payment = useMutation({ + mutationFn: (id: number) => + apiRequest('POST', links.demo_pay(id)), + onSuccess: (res) => { + window.open(res?.data?.payment_link, '_self'); + }, + }); + const certificateMutation = useMutation({ mutationFn: (payload: CertificatePayload) => apiRequest('POST', links.sertifikat(document_id), payload).then( @@ -53,13 +63,18 @@ export function useCertificateModal({ resetForm(); }, 1500); }, + onError: (error: AxiosError<{ code?: string }>) => { + if (error?.response?.data?.code === 'not_paid') { + payment.mutate(document_id); + } + }, }); const resetForm = () => { setForm({ fullname: '', document_theme: '', - document_type: '', + type: 0, document_id, }); }; @@ -90,16 +105,14 @@ export function useCertificateModal({ ) => setForm((prev) => ({ ...prev, [field]: value })); const isFormValid = - !!form.fullname.trim() && - !!form.document_theme.trim() && - !!form.document_type; + !!form.fullname.trim() && !!form.document_theme.trim() && !!form.type; const handleSubmit = () => { if (!isFormValid || certificateMutation.isPending) return; certificateMutation.mutate({ full_name: form.fullname, file_name: form.document_theme, - document_type: Number(form.document_type), + document_type: Number(form.type), }); }; diff --git a/src/features/modals/siModal/page.tsx b/src/features/modals/siModal/page.tsx index a74c03e..9e8b8af 100644 --- a/src/features/modals/siModal/page.tsx +++ b/src/features/modals/siModal/page.tsx @@ -3,9 +3,11 @@ import { useState } from 'react'; import { ArrowRight, BrainCircuit, Plus } from 'lucide-react'; import { FileUploadModal } from './ui/fileUploadModal'; +import { useTranslations } from 'next-intl'; export function SiCTACard() { const [isOpen, setIsOpen] = useState(false); + const t = useTranslations('Cabinet'); return ( <> @@ -17,12 +19,14 @@ export function SiCTACard() { -

SI detektor

+

+ {t('siDetector')} +

- Matnni sun'iy intellekt uchun tekshiring + {t('siDesc')}

- Yuborish + {t('submit')} setIsOpen(false)} /> @@ -32,6 +36,7 @@ export function SiCTACard() { export function SiButton() { const [isOpen, setIsOpen] = useState(false); + const t = useTranslations('Cabinet'); return ( <> setIsOpen(false)} /> diff --git a/src/features/modals/siModal/utils/useFileUpload.ts b/src/features/modals/siModal/utils/useFileUpload.ts index b45e20c..40dd445 100644 --- a/src/features/modals/siModal/utils/useFileUpload.ts +++ b/src/features/modals/siModal/utils/useFileUpload.ts @@ -20,7 +20,7 @@ interface CreateSIOrderResponse { order_id: number; } -interface SIPaymentResponse { +export interface SIPaymentResponse { payment_link: string; } @@ -57,7 +57,7 @@ export function useFileUpload(): UseFileUploadReturn { const siPayment = useMutation({ mutationKey: ['si-payment'], mutationFn: (order_id: number) => - apiRequest('POST', links.si_payment(order_id)), + apiRequest('POST', links.demo_pay(order_id)), onSuccess: (res) => { window.open(res.data.payment_link, '_self'); }, diff --git a/src/shared/config/i18n/messages/en.json b/src/shared/config/i18n/messages/en.json index f1fce94..8527d8d 100644 --- a/src/shared/config/i18n/messages/en.json +++ b/src/shared/config/i18n/messages/en.json @@ -76,7 +76,8 @@ "resultClean": "Clean", "resultPlagiarismFound": "Plagiarism Found", "resultPending": "Pending", - "resultFailed": "Failed" + "resultFailed": "Failed", + "plagiatCheck": "Plagiarism Check" }, "DetailPage": { "id": "ID", @@ -126,7 +127,11 @@ "unknownError": "Unknown error", "words": "words", "aiProbabilityText": "Probability that the text was generated with AI has been detected", - "documentNumber": "Document subject" + "documentNumber": "Document subject", + "scoreAiContent": "Self-citation", + "scoreOriginality": "Originality", + "scorePlagiarism": "Plagiarism", + "scoreCitation": "Citation" }, "Hero": { "badge": "Academic Integrity Platform", @@ -240,5 +245,68 @@ }, "unknownUser": "Username not found", "file": "File", - "upload": "Download certificate" + "upload": "Download certificate", + "Cabinet": { + "plagiatCheck": "Plagiarism Check", + "checkDesc": "Check your document for originality", + "submit": "Submit", + "siDetector": "AI Detector", + "siDesc": "Check text for AI content", + "home": "Home", + "plagiat": "Plagiarism", + "siNav": "AI Detector", + "payments": "Payment History", + "profile": "Profile", + "close": "Close", + "personalCabinet": "Personal Cabinet", + "plagiatChecks": "Plagiarism Checks", + "dashboard": "Dashboard" + }, + "SiDetail": { + "siCheck": "AI Check", + "basicInfo": "Basic Information", + "documentInfo": "Document Information", + "documentName": "Document Name", + "checker": "Checker", + "uploadedAt": "Document Upload Time", + "originalFileName": "Original File Name", + "wordCount": "Word Count", + "fileExt": "File Extension", + "fileSize": "File Size", + "amountCharged": "Amount Charged", + "downloadOriginal": "Download Original Document", + "siResultsTitle": "Document AI Detector Results", + "siResultsDesc": "This window displays the analysis results of the text uploaded by the user regarding the probability of being written with the help of artificial intelligence. The detector evaluates the stylistic, grammatical and semantic features of the text and shows in percentage how likely it was generated by artificial intelligence.", + "download": "Download", + "originalText": "Original Text", + "possibleAi": "Possible AI", + "aiContent": "Artificial Intelligence" + }, + "PlagiatResult": { + "plagiarismLevel": "Plagiarism Level", + "aiWritten": "AI Written", + "originality": "Originality", + "citation": "Citation", + "plagiat": "Plagiarism", + "aiGeneration": "AI Generation", + "original": "Original", + "checked": "Checked" + }, + "CertificateModal": { + "title": "Create Certificate", + "close": "Close", + "authorName": "Author's Full Name", + "namePlaceholder": "Enter your name...", + "documentTheme": "Document Theme", + "themePlaceholder": "Enter the topic...", + "documentId": "Document ID", + "creating": "Creating...", + "created": "Certificate Created!", + "create": "Create Certificate" + }, + "DocumentTypes": { + "label": "Document Type", + "loading": "Loading...", + "placeholder": "Select document type..." + } } diff --git a/src/shared/config/i18n/messages/ru.json b/src/shared/config/i18n/messages/ru.json index d831516..5127112 100644 --- a/src/shared/config/i18n/messages/ru.json +++ b/src/shared/config/i18n/messages/ru.json @@ -75,7 +75,8 @@ "resultClean": "Чисто", "resultPlagiarismFound": "Обнаружен плагиат", "resultPending": "В ожидании", - "resultFailed": "Не удалось" + "resultFailed": "Не удалось", + "plagiatCheck": "Проверка на плагиат" }, "DetailPage": { "id": "ID", @@ -125,7 +126,11 @@ "unknownError": "Неизвестная ошибка", "words": "слов", "aiProbabilityText": "Обнаружена вероятность того, что текст создан с помощью ИИ", - "documentNumber": "Тема документа" + "documentNumber": "Тема документа", + "scoreAiContent": "Самоцитирование", + "scoreOriginality": "Оригинальность", + "scorePlagiarism": "Плагиат", + "scoreCitation": "Цитирование" }, "Hero": { "badge": "Платформа академической честности", @@ -239,5 +244,68 @@ }, "unknownUser": "Имя пользователя не найдено", "file": "Файл", - "upload": "Скачать сертификат" + "upload": "Скачать сертификат", + "Cabinet": { + "plagiatCheck": "Проверка на плагиат", + "checkDesc": "Проверьте ваш документ на оригинальность", + "submit": "Отправить", + "siDetector": "ИИ детектор", + "siDesc": "Проверьте текст на искусственный интеллект", + "home": "Главная", + "plagiat": "Плагиат", + "siNav": "ИИ детектор", + "payments": "История платежей", + "profile": "Профиль", + "close": "Закрыть", + "personalCabinet": "Личный кабинет", + "plagiatChecks": "Проверки на плагиат", + "dashboard": "Dashboard" + }, + "SiDetail": { + "siCheck": "Проверка ИИ", + "basicInfo": "Основная информация", + "documentInfo": "Информация о документе", + "documentName": "Название документа", + "checker": "Проверяющий", + "uploadedAt": "Дата загрузки документа", + "originalFileName": "Оригинальное имя файла", + "wordCount": "Количество слов", + "fileExt": "Расширение файла", + "fileSize": "Размер файла", + "amountCharged": "Списанная сумма", + "downloadOriginal": "Скачать оригинальный документ", + "siResultsTitle": "Результаты ИИ детектора документа", + "siResultsDesc": "В этом окне отображены результаты анализа текста, загруженного пользователем, на вероятность написания с помощью искусственного интеллекта. Детектор оценивает стилистические, грамматические и семантические особенности текста и показывает в процентах, насколько вероятно, что он был сгенерирован искусственным интеллектом.", + "download": "Скачать", + "originalText": "Оригинальный текст", + "possibleAi": "Возможный ИИ", + "aiContent": "Искусственный интеллект" + }, + "PlagiatResult": { + "plagiarismLevel": "Уровень плагиата", + "aiWritten": "Написано ИИ", + "originality": "Оригинальность", + "citation": "Цитирование", + "plagiat": "Плагиат", + "aiGeneration": "Генерация ИИ", + "original": "Оригинал", + "checked": "Проверено" + }, + "CertificateModal": { + "title": "Создать сертификат", + "close": "Закрыть", + "authorName": "Полное имя автора", + "namePlaceholder": "Введите ваше имя...", + "documentTheme": "Тема документа", + "themePlaceholder": "Введите тему...", + "documentId": "ID документа", + "creating": "Создание...", + "created": "Сертификат создан!", + "create": "Создать сертификат" + }, + "DocumentTypes": { + "label": "Тип документа", + "loading": "Загрузка...", + "placeholder": "Выберите тип документа..." + } } diff --git a/src/shared/config/i18n/messages/uz.d.json.ts b/src/shared/config/i18n/messages/uz.d.json.ts index 8f610e2..06b66f1 100644 --- a/src/shared/config/i18n/messages/uz.d.json.ts +++ b/src/shared/config/i18n/messages/uz.d.json.ts @@ -80,6 +80,7 @@ declare const messages: { resultPlagiarismFound: 'Plagiat topildi'; resultPending: 'Kutilmoqda'; resultFailed: 'Muvaffaqiyatsiz'; + plagiatCheck: 'Plagiat tekshiruvi'; }; DetailPage: { id: 'ID'; @@ -130,6 +131,10 @@ declare const messages: { words: "so'z"; aiProbabilityText: 'Ai yordamida yaratilganlik ehtimoli aniqlandi'; documentNumber: 'Dokument mavzusi'; + scoreAiContent: "O'zidan iqtibos keltirish"; + scoreOriginality: 'Originallik'; + scorePlagiarism: 'Plagiat'; + scoreCitation: 'Iqtibos'; }; Hero: { badge: 'Akademik halollik platformasi'; @@ -244,5 +249,68 @@ declare const messages: { unknownUser: 'Foydalanuvchi topilmadi'; file: 'Fayl'; upload: 'Sertifikatni yuklab olish'; + Cabinet: { + plagiatCheck: 'Plagiat tekshiruvi'; + checkDesc: 'Hujjatingizni originallik uchun tekshiring'; + submit: 'Yuborish'; + siDetector: 'SI detektor'; + siDesc: "Matnni sun'iy intellekt uchun tekshiring"; + home: 'Bosh sahifa'; + plagiat: 'Plagiat'; + siNav: 'SI detektor'; + payments: "To'lovlar tarixi"; + profile: 'Profil'; + close: 'Yopish'; + personalCabinet: 'Shaxsiy kabinet'; + plagiatChecks: 'Plagiat tekshiruvlar'; + dashboard: 'Dashboard'; + }; + SiDetail: { + siCheck: 'SI tekshiruv'; + basicInfo: "Asosiy ma'lumotlar"; + documentInfo: "Hujjat haqida ma'lumotlar"; + documentName: 'Hujjat nomi'; + checker: 'Tekshiruvchi'; + uploadedAt: 'Hujjat yuklangan vaqti'; + originalFileName: 'Hujjat faylining original nomi'; + wordCount: "So'zlar soni"; + fileExt: 'Hujjat fayli kenggaytmasi'; + fileSize: "Hujjat fayli o'lchami"; + amountCharged: 'Yechilgan summa'; + downloadOriginal: 'Original hujjatni yuklab olish'; + siResultsTitle: 'Hujjatning SI detektori natijalari'; + siResultsDesc: "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."; + download: 'Yuklab olish'; + originalText: 'Original matn'; + possibleAi: "Ehtimoliy Sun'iy Intellekt"; + aiContent: "Sun'iy Intellekt"; + }; + PlagiatResult: { + plagiarismLevel: 'Plagiat darajasi'; + aiWritten: 'AI yozgan'; + originality: 'Originallik'; + citation: 'Iqtibos'; + plagiat: 'Plagiat'; + aiGeneration: 'AI generatsiya'; + original: 'Original'; + checked: 'Tekshirilgan'; + }; + CertificateModal: { + title: 'Sertifikat yaratish'; + close: 'Yopish'; + authorName: "Muallifning to'liq ismi"; + namePlaceholder: 'Ismingizni kiriting...'; + documentTheme: 'Hujjat mavzusi'; + themePlaceholder: 'Mavzuni kiriting...'; + documentId: 'Hujjat ID'; + creating: 'Yaratilmoqda...'; + created: 'Sertifikat yaratildi!'; + create: 'Sertifikat yaratish'; + }; + DocumentTypes: { + label: 'Hujjat turi'; + loading: 'Yuklanmoqda...'; + placeholder: 'Hujjat turini tanlang...'; + }; }; export default messages; diff --git a/src/shared/config/i18n/messages/uz.json b/src/shared/config/i18n/messages/uz.json index 414ef3e..7ad8a85 100644 --- a/src/shared/config/i18n/messages/uz.json +++ b/src/shared/config/i18n/messages/uz.json @@ -76,7 +76,8 @@ "resultClean": "Toza", "resultPlagiarismFound": "Plagiat topildi", "resultPending": "Kutilmoqda", - "resultFailed": "Muvaffaqiyatsiz" + "resultFailed": "Muvaffaqiyatsiz", + "plagiatCheck": "Plagiat tekshiruvi" }, "DetailPage": { "id": "ID", @@ -126,7 +127,11 @@ "unknownError": "Noma'lum xato", "words": "so'z", "aiProbabilityText":"Ai yordamida yaratilganlik ehtimoli aniqlandi", - "documentNumber":"Dokument mavzusi" + "documentNumber":"Dokument mavzusi", + "scoreAiContent": "O'zidan iqtibos keltirish", + "scoreOriginality": "Originallik", + "scorePlagiarism": "Plagiat", + "scoreCitation": "Iqtibos" }, "Hero": { "badge": "Akademik halollik platformasi", @@ -240,5 +245,68 @@ }, "unknownUser": "Foydalanuvchi topilmadi", "file": "Fayl", - "upload": "Sertifikatni yuklab olish" + "upload": "Sertifikatni yuklab olish", + "Cabinet": { + "plagiatCheck": "Plagiat tekshiruvi", + "checkDesc": "Hujjatingizni originallik uchun tekshiring", + "submit": "Yuborish", + "siDetector": "SI detektor", + "siDesc": "Matnni sun'iy intellekt uchun tekshiring", + "home": "Bosh sahifa", + "plagiat": "Plagiat", + "siNav": "SI detektor", + "payments": "To'lovlar tarixi", + "profile": "Profil", + "close": "Yopish", + "personalCabinet": "Shaxsiy kabinet", + "plagiatChecks": "Plagiat tekshiruvlar", + "dashboard": "Dashboard" + }, + "SiDetail": { + "siCheck": "SI tekshiruv", + "basicInfo": "Asosiy ma'lumotlar", + "documentInfo": "Hujjat haqida ma'lumotlar", + "documentName": "Hujjat nomi", + "checker": "Tekshiruvchi", + "uploadedAt": "Hujjat yuklangan vaqti", + "originalFileName": "Hujjat faylining original nomi", + "wordCount": "So'zlar soni", + "fileExt": "Hujjat fayli kenggaytmasi", + "fileSize": "Hujjat fayli o'lchami", + "amountCharged": "Yechilgan summa", + "downloadOriginal": "Original hujjatni yuklab olish", + "siResultsTitle": "Hujjatning SI detektori natijalari", + "siResultsDesc": "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.", + "download": "Yuklab olish", + "originalText": "Original matn", + "possibleAi": "Ehtimoliy Sun'iy Intellekt", + "aiContent": "Sun'iy Intellekt" + }, + "PlagiatResult": { + "plagiarismLevel": "Plagiat darajasi", + "aiWritten": "AI yozgan", + "originality": "Originallik", + "citation": "Iqtibos", + "plagiat": "Plagiat", + "aiGeneration": "AI generatsiya", + "original": "Original", + "checked": "Tekshirilgan" + }, + "CertificateModal": { + "title": "Sertifikat yaratish", + "close": "Yopish", + "authorName": "Muallifning to'liq ismi", + "namePlaceholder": "Ismingizni kiriting...", + "documentTheme": "Hujjat mavzusi", + "themePlaceholder": "Mavzuni kiriting...", + "documentId": "Hujjat ID", + "creating": "Yaratilmoqda...", + "created": "Sertifikat yaratildi!", + "create": "Sertifikat yaratish" + }, + "DocumentTypes": { + "label": "Hujjat turi", + "loading": "Yuklanmoqda...", + "placeholder": "Hujjat turini tanlang..." + } } diff --git a/src/shared/request/apiRequest.ts b/src/shared/request/apiRequest.ts index 2d4fc3b..ad625c4 100644 --- a/src/shared/request/apiRequest.ts +++ b/src/shared/request/apiRequest.ts @@ -195,5 +195,7 @@ export const apiRequest = async ( }, }); + console.log('resposne: ', response); + return response; }; diff --git a/src/shared/request/links.ts b/src/shared/request/links.ts index 36cc386..b434082 100644 --- a/src/shared/request/links.ts +++ b/src/shared/request/links.ts @@ -6,15 +6,16 @@ export const links = { detail: (id: number) => `/shared/documents/${id}/`, payment: (order_id: number) => `/users/payme/link/${order_id}/`, sertifikat: (document_id: number) => - `/shared/certificate/${document_id}/pdf/`, + `/shared/certificate/${document_id}/download/`, si: '/shared/ai_document/list/', - si_id: (si_id: number) => `/shared/ai_document/list/${si_id}/`, + si_id: (si_id: number) => `/shared/ai_document/${si_id}/`, si_payment: (document_id: number) => `/shared/ai_document/pay/${document_id}/`, si_create: '/shared/ai_document/create/', - document_types: '/shared/document_types/', + document_types: '/shared/documents/types/', pay_history: '/shared/orders/all/', statistics: '/shared/statistics/', wordCount: '/shared/check_file/', users: '/users/profile/', + demo_pay: (order_id: number) => `/users/payme/link/${order_id}/`, }; diff --git a/src/widgets/cabinet/ui/CabinetNav.tsx b/src/widgets/cabinet/ui/CabinetNav.tsx index b4de3a6..29179c3 100644 --- a/src/widgets/cabinet/ui/CabinetNav.tsx +++ b/src/widgets/cabinet/ui/CabinetNav.tsx @@ -1,18 +1,9 @@ 'use client'; import React from 'react'; import { Menu } from 'lucide-react'; +import { useTranslations } from 'next-intl'; import type { CabinetSection } from '../lib/types'; -// ─── Labels ──────────────────────────────────────────────────────────────────── - -const SECTION_LABELS: Record = { - dashboard: 'Dashboard', - plagiat: 'Plagiat tekshiruvlar', - si: 'SI detektor', - payments: "To'lovlar tarixi", - profile: 'Profil', -}; - // ─── Props ───────────────────────────────────────────────────────────────────── interface CabinetNavProps { @@ -25,19 +16,31 @@ interface CabinetNavProps { export const CabinetNav: React.FC = ({ activeSection, onMenuClick, -}) => ( -
-
- -

- {SECTION_LABELS[activeSection]} -

-
-
-); +}) => { + const t = useTranslations('Cabinet'); + + const SECTION_LABELS: Record = { + dashboard: t('dashboard'), + plagiat: t('plagiatChecks'), + si: t('siNav'), + payments: t('payments'), + profile: t('profile'), + }; + + return ( +
+
+ +

+ {SECTION_LABELS[activeSection]} +

+
+
+ ); +}; diff --git a/src/widgets/cabinet/ui/Sidebar.tsx b/src/widgets/cabinet/ui/Sidebar.tsx index b10a062..1589e75 100644 --- a/src/widgets/cabinet/ui/Sidebar.tsx +++ b/src/widgets/cabinet/ui/Sidebar.tsx @@ -10,23 +10,9 @@ import { X, } from 'lucide-react'; import { Link } from '@/shared/config/i18n/navigation'; +import { useTranslations } from 'next-intl'; import type { CabinetSection } from '../lib/types'; -// ─── Nav items ───────────────────────────────────────────────────────────────── - -type NavItemDef = - | { id: CabinetSection; label: string; icon: React.ElementType; href?: never } - | { id: 'home'; label: string; icon: React.ElementType; href: string }; - -const NAV_ITEMS: NavItemDef[] = [ - { id: 'home', label: 'Bosh sahifa', icon: Home, href: '/' }, - { id: 'dashboard', label: 'Dashboard', icon: LayoutDashboard }, - { id: 'plagiat', label: 'Plagiat', icon: FileSearch }, - { id: 'si', label: 'SI detektor', icon: BrainCircuit }, - { id: 'payments', label: "To'lovlar tarixi", icon: CreditCard }, - { id: 'profile', label: 'Profil', icon: User }, -]; - // ─── Props ───────────────────────────────────────────────────────────────────── interface SidebarProps { @@ -45,95 +31,118 @@ export const Sidebar: React.FC = ({ isOpen, onClose, userName, -}) => ( - <> - {/* Mobile backdrop */} - {isOpen && ( -
- )} +}) => { + const t = useTranslations('Cabinet'); - - -); + })} + + + + ); +}; diff --git a/src/widgets/cabinet/ui/dashboard/CtaCards.tsx b/src/widgets/cabinet/ui/dashboard/CtaCards.tsx index 685e1dd..5a0ba6b 100644 --- a/src/widgets/cabinet/ui/dashboard/CtaCards.tsx +++ b/src/widgets/cabinet/ui/dashboard/CtaCards.tsx @@ -1,33 +1,38 @@ +'use client'; import React from 'react'; import { FileSearch, ArrowRight } from 'lucide-react'; import Link from 'next/link'; import { SiCTACard } from '@/features/modals/siModal/page'; +import { useTranslations } from 'next-intl'; -export const CtaCards = () => ( - <> -
- {/* Plagiat */} - -
- -
- -

- Plagiat tekshiruvi -

-

- Hujjatingizni originallik uchun tekshiring -

- - Yuborish - - +export const CtaCards = () => { + const t = useTranslations('Cabinet'); + return ( + <> +
+ {/* Plagiat */} + +
+ +
+ +

+ {t('plagiatCheck')} +

+

+ {t('checkDesc')} +

+ + {t('submit')} + + - {/* SI */} - -
- -); + {/* SI */} + +
+ + ); +}; diff --git a/src/widgets/cabinet/ui/tables/SiTable.tsx b/src/widgets/cabinet/ui/tables/SiTable.tsx index 1504db1..4a3c567 100644 --- a/src/widgets/cabinet/ui/tables/SiTable.tsx +++ b/src/widgets/cabinet/ui/tables/SiTable.tsx @@ -96,7 +96,7 @@ const SiRow: React.FC<{ item: SiDocument; index: number }> = ({ const pay = useMutation({ mutationKey: ['si-payment', item.id], mutationFn: () => - apiRequest<{ payment_link: string }>('POST', links.si_payment(item.id)), + apiRequest<{ payment_link: string }>('POST', links.demo_pay(item.id)), onSuccess: (res) => { window.open(res.data.payment_link, '_self'); }, diff --git a/src/widgets/detail/SiDetailPage.tsx b/src/widgets/detail/SiDetailPage.tsx index 12b83cb..2a666ce 100644 --- a/src/widgets/detail/SiDetailPage.tsx +++ b/src/widgets/detail/SiDetailPage.tsx @@ -3,16 +3,35 @@ import React, { useEffect } from 'react'; import { useQuery } from '@tanstack/react-query'; import { useParams } from 'next/navigation'; +import { useTranslations } from 'next-intl'; import { apiRequest } from '@/shared/request/apiRequest'; import { links } from '@/shared/request/links'; -import { Download, CloudDownload } from 'lucide-react'; +import { Download } from 'lucide-react'; // ── Types ──────────────────────────────────────────────────────────────────── -type SiResult = { - original: number; - ai_possible: number; +type SiResultRes = { ai: number; + hash: string; + text: string; + citation: number; + plagiarism: number; + originality: number; +}; + +type SiResultData = { + ok: boolean; + res: SiResultRes; + error: string; + success: string; + text_res: string; + analyze_text?: Record; +}; + +type SiResult = { + id: number; + document: number; + result: SiResultData; }; type SiDetail = { @@ -134,6 +153,7 @@ function LoadingSkeleton() { // ── Main Page ───────────────────────────────────────────────────────────────── export default function SiDetailPage({ id }: { id: number }) { + const t = useTranslations('SiDetail'); const { locale } = useParams() as { locale: string }; useEffect(() => { console.log(locale); @@ -172,9 +192,10 @@ export default function SiDetailPage({ id }: { id: number }) { } // 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; + const res = doc.result?.result?.res; + const original = res?.originality ?? 100 - (doc.si_percantage ?? 0); + const aiPossible = res?.plagiarism ?? 0; + const ai = res?.ai ?? doc.si_percantage ?? 0; return (
@@ -200,7 +221,7 @@ export default function SiDetailPage({ id }: { id: number }) {

- {doc.title || 'SI tekshiruv'} + {doc.title || t('siCheck')}

@@ -211,7 +232,7 @@ export default function SiDetailPage({ id }: { id: number }) { {/* Section header */}

- Asosiy ma'lumotlar + {t('basicInfo')}

@@ -219,48 +240,42 @@ export default function SiDetailPage({ id }: { id: number }) {
{/* Sub-header */}

- Hujjat haqida ma'lumotlar + {t('documentInfo')}

{doc.user && ( )} + - 0 ? doc.total_words.toLocaleString('uz-UZ') : '—' } /> - + {doc.file_size !== undefined && ( )} {doc.total_price !== undefined && ( )} @@ -275,7 +290,7 @@ export default function SiDetailPage({ id }: { id: number }) { className="inline-flex items-center gap-2 px-5 py-2.5 rounded-xl border border-cyan-500 text-cyan-600 text-sm font-semibold hover:bg-cyan-50 transition-colors" > - Original hujjatni yuklab olish + {t('downloadOriginal')}
)} @@ -308,21 +323,15 @@ export default function SiDetailPage({ id }: { id: number }) {

- Hujjatning SI detektori natijalari + {t('siResultsTitle')}

- 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. + {t('siResultsDesc')}

- {doc.file && ( + {/* {doc.file && ( - Yuklab olish + {t('download')} - )} + )} */} {/* Bars */}
- +
diff --git a/src/widgets/detail/pageDetail.tsx b/src/widgets/detail/pageDetail.tsx index af0e291..062b678 100644 --- a/src/widgets/detail/pageDetail.tsx +++ b/src/widgets/detail/pageDetail.tsx @@ -10,7 +10,7 @@ import PaymentStatus from './paidStatus'; import Sertifikat from '@/features/modals/sertificateModal/sertifikat'; // ── Types ──────────────────────────────────────────────────────────────────── - +const baseUrl = 'https://dev-api.anti-plagiat.uz/api/v1'; interface AnalyzeText { [key: string]: number | string; } @@ -397,10 +397,10 @@ export default function DocumentDetailPage({ id }: { id: number }) {
- {doc.certificate && } + {doc.file && (
+ - +
diff --git a/src/widgets/detail/ui/components/Header.tsx b/src/widgets/detail/ui/components/Header.tsx index 98470b2..acc4d09 100644 --- a/src/widgets/detail/ui/components/Header.tsx +++ b/src/widgets/detail/ui/components/Header.tsx @@ -1,3 +1,5 @@ +'use client'; +import { useTranslations } from 'next-intl'; import { blue } from '../../lib/constant'; import { PlagiatData } from '../../lib/types'; @@ -21,6 +23,7 @@ export default function Header({ location, checkedAt, }: Props) { + const t = useTranslations('PlagiatResult'); return (
- {plagiarismPercent}% plagiat + {plagiarismPercent}% {t('plagiat').toLowerCase()}

@@ -50,7 +53,7 @@ export default function Header({

- Tekshirilgan + {t('checked')}

{checkedAt} diff --git a/src/widgets/detail/ui/components/TopMetrics.tsx b/src/widgets/detail/ui/components/TopMetrics.tsx index 49a1145..e58778a 100644 --- a/src/widgets/detail/ui/components/TopMetrics.tsx +++ b/src/widgets/detail/ui/components/TopMetrics.tsx @@ -1,3 +1,5 @@ +'use client'; +import { useTranslations } from 'next-intl'; import { PlagiatData } from '../../lib/types'; import MetricCard from './Metriccard'; @@ -12,12 +14,16 @@ export default function TopMetrics({ originalityPercent, citationPercent, }: Props) { + const t = useTranslations('PlagiatResult'); return (

- - - - + + + +
); } diff --git a/src/widgets/detail/ui/index.tsx b/src/widgets/detail/ui/index.tsx index 2d14174..62cfdb7 100644 --- a/src/widgets/detail/ui/index.tsx +++ b/src/widgets/detail/ui/index.tsx @@ -145,26 +145,6 @@ function Skeleton() { ); } -// ─── Error state ────────────────────────────────────────────────────────────── - -function ErrorState() { - return ( -
-
-

- Ma'lumot topilmadi -

-

- Ushbu tekshiruv mavjud emas yoki o'chirilgan -

-
-
- ); -} - // ─── Component ──────────────────────────────────────────────────────────────── export default function PlagiatResult({ id }: { id: number }) { @@ -186,7 +166,22 @@ export default function PlagiatResult({ id }: { id: number }) { }); if (isLoading) return ; - if (isError || !rawData) return ; + if (isError || !rawData) + return ( +
+
+

+ Ma'lumot topilmadi +

+

+ Ushbu tekshiruv mavjud emas yoki o'chirilgan +

+
+
+ ); const data: PlagiatData = transformResponse(rawData); diff --git a/src/widgets/history/ui/historyPage.tsx b/src/widgets/history/ui/historyPage.tsx index b486613..fd58cb9 100644 --- a/src/widgets/history/ui/historyPage.tsx +++ b/src/widgets/history/ui/historyPage.tsx @@ -30,7 +30,7 @@ const PageHeader: React.FC = () => { >

- Plagiat tekshiruvi + {t('plagiatCheck')}

diff --git a/src/widgets/home/index.tsx b/src/widgets/home/index.tsx index dc2bc1a..28316d4 100644 --- a/src/widgets/home/index.tsx +++ b/src/widgets/home/index.tsx @@ -1,10 +1,20 @@ 'use client'; +import { useEffect } from 'react'; import Hero from './components/Hero'; import InfoSection from './components/InfoSection'; import StepsSection from './components/StepsSection'; import Ticker from './components/Ticker'; +import { useRouter } from '@/shared/config/i18n/navigation'; const PlagiarismLanding = () => { + const route = useRouter(); + useEffect(() => { + const data = localStorage.getItem('user'); + + if (data) { + route.push('/plagat'); + } + }, []); return ( <> diff --git a/src/widgets/plagiatCheck/lib/types.ts b/src/widgets/plagiatCheck/lib/types.ts index c53f885..9d32cac 100644 --- a/src/widgets/plagiatCheck/lib/types.ts +++ b/src/widgets/plagiatCheck/lib/types.ts @@ -35,7 +35,7 @@ export interface PlagiarismFormState { file: File | null; certificate: boolean; text?: string; - type: string; + type: number; } export type PlagiarismFormErrors = Partial< diff --git a/src/widgets/plagiatCheck/lib/usePlagiraism.ts b/src/widgets/plagiatCheck/lib/usePlagiraism.ts index 8f665c3..b37d3b3 100644 --- a/src/widgets/plagiatCheck/lib/usePlagiraism.ts +++ b/src/widgets/plagiatCheck/lib/usePlagiraism.ts @@ -21,7 +21,7 @@ const INITIAL_FORM: PlagiarismFormState = { file: null, certificate: true, text: '', - type: 'boshqa', + type: 0, }; const PRICE: PriceCalculate = { @@ -71,6 +71,7 @@ export function usePlagiarismForm() { const priceInfo: PriceCalculate = { total_price: resdata?.total_price || 0, discount: resdata?.discount || 0, + certificate: resdata?.certificate || 0, service_fee: resdata?.service_fee || 0, }; setPrices(priceInfo); @@ -90,7 +91,7 @@ export function usePlagiarismForm() { const payment = useMutation({ mutationKey: ['payload'], mutationFn: ({ order_id }: { order_id: number }) => - apiRequest<{ payment_link: string }>('POST', links.payment(order_id)), + apiRequest<{ payment_link: string }>('POST', links.demo_pay(order_id)), onSuccess: (res) => { console.log('payment res: ', res); window.open(res.data.payment_link, '_self'); @@ -116,9 +117,9 @@ export function usePlagiarismForm() { setErrors((prev) => ({ ...prev, file: undefined })); }, []); - const setOption = useCallback((option: string) => { - setForm((prev) => ({ ...prev, document_type: option })); - setErrors((prev) => ({ ...prev, document_type: undefined })); + const setOption = useCallback((option: number) => { + setForm((prev) => ({ ...prev, type: option })); + setErrors((prev) => ({ ...prev, type: undefined })); }, []); const toggleCertificate = useCallback(() => { @@ -150,7 +151,7 @@ export function usePlagiarismForm() { fd.append('text', form.text || ''); fd.append('file', form.file!); fd.append('certificate', String(form.certificate)); - fd.append('type', form.type); + fd.append('type', String(form.type)); console.log('sended data: ', fd); checkdocumentRequest.mutate(fd); }, diff --git a/src/widgets/plagiatCheck/ui/documentsType.tsx b/src/widgets/plagiatCheck/ui/documentsType.tsx index 8954552..6e5e92a 100644 --- a/src/widgets/plagiatCheck/ui/documentsType.tsx +++ b/src/widgets/plagiatCheck/ui/documentsType.tsx @@ -1,5 +1,6 @@ 'use client'; import React from 'react'; +import { useTranslations } from 'next-intl'; import { FieldWrapper } from './Plagiraismui'; import { useQuery } from '@tanstack/react-query'; import { apiRequest } from '@/shared/request/apiRequest'; @@ -12,8 +13,8 @@ type DocumentType = { }; interface DocumentsTypesProps { - value: string; - onChange: (value: string) => void; + value: number; + onChange: (value: number) => void; disabled?: boolean; } @@ -22,6 +23,7 @@ export default function DocumentsTypes({ onChange, disabled, }: DocumentsTypesProps) { + const t = useTranslations('DocumentTypes'); const { data, isLoading } = useQuery({ queryKey: ['document_types'], queryFn: (): Promise => @@ -30,20 +32,24 @@ export default function DocumentsTypes({ ), }); + const selected = data?.find((item) => item.id === value); + return ( - +