From fc8ac729f7738c7773aefde40a5f65f68bb982e6 Mon Sep 17 00:00:00 2001 From: hamid zarghami Date: Tue, 16 Jun 2026 08:55:31 +0330 Subject: [PATCH] update design --- .../[id]/components/PaymentSection.tsx | 412 ++++++++---------- .../(Dialogs)/order/track/[id]/page.tsx | 390 ++++++++--------- src/locales/fa/parallels.json | 4 +- 3 files changed, 375 insertions(+), 431 deletions(-) diff --git a/src/app/[name]/(Dialogs)/order/checkout/[id]/components/PaymentSection.tsx b/src/app/[name]/(Dialogs)/order/checkout/[id]/components/PaymentSection.tsx index 8e903e7..2dfb3c1 100644 --- a/src/app/[name]/(Dialogs)/order/checkout/[id]/components/PaymentSection.tsx +++ b/src/app/[name]/(Dialogs)/order/checkout/[id]/components/PaymentSection.tsx @@ -1,249 +1,221 @@ -'use client'; +"use client"; -import { Card, Icon, Wallet2 } from 'iconsax-react'; -import { useCallback, useMemo, useRef } from 'react'; -import { useTranslation } from 'react-i18next'; -import { RadioGroup, RadioGroupItem } from '@/components/ui/radio-group'; -import { useGetPaymentMethod } from '../../hooks/useOrderData'; -import { useCheckoutStore } from '../../store/Store'; -import { useGetUserWallet } from '@/app/[name]/(Main)/transactions/hooks/useTransactionData'; -import { useGetCartItems } from '@/app/[name]/(Main)/cart/hooks/useCartData'; -import { useGetProfile, useSingleUpload } from '@/app/[name]/(Profile)/profile/hooks/userProfileData'; -import { PaymentMethodEnum } from '../../enum/Enum'; -import { toast } from '@/components/Toast'; -import { extractErrorMessage } from '@/lib/func'; -import Image from 'next/image'; +import { useGetCartItems } from "@/app/[name]/(Main)/cart/hooks/useCartData"; +import { useGetUserWallet } from "@/app/[name]/(Main)/transactions/hooks/useTransactionData"; +import { useGetProfile, useSingleUpload } from "@/app/[name]/(Profile)/profile/hooks/userProfileData"; +import { toast } from "@/components/Toast"; +import { RadioGroup, RadioGroupItem } from "@/components/ui/radio-group"; +import { extractErrorMessage } from "@/lib/func"; +import { Card, Icon, Wallet2 } from "iconsax-react"; +import Image from "next/image"; +import { useCallback, useMemo, useRef } from "react"; +import { useTranslation } from "react-i18next"; +import { PaymentMethodEnum } from "../../enum/Enum"; +import { useGetPaymentMethod } from "../../hooks/useOrderData"; +import { useCheckoutStore } from "../../store/Store"; type PaymentSectionProps = { - paymentType: string; - onPaymentTypeChange: (id: string) => void; + paymentType: string; + onPaymentTypeChange: (id: string) => void; }; const getIconByMethod = (method: PaymentMethodEnum): Icon => { - if (method === PaymentMethodEnum.Online || method === PaymentMethodEnum.CreditCard) { - return Card; - } - if (method === PaymentMethodEnum.Cash || method === PaymentMethodEnum.Wallet) { - return Wallet2; - } + if (method === PaymentMethodEnum.Online || method === PaymentMethodEnum.CreditCard) { return Card; + } + if (method === PaymentMethodEnum.Cash || method === PaymentMethodEnum.Wallet) { + return Wallet2; + } + return Card; }; export const PaymentSection = ({ paymentType, onPaymentTypeChange }: PaymentSectionProps) => { + const { t: tOrderDetail } = useTranslation("parallels", { keyPrefix: "OrderDetail" }); + const { t: tOrders } = useTranslation("orders"); + const { data: paymentMethod } = useGetPaymentMethod(); + const { setIsSelectedPayment, paymentDesc, setPaymentDesc, paymentAttachments, setPaymentAttachments } = useCheckoutStore(); + const { data: userWallet } = useGetUserWallet(); + const { isSuccess } = useGetProfile(); + const { data: cartData } = useGetCartItems(isSuccess); + const { mutateAsync: singleUpload, isPending: isUploading } = useSingleUpload(); + const fileInputRef = useRef(null); - const { t: tOrderDetail } = useTranslation('parallels', { keyPrefix: 'OrderDetail' }); - const { t: tOrders } = useTranslation('orders'); - const { data: paymentMethod } = useGetPaymentMethod(); - const { - setIsSelectedPayment, - paymentDesc, - setPaymentDesc, - paymentAttachments, - setPaymentAttachments, - } = useCheckoutStore(); - const { data: userWallet } = useGetUserWallet(); - const { isSuccess } = useGetProfile(); - const { data: cartData } = useGetCartItems(isSuccess); - const { mutateAsync: singleUpload, isPending: isUploading } = useSingleUpload(); - const fileInputRef = useRef(null); + const walletAmount = userWallet?.data?.balance ?? 0; + const totalAmount = cartData?.data?.total ?? 0; + const isWalletInsufficient = walletAmount < totalAmount; - const walletAmount = userWallet?.data?.balance ?? 0; - const totalAmount = cartData?.data?.total ?? 0; - const isWalletInsufficient = walletAmount < totalAmount; + const formatPrice = useCallback((value: number) => value.toLocaleString("fa-IR"), []); - const formatPrice = useCallback( - (value: number) => value.toLocaleString('fa-IR'), - [] - ); + const getPaymentMethodTranslation = useCallback( + (method: string, fallbackTitle: string) => { + const translationKey = `paymentMethod.${method}`; + const translation = tOrders(translationKey); + return translation !== translationKey ? translation : fallbackTitle; + }, + [tOrders], + ); - const getPaymentMethodTranslation = useCallback((method: string, fallbackTitle: string) => { - const translationKey = `paymentMethod.${method}`; - const translation = tOrders(translationKey); - return translation !== translationKey ? translation : fallbackTitle; - }, [tOrders]); + const paymentOptions = useMemo(() => { + if (!paymentMethod?.data) return []; - const paymentOptions = useMemo(() => { - if (!paymentMethod?.data) return []; + return paymentMethod.data + .filter((item) => item.enabled) + .sort((a, b) => a.order - b.order) + .map((item) => ({ + id: item.id, + label: getPaymentMethodTranslation(item.method, item.description), + icon: getIconByMethod(item.method), + method: item.method, + cardNumber: item.cardNumber, + cardOwner: item.cardOwner, + description: item.description, + isWallet: item.method === PaymentMethodEnum.Wallet, + })); + }, [paymentMethod, getPaymentMethodTranslation]); - return paymentMethod.data - .filter(item => item.enabled) - .sort((a, b) => a.order - b.order) - .map(item => ({ - id: item.id, - label: getPaymentMethodTranslation(item.method, item.description), - icon: getIconByMethod(item.method), - method: item.method, - cardNumber: item.cardNumber, - cardOwner: item.cardOwner, - description: item.description, - isWallet: item.method === PaymentMethodEnum.Wallet, - })); - }, [paymentMethod, getPaymentMethodTranslation]); + const selectedCreditCard = useMemo(() => { + const selected = paymentOptions.find((opt) => opt.id === paymentType); + if (selected?.method === PaymentMethodEnum.CreditCard) return selected; + return null; + }, [paymentOptions, paymentType]); - const selectedCreditCard = useMemo(() => { - const selected = paymentOptions.find(opt => opt.id === paymentType); - if (selected?.method === PaymentMethodEnum.CreditCard) return selected; - return null; - }, [paymentOptions, paymentType]); + const handlePaymentTypeChange = (value: string) => { + const selected = paymentOptions.find((opt) => opt.id === value); + if (selected?.method !== PaymentMethodEnum.CreditCard) { + setPaymentDesc(""); + setPaymentAttachments([]); + } + onPaymentTypeChange(value); + setIsSelectedPayment(true); + }; - const handlePaymentTypeChange = (value: string) => { - const selected = paymentOptions.find(opt => opt.id === value); - if (selected?.method !== PaymentMethodEnum.CreditCard) { - setPaymentDesc(''); - setPaymentAttachments([]); - } - onPaymentTypeChange(value); - setIsSelectedPayment(true); - }; + const handleCopyCardNumber = useCallback( + async (cardNumber: string) => { + try { + await navigator.clipboard.writeText(cardNumber); + toast(tOrderDetail("SectionPayment.CreditCard.CopySuccess"), "success"); + } catch { + toast(tOrderDetail("SectionPayment.CreditCard.CopyError"), "error"); + } + }, + [tOrderDetail], + ); - const handleReceiptUpload = async (e: React.ChangeEvent) => { - const file = e.target.files?.[0]; - if (!file) return; + const handleReceiptUpload = async (e: React.ChangeEvent) => { + const file = e.target.files?.[0]; + if (!file) return; - try { - const response = await singleUpload(file); - if (response?.data?.url) { - setPaymentAttachments([response.data.url]); - toast(tOrderDetail('SectionPayment.CreditCard.UploadSuccess'), 'success'); - } - } catch (error) { - toast(extractErrorMessage(error), 'error'); - } finally { - if (fileInputRef.current) { - fileInputRef.current.value = ''; - } - } - }; + try { + const response = await singleUpload(file); + if (response?.data?.url) { + setPaymentAttachments([response.data.url]); + toast(tOrderDetail("SectionPayment.CreditCard.UploadSuccess"), "success"); + } + } catch (error) { + toast(extractErrorMessage(error), "error"); + } finally { + if (fileInputRef.current) { + fileInputRef.current.value = ""; + } + } + }; - return ( -
-
-

{tOrderDetail("SectionPayment.Title")}

+ return ( +
+
+

{tOrderDetail("SectionPayment.Title")}

- - {paymentOptions.map(({ id, label, icon: Icon, isWallet }) => { - const isDisabled = isWallet && isWalletInsufficient; + + {paymentOptions.map(({ id, label, icon: Icon, isWallet }) => { + const isDisabled = isWallet && isWalletInsufficient; - return ( -
- - -
- ); - })} -
+ return ( +
+ + +
+ ); + })} +
- {selectedCreditCard && ( -
- {selectedCreditCard.cardOwner && ( -
- - {tOrderDetail('SectionPayment.CreditCard.CardOwnerLabel')} - -

- {selectedCreditCard.cardOwner} -

-
- )} - {selectedCreditCard.cardNumber && ( -
- - {tOrderDetail('SectionPayment.CreditCard.CardNumberLabel')} - -

- {selectedCreditCard.cardNumber} -

-
- )} - {selectedCreditCard.description && ( + {selectedCreditCard && ( +
+ {(selectedCreditCard.cardOwner || selectedCreditCard.cardNumber) && ( +
+ {selectedCreditCard.cardOwner && ( +
+ {tOrderDetail("SectionPayment.CreditCard.CardOwnerLabel")} +

{selectedCreditCard.cardOwner}

+
+ )} + {selectedCreditCard.cardNumber && ( +
+ {tOrderDetail("SectionPayment.CreditCard.CardNumberLabel")} + +
+ )} +
+ )} + {/* {selectedCreditCard.description && (

{selectedCreditCard.description}

- )} -
- -