import React, { useMemo, useState } from "react"; import DatePicker from "../common/DatePicker"; import EmployeeSearchInput from "../common/EmployeeSearchInput"; import Label from "../common/Label"; import { zodResolver } from "@hookform/resolvers/zod"; import { defaultPRActionValues, PaymentRequestActionScheam, } from "./PaymentRequestSchema"; import { useActionOnPaymentRequest, usePaymentRequestDetail, } from "../../hooks/useExpense"; import { CREATE_EXEPENSE, EXPENSE_CREATE, EXPENSE_PROCESSED, EXPENSE_REJECTEDBY, PROCESS_EXPENSE, REVIEW_EXPENSE, } from "../../utils/constants"; import { useHasUserPermission } from "../../hooks/useHasUserPermission"; import { useNavigate } from "react-router-dom"; import { useForm } from "react-hook-form"; import { useSelector } from "react-redux"; import { usePaymentRequestContext } from "../../pages/PaymentRequest/PaymentRequestPage"; import { calculateTDSPercentage, localToUtc } from "../../utils/appUtils"; import { usePaymentMode } from "../../hooks/masterHook/useMaster"; import Filelist from "../Expenses/Filelist"; const ActionPaymentRequest = ({ requestId }) => { const { setIsExpenseGenerate, setVieRequest } = usePaymentRequestContext(); const { data, isLoading, isError, error, isFetching } = usePaymentRequestDetail(requestId); const [IsPaymentProcess, setIsPaymentProcess] = useState(false); const [clickedStatusId, setClickedStatusId] = useState(null); const { PaymentModes, loading: PaymentModeLoading, error: PaymentModeError, } = usePaymentMode(); const IsReview = useHasUserPermission(REVIEW_EXPENSE); const [imageLoaded, setImageLoaded] = useState({}); const isRejectedRequest = useMemo(() => { return EXPENSE_REJECTEDBY.includes(data?.status?.id); }, [data]); const isProccesed = useMemo(() => { return data?.expenseStatus?.id === EXPENSE_PROCESSED; }, [data]); const ActionSchema = PaymentRequestActionScheam(IsPaymentProcess, isProccesed) ?? z.object({}); const navigate = useNavigate(); const { register, handleSubmit, setValue, reset, control, watch, formState: { errors }, } = useForm({ resolver: zodResolver(ActionSchema), defaultValues: defaultPRActionValues, }); const baseAmount = watch("baseAmount") || 0; const taxAmount = watch("taxAmount") || 0; const tdsPercentage = watch("tdsPercentage") || 0; const { grossAmount, tdsAmount, netPayable } = useMemo(() => { return calculateTDSPercentage(baseAmount, taxAmount, tdsPercentage); }, [baseAmount, taxAmount, tdsPercentage]); const userPermissions = useSelector( (state) => state?.globalVariables?.loginUser?.featurePermissions || [] ); const CurrentUser = useSelector( (state) => state?.globalVariables?.loginUser?.employeeInfo ); const nextStatusWithPermission = useMemo(() => { if (!Array.isArray(data?.nextStatus)) return []; return data.nextStatus.filter((status) => { const permissionIds = Array.isArray(status?.permissionIds) ? status.permissionIds : []; if (permissionIds?.length === 0) return true; if (permissionIds.includes(PROCESS_EXPENSE)) { setIsPaymentProcess(true); } return permissionIds.some((id) => userPermissions.includes(id)); }); }, [data, userPermissions]); const isCreatedBy = useMemo(() => { return data?.createdBy?.id === CurrentUser?.id; }, [data, CurrentUser]); const { mutate: MakeAction, isPending } = useActionOnPaymentRequest(() => { setClickedStatusId(null); reset(); }); const onSubmit = (formData) => { const Payload = { ...formData, paidAt: localToUtc(formData.paidAt), paymentRequestId: data.id, comment: formData.comment, }; MakeAction(Payload); }; if (isLoading) return
Lading..
; if (isError) return ; const handleImageLoad = (id) => { setImageLoaded((prev) => ({ ...prev, [id]: true })); }; const handleExpense = () => { setIsExpenseGenerate({ IsOpen: true, requestId: requestId }); setVieRequest({ IsOpen: false, requestId: null }); }; const files = watch("billAttachments"); const onFileChange = async (e) => { const newFiles = Array.from(e.target.files); if (newFiles?.length === 0) return; const existingFiles = watch("billAttachments") || []; const parsedFiles = await Promise.all( newFiles.map(async (file) => { const base64Data = await toBase64(file); return { fileName: file.name, base64Data, contentType: file.type, fileSize: file.size, description: "", isActive: true, }; }) ); const combinedFiles = [ ...existingFiles, ...parsedFiles.filter( (newFile) => !existingFiles.some( (f) => f.fileName === newFile.fileName && f.fileSize === newFile.fileSize ) ), ]; setValue("billAttachments", combinedFiles, { shouldDirty: true, shouldValidate: true, }); }; const toBase64 = (file) => new Promise((resolve, reject) => { const reader = new FileReader(); reader.readAsDataURL(file); reader.onload = () => resolve(reader.result.split(",")[1]); reader.onerror = (error) => reject(error); }); const removeFile = (index) => { const newFiles = files.filter((_, i) => i !== index); setValue("billAttachments", newFiles, { shouldValidate: true }); }; const filteredPaymentModes = useMemo(() => { return PaymentModes?.filter((mode) => { if (mode.name === "Advance Payment" && data?.isAdvancePayment === false) { return false; } return true; }) || []; }, [PaymentModes, data]); return (
{IsPaymentProcess && nextStatusWithPermission?.length > 0 && ( <> {isProccesed ? (

{/* Expense Making */}
{errors.paymentModeId && ( {errors.paymentModeId.message} )}
{errors.gstNumber && ( {errors.gstNumber.message} )}
{errors.location && ( {errors.location.message} )}
document.getElementById("billAttachments").click() } > Click to select or click here to browse (PDF, JPG, PNG, max 5MB) { onFileChange(e); e.target.value = ""; }} />
{errors.billAttachments && ( {errors.billAttachments.message} )} {files?.length > 0 && ( )} {Array.isArray(errors.billAttachments) && errors.billAttachments.map((fileError, index) => (
{ (fileError?.fileSize?.message || fileError?.contentType?.message || fileError?.base64Data?.message, fileError?.documentId?.message) }
))}
) : ( // Payment process
{errors.paidTransactionId && ( {errors.paidTransactionId.message} )}
{errors.paidAt && ( {errors.paidAt.message} )}
{errors.baseAmount && ( {errors.baseAmount.message} )}
{errors.taxAmount && ( {errors.taxAmount.message} )}
{errors.tdsPercentage && ( {errors.tdsPercentage.message} )}
TDS Amount: {tdsAmount.toFixed(2)}
Net Payable: {netPayable.toFixed(2)}
)} )}
{((nextStatusWithPermission?.length > 0 && !isRejectedRequest) || (isRejectedRequest && isCreatedBy)) && ( <>