This commit is contained in:
nabijonovdavronbek619@gmail.com
2026-04-09 12:48:23 +05:00
parent 73158a1972
commit aba0d25cbd
8 changed files with 62 additions and 55 deletions

View File

@@ -23,4 +23,5 @@ export interface PaymentModalProps {
price: PriceCalculate; price: PriceCalculate;
onConfirmPayment: () => void; onConfirmPayment: () => void;
isLoading: boolean; isLoading: boolean;
hasSertificate: boolean;
} }

View File

@@ -55,6 +55,7 @@ export const PaymentModal: React.FC<PaymentModalProps> = ({
price, price,
onConfirmPayment, onConfirmPayment,
isLoading, isLoading,
hasSertificate,
}) => { }) => {
const dialogRef = useRef<HTMLDivElement>(null); const dialogRef = useRef<HTMLDivElement>(null);
const status = isLoading ? 'loading' : 'idle'; const status = isLoading ? 'loading' : 'idle';
@@ -144,18 +145,20 @@ export const PaymentModal: React.FC<PaymentModalProps> = ({
</div> </div>
{/* Certificate badge */} {/* Certificate badge */}
<div className="flex items-center gap-2 text-sm text-emerald-700 bg-emerald-50 border border-emerald-100 rounded-lg px-3.5 py-2.5"> {hasSertificate && (
<svg <div className="flex items-center gap-2 text-sm text-emerald-700 bg-emerald-50 border border-emerald-100 rounded-lg px-3.5 py-2.5">
width="15" <svg
height="15" width="15"
viewBox="0 0 24 24" height="15"
fill="currentColor" viewBox="0 0 24 24"
className="shrink-0" fill="currentColor"
> className="shrink-0"
<path d="M12 1l2.753 5.527 6.247.907-4.5 4.385 1.063 6.181L12 15.027l-5.563 2.973 1.063-6.181L3 7.434l6.247-.907z" /> >
</svg> <path d="M12 1l2.753 5.527 6.247.907-4.5 4.385 1.063 6.181L12 15.027l-5.563 2.973 1.063-6.181L3 7.434l6.247-.907z" />
<span>{t('certificateIncluded')}</span> </svg>
</div> <span>{t('certificateIncluded')}</span>
</div>
)}
{/* Payment method label */} {/* Payment method label */}
<div> <div>

View File

@@ -3,6 +3,9 @@ import { SEO_DATA, type SupportedLocale } from '../config/seo.config';
// ─── Site-wide constants ─────────────────────────────────────────────────────── // ─── Site-wide constants ───────────────────────────────────────────────────────
export const SERTIFICATE_PRICE = 20600;
export const PLAGIAT_SERVICE_FEE = 20600;
const SITE_URL = process.env.NEXT_PUBLIC_SITE_URL ?? 'https://antiplagiat.uz'; const SITE_URL = process.env.NEXT_PUBLIC_SITE_URL ?? 'https://antiplagiat.uz';
const OG_IMAGE_URL = `${SITE_URL}/og-image.png`; // 1200×630 px recommended const OG_IMAGE_URL = `${SITE_URL}/og-image.png`; // 1200×630 px recommended
const TWITTER_HANDLE = '@antiplagiatuz'; // update or remove if unused const TWITTER_HANDLE = '@antiplagiatuz'; // update or remove if unused

View File

@@ -1,7 +1,7 @@
export const links = { export const links = {
login: '/users/login/', login: '/users/login/',
register: '/users/register/', register: '/users/register/',
plagiarismCheck: '/shared/document/', plagiarismCheck: '/shared/documents/',
history: '/shared/documents/list/', history: '/shared/documents/list/',
detail: (id: number) => `/shared/documents/${id}/`, detail: (id: number) => `/shared/documents/${id}/`,
payment: (order_id: number) => `/users/payme/link/${order_id}/`, payment: (order_id: number) => `/users/payme/link/${order_id}/`,

View File

@@ -1,13 +1,13 @@
'use client'; 'use client';
import React, { useState } from 'react'; import React from 'react';
import { Clock, XCircle, ReceiptText } from 'lucide-react'; import { Clock, XCircle, ReceiptText } from 'lucide-react';
import { useMutation, useQuery } from '@tanstack/react-query'; import { useQuery } from '@tanstack/react-query';
import { useTranslations } from 'next-intl'; import { useTranslations } from 'next-intl';
import { apiRequest } from '@/shared/request/apiRequest'; import { apiRequest } from '@/shared/request/apiRequest';
import { links } from '@/shared/request/links'; import { links } from '@/shared/request/links';
import PaymentStatus from '@/widgets/detail/paidStatus'; import PaymentStatus from '@/widgets/detail/paidStatus';
import { toast } from 'react-toastify'; // import { toast } from 'react-toastify';
import { PaymentModal } from '@/features/modals/paymentModal/ui/Paymentmodal'; // import { PaymentModal } from '@/features/modals/paymentModal/ui/Paymentmodal';
// ─── Types ───────────────────────────────────────────────────────────────────── // ─── Types ─────────────────────────────────────────────────────────────────────
@@ -38,7 +38,7 @@ function formatPrice(price: string) {
export function PaymentsTable() { export function PaymentsTable() {
const t = useTranslations('Cabinet'); const t = useTranslations('Cabinet');
const [isPaymentOpen, setIsPaymentOpen] = useState(false); // const [isPaymentOpen, setIsPaymentOpen] = useState(false);
const { data, isLoading } = useQuery({ const { data, isLoading } = useQuery({
queryKey: ['pay_history'], queryKey: ['pay_history'],
queryFn: (): Promise<Inspection[]> => queryFn: (): Promise<Inspection[]> =>
@@ -47,29 +47,29 @@ export function PaymentsTable() {
), ),
}); });
const payment = useMutation({ // const payment = useMutation({
mutationKey: ['payload'], // mutationKey: ['payload'],
mutationFn: ({ order_id }: { order_id: number }) => // mutationFn: ({ order_id }: { order_id: number }) =>
apiRequest<{ payment_link: string }>('POST', links.payment(order_id)), // apiRequest<{ payment_link: string }>('POST', links.payment(order_id)),
onSuccess: (res) => { // onSuccess: (res) => {
window.open(res.data.payment_link, '_self'); // window.open(res.data.payment_link, '_self');
setIsPaymentOpen(false); // // setIsPaymentOpen(false);
}, // },
onError: (err) => { // onError: (err) => {
const message = // const message =
err instanceof Error ? err.message : 'An unexpected error occurred.'; // err instanceof Error ? err.message : 'An unexpected error occurred.';
toast.error(message); // toast.error(message);
setIsPaymentOpen(false); // // setIsPaymentOpen(false);
}, // },
}); // });
const handleSubmit = ({ document_id }: { document_id: number }) => { // const handleSubmit = ({ document_id }: { document_id: number }) => {
if (document_id === 0) { // if (document_id === 0) {
toast.error('Id not found'); // toast.error('Id not found');
return; // return;
} // }
payment.mutate({ order_id: document_id }); // payment.mutate({ order_id: document_id });
}; // };
return ( return (
<> <>
@@ -116,7 +116,7 @@ export function PaymentsTable() {
</thead> </thead>
<tbody className="divide-y divide-slate-50"> <tbody className="divide-y divide-slate-50">
{data.map((row) => { {data.map((row) => {
const service_fee = row.total_price + row.discount; // const service_fee = row.total_price + row.discount;
return ( return (
<tr <tr
key={row.id} key={row.id}
@@ -145,14 +145,7 @@ export function PaymentsTable() {
</td> </td>
<td className="px-5 py-3.5"> <td className="px-5 py-3.5">
{row.state ? ( {row.state ? (
<span <span className="inline-flex items-center gap-1.5 px-2.5 py-1 rounded-lg text-xs font-medium text-emerald-600 bg-emerald-50">
onClick={() => {
if (row.state === 'unpaid') {
setIsPaymentOpen(true);
}
}}
className="inline-flex items-center gap-1.5 px-2.5 py-1 rounded-lg text-xs font-medium text-emerald-600 bg-emerald-50"
>
<PaymentStatus status={row.state} /> <PaymentStatus status={row.state} />
</span> </span>
) : ( ) : (
@@ -162,7 +155,7 @@ export function PaymentsTable() {
</span> </span>
)} )}
</td> </td>
<PaymentModal {/* <PaymentModal
isOpen={isPaymentOpen} isOpen={isPaymentOpen}
onClose={() => setIsPaymentOpen(false)} onClose={() => setIsPaymentOpen(false)}
price={{ price={{
@@ -174,7 +167,7 @@ export function PaymentsTable() {
handleSubmit({ document_id: 0 }); handleSubmit({ document_id: 0 });
}} }}
isLoading={payment.isPending} isLoading={payment.isPending}
/> /> */}
</tr> </tr>
); );
})} })}

View File

@@ -10,6 +10,7 @@ import { apiRequest } from '@/shared/request/apiRequest';
import { links } from '@/shared/request/links'; import { links } from '@/shared/request/links';
import { toast } from 'react-toastify'; import { toast } from 'react-toastify';
import { PaymentModal } from '@/features/modals/paymentModal/ui/Paymentmodal'; import { PaymentModal } from '@/features/modals/paymentModal/ui/Paymentmodal';
import { PLAGIAT_SERVICE_FEE, SERTIFICATE_PRICE } from '@/shared/lib/metadata';
// ─── State badge ─────────────────────────────────────────────────────────────── // ─── State badge ───────────────────────────────────────────────────────────────
@@ -60,8 +61,9 @@ export const HistoryTableRow: React.FC<
}); });
const price = item.price_calculation ?? { const price = item.price_calculation ?? {
service_fee: 41200, service_fee: item.state === 'unpaid' ? PLAGIAT_SERVICE_FEE : 0,
discount: 0, discount: 0,
certificate: item.certificate ? SERTIFICATE_PRICE : 0,
total_price: 41200, total_price: 41200,
currency: 'UZS', currency: 'UZS',
}; };
@@ -142,6 +144,7 @@ export const HistoryTableRow: React.FC<
payment.mutate({ order_id: Number(item.order_id) }) payment.mutate({ order_id: Number(item.order_id) })
} }
isLoading={payment.isPending} isLoading={payment.isPending}
hasSertificate={item.certificate}
/> />
</> </>
); );

View File

@@ -13,6 +13,8 @@ import { useMutation } from '@tanstack/react-query';
import { links } from '@/shared/request/links'; import { links } from '@/shared/request/links';
import { apiRequest } from '@/shared/request/apiRequest'; import { apiRequest } from '@/shared/request/apiRequest';
import { PriceCalculate } from '@/features/modals/paymentModal/lib/types'; import { PriceCalculate } from '@/features/modals/paymentModal/lib/types';
import { SERTIFICATE_PRICE, PLAGIAT_SERVICE_FEE } from '@/shared/lib/metadata';
// import { fromTheme } from 'tailwind-merge';
// ─── Initial States ────────────────────────────────────────────────────────── // ─── Initial States ──────────────────────────────────────────────────────────
@@ -25,7 +27,8 @@ const INITIAL_FORM: PlagiarismFormState = {
}; };
const PRICE: PriceCalculate = { const PRICE: PriceCalculate = {
service_fee: 0, service_fee: PLAGIAT_SERVICE_FEE,
certificate: SERTIFICATE_PRICE,
discount: 0, discount: 0,
total_price: 0, total_price: 0,
}; };
@@ -71,8 +74,8 @@ export function usePlagiarismForm() {
const priceInfo: PriceCalculate = { const priceInfo: PriceCalculate = {
total_price: resdata?.total_price || 0, total_price: resdata?.total_price || 0,
discount: resdata?.discount || 0, discount: resdata?.discount || 0,
certificate: resdata?.certificate || 0, certificate: form.certificate ? SERTIFICATE_PRICE : 0,
service_fee: resdata?.service_fee || 0, service_fee: PLAGIAT_SERVICE_FEE,
}; };
setPrices(priceInfo); setPrices(priceInfo);
console.log('order_id:', resdata.id); console.log('order_id:', resdata.id);

View File

@@ -209,6 +209,7 @@ export function PlagiarismCheckForm() {
price={prices} price={prices}
onConfirmPayment={handleSubmit} onConfirmPayment={handleSubmit}
isLoading={isLoading} isLoading={isLoading}
hasSertificate={!!form.certificate}
/> />
</> </>
); );