Files
negareh-admin/src/pages/invoice/ProformaInvoice.tsx
T
hamid zarghami f2ebdc9836 update invoice
2026-02-21 14:28:32 +03:30

208 lines
8.4 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import Tabs from '@/components/Tabs'
import { useMemo, useState, type FC } from 'react'
import { ProformaInvoiceStatusEnum } from './enum/InvoiceEnum'
import Filters from '@/components/Filters'
import Table from '@/components/Table'
import { Eye, Add } from 'iconsax-react'
import { Link } from 'react-router-dom'
import { Paths } from '@/config/Paths'
import moment from 'moment-jalaali'
import type { FilterValues } from '@/components/Filters'
import { useGetInvoice } from './hooks/useInvoiceData'
import type { InvoiceType } from './types/Types'
const isInvoiceConfirmed = (item: InvoiceType) => {
const items = item.items ?? []
return items.length > 0 && items.every((i) => !!i.confirmedAt)
}
const ProformaInvoice: FC = () => {
const [activeTab, setActiveTab] = useState<ProformaInvoiceStatusEnum>(ProformaInvoiceStatusEnum.ALL)
const [page, setPage] = useState(1)
const [filters, setFilters] = useState<FilterValues>({})
const { data, isLoading } = useGetInvoice(page)
const meta = data?.meta
const filteredData = useMemo(() => {
const list = data?.data ?? []
if (activeTab === ProformaInvoiceStatusEnum.CONFIRMED) {
return list.filter((o) => isInvoiceConfirmed(o))
}
if (activeTab === ProformaInvoiceStatusEnum.NOT_CONFIRMED) {
return list.filter((o) => !isInvoiceConfirmed(o))
}
let result = list
const search = (filters.search ?? '').trim()
if (search) {
const lower = search.toLowerCase()
result = result.filter(
(o) =>
String(o.invoiceNumber).includes(search) ||
o.user?.firstName?.toLowerCase().includes(lower) ||
o.user?.lastName?.toLowerCase().includes(lower) ||
o.user?.phone?.includes(search)
)
}
const dateFilter = filters.date
if (dateFilter) {
const filterDate = moment(dateFilter, 'jYYYY/jMM/jDD').format('YYYY-MM-DD')
result = result.filter((o) => {
const d = o.createdAt
return d && moment(d).format('YYYY-MM-DD') === filterDate
})
}
return result
}, [data?.data, activeTab, filters.search, filters.date])
const getPaymentStatus = (item: InvoiceType) => {
const total = Number(item.total) || 0
const paid = Number(item.paidAmount) || 0
if (total <= 0) return '-'
if (paid >= total) return 'پرداخت شده'
if (paid > 0) return 'پرداخت جزئی'
return 'پرداخت نشده'
}
const getServiceLabel = (item: InvoiceType) => {
if (!item.items?.length) return '-'
if (item.items.length === 1) return item.items[0].product?.title ?? '-'
return `${item.items.length} خدمت`
}
return (
<div className='mt-5'>
<div className='flex justify-between items-center'>
<h1 className='text-lg font-light'>پیش فاکتورها</h1>
<Link to={Paths.perfomaInvoice.create}>
<button className='flex items-center gap-2 px-4 py-2 bg-primary text-black text-sm font-medium rounded-xl hover:opacity-90 transition-opacity'>
<Add size={18} />
پیش فاکتور جدید
</button>
</Link>
</div>
<div className='mt-8'>
<Tabs
items={[
{ label: 'همه', value: ProformaInvoiceStatusEnum.ALL },
{ label: 'تایید نشده', value: ProformaInvoiceStatusEnum.NOT_CONFIRMED },
{ label: 'تایید شده', value: ProformaInvoiceStatusEnum.CONFIRMED },
]}
activeTab={activeTab}
onTabChange={(tab) => setActiveTab(tab as ProformaInvoiceStatusEnum)}
/>
</div>
<div className='mt-8'>
<Filters
fields={[
{
type: 'input',
name: 'search',
placeholder: 'جستجو (شماره سفارش / مشتری)',
},
{
type: 'date',
name: 'date',
placeholder: 'تاریخ',
},
]}
onChange={setFilters}
/>
</div>
<div className='mt-8'>
<Table
columns={[
{
key: 'invoiceNumber',
title: 'شماره',
render: (item) => item.invoiceNumber,
},
{
key: 'service',
title: 'خدمت',
render: (item) => getServiceLabel(item),
},
{
key: 'issueDate',
title: 'تاریخ صدور',
render: (item) =>
item.createdAt
? moment(item.createdAt).format('jYYYY/jMM/jDD')
: '-',
},
{
key: 'lastConfirmDate',
title: 'آخرین مهلت تایید',
render: (item) =>
item.approvalDeadline
? moment(item.approvalDeadline).format('jYYYY/jMM/jDD')
: '-',
},
{
key: 'total',
title: 'مجموع',
render: (item) =>
item.total
? Number(item.total).toLocaleString('fa-IR') + ' تومان'
: '-',
},
{
key: 'confirmStatus',
title: 'وضعیت تایید',
render: (item) => {
const confirmed = isInvoiceConfirmed(item)
return (
<span
className={`inline-flex h-6 items-center rounded-full px-2.5 text-xs ${confirmed ? 'bg-green-100 text-green-800' : 'bg-amber-100 text-amber-800'
}`}
>
{confirmed ? 'تایید شده' : 'تایید نشده'}
</span>
)
},
},
{
key: 'paymentStatus',
title: 'وضعیت پرداخت',
render: (item) => getPaymentStatus(item),
},
{
key: 'actions',
title: '',
render: (item) => (
<div className='flex gap-2 items-center'>
<Link to={Paths.perfomaInvoice.update + item.id}>
<Eye size={20} color='#8C90A3' />
</Link>
</div>
),
},
]}
data={filteredData}
isLoading={isLoading}
noDataMessage='پیش فاکتوری یافت نشد.'
pagination={
meta && meta.totalPages > 1
? {
currentPage: meta.page,
totalPages: meta.totalPages,
onPageChange: setPage,
}
: undefined
}
/>
</div>
</div>
)
}
export default ProformaInvoice