216 lines
7.4 KiB
TypeScript
216 lines
7.4 KiB
TypeScript
'use client';
|
|
import React from 'react';
|
|
import {
|
|
FieldWrapper,
|
|
TextInput,
|
|
ReadonlyField,
|
|
FileUploadField,
|
|
CertificateCheckbox,
|
|
SubmitButton,
|
|
StatusBanner,
|
|
} from './Plagiraismui';
|
|
import { usePlagiarismForm } from '../lib/usePlagiraism';
|
|
import { useTranslations } from 'next-intl';
|
|
import { PaymentModal } from '@/features/modals/paymentModal/ui/Paymentmodal';
|
|
import DocumentsTypes from './documentsType';
|
|
|
|
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
|
|
focus:outline-none focus:ring-2 focus:ring-blue-400/40 focus:border-blue-400
|
|
hover:border-blue-300
|
|
transition-all duration-150
|
|
disabled:opacity-60 disabled:cursor-not-allowed
|
|
`.trim();
|
|
// ─── UserIcon (inline) ───────────────────────────────────────────────────────
|
|
|
|
function UserIcon() {
|
|
return (
|
|
<svg
|
|
className="w-4 h-4"
|
|
fill="none"
|
|
viewBox="0 0 24 24"
|
|
stroke="currentColor"
|
|
strokeWidth={1.5}
|
|
>
|
|
<path
|
|
strokeLinecap="round"
|
|
strokeLinejoin="round"
|
|
d="M15.75 6a3.75 3.75 0 11-7.5 0 3.75 3.75 0 017.5 0zM4.501 20.118a7.5 7.5 0 0114.998 0A17.933 17.933 0 0112 21.75c-2.676 0-5.216-.584-7.499-1.632z"
|
|
/>
|
|
</svg>
|
|
);
|
|
}
|
|
|
|
// ─── Component ───────────────────────────────────────────────────────────────
|
|
|
|
export function PlagiarismCheckForm() {
|
|
const t = useTranslations('PlagiarismCheck');
|
|
|
|
const {
|
|
form,
|
|
errors,
|
|
submission,
|
|
senderFullName,
|
|
isLoading,
|
|
setTopic,
|
|
setFile,
|
|
toggleCertificate,
|
|
handleSubmit,
|
|
resetSubmission,
|
|
handleSubmitWithModal,
|
|
isPaymentOpen,
|
|
setOption,
|
|
setIsPaymentOpen,
|
|
prices,
|
|
} = usePlagiarismForm();
|
|
|
|
return (
|
|
<>
|
|
<div className=" flex items-center justify-center p-4 font-['DM_Sans',sans-serif]">
|
|
<div className="w-full max-w-4xl">
|
|
{/* ── Header ────────────────────────────────────────────────────── */}
|
|
<div className="mb-8">
|
|
<div className="inline-flex items-center gap-2 bg-blue-100 text-blue-700 text-xs font-bold uppercase tracking-widest px-3 py-1.5 rounded-full mb-4">
|
|
<span className="w-1.5 h-1.5 rounded-full bg-blue-500" />
|
|
{t('badge')}
|
|
</div>
|
|
<h1 className="text-3xl font-black text-stone-900 leading-tight">
|
|
{t('title')}
|
|
</h1>
|
|
<p className="text-stone-500 mt-2 text-sm leading-relaxed">
|
|
{t('description')}
|
|
</p>
|
|
</div>
|
|
|
|
{/* ── Card ──────────────────────────────────────────────────────── */}
|
|
<div className="bg-white rounded-3xl shadow-xl shadow-stone-200/80 border border-stone-100 overflow-hidden">
|
|
{/* Progress bar accent */}
|
|
<div className="h-1 w-full bg-linear-to-r from-blue-400 via-blue-500 to-indigo-400" />
|
|
|
|
<form
|
|
onSubmit={handleSubmitWithModal}
|
|
noValidate
|
|
className="p-7 flex md:flex-row flex-col gap-6"
|
|
>
|
|
{/* Status banners */}
|
|
{submission.status === 'success' && (
|
|
<StatusBanner
|
|
status="success"
|
|
message={t('submissionSuccess')}
|
|
onDismiss={resetSubmission}
|
|
dismissText={t('dismiss')}
|
|
/>
|
|
)}
|
|
{submission.status === 'error' && submission.error && (
|
|
<StatusBanner
|
|
status="error"
|
|
message={submission.error}
|
|
onDismiss={resetSubmission}
|
|
dismissText={t('dismiss')}
|
|
/>
|
|
)}
|
|
|
|
{/* left part */}
|
|
<div className="flex flex-col gap-9 md:max-w-[50%] w-full">
|
|
{/* Topic */}
|
|
<FieldWrapper
|
|
label={t('documentTopic')}
|
|
htmlFor="title"
|
|
error={errors.title}
|
|
required
|
|
>
|
|
<TextInput
|
|
id="title"
|
|
type="text"
|
|
placeholder={t('topicPlaceholder')}
|
|
value={form.title}
|
|
onChange={(e) => setTopic(e.target.value)}
|
|
hasError={!!errors.title}
|
|
maxLength={200}
|
|
disabled={isLoading}
|
|
/>
|
|
</FieldWrapper>
|
|
|
|
{/* Sender Full Name (read-only) */}
|
|
<FieldWrapper label={t('senderFullName')}>
|
|
<ReadonlyField
|
|
value={senderFullName || t('notLoggedIn')}
|
|
icon={<UserIcon />}
|
|
autoFilledText={t('autoFilled')}
|
|
/>
|
|
</FieldWrapper>
|
|
|
|
{/* Certificate Option */}
|
|
<div>
|
|
<p className="text-sm font-semibold tracking-wide text-stone-700 uppercase mb-2">
|
|
{t('certificateOption')}
|
|
</p>
|
|
<CertificateCheckbox
|
|
checked={form.certificate}
|
|
onChange={toggleCertificate}
|
|
title={t('certificateTitle')}
|
|
description={t('certificateDescription')}
|
|
/>
|
|
</div>
|
|
</div>
|
|
|
|
{/* right part */}
|
|
<div className="flex flex-col gap-4 md:max-w-[50%] w-full">
|
|
{/* File Upload */}
|
|
<FieldWrapper
|
|
label={t('documentFile')}
|
|
error={errors.file}
|
|
required
|
|
>
|
|
<FileUploadField
|
|
file={form.file}
|
|
onFileChange={setFile}
|
|
hasError={!!errors.file}
|
|
clickToUploadText={t('clickToUpload')}
|
|
fileTypesText={t('fileTypes')}
|
|
removeFileAriaLabel={t('removeFile')}
|
|
/>
|
|
</FieldWrapper>
|
|
|
|
{/* Divider */}
|
|
<div className="border-t border-stone-100" />
|
|
|
|
{/* Document type */}
|
|
<DocumentsTypes
|
|
value={form.type}
|
|
onChange={setOption}
|
|
disabled={submission.status === 'success'}
|
|
hasError={!!errors.type}
|
|
error={errors.type}
|
|
/>
|
|
|
|
{/* Submit */}
|
|
<SubmitButton
|
|
isLoading={isLoading}
|
|
submittingText={t('submitting')}
|
|
submitText={t('submitButton')}
|
|
/>
|
|
</div>
|
|
</form>
|
|
</div>
|
|
|
|
{/* Footer note */}
|
|
<p className="text-center text-xs text-stone-400 mt-5">
|
|
{t('secureNote')}
|
|
</p>
|
|
</div>
|
|
</div>
|
|
|
|
<PaymentModal
|
|
isOpen={isPaymentOpen}
|
|
onClose={() => setIsPaymentOpen(false)}
|
|
price={prices}
|
|
onConfirmPayment={handleSubmit}
|
|
isLoading={isLoading}
|
|
/>
|
|
</>
|
|
);
|
|
}
|