invoice pay approve , ...

This commit is contained in:
hamid zarghami
2025-02-22 12:42:12 +03:30
parent 983deef7c8
commit 1532fbc0ad
7 changed files with 260 additions and 6 deletions
+68
View File
@@ -0,0 +1,68 @@
import { FC, useState } from 'react'
import DefaulModal from './DefaulModal'
import { useTranslation } from 'react-i18next'
import Button from './Button'
import Textarea from './Textarea'
type Props = {
isLoading?: boolean,
close: () => void,
isOpen: boolean,
onConfrim: (text?: string) => void,
label?: string,
isHasDescription?: boolean
}
const ModalConfrim: FC<Props> = (props: Props) => {
const { t } = useTranslation('global')
const [description, setDescription] = useState<string>('')
return (
<DefaulModal
open={props.isOpen}
close={props.close}
title_header={t('confrim.subject')}
isHeader
>
<div className='mt-6'>
<div className='text-sm text-center'>
{
props.label ?
props.label
:
t('confrim.content')
}
{
props.isHasDescription &&
<div className='mt-4'>
<Textarea
placeholder={t('description')}
onChange={(e) => setDescription(e.target.value)}
value={description}
className='bg-transparent border border-gray-500 rounded-xl w-[300px] p-2'
label=''
/>
</div>
}
</div>
<div className='flex gap-4 justify-center mt-10'>
<Button
label={t('confrim.yes')}
onClick={() => props.onConfrim(props.isHasDescription ? description : undefined)}
isLoading={props.isLoading}
/>
<Button
label={t('confrim.cancel')}
className='bg-transparent text-black border border-primary'
onClick={props.close}
/>
</div>
</div>
</DefaulModal>
)
}
export default ModalConfrim
+17 -2
View File
@@ -219,14 +219,29 @@
"service": "سرویس",
"status": "وضعیت تایید",
"status_paid": "وضعیت پرداخت",
"PENDING": "در انتظار پرداخت",
"PENDING": "در انتظار ",
"PAID": "پرداخت شده",
"CANCELED": "لغو شده",
"EXPIRED": "منقضی شده",
"APPROVED": "تایید شده",
"real_person": "شخص حقیقی",
"fullName": "نام و نام خانوادگی",
"compelete_financal_info_error": "برای دریافت فاکتور رسمی اطلاعات مالی خود را وارد کنید",
"compelete_financal_info": "تکمیل اطلاعات مالی"
"compelete_financal_info": "تکمیل اطلاعات مالی",
"get_factor": "دریافت پیش فاکتور",
"pay": "پرداخت",
"confrim_factor": "تایید فاکتور",
"sure_confrim_factor": "برای تایید فاکتور مطمئن هستید؟",
"accepted": "تایید شده",
"sure_confrim_pay": "آیا مطمئن هستید که مبلغ صورتحساب از کیف پول شما کسر شود؟",
"thank_pay_1": "ضمن تشکر از خرید شما",
"thank_pay_2": "مبلغ این صورت حساب پرداخت شده است."
},
"confrim": {
"subject": "حذف",
"content": "برای حذف این آیتم مطمئن هستید؟",
"yes": "بله",
"cancel": "لغو"
},
"edit": "ویرایش",
"transaction": {
+26 -3
View File
@@ -11,6 +11,9 @@ import LegalInfo from './components/LegalInfo'
import RealInfo from './components/RealInfo'
import RegisterInfo from './components/RegisterInfo'
import { clx } from '../../helpers/utils'
import Button from '../../components/Button'
import ApproveInvoice from './components/ApproveInvoice'
import PayInvoice from './components/PayInvoice'
const ReceiptsDetail: FC = () => {
@@ -21,8 +24,10 @@ const ReceiptsDetail: FC = () => {
return (
<div className='mt-4'>
<div>
{t('receip.detail_account')}
<div className='flex gap-6 items-center'>
<div>{t('receip.detail_account')}</div>
<ApproveInvoice status={getInvoce.data?.data?.invoice?.status} id={id ? id : ''} refetch={getInvoce.refetch} />
</div>
{
@@ -107,13 +112,17 @@ const ReceiptsDetail: FC = () => {
</div>
<div className='bg-white xl:w-sidebar text-sm h-fit rounded-3xl p-8'>
<div className='p-6 bg-green-50 rounded-2xl text-green-400 text-xs mb-6'>
<p>{t('receip.thank_pay_1')}</p>
<p className='mt-1'>{t('receip.thank_pay_2')}</p>
</div>
<div className='flex justify-between items-center'>
<div>
{t('receip.receip_information')}
</div>
<div className={clx(
'border border-orange-400 text-orange-400 rounded-lg text-[9px] h-6 flex items-center px-1',
getInvoce.data?.data?.invoice?.status === 'PAID' ? 'border-green-400 text-green-400' : getInvoce.data?.data?.invoice?.status !== 'PENDING' ? 'border-red-400 text-red-400' : 'border-orange-400 text-orange-400'
getInvoce.data?.data?.invoice?.status === 'PAID' || getInvoce.data?.data?.invoice?.status === 'APPROVED' ? 'border-green-400 text-green-400' : getInvoce.data?.data?.invoice?.status !== 'PENDING' ? 'border-red-400 text-red-400' : 'border-orange-400 text-orange-400'
)}>
<div>{t(`receip.${getInvoce.data?.data?.invoice?.status}`)}</div>
</div>
@@ -152,6 +161,20 @@ const ReceiptsDetail: FC = () => {
{t(`receip.${getInvoce.data?.data?.invoice?.status}`)}
</div>
</div>
{
getInvoce.data?.data?.invoice?.status === 'APPROVED' &&
<div className='flex gap-4 items-center mt-8'>
<Button
label={t('receip.get_factor')}
className='bg-[#E8E8E8] text-description text-xs'
/>
<PayInvoice
id={id ? id : ''}
refetch={getInvoce.refetch}
/>
</div>
}
</div>
@@ -0,0 +1,74 @@
import { Fragment, FC, useState } from 'react'
import Button from '../../../components/Button'
import { TickCircle } from 'iconsax-react'
import { useTranslation } from 'react-i18next'
import ModalConfrim from '../../../components/ModalConfrim'
import { useApproveInvoice } from '../hooks/useReceiptData'
import { ErrorType } from '../../../helpers/types'
import { toast } from 'react-toastify'
import { clx } from '../../../helpers/utils'
type Props = {
id: string,
refetch: () => void,
status: string
}
const ApproveInvoice: FC<Props> = ({ id, refetch, status }) => {
const approveInvoce = useApproveInvoice()
const [showModal, setShowModal] = useState<boolean>(false)
const { t } = useTranslation('global')
const handleConfrim = () => {
approveInvoce.mutate(id, {
onSuccess: () => {
toast.success(t('success'))
refetch()
setShowModal(false)
},
onError: (error: ErrorType) => {
toast.error(error.response?.data?.error.message[0])
}
})
}
if (status === 'PENDING' || status === 'APPROVED')
return (
<Fragment>
<Button
onClick={() => status === 'PENDING' ? setShowModal(true) : null}
className={clx(
'px-9 w-fit bg-white bg-opacity-70 text-description',
status === 'APPROVED' && 'bg-green-300 text-[#00BA4B] bg-opacity-10'
)}
>
<div className='flex gap-2.5'>
<TickCircle
size={20}
color={status === 'PENDING' ? '#888888' : '#00BA4B'}
/>
<div>
{
status === 'APPROVED' ?
t('receip.accepted')
:
t('receip.confrim_factor')
}
</div>
</div>
</Button>
<ModalConfrim
isOpen={showModal}
close={() => setShowModal(false)}
onConfrim={handleConfrim}
label={t('receip.sure_confrim_pay')}
isLoading={approveInvoce.isPending}
/>
</Fragment>
)
else return null
}
export default ApproveInvoice
@@ -0,0 +1,52 @@
import { FC, Fragment, useState } from 'react'
import Button from '../../../components/Button'
import { useTranslation } from 'react-i18next'
import { usePayInvoice } from '../hooks/useReceiptData'
import { toast } from 'react-toastify'
import { ErrorType } from '../../../helpers/types'
import ModalConfrim from '../../../components/ModalConfrim'
type Props = {
id: string,
refetch: () => void,
}
const PayInvoice: FC<Props> = ({ id, refetch }) => {
const { t } = useTranslation('global')
const [showModal, setShowModal] = useState<boolean>(false)
const payInvoice = usePayInvoice()
const handleConfrim = () => {
payInvoice.mutate(id, {
onSuccess: () => {
toast.success(t('success'))
refetch()
setShowModal(false)
},
onError: (error: ErrorType) => {
toast.error(error.response?.data?.error.message[0])
}
})
}
return (
<Fragment>
<Button
label={t('receip.pay')}
onClick={() => setShowModal(true)}
/>
<ModalConfrim
isOpen={showModal}
close={() => setShowModal(false)}
onConfrim={handleConfrim}
label={t('receip.sure_confrim_pay')}
isLoading={payInvoice.isPending}
/>
</Fragment>
)
}
export default PayInvoice
+13 -1
View File
@@ -1,4 +1,4 @@
import { useQuery } from "@tanstack/react-query";
import { useMutation, useQuery } from "@tanstack/react-query";
import * as api from "../service/ReceiptService";
export const useGetInvoices = (status: string) => {
@@ -15,3 +15,15 @@ export const useGetInvoiceDetail = (id: string) => {
enabled: !!id,
});
};
export const useApproveInvoice = () => {
return useMutation({
mutationFn: (variables: string) => api.approveInvoice(variables),
});
};
export const usePayInvoice = () => {
return useMutation({
mutationFn: (variables: string) => api.payInvoice(variables),
});
};
@@ -9,3 +9,13 @@ export const getInvoiceDetail = async (id: string) => {
const { data } = await axios.get(`/invoices/${id}`);
return data;
};
export const approveInvoice = async (id: string) => {
const { data } = await axios.patch(`/invoices/${id}/approve`);
return data;
};
export const payInvoice = async (id: string) => {
const { data } = await axios.post(`/invoices/${id}/pay`);
return data;
};