241 lines
8.0 KiB
JavaScript
241 lines
8.0 KiB
JavaScript
import React, { createContext, useContext, useState } from "react";
|
|
import moment from "moment";
|
|
import Breadcrumb from "../../components/common/Breadcrumb";
|
|
import CollectionList from "../../components/collections/CollectionList";
|
|
import { useModal } from "../../hooks/useAuth";
|
|
import { FormProvider, useForm } from "react-hook-form";
|
|
import { zodResolver } from "@hookform/resolvers/zod";
|
|
import { DateRangePicker1 } from "../../components/common/DateRangePicker";
|
|
import { isPending } from "@reduxjs/toolkit";
|
|
import ConfirmModal from "../../components/common/ConfirmModal";
|
|
import showToast from "../../services/toastService";
|
|
import { useMarkedPaymentReceived } from "../../hooks/useCollections";
|
|
import GlobalModel from "../../components/common/GlobalModel";
|
|
import AddPayment from "../../components/collections/AddPayment";
|
|
import ViewCollection from "../../components/collections/ViewCollection";
|
|
import ManageCollection from "../../components/collections/ManageCollection";
|
|
import PreviewDocument from "../../components/Expenses/PreviewDocument";
|
|
import { useHasUserPermission } from "../../hooks/useHasUserPermission";
|
|
import {
|
|
ADDPAYMENT_COLLECTION,
|
|
ADMIN_COLLECTION,
|
|
CREATE_COLLECTION,
|
|
EDIT_COLLECTION,
|
|
VIEW_COLLECTION,
|
|
} from "../../utils/constants";
|
|
import AccessDenied from "../../components/common/AccessDenied";
|
|
|
|
const CollectionContext = createContext();
|
|
export const useCollectionContext = () => {
|
|
const context = useContext(CollectionContext);
|
|
if (!context) {
|
|
window.location = "/dashboard";
|
|
showToast("Out of Context Happend inside Collection Context", "warning");
|
|
}
|
|
return context;
|
|
};
|
|
const CollectionPage = () => {
|
|
const [viewCollection, setViewCollection] = useState(null);
|
|
const [makeCollection, setCollection] = useState({
|
|
isOpen: false,
|
|
invoiceId: null,
|
|
});
|
|
const [ViewDocument, setDocumentView] = useState({
|
|
IsOpen: false,
|
|
Image: null,
|
|
});
|
|
const [processedPayment, setProcessedPayment] = useState(null);
|
|
const [addPayment, setAddPayment] = useState({
|
|
isOpen: false,
|
|
invoiceId: null,
|
|
});
|
|
const [showPending, setShowPending] = useState(false);
|
|
const [searchText, setSearchText] = useState("");
|
|
const isAdmin = useHasUserPermission(ADMIN_COLLECTION);
|
|
const canViewCollection = useHasUserPermission(VIEW_COLLECTION);
|
|
const canCreate = useHasUserPermission(CREATE_COLLECTION);
|
|
const canEditCollection = useHasUserPermission(EDIT_COLLECTION);
|
|
const canAddPayment = useHasUserPermission(ADDPAYMENT_COLLECTION);
|
|
const methods = useForm({
|
|
defaultValues: {
|
|
fromDate: moment().subtract(180, "days").format("DD-MM-YYYY"),
|
|
toDate: moment().format("DD-MM-YYYY"),
|
|
},
|
|
});
|
|
const { watch } = methods;
|
|
const [fromDate, toDate] = watch(["fromDate", "toDate"]);
|
|
|
|
const handleToggleActive = (e) => setShowPending(e.target.checked);
|
|
|
|
const contextMassager = {
|
|
setProcessedPayment,
|
|
setCollection,
|
|
setAddPayment,
|
|
addPayment,
|
|
setViewCollection,
|
|
viewCollection,
|
|
setDocumentView,
|
|
};
|
|
const { mutate: MarkedReceived, isPending } = useMarkedPaymentReceived(() => {
|
|
setProcessedPayment(null);
|
|
});
|
|
const handleMarkedPayment = (payload) => {
|
|
MarkedReceived(payload);
|
|
};
|
|
if (
|
|
isAdmin === undefined ||
|
|
canAddPayment === undefined ||
|
|
canEditCollection === undefined ||
|
|
canViewCollection === undefined ||
|
|
canCreate === undefined
|
|
) {
|
|
return <div className="text-center py-5">Checking access...</div>;
|
|
}
|
|
|
|
if (
|
|
!isAdmin &&
|
|
!canAddPayment &&
|
|
!canEditCollection &&
|
|
!canViewCollection &&
|
|
!canCreate
|
|
) {
|
|
return (
|
|
<AccessDenied
|
|
data={[{ label: "Home", link: "/dashboard" }, { label: "Collection" }]}
|
|
/>
|
|
);
|
|
}
|
|
return (
|
|
<CollectionContext.Provider value={contextMassager}>
|
|
<div className="container-fluid">
|
|
<Breadcrumb
|
|
data={[
|
|
{ label: "Home", link: "/dashboard" },
|
|
{ label: "Collection" },
|
|
]}
|
|
/>
|
|
|
|
<div className="card my-3 py-2 px-sm-4 px-2">
|
|
<div className="row align-items-center mx-0">
|
|
{/* Left side: Date Picker + Show Pending (stacked on mobile) */}
|
|
<div className="col-12 col-md-6 d-flex flex-column flex-md-row flex-wrap align-items-start align-md-items-center gap-2 gap-md-3 mb-3 mb-md-0">
|
|
<FormProvider {...methods}>
|
|
<DateRangePicker1 howManyDay={180} startField="fromDate"
|
|
endField="toDate" />
|
|
</FormProvider>
|
|
|
|
<div className="form-check form-switch d-flex align-items-center mt-1">
|
|
<input
|
|
type="checkbox"
|
|
className="form-check-input"
|
|
role="switch"
|
|
id="inactiveEmployeesCheckbox"
|
|
checked={showPending}
|
|
onChange={(e) => setShowPending(e.target.checked)}
|
|
/>
|
|
<label
|
|
className="form-check-label ms-2"
|
|
htmlFor="inactiveEmployeesCheckbox"
|
|
>
|
|
Show Completed Collections
|
|
</label>
|
|
</div>
|
|
</div>
|
|
|
|
{/* Right side: Search + Add Button */}
|
|
<div className="col-12 col-sm-6 d-flex justify-content-end align-items-center gap-2">
|
|
<input
|
|
type="search"
|
|
value={searchText}
|
|
onChange={(e) => setSearchText(e.target.value)}
|
|
placeholder="Search Collection"
|
|
className="form-control form-control-sm w-auto"
|
|
/>
|
|
|
|
{(canCreate || isAdmin) && (
|
|
<button
|
|
className="btn btn-sm btn-primary"
|
|
type="button"
|
|
onClick={() =>
|
|
setCollection({ isOpen: true, invoiceId: null })
|
|
}
|
|
>
|
|
<i className="bx bx-plus-circle me-2"></i>
|
|
<span className="d-none d-md-inline-block">
|
|
Add New Collection
|
|
</span>
|
|
</button>
|
|
)}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<CollectionList
|
|
fromDate={fromDate}
|
|
toDate={toDate}
|
|
isPending={showPending}
|
|
searchString={searchText}
|
|
/>
|
|
|
|
{makeCollection.isOpen && (
|
|
<GlobalModel
|
|
isOpen={makeCollection.isOpen}
|
|
size="lg"
|
|
closeModal={() => setCollection({ isOpen: false, invoiceId: null })}
|
|
>
|
|
<ManageCollection
|
|
collectionId={makeCollection?.invoiceId ?? null}
|
|
onClose={() => setCollection({ isOpen: false, invoiceId: null })}
|
|
/>
|
|
</GlobalModel>
|
|
)}
|
|
|
|
{addPayment.isOpen && (
|
|
<GlobalModel
|
|
size="lg"
|
|
isOpen={addPayment.isOpen}
|
|
closeModal={() => setAddPayment({ isOpen: false, invoiceId: null })}
|
|
>
|
|
<AddPayment
|
|
onClose={() => setAddPayment({ isOpen: false, invoiceId: null })}
|
|
/>
|
|
</GlobalModel>
|
|
)}
|
|
|
|
{viewCollection && (
|
|
<GlobalModel
|
|
size="lg"
|
|
isOpen={viewCollection}
|
|
closeModal={() => setViewCollection(null)}
|
|
>
|
|
<ViewCollection onClose={() => setViewCollection(null)} />
|
|
</GlobalModel>
|
|
)}
|
|
|
|
{ViewDocument.IsOpen && (
|
|
<GlobalModel
|
|
isOpen
|
|
size="md"
|
|
key={ViewDocument.Image ?? "doc"}
|
|
closeModal={() => setDocumentView({ IsOpen: false, Image: null })}
|
|
>
|
|
<PreviewDocument imageUrl={ViewDocument.Image} />
|
|
</GlobalModel>
|
|
)}
|
|
|
|
<ConfirmModal
|
|
type="success"
|
|
header="Payment Successful Received"
|
|
message="Payment has been recored successfully."
|
|
isOpen={processedPayment?.isOpen}
|
|
loading={isPending}
|
|
onSubmit={() => handleMarkedPayment(processedPayment?.invoiceId)}
|
|
onClose={() => setProcessedPayment(null)}
|
|
/>
|
|
</div>
|
|
</CollectionContext.Provider>
|
|
);
|
|
};
|
|
|
|
export default CollectionPage;
|