update order page
This commit is contained in:
@@ -92,7 +92,6 @@ const DetailPerfomaInvoice: FC = () => {
|
|||||||
const lineTotal = item.total ?? 0;
|
const lineTotal = item.total ?? 0;
|
||||||
const convertToOrderUrl = `${Paths.convertToOrder}?${new URLSearchParams({
|
const convertToOrderUrl = `${Paths.convertToOrder}?${new URLSearchParams({
|
||||||
invoiceItemId: item.id,
|
invoiceItemId: item.id,
|
||||||
productId: item.product?.id ?? '',
|
|
||||||
}).toString()}`;
|
}).toString()}`;
|
||||||
return (
|
return (
|
||||||
<tr key={item.id} className="border-b border-border/50">
|
<tr key={item.id} className="border-b border-border/50">
|
||||||
|
|||||||
@@ -28,6 +28,14 @@ export const useGetInvoiceDetail = (id: string | undefined) => {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const useGetInvoiceItem = (id: string | null) => {
|
||||||
|
return useQuery({
|
||||||
|
queryKey: ["invoice-item", id],
|
||||||
|
queryFn: () => api.getInvoiceItemById(id!),
|
||||||
|
enabled: !!id,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
export const useUpdateInvoice = () => {
|
export const useUpdateInvoice = () => {
|
||||||
const queryClient = useQueryClient();
|
const queryClient = useQueryClient();
|
||||||
|
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ import axios from "@/config/axios";
|
|||||||
import type {
|
import type {
|
||||||
CreatePreInvoiceType,
|
CreatePreInvoiceType,
|
||||||
GetInvoiceResponseType,
|
GetInvoiceResponseType,
|
||||||
|
InvoiceItemDetailType,
|
||||||
InvoiceType,
|
InvoiceType,
|
||||||
UpdatePreInvoiceType,
|
UpdatePreInvoiceType,
|
||||||
} from "../types/Types";
|
} from "../types/Types";
|
||||||
@@ -23,6 +24,13 @@ export const getInvoiceById = async (id: string) => {
|
|||||||
return data;
|
return data;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const getInvoiceItemById = async (id: string) => {
|
||||||
|
const { data } = await axios.get<{ data: InvoiceItemDetailType }>(
|
||||||
|
`/admin/invoice/item/${id}`,
|
||||||
|
);
|
||||||
|
return data;
|
||||||
|
};
|
||||||
|
|
||||||
export const updateInvoice = async (id: string, params: UpdatePreInvoiceType) => {
|
export const updateInvoice = async (id: string, params: UpdatePreInvoiceType) => {
|
||||||
const { data } = await axios.patch(`/admin/invoice/${id}`, params);
|
const { data } = await axios.patch(`/admin/invoice/${id}`, params);
|
||||||
return data;
|
return data;
|
||||||
|
|||||||
@@ -97,6 +97,10 @@ export type InvoiceItemType = {
|
|||||||
confirmedAt: string | null;
|
confirmedAt: string | null;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export type InvoiceItemDetailType = Omit<InvoiceItemType, 'invoice'> & {
|
||||||
|
invoice: Pick<InvoiceType, 'id' | 'invoiceNumber' | 'user'>;
|
||||||
|
};
|
||||||
|
|
||||||
export type InvoiceType = {
|
export type InvoiceType = {
|
||||||
id: string;
|
id: string;
|
||||||
createdAt: string;
|
createdAt: string;
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
import { useState, type FC } from 'react'
|
import { useState, type FC } from 'react'
|
||||||
import { useFormik } from 'formik'
|
import { useFormik } from 'formik'
|
||||||
import * as Yup from 'yup'
|
import * as Yup from 'yup'
|
||||||
|
import moment from 'moment-jalaali'
|
||||||
|
import { Link, useNavigate, useSearchParams } from 'react-router-dom'
|
||||||
import Input from '@/components/Input'
|
import Input from '@/components/Input'
|
||||||
import Textarea from '@/components/Textarea'
|
import Textarea from '@/components/Textarea'
|
||||||
import Select from '@/components/Select'
|
import Select from '@/components/Select'
|
||||||
@@ -11,18 +13,19 @@ import type { ConvertToOrderItemType } from './types/Types'
|
|||||||
import { useConverToOrder, useGetProducts } from './hooks/useOrderData'
|
import { useConverToOrder, useGetProducts } from './hooks/useOrderData'
|
||||||
import { useGetCategory } from '@/pages/product/hooks/useProductData'
|
import { useGetCategory } from '@/pages/product/hooks/useProductData'
|
||||||
import { useGetUsers } from '@/pages/user/hooks/useUserData'
|
import { useGetUsers } from '@/pages/user/hooks/useUserData'
|
||||||
import { useNavigate, useSearchParams } from 'react-router-dom'
|
|
||||||
import { toast } from 'react-toastify'
|
import { toast } from 'react-toastify'
|
||||||
import { Paths } from '@/config/Paths'
|
import { Paths } from '@/config/Paths'
|
||||||
import { extractErrorMessage } from '@/config/func'
|
import { extractErrorMessage } from '@/config/func'
|
||||||
import { useGetAdmins } from '../admin/hooks/useAdminData'
|
import { useGetAdmins } from '../admin/hooks/useAdminData'
|
||||||
|
import { useGetInvoiceItem } from '@/pages/invoice/hooks/useInvoiceData'
|
||||||
|
import { formatItemDiscountDisplay } from '@/pages/invoice/utils/invoiceItem'
|
||||||
|
|
||||||
const getInitialValues = (
|
const formatAmount = (amount: number) =>
|
||||||
invoiceItemId: string | null,
|
Number(amount).toLocaleString('fa-IR') + ' ریال'
|
||||||
productId: string | null
|
|
||||||
): ConvertToOrderItemType => ({
|
const getInitialValues = (invoiceItemId: string | null): ConvertToOrderItemType => ({
|
||||||
invoiceItemId: invoiceItemId ?? '',
|
invoiceItemId: invoiceItemId ?? '',
|
||||||
productId: productId ?? '',
|
productId: '',
|
||||||
userId: '',
|
userId: '',
|
||||||
typeId: '',
|
typeId: '',
|
||||||
estimatedDays: 0,
|
estimatedDays: 0,
|
||||||
@@ -49,18 +52,19 @@ const ConvertToOrders: FC = () => {
|
|||||||
const navigate = useNavigate()
|
const navigate = useNavigate()
|
||||||
const [searchParams] = useSearchParams()
|
const [searchParams] = useSearchParams()
|
||||||
const invoiceItemId = searchParams.get('invoiceItemId')
|
const invoiceItemId = searchParams.get('invoiceItemId')
|
||||||
const productId = searchParams.get('productId')
|
|
||||||
const multiUpload = useMultiUpload()
|
const multiUpload = useMultiUpload()
|
||||||
const [attachmentFiles, setAttachmentFiles] = useState<File[]>([])
|
const [attachmentFiles, setAttachmentFiles] = useState<File[]>([])
|
||||||
const { data: categories } = useGetCategory()
|
const { data: categories } = useGetCategory()
|
||||||
const { data: users } = useGetUsers()
|
const { data: users } = useGetUsers()
|
||||||
const { data: products } = useGetProducts()
|
const { data: products } = useGetProducts()
|
||||||
const { data: admins } = useGetAdmins(1, 50)
|
const { data: admins } = useGetAdmins(1, 50)
|
||||||
|
const { data: invoiceItemData, isLoading: isInvoiceItemLoading } = useGetInvoiceItem(invoiceItemId)
|
||||||
|
const invoiceItem = invoiceItemData?.data
|
||||||
|
|
||||||
const { mutate: converToOrder, isPending } = useConverToOrder()
|
const { mutate: converToOrder, isPending } = useConverToOrder()
|
||||||
|
|
||||||
const formik = useFormik<ConvertToOrderItemType>({
|
const formik = useFormik<ConvertToOrderItemType>({
|
||||||
initialValues: getInitialValues(invoiceItemId, productId),
|
initialValues: getInitialValues(invoiceItemId),
|
||||||
validationSchema: getValidationSchema(invoiceItemId),
|
validationSchema: getValidationSchema(invoiceItemId),
|
||||||
enableReinitialize: true,
|
enableReinitialize: true,
|
||||||
onSubmit: async (values) => {
|
onSubmit: async (values) => {
|
||||||
@@ -76,7 +80,9 @@ const ConvertToOrders: FC = () => {
|
|||||||
const payload: ConvertToOrderItemType = {
|
const payload: ConvertToOrderItemType = {
|
||||||
...values,
|
...values,
|
||||||
invoiceItemId: invoiceItemId ?? values.invoiceItemId ?? '',
|
invoiceItemId: invoiceItemId ?? values.invoiceItemId ?? '',
|
||||||
productId: values.productId || undefined,
|
productId: invoiceItemId
|
||||||
|
? invoiceItem?.product?.id
|
||||||
|
: values.productId || undefined,
|
||||||
userId: invoiceItemId ? undefined : values.userId,
|
userId: invoiceItemId ? undefined : values.userId,
|
||||||
estimatedDays: Number(values.estimatedDays),
|
estimatedDays: Number(values.estimatedDays),
|
||||||
description: values.description || undefined,
|
description: values.description || undefined,
|
||||||
@@ -95,10 +101,95 @@ const ConvertToOrders: FC = () => {
|
|||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
|
const customerName =
|
||||||
|
invoiceItem?.invoice?.user?.firstName && invoiceItem?.invoice?.user?.lastName
|
||||||
|
? `${invoiceItem.invoice.user.firstName} ${invoiceItem.invoice.user.lastName}`
|
||||||
|
: invoiceItem?.invoice?.user?.phone ?? '-'
|
||||||
|
|
||||||
|
const discounts = invoiceItem ? formatItemDiscountDisplay(invoiceItem) : null
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="mt-5">
|
<div className="mt-5">
|
||||||
<h1 className="text-lg font-light">تبدیل به سفارش</h1>
|
<h1 className="text-lg font-light">تبدیل به سفارش</h1>
|
||||||
|
|
||||||
|
{invoiceItemId && (
|
||||||
|
<div className="mt-8 rounded-3xl bg-white p-6">
|
||||||
|
<div className="font-light">اطلاعات آیتم پیش فاکتور</div>
|
||||||
|
|
||||||
|
{isInvoiceItemLoading ? (
|
||||||
|
<div className="mt-6 flex min-h-[120px] items-center justify-center text-[#888888]">
|
||||||
|
در حال بارگذاری...
|
||||||
|
</div>
|
||||||
|
) : invoiceItem ? (
|
||||||
|
<div className="mt-6 grid grid-cols-1 gap-4 sm:grid-cols-2 lg:grid-cols-3">
|
||||||
|
<div>
|
||||||
|
<div className="mb-1.5 text-[13px] text-[#888888]">پیش فاکتور</div>
|
||||||
|
<Link
|
||||||
|
to={Paths.perfomaInvoice.detail + invoiceItem.invoice.id}
|
||||||
|
className="text-[15px] text-primary hover:underline"
|
||||||
|
>
|
||||||
|
#{invoiceItem.invoice.invoiceNumber}
|
||||||
|
</Link>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<div className="mb-1.5 text-[13px] text-[#888888]">مشتری</div>
|
||||||
|
<div className="text-[15px]">{customerName}</div>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<div className="mb-1.5 text-[13px] text-[#888888]">محصول</div>
|
||||||
|
<div className="text-[15px]">{invoiceItem.product?.title ?? '-'}</div>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<div className="mb-1.5 text-[13px] text-[#888888]">تعداد</div>
|
||||||
|
<div className="text-[15px]">{invoiceItem.quantity ?? '-'}</div>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<div className="mb-1.5 text-[13px] text-[#888888]">مبلغ واحد</div>
|
||||||
|
<div className="text-[15px]">
|
||||||
|
{invoiceItem.unitPrice != null
|
||||||
|
? formatAmount(invoiceItem.unitPrice)
|
||||||
|
: '-'}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<div className="mb-1.5 text-[13px] text-[#888888]">تخفیف (مبلغ)</div>
|
||||||
|
<div className="text-[15px]">{discounts?.value ?? '-'}</div>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<div className="mb-1.5 text-[13px] text-[#888888]">تخفیف (درصد)</div>
|
||||||
|
<div className="text-[15px]">{discounts?.percent ?? '-'}</div>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<div className="mb-1.5 text-[13px] text-[#888888]">مبلغ کل</div>
|
||||||
|
<div className="text-[15px] font-semibold">
|
||||||
|
{formatAmount(invoiceItem.total ?? 0)}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<div className="mb-1.5 text-[13px] text-[#888888]">تاریخ تایید</div>
|
||||||
|
<div className="text-[15px]">
|
||||||
|
{invoiceItem.confirmedAt
|
||||||
|
? moment(invoiceItem.confirmedAt).format('jYYYY/jMM/jDD HH:mm')
|
||||||
|
: '-'}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{invoiceItem.description && (
|
||||||
|
<div className="sm:col-span-2 lg:col-span-3">
|
||||||
|
<div className="mb-1.5 text-[13px] text-[#888888]">توضیحات</div>
|
||||||
|
<div className="whitespace-pre-wrap text-[15px]">
|
||||||
|
{invoiceItem.description}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
) : (
|
||||||
|
<div className="mt-6 text-[15px] text-red-500">
|
||||||
|
آیتم پیش فاکتور یافت نشد.
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
|
||||||
<div className="bg-white rounded-3xl p-6 mt-8">
|
<div className="bg-white rounded-3xl p-6 mt-8">
|
||||||
<form
|
<form
|
||||||
onSubmit={formik.handleSubmit}
|
onSubmit={formik.handleSubmit}
|
||||||
|
|||||||
+10
-14
@@ -1,7 +1,7 @@
|
|||||||
import Filters, { type FilterValues } from '@/components/Filters'
|
import Filters, { type FilterValues } from '@/components/Filters'
|
||||||
import { type FC, useState } from 'react'
|
import { type FC, useState } from 'react'
|
||||||
import Table from '@/components/Table'
|
import Table from '@/components/Table'
|
||||||
import { AddSquare, Edit2, Eye, Printer, Receipt21 } from 'iconsax-react'
|
import { AddSquare, Edit2, Printer, Receipt21 } from 'iconsax-react'
|
||||||
import { useGetOrders } from './hooks/useOrderData'
|
import { useGetOrders } from './hooks/useOrderData'
|
||||||
import moment from 'moment-jalaali'
|
import moment from 'moment-jalaali'
|
||||||
import { Link } from 'react-router-dom'
|
import { Link } from 'react-router-dom'
|
||||||
@@ -88,13 +88,14 @@ const OrdersList: FC = () => {
|
|||||||
{
|
{
|
||||||
key: 'title',
|
key: 'title',
|
||||||
title: 'عنوان',
|
title: 'عنوان',
|
||||||
render: (item) => {
|
render: (item) => (
|
||||||
return (
|
<Link
|
||||||
<div>
|
to={Paths.order.details + item.id}
|
||||||
{item.title}
|
className="text-[#0037FF] hover:underline"
|
||||||
</div>
|
>
|
||||||
)
|
{item.title}
|
||||||
}
|
</Link>
|
||||||
|
),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
key: 'customer',
|
key: 'customer',
|
||||||
@@ -162,15 +163,10 @@ const OrdersList: FC = () => {
|
|||||||
color='black'
|
color='black'
|
||||||
/>
|
/>
|
||||||
</Link>
|
</Link>
|
||||||
<Link
|
|
||||||
to={Paths.order.details + item.id}
|
|
||||||
>
|
|
||||||
<Eye size={20} color='#8C90A3' />
|
|
||||||
</Link>
|
|
||||||
<Link to={Paths.order.edit + item.id}>
|
<Link to={Paths.order.edit + item.id}>
|
||||||
<Edit2 size={20} color='#0037FF' />
|
<Edit2 size={20} color='#0037FF' />
|
||||||
</Link>
|
</Link>
|
||||||
<Receipt21 size={20} color='#FF8000' />
|
{/* <Receipt21 size={20} color='#FF8000' /> */}
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user