From c01f3917d26f1b1285df715e23bd545e2cc743a7 Mon Sep 17 00:00:00 2001 From: "nabijonovdavronbek619@gmail.com" Date: Mon, 6 Apr 2026 10:38:17 +0500 Subject: [PATCH] payme price calculation update on modal --- .../modals}/paymentModal/lib/constant.ts | 0 .../modals}/paymentModal/lib/types.ts | 24 ++----- .../modals}/paymentModal/lib/usePayment.ts | 0 src/features/modals/paymentModal/lib/utils.ts | 20 ++++++ .../modals}/paymentModal/ui/Paymebutton.tsx | 0 .../modals}/paymentModal/ui/Paymentmodal.tsx | 32 ++++----- .../modals}/paymentModal/ui/Pricesummary.tsx | 27 ++++--- .../modals/sertificateModal}/modalField.tsx | 0 .../sertificateModal}/sertificateModal.tsx | 0 .../modals/sertificateModal}/sertifikat.tsx | 0 .../modals/sertificateModal}/types.ts | 0 .../sertificateModal}/useSertificateModal.ts | 0 src/widgets/detail/pageDetail.tsx | 2 +- .../fileUpload/ui/Plagiraismcheckform.tsx | 11 ++- src/widgets/history/lib/types.ts | 3 + src/widgets/history/ui/historyTableRow.tsx | 9 ++- src/widgets/paymentModal/lib/utils.ts | 71 ------------------- 17 files changed, 73 insertions(+), 126 deletions(-) rename src/{widgets => features/modals}/paymentModal/lib/constant.ts (100%) rename src/{widgets => features/modals}/paymentModal/lib/types.ts (78%) rename src/{widgets => features/modals}/paymentModal/lib/usePayment.ts (100%) create mode 100644 src/features/modals/paymentModal/lib/utils.ts rename src/{widgets => features/modals}/paymentModal/ui/Paymebutton.tsx (100%) rename src/{widgets => features/modals}/paymentModal/ui/Paymentmodal.tsx (89%) rename src/{widgets => features/modals}/paymentModal/ui/Pricesummary.tsx (78%) rename src/{widgets/detail/ui/sertificate => features/modals/sertificateModal}/modalField.tsx (100%) rename src/{widgets/detail/ui/sertificate => features/modals/sertificateModal}/sertificateModal.tsx (100%) rename src/{widgets/detail/ui/sertificate => features/modals/sertificateModal}/sertifikat.tsx (100%) rename src/{widgets/detail/ui/sertificate => features/modals/sertificateModal}/types.ts (100%) rename src/{widgets/detail/ui/sertificate => features/modals/sertificateModal}/useSertificateModal.ts (100%) delete mode 100644 src/widgets/paymentModal/lib/utils.ts diff --git a/src/widgets/paymentModal/lib/constant.ts b/src/features/modals/paymentModal/lib/constant.ts similarity index 100% rename from src/widgets/paymentModal/lib/constant.ts rename to src/features/modals/paymentModal/lib/constant.ts diff --git a/src/widgets/paymentModal/lib/types.ts b/src/features/modals/paymentModal/lib/types.ts similarity index 78% rename from src/widgets/paymentModal/lib/types.ts rename to src/features/modals/paymentModal/lib/types.ts index f93a154..135ed38 100644 --- a/src/widgets/paymentModal/lib/types.ts +++ b/src/features/modals/paymentModal/lib/types.ts @@ -1,16 +1,5 @@ // ─── Domain Types ────────────────────────────────────────────────────────────── -export interface ServicePricing { - serviceFee: number; - certificateFee: number; - currency: string; -} - -export interface OrderSummary { - hasCertificate: boolean; - pricing: ServicePricing; -} - export interface PaymePaymentRequest { amount: number; // in tiyin (1 UZS = 100 tiyin) orderId: string; @@ -26,20 +15,21 @@ export interface PaymePaymentResponse { export type PaymentStatus = 'idle' | 'loading' | 'success' | 'error'; // ─── Component Props ─────────────────────────────────────────────────────────── +export interface PriceCalculate { + service_fee: number; + discount?: number; + total_price: number; + currency: string; +} export interface PaymentModalProps { isOpen: boolean; onClose: () => void; - hasCertificate: boolean; + price: PriceCalculate; onConfirmPayment: () => void; isLoading: boolean; } -export interface PriceSummaryProps { - hasCertificate: boolean; - pricing: ServicePricing; -} - export interface PaymeButtonProps { amount: number; orderId: string; diff --git a/src/widgets/paymentModal/lib/usePayment.ts b/src/features/modals/paymentModal/lib/usePayment.ts similarity index 100% rename from src/widgets/paymentModal/lib/usePayment.ts rename to src/features/modals/paymentModal/lib/usePayment.ts diff --git a/src/features/modals/paymentModal/lib/utils.ts b/src/features/modals/paymentModal/lib/utils.ts new file mode 100644 index 0000000..244e300 --- /dev/null +++ b/src/features/modals/paymentModal/lib/utils.ts @@ -0,0 +1,20 @@ +// ─── Pricing Utilities ───────────────────────────────────────────────────────── +export const formatPrice = (amount: number, currency: string): string => + `${amount.toLocaleString('uz-UZ')} ${currency}`; + +// ─── Order ID Generator ──────────────────────────────────────────────────────── + +export const generateOrderId = (): string => { + const timestamp = Date.now(); + const random = Math.random().toString(36).slice(2, 8).toUpperCase(); + return `ORDER-${timestamp}-${random}`; +}; + +// ─── Payme API ───────────────────────────────────────────────────────────────── + +/** + * Redirects the user to the Payme checkout page. + */ +export const redirectToPayme = (redirectUrl: string): void => { + window.location.href = redirectUrl; +}; diff --git a/src/widgets/paymentModal/ui/Paymebutton.tsx b/src/features/modals/paymentModal/ui/Paymebutton.tsx similarity index 100% rename from src/widgets/paymentModal/ui/Paymebutton.tsx rename to src/features/modals/paymentModal/ui/Paymebutton.tsx diff --git a/src/widgets/paymentModal/ui/Paymentmodal.tsx b/src/features/modals/paymentModal/ui/Paymentmodal.tsx similarity index 89% rename from src/widgets/paymentModal/ui/Paymentmodal.tsx rename to src/features/modals/paymentModal/ui/Paymentmodal.tsx index ac01019..0df24e8 100644 --- a/src/widgets/paymentModal/ui/Paymentmodal.tsx +++ b/src/features/modals/paymentModal/ui/Paymentmodal.tsx @@ -1,7 +1,6 @@ 'use client'; import React, { useEffect, useRef } from 'react'; import { PaymentModalProps } from '../lib/types'; -import { getPricing } from '../lib/utils'; import { PriceSummary } from './Pricesummary'; import { PaymeButton } from './Paymebutton'; import { useTranslations } from 'next-intl'; @@ -85,12 +84,11 @@ const SecurityBadge: React.FC<{ securityText: string }> = ({ export const PaymentModal: React.FC = ({ isOpen, onClose, - hasCertificate, + price, onConfirmPayment, isLoading, }) => { const dialogRef = useRef(null); - const pricing = getPricing(); const status = isLoading ? 'loading' : 'idle'; const t = useTranslations('Payment'); @@ -174,24 +172,22 @@ export const PaymentModal: React.FC = ({

