detail page

This commit is contained in:
nabijonovdavronbek619@gmail.com
2026-04-02 13:53:15 +05:00
parent a9be6ba9f5
commit dc653652c7
14 changed files with 560 additions and 79 deletions

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.3 KiB

View File

@@ -1,4 +1,4 @@
import { PlagiarismDetailPage } from '@/widgets/detail/ui/detailPage'; import PlagiatResult from '@/widgets/detail/ui/PlagiatResult';
interface Props { interface Props {
params: Promise<{ detail: string }>; params: Promise<{ detail: string }>;
@@ -6,5 +6,6 @@ interface Props {
export default async function DetailPage({ params }: Props) { export default async function DetailPage({ params }: Props) {
const { detail } = await params; const { detail } = await params;
return <PlagiarismDetailPage checkId={detail} />; console.log(detail);
return <PlagiatResult />;
} }

1
src/image/index.ts Normal file
View File

@@ -0,0 +1 @@
export { default as Logo_image } from './logo.png';

BIN
src/image/logo.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 253 KiB

View File

@@ -1,6 +1,6 @@
export const links = { export const links = {
login: '/users/login/', login: '/users/login/',
register: '/users/register/', register: '/users/register/',
plagiarismCheck: '/plagiarism/check/', plagiarismCheck: '/shared/documents/',
history: '/shared/documents/list/', history: '/shared/documents/list/',
}; };

View File

@@ -0,0 +1,460 @@
'use client';
import { useState } from 'react';
interface Source {
url: string;
title: string;
matchPercentage: number;
matchedWords: number;
}
interface CheckResult {
ai: number;
plagiarism: number;
originality: number;
citation: number;
checkedWords: number;
uniqueWords: number;
lexicalUniqueness: number;
sentences: number;
avgWordsPerSentence: number;
lines: number;
sources: Source[];
}
interface Certificate {
id: string;
issuedAt: string;
expiresAt: string;
verificationCode: string;
issuerName: string;
downloadUrl: string;
}
interface PlagiatResultProps {
name: string;
initials: string;
email: string;
location: string;
fileName: string;
checkedAt: string;
result: CheckResult;
certificate: Certificate;
}
// Blue palette
const blue = {
50: '#E6F1FB',
100: '#B5D4F4',
200: '#85B7EB',
400: '#378ADD',
600: '#185FA5',
800: '#0C447C',
900: '#042C53',
};
const mockData: PlagiatResultProps = {
name: 'Sokhibjon Orzikulov',
initials: 'SO',
email: 'sakhib@orzklv.uz',
location: 'Tashkent, Uzbekistan',
fileName: 'resume_sokhibjon.pdf',
checkedAt: '2026-04-02',
result: {
ai: 86,
plagiarism: 92,
originality: 5,
citation: 3,
checkedWords: 1477,
uniqueWords: 593,
lexicalUniqueness: 40,
sentences: 105,
avgWordsPerSentence: 14.1,
lines: 191,
sources: [
{
url: 'https://arxiv.org/abs/1706.03762',
title: 'arxiv.org — Attention Is All You Need',
matchPercentage: 9,
matchedWords: 937,
},
{
url: 'https://en.wikipedia.org/wiki/Machine_learning',
title: 'Wikipedia — Machine Learning',
matchPercentage: 7,
matchedWords: 730,
},
{
url: 'https://towardsdatascience.com/introduction-to-neural-networks',
title: 'Towards Data Science — Introduction to Neural Networks',
matchPercentage: 6,
matchedWords: 625,
},
],
},
certificate: {
id: 'cert-9001',
issuedAt: '2026-03-30',
expiresAt: '2027-03-30',
verificationCode: 'PLAG-9001-VERIFY',
issuerName: 'Global Plagiarism Checker',
downloadUrl: '/certificates/cert-9001.pdf',
},
};
// ─── Sub-components ───────────────────────────────────────────────────────────
function CircleGauge({ value }: { value: number }) {
const r = 50;
const circ = 2 * Math.PI * r;
const offset = circ - (value / 100) * circ;
return (
<svg
width="130"
height="130"
viewBox="0 0 130 130"
aria-label={`${value}% plagiat`}
>
<circle
cx="65"
cy="65"
r={r}
fill="none"
stroke={blue[100]}
strokeWidth="14"
/>
<circle
cx="65"
cy="65"
r={r}
fill="none"
stroke={blue[900]}
strokeWidth="14"
strokeDasharray={circ}
strokeDashoffset={offset}
strokeLinecap="round"
transform="rotate(-90 65 65)"
style={{ transition: 'stroke-dashoffset 0.8s ease' }}
/>
<text
x="65"
y="60"
textAnchor="middle"
fontSize="26"
fontWeight="500"
fill={blue[900]}
>
{value}%
</text>
<text x="65" y="78" textAnchor="middle" fontSize="11" fill={blue[400]}>
plagiat
</text>
</svg>
);
}
function BarRow({
label,
value,
color,
}: {
label: string;
value: number;
color: string;
}) {
return (
<div className="mb-2.5">
<div className="flex justify-between items-center text-sm mb-1">
<span className="flex items-center gap-1.5 text-slate-500">
<span
className="inline-block w-2.5 h-2.5 rounded-full"
style={{ background: color }}
/>
{label}
</span>
<span className="font-medium" style={{ color: blue[900] }}>
{value}%
</span>
</div>
<div
className="h-1.5 rounded-full overflow-hidden"
style={{ background: blue[100] }}
>
<div
className="h-full rounded-full"
style={{
width: `${value}%`,
background: color,
transition: 'width 0.8s ease',
}}
/>
</div>
</div>
);
}
function MetricCard({ label, value }: { label: string; value: string }) {
return (
<div className="rounded-lg p-3.5" style={{ background: blue[50] }}>
<p className="text-xs mb-1" style={{ color: blue[600] }}>
{label}
</p>
<p className="text-xl font-medium" style={{ color: blue[900] }}>
{value}
</p>
</div>
);
}
function SourceItem({ source, index }: { source: Source; index: number }) {
const colors = [blue[900], blue[600], blue[400]];
const color = colors[index] ?? blue[400];
return (
<div
className="rounded-lg p-3"
style={{ border: `0.5px solid ${blue[100]}` }}
>
<div className="flex items-center justify-between mb-1">
<span
className="text-sm font-medium truncate max-w-[72%]"
style={{ color: blue[900] }}
>
{source.title}
</span>
<span className="text-sm font-medium" style={{ color }}>
{source.matchPercentage}%
</span>
</div>
<p className="text-[11px] mb-1.5 truncate" style={{ color: blue[400] }}>
{source.url}
</p>
<div
className="h-1.5 rounded-full overflow-hidden"
style={{ background: blue[100] }}
>
<div
className="h-full rounded-full"
style={{
width: `${source.matchPercentage}%`,
background: color,
transition: 'width 0.8s ease',
}}
/>
</div>
</div>
);
}
// ─── Main component ───────────────────────────────────────────────────────────
export default function PlagiatResult({
data = mockData,
}: {
data?: PlagiatResultProps;
}) {
const [downloading, setDownloading] = useState(false);
const { result, certificate } = data;
const handleDownload = () => {
setDownloading(true);
setTimeout(() => setDownloading(false), 1500);
};
const divider = (
<hr
style={{
borderColor: blue[100],
borderTopWidth: '0.5px',
borderStyle: 'solid',
margin: '1.25rem 0',
}}
/>
);
return (
<div className="min-h-screen flex items-start justify-center p-6 bg-slate-50">
<div
className="w-full max-w-2xl rounded-xl p-5"
style={{ background: '#ffffff', border: `0.5px solid ${blue[100]}` }}
>
{/* ── Header ── */}
<div className="flex items-center gap-3 mb-5">
<div
className="w-11 h-11 rounded-full flex items-center justify-center text-sm font-medium shrink-0"
style={{ background: blue[50], color: blue[600] }}
>
{data.initials}
</div>
<div className="flex-1 min-w-0">
<div className="flex items-center gap-2 flex-wrap">
<span
className="text-[15px] font-medium"
style={{ color: blue[900] }}
>
{data.name}
</span>
<span
className="text-xs px-2.5 py-0.5 rounded-md font-medium"
style={{ background: blue[100], color: blue[800] }}
>
{result.plagiarism}% plagiat
</span>
</div>
<p
className="text-[13px] mt-0.5 truncate"
style={{ color: blue[400] }}
>
{data.fileName} · {data.email} · {data.location}
</p>
</div>
<div className="text-right shrink-0">
<p className="text-[11px]" style={{ color: blue[400] }}>
Tekshirilgan
</p>
<p className="text-[12px] mt-0.5" style={{ color: blue[600] }}>
{data.checkedAt}
</p>
</div>
</div>
{divider}
{/* ── Top metrics ── */}
<div className="grid grid-cols-4 gap-2.5 mb-5">
<MetricCard
label="Plagiat darajasi"
value={`${result.plagiarism}%`}
/>
<MetricCard label="AI yozgan" value={`${result.ai}%`} />
<MetricCard label="Originallik" value={`${result.originality}%`} />
<MetricCard label="Iqtibos" value={`${result.citation}%`} />
</div>
{/* ── Gauge + bars ── */}
<div className="flex items-center gap-5 mb-5">
<CircleGauge value={result.plagiarism} />
<div className="flex-1">
<BarRow
label="Plagiat"
value={result.plagiarism}
color={blue[900]}
/>
<BarRow
label="AI generatsiya"
value={result.ai}
color={blue[600]}
/>
<BarRow
label="Original"
value={result.originality}
color={blue[400]}
/>
<BarRow label="Iqtibos" value={result.citation} color={blue[200]} />
</div>
</div>
{divider}
{/* ── Text analysis ── */}
<p
className="text-[13px] font-medium uppercase tracking-wider mb-3"
style={{ color: blue[400] }}
>
Matn tahlili
</p>
<div className="grid grid-cols-3 gap-2 mb-5">
<MetricCard
label="Jami so'z"
value={result.checkedWords.toLocaleString()}
/>
<MetricCard
label="Unikal so'z"
value={result.uniqueWords.toLocaleString()}
/>
<MetricCard
label="Leksik unikalligi"
value={`${result.lexicalUniqueness}%`}
/>
<MetricCard label="Jumlalar" value={String(result.sentences)} />
<MetricCard
label="O'rt. so'z/juml."
value={String(result.avgWordsPerSentence)}
/>
<MetricCard label="Qatorlar" value={String(result.lines)} />
</div>
{divider}
{/* ── Sources ── */}
<p
className="text-[13px] font-medium uppercase tracking-wider mb-3"
style={{ color: blue[400] }}
>
Manba yo&lsquo;nalishlari
</p>
<div className="flex flex-col gap-2.5 mb-5">
{result.sources.map((source, i) => (
<SourceItem key={source.url} source={source} index={i} />
))}
</div>
{divider}
{/* ── Certificate ── */}
<p
className="text-[13px] font-medium uppercase tracking-wider mb-3"
style={{ color: blue[400] }}
>
Sertifikat
</p>
<div
className="flex items-center gap-3 rounded-lg p-3.5"
style={{ background: blue[50], border: `0.5px solid ${blue[100]}` }}
>
<div
className="w-9 h-9 rounded-lg flex items-center justify-center shrink-0"
style={{ background: blue[600] }}
>
<svg
width="16"
height="16"
viewBox="0 0 18 18"
fill="none"
aria-hidden="true"
>
<path
d="M9 1L11.2 6.5H17L12.4 10L14.1 16L9 12.8L3.9 16L5.6 10L1 6.5H6.8L9 1Z"
fill="#E6F1FB"
/>
</svg>
</div>
<div className="flex-1 min-w-0">
<p className="text-[13px] font-medium" style={{ color: blue[900] }}>
{certificate.issuerName} sertifikati
</p>
<p
className="text-[11px] mt-0.5 font-mono truncate"
style={{ color: blue[600] }}
>
{certificate.verificationCode} · Amal qilish:{' '}
{certificate.expiresAt}
</p>
</div>
<button
onClick={handleDownload}
className="text-xs px-3 py-1.5 rounded-md shrink-0 transition-colors cursor-pointer"
style={{
border: `0.5px solid ${blue[400]}`,
color: blue[600],
background: downloading ? blue[100] : 'transparent',
}}
>
{downloading ? 'Yuklanmoqda...' : 'Yuklab olish ↗'}
</button>
</div>
</div>
</div>
);
}

View File

@@ -24,9 +24,11 @@ export interface PlagiarismSubmissionResponse {
// ─── Form State Types ──────────────────────────────────────────────────────── // ─── Form State Types ────────────────────────────────────────────────────────
export interface PlagiarismFormState { export interface PlagiarismFormState {
topic: string; title: string;
file: File | null; file: File | null;
withCertificate: boolean; certificate: boolean;
text?: string;
total_price: number;
} }
export type PlagiarismFormErrors = Partial< export type PlagiarismFormErrors = Partial<
@@ -39,6 +41,5 @@ export type SubmissionStatus = 'idle' | 'loading' | 'success' | 'error';
export interface SubmissionState { export interface SubmissionState {
status: SubmissionStatus; status: SubmissionStatus;
response: PlagiarismSubmissionResponse | null;
error: string | null; error: string | null;
} }

View File

@@ -5,30 +5,31 @@ import {
PlagiarismFormState, PlagiarismFormState,
SubmissionState, SubmissionState,
} from './types'; } from './types';
import { selectFullName, useUserStore } from './userStore';
import { isFormValid, validatePlagiarismForm } from './validation'; import { isFormValid, validatePlagiarismForm } from './validation';
import { submitPlagiarismCheck } from '@/shared/request/plagiarismapi';
import { toast } from 'react-toastify'; import { toast } from 'react-toastify';
import { useUserPlagiatStore } from '@/shared/zustand/user'; import { useUserPlagiatStore } from '@/shared/zustand/user';
import { useMutation } from '@tanstack/react-query';
import { links } from '@/shared/request/links';
import { apiRequest } from '@/shared/request/apiRequest';
// ─── Initial States ────────────────────────────────────────────────────────── // ─── Initial States ──────────────────────────────────────────────────────────
const INITIAL_FORM: PlagiarismFormState = { const INITIAL_FORM: PlagiarismFormState = {
topic: '', title: '',
file: null, file: null,
withCertificate: false, certificate: true,
text: '',
total_price: 41200,
}; };
const INITIAL_SUBMISSION: SubmissionState = { const INITIAL_SUBMISSION: SubmissionState = {
status: 'idle', status: 'idle',
response: null,
error: null, error: null,
}; };
// ─── Hook ──────────────────────────────────────────────────────────────────── // ─── Hook ────────────────────────────────────────────────────────────────────
export function usePlagiarismForm() { export function usePlagiarismForm() {
const senderFullName = useUserStore(selectFullName);
const user = useUserPlagiatStore((state) => state.user); const user = useUserPlagiatStore((state) => state.user);
const [form, setForm] = useState<PlagiarismFormState>(INITIAL_FORM); const [form, setForm] = useState<PlagiarismFormState>(INITIAL_FORM);
const [errors, setErrors] = useState<PlagiarismFormErrors>({}); const [errors, setErrors] = useState<PlagiarismFormErrors>({});
@@ -36,15 +37,28 @@ export function usePlagiarismForm() {
const [submission, setSubmission] = const [submission, setSubmission] =
useState<SubmissionState>(INITIAL_SUBMISSION); useState<SubmissionState>(INITIAL_SUBMISSION);
// const checkdocumentRequest = useMutation({ const checkdocumentRequest = useMutation({
// mutationFn: (data:any) => apiRequest("POST",links.plagiarismCheck, data) mutationKey: ['plagiarismCheck'],
// }) mutationFn: (data: FormData) =>
apiRequest('POST', links.plagiarismCheck, data),
onSuccess: () => {
setSubmission({ status: 'success', error: null });
setForm(INITIAL_FORM);
setIsPaymentOpen(false);
},
onError: (err) => {
const message =
err instanceof Error ? err.message : 'An unexpected error occurred.';
setSubmission({ status: 'error', error: message });
setIsPaymentOpen(false);
},
});
// ── Field updaters ─────────────────────────────────────────────────────── // ── Field updaters ───────────────────────────────────────────────────────
const setTopic = useCallback((topic: string) => { const setTopic = useCallback((topic: string) => {
setForm((prev) => ({ ...prev, topic })); setForm((prev) => ({ ...prev, title: topic }));
setErrors((prev) => ({ ...prev, topic: undefined })); setErrors((prev) => ({ ...prev, title: undefined }));
}, []); }, []);
const setFile = useCallback((file: File | null) => { const setFile = useCallback((file: File | null) => {
@@ -53,7 +67,7 @@ export function usePlagiarismForm() {
}, []); }, []);
const toggleCertificate = useCallback(() => { const toggleCertificate = useCallback(() => {
setForm((prev) => ({ ...prev, withCertificate: !prev.withCertificate })); setForm((prev) => ({ ...prev, certificate: !prev.certificate }));
}, []); }, []);
// ── Submission ─────────────────────────────────────────────────────────── // ── Submission ───────────────────────────────────────────────────────────
@@ -82,23 +96,15 @@ export function usePlagiarismForm() {
); );
const handleSubmit = useCallback(async () => { const handleSubmit = useCallback(async () => {
setSubmission({ status: 'loading', response: null, error: null }); setSubmission({ status: 'loading', error: null });
try { const fd = new FormData();
const response = await submitPlagiarismCheck({ fd.append('title', form.title.trim());
topic: form.topic.trim(), fd.append('text', `${user?.name} ${user?.surname}` || '');
senderFullName, fd.append('file', form.file!); // File object — multipart/form-data
file: form.file!, fd.append('certificate', String(form.certificate));
withCertificate: form.withCertificate, fd.append('total_price', '41200');
}); checkdocumentRequest.mutate(fd);
setSubmission({ status: 'success', response, error: null }); }, [form, user]);
setForm(INITIAL_FORM);
setIsPaymentOpen(false); // Close modal on success
} catch (err) {
const message =
err instanceof Error ? err.message : 'An unexpected error occurred.';
setSubmission({ status: 'error', response: null, error: message });
}
}, [form, senderFullName]);
const resetSubmission = useCallback(() => { const resetSubmission = useCallback(() => {
setSubmission(INITIAL_SUBMISSION); setSubmission(INITIAL_SUBMISSION);
@@ -112,7 +118,7 @@ export function usePlagiarismForm() {
form, form,
errors, errors,
submission, submission,
senderFullName, senderFullName: user ? `${user?.name} ${user?.surname}` : null,
isLoading, isLoading,
setTopic, setTopic,
setFile, setFile,

View File

@@ -22,13 +22,13 @@ export function validatePlagiarismForm(
const errors: PlagiarismFormErrors = {}; const errors: PlagiarismFormErrors = {};
// Topic validation // Topic validation
const trimmedTopic = state.topic.trim(); const trimmedTopic = state.title.trim();
if (!trimmedTopic) { if (!trimmedTopic) {
errors.topic = 'Topic is required.'; errors.title = 'Title is required.';
} else if (trimmedTopic.length < 3) { } else if (trimmedTopic.length < 3) {
errors.topic = 'Topic must be at least 3 characters.'; errors.title = 'Title must be at least 3 characters.';
} else if (trimmedTopic.length > 200) { } else if (trimmedTopic.length > 200) {
errors.topic = 'Topic must not exceed 200 characters.'; errors.title = 'Title must not exceed 200 characters.';
} }
// File validation // File validation

View File

@@ -83,10 +83,10 @@ export function PlagiarismCheckForm() {
className="p-7 flex md:flex-row flex-col gap-6" className="p-7 flex md:flex-row flex-col gap-6"
> >
{/* Status banners */} {/* Status banners */}
{submission.status === 'success' && submission.response && ( {submission.status === 'success' && (
<StatusBanner <StatusBanner
status="success" status="success"
message={`Submission successful! ID: ${submission.response.submissionId}. ${submission.response.message}`} message={`Submission successful! ID`}
onDismiss={resetSubmission} onDismiss={resetSubmission}
dismissText={t('dismiss')} dismissText={t('dismiss')}
/> />
@@ -105,17 +105,17 @@ export function PlagiarismCheckForm() {
{/* Topic */} {/* Topic */}
<FieldWrapper <FieldWrapper
label={t('documentTopic')} label={t('documentTopic')}
htmlFor="topic" htmlFor="title"
error={errors.topic} error={errors.title}
required required
> >
<TextInput <TextInput
id="topic" id="title"
type="text" type="text"
placeholder={t('topicPlaceholder')} placeholder={t('topicPlaceholder')}
value={form.topic} value={form.title}
onChange={(e) => setTopic(e.target.value)} onChange={(e) => setTopic(e.target.value)}
hasError={!!errors.topic} hasError={!!errors.title}
maxLength={200} maxLength={200}
disabled={isLoading} disabled={isLoading}
/> />
@@ -136,7 +136,7 @@ export function PlagiarismCheckForm() {
{t('certificateOption')} {t('certificateOption')}
</p> </p>
<CertificateCheckbox <CertificateCheckbox
checked={form.withCertificate} checked={form.certificate}
onChange={toggleCertificate} onChange={toggleCertificate}
title={t('certificateTitle')} title={t('certificateTitle')}
description={t('certificateDescription')} description={t('certificateDescription')}
@@ -186,7 +186,7 @@ export function PlagiarismCheckForm() {
<PaymentModal <PaymentModal
isOpen={isPaymentOpen} isOpen={isPaymentOpen}
onClose={() => setIsPaymentOpen(false)} onClose={() => setIsPaymentOpen(false)}
hasCertificate={form.withCertificate} hasCertificate={form.certificate}
onConfirmPayment={handleSubmit} onConfirmPayment={handleSubmit}
isLoading={isLoading} isLoading={isLoading}
/> />

View File

@@ -3,6 +3,9 @@ import { useState, useEffect, useCallback } from 'react';
import { DEFAULT_PAGE_SIZE } from './constants'; import { DEFAULT_PAGE_SIZE } from './constants';
import { HistoryState } from './types'; import { HistoryState } from './types';
import { DEFAULT_HISTORY_ITEMS } from './mock'; import { DEFAULT_HISTORY_ITEMS } from './mock';
import { useQuery } from '@tanstack/react-query';
import { links } from '@/shared/request/links';
import { apiRequest } from '@/shared/request/apiRequest';
interface UseHistoryReturn extends HistoryState { interface UseHistoryReturn extends HistoryState {
refetch: () => void; refetch: () => void;
@@ -20,27 +23,37 @@ export const useHistory = (pageSize = DEFAULT_PAGE_SIZE): UseHistoryReturn => {
const [currentPage, setCurrentPage] = useState(1); const [currentPage, setCurrentPage] = useState(1);
const [total, setTotal] = useState(0); const [total, setTotal] = useState(0);
const loadHistory = useCallback( const { data, refetch } = useQuery({
async (page: number) => { queryKey: ['history'],
setState((prev) => ({ ...prev, status: 'loading', error: null })); queryFn: () => apiRequest('GET', links.history),
setTotal(0); select: (response) => {
console.log(page); const { results, total } = response.data as {
results: [];
total: number;
};
return { results, total };
}, },
[pageSize], });
);
useEffect(() => { useEffect(() => {
loadHistory(currentPage); if (data) {
}, [currentPage, loadHistory]); setState({
items: data?.results || [],
status: 'success',
error: null,
});
setTotal(data?.total || 0);
}
}, [data]);
useEffect(() => {
refetch();
}, [currentPage]);
const goToPage = useCallback((page: number) => { const goToPage = useCallback((page: number) => {
setCurrentPage(page); setCurrentPage(page);
}, []); }, []);
const refetch = useCallback(() => {
loadHistory(currentPage);
}, [currentPage, loadHistory]);
const totalPages = Math.ceil(total / pageSize); const totalPages = Math.ceil(total / pageSize);
return { return {

View File

@@ -4,19 +4,11 @@ import { useTranslations } from 'next-intl';
import { useHistory } from '../lib/useHistory'; import { useHistory } from '../lib/useHistory';
import { HistoryTable } from './historyTable'; import { HistoryTable } from './historyTable';
import { Pagination } from './pagination'; import { Pagination } from './pagination';
import { useQuery } from '@tanstack/react-query';
import { apiRequest } from '@/shared/request/apiRequest';
import { links } from '@/shared/request/links';
// ─── Page Header ─────────────────────────────────────────────────────────────── // ─── Page Header ───────────────────────────────────────────────────────────────
const PageHeader: React.FC = () => { const PageHeader: React.FC = () => {
const t = useTranslations('HistoryPage'); const t = useTranslations('HistoryPage');
const { data } = useQuery({
queryKey: ['history'],
queryFn: () => apiRequest('GET', links.history),
});
console.log('History data:', data); // Debugging log
return ( return (
<div className="mb-6"> <div className="mb-6">

View File

@@ -14,6 +14,8 @@ import { ChangeLang } from './ChangeLang';
import Link from 'next/link'; import Link from 'next/link';
import { AuthButtons } from './authButtons'; import { AuthButtons } from './authButtons';
import { useTranslations } from 'next-intl'; import { useTranslations } from 'next-intl';
import { Logo_image } from '@/image';
import Image from 'next/image';
const Navbar = () => { const Navbar = () => {
const t = useTranslations('Navbar'); const t = useTranslations('Navbar');
@@ -23,16 +25,22 @@ const Navbar = () => {
<section className="py-4 flex items-center justify-center w-full "> <section className="py-4 flex items-center justify-center w-full ">
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 w-full"> <div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 w-full">
{/* Desktop Menu */} {/* Desktop Menu */}
<nav className="justify-between flex max-sm:flex-col gap-5"> <nav className="justify-between items-center flex max-sm:flex-col gap-5">
<div className="flex items-center justify-between gap-6"> <div className="flex items-center justify-between gap-6">
{/* Logo */} {/* Logo */}
<Link <Link
href={'/'} href={'/'}
className="flex items-center gap-2 text-2xl font-bold " className="flex items-center gap-2 text-2xl font-bold "
> >
{t('logo')} <Image
src={Logo_image}
className="min-h-4"
alt="Anti-Plagiat.uz"
width={200}
height={50}
/>
</Link> </Link>
<div className="flex sm:hidden"> <div className="flex sm:hidden items-center justify-center">
<ChangeLang /> <ChangeLang />
</div> </div>
</div> </div>

View File

@@ -51,26 +51,25 @@ export const PriceSummary: React.FC<PriceSummaryProps> = ({
hasCertificate, hasCertificate,
pricing, pricing,
}) => { }) => {
const total = hasCertificate console.log(hasCertificate);
? pricing.serviceFee + pricing.certificateFee const total = 41200;
: pricing.serviceFee;
const t = useTranslations('Payment'); const t = useTranslations('Payment');
return ( return (
<div className="rounded-xl bg-slate-50 border border-slate-100 px-5 py-2 space-y-0"> <div className="rounded-xl bg-slate-50 border border-slate-100 px-5 py-2 space-y-0">
<PriceRow <PriceRow
label={t('serviceFee')} label={t('serviceFee')}
amount={pricing.serviceFee} amount={41200}
currency={pricing.currency} currency={pricing.currency}
/> />
{hasCertificate && ( {/* {hasCertificate && (
<PriceRow <PriceRow
label={t('certificateLabel')} label={t('certificateLabel')}
amount={pricing.certificateFee} amount={pricing.certificateFee}
currency={pricing.currency} currency={pricing.currency}
/> />
)} )} */}
<PriceRow <PriceRow
label={t('total')} label={t('total')}