fix: price variant + perfoma invoice download

This commit is contained in:
hamid zarghami
2025-10-26 13:12:02 +03:30
parent 5a14c2ec24
commit 10b395577a
5 changed files with 238 additions and 13 deletions
+192
View File
@@ -0,0 +1,192 @@
'use client'
import { useGetCart } from "@/app/cart/hooks/useCartData"
import { NumberFormat, toJalaliDate } from "@/config/func"
import { useRouter } from "next/navigation"
import { useEffect } from "react"
import Image from "next/image"
const InvoicePage = () => {
const { data, isLoading } = useGetCart()
const router = useRouter()
useEffect(() => {
if (!isLoading && !data?.results?.cart?.items?.length) {
router.push('/cart')
}
}, [data, isLoading, router])
if (isLoading) {
return (
<div className="flex items-center justify-center min-h-screen">
<div className="text-lg">در حال بارگذاری...</div>
</div>
)
}
const cart = data?.results?.cart
if (!cart?.items?.length) return null
const handlePrint = () => {
window.print()
}
return (
<div className="min-h-screen bg-white p-4 sm:p-8">
<div className="max-w-4xl mx-auto">
<div className="no-print mb-6 flex justify-between items-center">
<button
onClick={() => router.back()}
className="px-4 py-2 bg-gray-200 rounded-lg hover:bg-gray-300"
>
بازگشت
</button>
<button
onClick={handlePrint}
className="px-6 py-2 bg-primary text-white rounded-lg hover:bg-primary/90"
>
پرینت فاکتور
</button>
</div>
<div className="bg-white border-2 border-gray-200 rounded-lg p-6 sm:p-8 print:border-0">
<div className="flex items-center justify-between border-b pb-4 mb-6">
<div>
<Image
src="/images/logo.png"
alt="لوگو"
width={120}
height={40}
className="h-10 w-auto"
/>
</div>
<div className="text-left">
<h1 className="text-2xl font-bold mb-2">پیشفاکتور خرید</h1>
<p className="text-sm text-gray-600">
تاریخ: {toJalaliDate(new Date())}
</p>
</div>
</div>
<div className="mb-6 grid grid-cols-2 gap-4 bg-gray-50 p-4 rounded-lg">
<div>
<p className="text-sm text-gray-600">نام و نام خانوادگی</p>
<p className="font-medium">{cart.user?.fullName || '-'}</p>
</div>
<div>
<p className="text-sm text-gray-600">شماره تماس</p>
<p className="font-medium">{cart.user?.phoneNumber || '-'}</p>
</div>
<div>
<p className="text-sm text-gray-600">شماره فاکتور</p>
<p className="font-medium">{cart._id.slice(-8).toUpperCase()}</p>
</div>
<div>
<p className="text-sm text-gray-600">تعداد کالا</p>
<p className="font-medium">{NumberFormat(cart.items_count)} محصول</p>
</div>
</div>
<div className="mb-6">
<h2 className="text-lg font-bold mb-4">لیست محصولات</h2>
<div className="overflow-x-auto">
<table className="w-full border-collapse">
<thead>
<tr className="bg-gray-100">
<th className="border border-gray-300 p-3 text-right">ردیف</th>
<th className="border border-gray-300 p-3 text-right">محصول</th>
<th className="border border-gray-300 p-3 text-center">تعداد</th>
<th className="border border-gray-300 p-3 text-left">قیمت واحد</th>
<th className="border border-gray-300 p-3 text-left">تخفیف</th>
<th className="border border-gray-300 p-3 text-left">قیمت کل</th>
</tr>
</thead>
<tbody>
{cart.items.map((item, index) => {
const retailPrice = item.variant.price.retailPrice
const sellingPrice = item.variant.price.selling_price
const totalRetail = retailPrice * item.quantity
const totalSelling = sellingPrice * item.quantity
const discount = totalRetail - totalSelling
return (
<tr key={`${item.product._id}-${item.variant._id}`}>
<td className="border border-gray-300 p-3 text-center">
{NumberFormat(index + 1)}
</td>
<td className="border border-gray-300 p-3">
<div>
<p className="font-medium">{item.product.title_fa}</p>
<p className="text-xs text-gray-600 mt-1">
فروشنده: {item.variant.shop.shopName}
</p>
{item.variant.warranty && (
<p className="text-xs text-gray-600">
گارانتی: {item.variant.warranty.name}
</p>
)}
</div>
</td>
<td className="border border-gray-300 p-3 text-center">
{NumberFormat(item.quantity)}
</td>
<td className="border border-gray-300 p-3 text-left">
{NumberFormat(retailPrice)} تومان
</td>
<td className="border border-gray-300 p-3 text-left">
{discount > 0 ? `${NumberFormat(discount)} تومان` : '-'}
</td>
<td className="border border-gray-300 p-3 text-left font-medium">
{NumberFormat(totalSelling)} تومان
</td>
</tr>
)
})}
</tbody>
</table>
</div>
</div>
<div className="border-t pt-4">
<div className="flex justify-end">
<div className="w-full sm:w-80 space-y-3">
<div className="flex justify-between text-gray-700">
<span>قیمت کالاها:</span>
<span>{NumberFormat(cart.retail_price)} تومان</span>
</div>
<div className="flex justify-between text-gray-700">
<span>تخفیف:</span>
<span className="text-red-600">
{NumberFormat(cart.total_discount)} تومان
</span>
</div>
{cart.coupon_discount > 0 && (
<div className="flex justify-between text-gray-700">
<span>تخفیف کد تخفیف:</span>
<span className="text-red-600">
{NumberFormat(cart.coupon_discount)} تومان
</span>
</div>
)}
<div className="flex justify-between text-xl font-bold border-t pt-3">
<span>جمع کل:</span>
<span className="text-primary">
{NumberFormat(cart.payable_price)} تومان
</span>
</div>
</div>
</div>
</div>
<div className="mt-8 pt-6 border-t text-center text-sm text-gray-600">
<p>
این پیشفاکتور صرفاً جهت اطلاع شما صادر شده و فاکتور نهایی پس از تکمیل خرید ارسال خواهد شد.
</p>
</div>
</div>
</div>
</div>
)
}
export default InvoicePage
+3 -1
View File
@@ -8,9 +8,10 @@ import { NextPage } from "next"
import { useGetCart, useRemoveAllCart } from "./hooks/useCartData"
import { toast } from "@/components/Toast"
import { useState } from "react"
import { useRouter } from "next/navigation"
const Cart: NextPage = () => {
const router = useRouter()
const { data, isLoading, error } = useGetCart();
const removeAllCartMutation = useRemoveAllCart()
const [isClearingAll, setIsClearingAll] = useState(false)
@@ -113,6 +114,7 @@ const Cart: NextPage = () => {
total={cart?.payable_price || 0}
confirmHref="/cart/shipping"
confirmLabel="ادامه به آدرس و ارسال"
onDownloadInvoice={() => router.push('/cart/invoice')}
className="w-full lg:w-[360px] xl:w-[400px]"
/>
</div>
+23
View File
@@ -282,3 +282,26 @@ textarea.place-black::placeholder {
.rmdp-container {
width: 100%;
}
/* Print Styles */
@media print {
body {
print-color-adjust: exact;
-webkit-print-color-adjust: exact;
padding-bottom: 0 !important;
}
/* Hide all fixed elements (header, mobile menu, etc) */
.fixed {
display: none !important;
}
/* Hide no-print class */
.no-print {
display: none !important;
}
@page {
margin: 1cm;
}
}
+11 -5
View File
@@ -8,6 +8,7 @@ import Image from 'next/image'
import Cart from './Cart'
import { PRIMARY_COLOR } from '@/config/const'
import { useRouter } from 'next/navigation'
import { useProductStore } from '../store/Store'
interface ShopInformationProps {
product: Product
@@ -15,12 +16,17 @@ interface ShopInformationProps {
const ShopInformation = ({ product }: ShopInformationProps) => {
const router = useRouter()
const { variantId } = useProductStore()
const defaultVariant = product.default_variant
const shop = defaultVariant.shop
const price = defaultVariant.price
const warranty = defaultVariant.warranty
const postingTime = defaultVariant.postingTime
// پیدا کردن variant انتخابی یا استفاده از default_variant
const selectedVariant = variantId
? product.variants.find((variant) => variant._id === variantId) || product.default_variant
: product.default_variant
const shop = selectedVariant.shop
const price = selectedVariant.price
const warranty = selectedVariant.warranty
const postingTime = selectedVariant.postingTime
const formatPrice = (price: number) => {
return price.toLocaleString('fa-IR')
+2
View File
@@ -53,6 +53,7 @@ const CartSummary: FC<CartSummaryProps> = (props) => {
</div>
<div className="mt-6 sm:mt-8 space-y-2 sm:space-y-3">
{onDownloadInvoice && (
<Button
type="button"
onClick={() => onDownloadInvoice?.()}
@@ -60,6 +61,7 @@ const CartSummary: FC<CartSummaryProps> = (props) => {
>
دانلود پیشفاکتور
</Button>
)}
<Button
type="button"
onClick={() => !confirmHref && onConfirm?.()}