{t('orderSummary')}

- + {/* Certificate badge */} - {hasCertificate && ( -
- - - - {t('certificateIncluded')} -
- )} +
+ + + + {t('certificateIncluded')} +
{/* Payment method label */}
diff --git a/src/widgets/paymentModal/ui/Pricesummary.tsx b/src/features/modals/paymentModal/ui/Pricesummary.tsx similarity index 78% rename from src/widgets/paymentModal/ui/Pricesummary.tsx rename to src/features/modals/paymentModal/ui/Pricesummary.tsx index 2ae25e7..65c57c4 100644 --- a/src/widgets/paymentModal/ui/Pricesummary.tsx +++ b/src/features/modals/paymentModal/ui/Pricesummary.tsx @@ -1,8 +1,8 @@ 'use client'; import React from 'react'; import { formatPrice } from '../lib/utils'; -import { PriceSummaryProps } from '../lib/types'; import { useTranslations } from 'next-intl'; +import { PriceCalculate } from '../lib/types'; // ─── Price Row ───────────────────────────────────────────────────────────────── @@ -47,34 +47,33 @@ const PriceRow: React.FC = ({ // ─── Price Summary ───────────────────────────────────────────────────────────── -export const PriceSummary: React.FC = ({ - hasCertificate, - pricing, +export const PriceSummary = ({ + priceCalculate, +}: { + priceCalculate: PriceCalculate; }) => { - console.log(hasCertificate); - const total = 41200; const t = useTranslations('Payment'); return (
- {/* {hasCertificate && ( + {priceCalculate.discount && ( - )} */} + )}
diff --git a/src/widgets/detail/ui/sertificate/modalField.tsx b/src/features/modals/sertificateModal/modalField.tsx similarity index 100% rename from src/widgets/detail/ui/sertificate/modalField.tsx rename to src/features/modals/sertificateModal/modalField.tsx diff --git a/src/widgets/detail/ui/sertificate/sertificateModal.tsx b/src/features/modals/sertificateModal/sertificateModal.tsx similarity index 100% rename from src/widgets/detail/ui/sertificate/sertificateModal.tsx rename to src/features/modals/sertificateModal/sertificateModal.tsx diff --git a/src/widgets/detail/ui/sertificate/sertifikat.tsx b/src/features/modals/sertificateModal/sertifikat.tsx similarity index 100% rename from src/widgets/detail/ui/sertificate/sertifikat.tsx rename to src/features/modals/sertificateModal/sertifikat.tsx diff --git a/src/widgets/detail/ui/sertificate/types.ts b/src/features/modals/sertificateModal/types.ts similarity index 100% rename from src/widgets/detail/ui/sertificate/types.ts rename to src/features/modals/sertificateModal/types.ts diff --git a/src/widgets/detail/ui/sertificate/useSertificateModal.ts b/src/features/modals/sertificateModal/useSertificateModal.ts similarity index 100% rename from src/widgets/detail/ui/sertificate/useSertificateModal.ts rename to src/features/modals/sertificateModal/useSertificateModal.ts diff --git a/src/widgets/detail/pageDetail.tsx b/src/widgets/detail/pageDetail.tsx index 9b214d2..af0e291 100644 --- a/src/widgets/detail/pageDetail.tsx +++ b/src/widgets/detail/pageDetail.tsx @@ -7,7 +7,7 @@ import { useParams } from 'next/navigation'; import { links } from '@/shared/request/links'; import { apiRequest } from '@/shared/request/apiRequest'; import PaymentStatus from './paidStatus'; -import Sertifikat from './ui/sertificate/sertifikat'; +import Sertifikat from '@/features/modals/sertificateModal/sertifikat'; // ── Types ──────────────────────────────────────────────────────────────────── diff --git a/src/widgets/fileUpload/ui/Plagiraismcheckform.tsx b/src/widgets/fileUpload/ui/Plagiraismcheckform.tsx index 8058650..21de95b 100644 --- a/src/widgets/fileUpload/ui/Plagiraismcheckform.tsx +++ b/src/widgets/fileUpload/ui/Plagiraismcheckform.tsx @@ -10,9 +10,9 @@ import { StatusBanner, } from './Plagiraismui'; import { usePlagiarismForm } from '../lib/usePlagiraism'; -import { PaymentModal } from '@/widgets/paymentModal/ui/Paymentmodal'; import { useTranslations } from 'next-intl'; -import { DOCUMENT_TYPES } from '@/widgets/detail/ui/sertificate/types'; +import { DOCUMENT_TYPES } from '@/features/modals/sertificateModal/types'; +import { PaymentModal } from '@/features/modals/paymentModal/ui/Paymentmodal'; const inputCls = ` w-full px-3.5 py-3.5 text-[14px] text-slate-800 @@ -218,7 +218,12 @@ export function PlagiarismCheckForm() { setIsPaymentOpen(false)} - hasCertificate={form.certificate} + price={{ + service_fee: 41200, + discount: 5200, + total_price: 36000, + currency: 'UZS', + }} onConfirmPayment={handleSubmit} isLoading={isLoading} /> diff --git a/src/widgets/history/lib/types.ts b/src/widgets/history/lib/types.ts index 5cbb900..4083097 100644 --- a/src/widgets/history/lib/types.ts +++ b/src/widgets/history/lib/types.ts @@ -1,5 +1,7 @@ // ─── Domain Types ────────────────────────────────────────────────────────────── +import { PriceCalculate } from '@/features/modals/paymentModal/lib/types'; + export type CheckResult = 'clean' | 'plagiarism_found' | 'pending' | 'failed'; export interface DocumentData { @@ -13,6 +15,7 @@ export interface DocumentData { results: []; state: 'paid' | 'unpaid'; order_id: number; + price_calculation?: PriceCalculate; } export interface PlagiarismCheckDetail extends DocumentData { diff --git a/src/widgets/history/ui/historyTableRow.tsx b/src/widgets/history/ui/historyTableRow.tsx index 65524c1..d698843 100644 --- a/src/widgets/history/ui/historyTableRow.tsx +++ b/src/widgets/history/ui/historyTableRow.tsx @@ -6,11 +6,11 @@ import { formatDate } from '../lib/utils'; import { useRouter } from '@/shared/config/i18n/navigation'; import { useUserPlagiatStore } from '@/shared/zustand/user'; import PaymentStatus from '@/widgets/detail/paidStatus'; -import { PaymentModal } from '@/widgets/paymentModal/ui/Paymentmodal'; import { useMutation } from '@tanstack/react-query'; import { apiRequest } from '@/shared/request/apiRequest'; import { links } from '@/shared/request/links'; import { toast } from 'react-toastify'; +import { PaymentModal } from '@/features/modals/paymentModal/ui/Paymentmodal'; export const HistoryTableRow: React.FC = ({ item }) => { const router = useRouter(); @@ -160,7 +160,12 @@ export const HistoryTableRow: React.FC = ({ item }) => { setIsPaymentOpen(false)} - hasCertificate={false} + price={{ + service_fee: 41200, + discount: 5200, + total_price: 36000, + currency: 'UZS', + }} onConfirmPayment={() => { handleSubmit({ document_id: Number(item.order_id) }); }} diff --git a/src/widgets/paymentModal/lib/utils.ts b/src/widgets/paymentModal/lib/utils.ts deleted file mode 100644 index 0051dab..0000000 --- a/src/widgets/paymentModal/lib/utils.ts +++ /dev/null @@ -1,71 +0,0 @@ -// ─── Pricing Utilities ───────────────────────────────────────────────────────── - -import { PAYME_CONFIG, PRICING } from './constant'; -import { - PaymePaymentRequest, - PaymePaymentResponse, - ServicePricing, -} from './types'; - -export const getPricing = (): ServicePricing => ({ - serviceFee: PRICING.SERVICE_FEE, - certificateFee: PRICING.CERTIFICATE_FEE, - currency: PRICING.CURRENCY, -}); - -export const calculateTotal = (hasCertificate: boolean): number => { - const base = PRICING.SERVICE_FEE; - return hasCertificate ? base + PRICING.CERTIFICATE_FEE : base; -}; - -export const toTiyin = (uzs: number): number => uzs * PRICING.TIYIN_MULTIPLIER; - -export const formatPrice = (amount: number, currency: string): string => - `${amount.toLocaleString('uz-UZ')} ${currency}`; - -// ─── Order ID Generator ──────────────────────────────────────────────────────── - -export const generateOrderId = (): string => { - const timestamp = Date.now(); - const random = Math.random().toString(36).slice(2, 8).toUpperCase(); - return `ORDER-${timestamp}-${random}`; -}; - -// ─── Payme API ───────────────────────────────────────────────────────────────── - -/** - * Sends payment details to the backend, which creates a Payme transaction - * and returns a redirect URL to the Payme checkout page. - */ -export const createPaymePayment = async ( - request: PaymePaymentRequest, -): Promise => { - const response = await fetch(PAYME_CONFIG.API_ENDPOINT, { - method: 'POST', - headers: { 'Content-Type': 'application/json' }, - body: JSON.stringify({ - amount: request.amount, // in tiyin - order_id: request.orderId, - description: request.description, - return_url: request.returnUrl, - }), - }); - - if (!response.ok) { - const errorBody = await response.json().catch(() => ({})); - throw new Error( - (errorBody as { message?: string }).message ?? - `Payment request failed with status ${response.status}`, - ); - } - - const data = (await response.json()) as PaymePaymentResponse; - return data; -}; - -/** - * Redirects the user to the Payme checkout page. - */ -export const redirectToPayme = (redirectUrl: string): void => { - window.location.href = redirectUrl; -};