Merge branch 'upgrade_Expense' of https://git.marcoaiot.com/admin/marco.pms.web into upgrade_Expense
This commit is contained in:
commit
1278e32da9
@ -14,8 +14,7 @@ const formSchema = z.object({
|
||||
selectedRole: z.record(z.boolean()),
|
||||
});
|
||||
|
||||
const ManageRole = ( {employeeId, onClosed} ) =>
|
||||
{
|
||||
const ManageRole = ({ employeeId, onClosed }) => {
|
||||
const dispatch = useDispatch();
|
||||
const formStateRef = useRef({});
|
||||
|
||||
@ -38,7 +37,7 @@ const ManageRole = ( {employeeId, onClosed} ) =>
|
||||
});
|
||||
const {
|
||||
updateRoles,
|
||||
isPending : isLoading,
|
||||
isPending: isLoading,
|
||||
isError,
|
||||
error,
|
||||
} = useUpdateEmployeeRoles({
|
||||
@ -112,56 +111,57 @@ const ManageRole = ( {employeeId, onClosed} ) =>
|
||||
const isLoadingData = roleLoading || empLoading;
|
||||
|
||||
return (
|
||||
<form onSubmit={handleSubmit(onSubmit)}>
|
||||
<div className="text-start mb-3">
|
||||
<h5 className="lead">Select Roles :</h5>
|
||||
</div>
|
||||
<form onSubmit={handleSubmit(onSubmit)}>
|
||||
<div className="text-center mb-3">
|
||||
<h5 className="lead">Select Roles :</h5>
|
||||
</div>
|
||||
|
||||
{isLoadingData ? (
|
||||
<p>Loading...</p>
|
||||
) : (
|
||||
<div
|
||||
className="d-flex flex-wrap justify-content-between pb-4"
|
||||
style={{ maxHeight: "70vh", overflowY: "auto" }}
|
||||
>
|
||||
{roles.map((role) => (
|
||||
<div className="col-md-6 col-lg-4 mb-3" key={role.id}>
|
||||
<div className="form-check ms-2 text-start">
|
||||
<input
|
||||
className="form-check-input"
|
||||
type="checkbox"
|
||||
id={role.id}
|
||||
{...register(`selectedRole.${role.id}`)}
|
||||
/>
|
||||
<label className="form-check-label" htmlFor={role.id}>
|
||||
<small>{role.role || "--"}</small>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
{isLoadingData ? (
|
||||
<p>Loading...</p>
|
||||
) : (
|
||||
<div
|
||||
className="d-flex flex-wrap justify-content-between pb-4"
|
||||
style={{ maxHeight: "70vh", overflowY: "auto" }}
|
||||
>
|
||||
{roles.slice()
|
||||
.sort((a, b) => a.role.localeCompare(b.role)).map((role) => (
|
||||
<div className="col-md-6 col-lg-4 mb-3" key={role.id}>
|
||||
<div className="form-check ms-2 text-start">
|
||||
<input
|
||||
className="form-check-input"
|
||||
type="checkbox"
|
||||
id={role.id}
|
||||
{...register(`selectedRole.${role.id}`)}
|
||||
/>
|
||||
<label className="form-check-label" htmlFor={role.id}>
|
||||
<small>{role.role || "--"}</small>
|
||||
</label>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{errors.selectedRole && (
|
||||
<div className="text-danger text-center">
|
||||
{errors.selectedRole.message}
|
||||
</div>
|
||||
)}
|
||||
|
||||
<div className="text-end mt-1">
|
||||
<button
|
||||
type="button"
|
||||
className="btn btn-sm btn-label-secondary me-2"
|
||||
data-bs-dismiss="modal"
|
||||
aria-label="Close"
|
||||
>
|
||||
Cancel
|
||||
</button>
|
||||
<button type="submit" className="btn btn-sm btn-primary" disabled={isLoading}>
|
||||
{isLoading ? "Please Wait..." : "Submit"}
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
|
||||
{errors.selectedRole && (
|
||||
<div className="text-danger text-center">
|
||||
{errors.selectedRole.message}
|
||||
</div>
|
||||
)}
|
||||
|
||||
<div className="text-end mt-1">
|
||||
<button
|
||||
type="button"
|
||||
className="btn btn-sm btn-label-secondary me-2"
|
||||
data-bs-dismiss="modal"
|
||||
aria-label="Close"
|
||||
>
|
||||
Cancel
|
||||
</button>
|
||||
<button type="submit" className="btn btn-sm btn-primary" disabled={isLoading}>
|
||||
{isLoading ? "Please Wait..." : "Submit"}
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
@ -386,7 +386,7 @@ const ViewExpense = ({ ExpenseId }) => {
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
<hr className="divider my-1 border-2 divider-primary my-2" />
|
||||
{/* <hr className="divider my-1 border-2 divider-primary my-2" /> */}
|
||||
|
||||
{Array.isArray(data?.nextStatus) && data.nextStatus.length > 0 && (
|
||||
<>
|
||||
@ -526,7 +526,7 @@ const ViewExpense = ({ ExpenseId }) => {
|
||||
</div>
|
||||
|
||||
<div className="col-12 col-lg-5 col-xl-4">
|
||||
<div className="d-flex align-items-center text-secondary mb-">
|
||||
<div className="d-flex align-items-center text-secondary mb-4">
|
||||
<i className="bx bx-time-five me-2"></i>{" "}
|
||||
<p className=" m-0">TimeLine</p>
|
||||
</div>
|
||||
|
||||
@ -253,7 +253,7 @@ const PaymentRequestList = ({ filters, groupBy = "submittedBy", search }) => {
|
||||
<td colSpan={8} className="text-start">
|
||||
<div className="d-flex align-items-center">
|
||||
{" "}
|
||||
<small className="fs-6 py-1">
|
||||
<small className="fs-6 py-1 ms-1">
|
||||
{displayField} :{" "}
|
||||
</small>{" "}
|
||||
<small className="fs-6 ms-3">
|
||||
|
||||
@ -411,7 +411,7 @@ const ViewPaymentRequest = ({ requestId }) => {
|
||||
</div>
|
||||
<div className="col-12 col-md-6 text-start mb-1">
|
||||
<label className="form-label">Transaction Date </label>
|
||||
<DatePicker
|
||||
<DatePicker className="w-100"
|
||||
name="paidAt"
|
||||
control={control}
|
||||
minDate={data?.createdAt}
|
||||
|
||||
@ -4,6 +4,7 @@ import {
|
||||
EXPENSE_REJECTEDBY,
|
||||
FREQUENCY_FOR_RECURRING,
|
||||
ITEMS_PER_PAGE,
|
||||
PAYEE_RECURRING_EXPENSE,
|
||||
} from "../../utils/constants";
|
||||
import { formatCurrency, useDebounce } from "../../utils/appUtils";
|
||||
import { formatUTCToLocalTime } from "../../utils/dateUtils";
|
||||
@ -16,7 +17,7 @@ import { useRecurringExpenseContext } from "../../pages/RecurringExpense/Recurri
|
||||
import { useRecurringExpenseList } from "../../hooks/useExpense";
|
||||
|
||||
const RecurringExpenseList = ({ search, filterStatuses }) => {
|
||||
const { setManageRequest, setVieRequest , setViewRecurring} = useRecurringExpenseContext();
|
||||
const { setManageRequest, setVieRequest, setViewRecurring } = useRecurringExpenseContext();
|
||||
const navigate = useNavigate();
|
||||
const [IsDeleteModalOpen, setIsDeleteModalOpen,] = useState(false);
|
||||
const [deletingId, setDeletingId] = useState(null);
|
||||
@ -25,6 +26,13 @@ const RecurringExpenseList = ({ search, filterStatuses }) => {
|
||||
(store) => store?.globalVariables?.loginUser?.employeeInfo?.id
|
||||
);
|
||||
|
||||
const statusColorMap = {
|
||||
"da462422-13b2-45cc-a175-910a225f6fc8": "primary", // Active
|
||||
"306856fb-5655-42eb-bf8b-808bb5e84725": "success", // Completed
|
||||
"3ec864d2-8bf5-42fb-ba70-5090301dd816": "danger", // De-Activated
|
||||
"8bfc9346-e092-4a80-acbf-515ae1ef6868": "warning", // Paused
|
||||
};
|
||||
|
||||
const recurringExpenseColumns = [
|
||||
{
|
||||
key: "expenseCategory",
|
||||
@ -72,8 +80,18 @@ const RecurringExpenseList = ({ search, filterStatuses }) => {
|
||||
{
|
||||
key: "status",
|
||||
label: "Status",
|
||||
align: "text-start",
|
||||
getValue: (e) => e?.status?.name || "N/A",
|
||||
align: "text-center",
|
||||
getValue: (e) => {
|
||||
const color = statusColorMap[e?.status?.id] || "secondary";
|
||||
const label = PAYEE_RECURRING_EXPENSE.find(
|
||||
(s) => s.id === e?.status?.id
|
||||
)?.label;
|
||||
return (
|
||||
<span className={`badge bg-label-${color}`}>
|
||||
{label || e?.status?.name || "N/A"}
|
||||
</span>
|
||||
);
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
@ -192,10 +210,10 @@ const RecurringExpenseList = ({ search, filterStatuses }) => {
|
||||
<i
|
||||
className="bx bx-show text-primary cursor-pointer"
|
||||
onClick={() =>
|
||||
setViewRecurring({
|
||||
recurringId: recurringExpense?.id,
|
||||
view: true,
|
||||
})
|
||||
setViewRecurring({
|
||||
recurringId: recurringExpense?.id,
|
||||
view: true,
|
||||
})
|
||||
}
|
||||
></i>
|
||||
|
||||
@ -261,9 +279,8 @@ const RecurringExpenseList = ({ search, filterStatuses }) => {
|
||||
{[...Array(totalPages)].map((_, index) => (
|
||||
<li
|
||||
key={index}
|
||||
className={`page-item ${
|
||||
currentPage === index + 1 ? "active" : ""
|
||||
}`}
|
||||
className={`page-item ${currentPage === index + 1 ? "active" : ""
|
||||
}`}
|
||||
>
|
||||
<button
|
||||
className="page-link"
|
||||
|
||||
@ -48,19 +48,6 @@ const CollectionList = ({ fromDate, toDate, isPending, searchString }) => {
|
||||
};
|
||||
|
||||
const collectionColumns = [
|
||||
{
|
||||
key: "invoiceDate",
|
||||
label: "Invoice Date",
|
||||
getValue: (col) => (
|
||||
<span
|
||||
className="text-truncate d-inline-block"
|
||||
style={{ maxWidth: "200px" }}
|
||||
>
|
||||
{formatUTCToLocalTime(col.invoiceDate)}
|
||||
</span>
|
||||
),
|
||||
align: "text-start",
|
||||
},
|
||||
{
|
||||
key: "invoiceId",
|
||||
label: "Invoice No",
|
||||
@ -88,18 +75,33 @@ const CollectionList = ({ fromDate, toDate, isPending, searchString }) => {
|
||||
align: "text-start",
|
||||
},
|
||||
{
|
||||
key: "submittedDate",
|
||||
label: "Submission Date",
|
||||
key: "invoiceDate",
|
||||
label: "Invoice Date",
|
||||
getValue: (col) => (
|
||||
<span
|
||||
className="text-truncate d-inline-block"
|
||||
style={{ maxWidth: "200px" }}
|
||||
>
|
||||
{formatUTCToLocalTime(col.createdAt)}
|
||||
{formatUTCToLocalTime(col.invoiceDate)}
|
||||
</span>
|
||||
),
|
||||
align: "text-center",
|
||||
align: "text-start",
|
||||
},
|
||||
|
||||
|
||||
// {
|
||||
// key: "submittedDate",
|
||||
// label: "Submission Date",
|
||||
// getValue: (col) => (
|
||||
// <span
|
||||
// className="text-truncate d-inline-block"
|
||||
// style={{ maxWidth: "200px" }}
|
||||
// >
|
||||
// {formatUTCToLocalTime(col.createdAt)}
|
||||
// </span>
|
||||
// ),
|
||||
// align: "text-center",
|
||||
// },
|
||||
{
|
||||
key: "expectedSubmittedDate",
|
||||
label: "Expected Payment Date",
|
||||
@ -145,6 +147,19 @@ const CollectionList = ({ fromDate, toDate, isPending, searchString }) => {
|
||||
),
|
||||
align: "text-end",
|
||||
},
|
||||
{
|
||||
key: "status",
|
||||
label: "Status",
|
||||
getValue: (col) => (
|
||||
<span
|
||||
className={`badge ${col.markAsCompleted ? "bg-label-primary" : "bg-label-danger"
|
||||
}`}
|
||||
>
|
||||
{col.markAsCompleted ? "Active" : "In-active"}
|
||||
</span>
|
||||
),
|
||||
align: "text-center",
|
||||
},
|
||||
];
|
||||
|
||||
if (isLoading) return <CollectionTableSkeleton />;
|
||||
@ -186,84 +201,84 @@ const CollectionList = ({ fromDate, toDate, isPending, searchString }) => {
|
||||
canViewCollection ||
|
||||
canEditCollection ||
|
||||
canCreate) && (
|
||||
<td
|
||||
className="sticky-action-column text-center"
|
||||
style={{ padding: "12px 8px" }}
|
||||
>
|
||||
<div className="dropdown z-2">
|
||||
<button
|
||||
type="button"
|
||||
className="btn btn-icon btn-text-secondary rounded-pill dropdown-toggle hide-arrow p-0"
|
||||
data-bs-toggle="dropdown"
|
||||
aria-expanded="false"
|
||||
>
|
||||
<i
|
||||
className="bx bx-dots-vertical-rounded bx-sm text-muted"
|
||||
data-bs-toggle="tooltip"
|
||||
data-bs-offset="0,8"
|
||||
data-bs-placement="top"
|
||||
data-bs-custom-class="tooltip-dark"
|
||||
title="More Action"
|
||||
></i>
|
||||
</button>
|
||||
<td
|
||||
className="sticky-action-column text-center"
|
||||
style={{ padding: "12px 8px" }}
|
||||
>
|
||||
<div className="dropdown z-2">
|
||||
<button
|
||||
type="button"
|
||||
className="btn btn-icon btn-text-secondary rounded-pill dropdown-toggle hide-arrow p-0"
|
||||
data-bs-toggle="dropdown"
|
||||
aria-expanded="false"
|
||||
>
|
||||
<i
|
||||
className="bx bx-dots-vertical-rounded bx-sm text-muted"
|
||||
data-bs-toggle="tooltip"
|
||||
data-bs-offset="0,8"
|
||||
data-bs-placement="top"
|
||||
data-bs-custom-class="tooltip-dark"
|
||||
title="More Action"
|
||||
></i>
|
||||
</button>
|
||||
|
||||
<ul className="dropdown-menu dropdown-menu-end">
|
||||
{/* View */}
|
||||
<ul className="dropdown-menu dropdown-menu-end">
|
||||
{/* View */}
|
||||
|
||||
<li>
|
||||
<a
|
||||
className="dropdown-item cursor-pointer"
|
||||
onClick={() => setViewCollection(row.id)}
|
||||
>
|
||||
<i className="bx bx-show me-2 text-primary"></i>
|
||||
<span>View</span>
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a
|
||||
className="dropdown-item cursor-pointer"
|
||||
onClick={() => setViewCollection(row.id)}
|
||||
>
|
||||
<i className="bx bx-show me-2 text-primary"></i>
|
||||
<span>View</span>
|
||||
</a>
|
||||
</li>
|
||||
|
||||
{/* Only if not completed */}
|
||||
{!row?.markAsCompleted && (
|
||||
<>
|
||||
{/* Add Payment */}
|
||||
{(isAdmin || canAddPayment) && (
|
||||
<li>
|
||||
<a
|
||||
className="dropdown-item cursor-pointer"
|
||||
onClick={() =>
|
||||
setAddPayment({
|
||||
isOpen: true,
|
||||
invoiceId: row.id,
|
||||
})
|
||||
}
|
||||
>
|
||||
<i className="bx bx-wallet me-2 text-warning"></i>
|
||||
<span>Add Payment</span>
|
||||
</a>
|
||||
</li>
|
||||
)}
|
||||
{/* Only if not completed */}
|
||||
{!row?.markAsCompleted && (
|
||||
<>
|
||||
{/* Add Payment */}
|
||||
{(isAdmin || canAddPayment) && (
|
||||
<li>
|
||||
<a
|
||||
className="dropdown-item cursor-pointer"
|
||||
onClick={() =>
|
||||
setAddPayment({
|
||||
isOpen: true,
|
||||
invoiceId: row.id,
|
||||
})
|
||||
}
|
||||
>
|
||||
<i className="bx bx-wallet me-2 text-warning"></i>
|
||||
<span>Add Payment</span>
|
||||
</a>
|
||||
</li>
|
||||
)}
|
||||
|
||||
{/* Mark Payment */}
|
||||
{isAdmin && (
|
||||
<li>
|
||||
<a
|
||||
className="dropdown-item cursor-pointer"
|
||||
onClick={() =>
|
||||
setProcessedPayment({
|
||||
isOpen: true,
|
||||
invoiceId: row.id,
|
||||
})
|
||||
}
|
||||
>
|
||||
<i className="bx bx-check-circle me-2 text-success"></i>
|
||||
<span>Mark Payment</span>
|
||||
</a>
|
||||
</li>
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
</ul>
|
||||
</div>
|
||||
</td>
|
||||
)}
|
||||
{/* Mark Payment */}
|
||||
{isAdmin && (
|
||||
<li>
|
||||
<a
|
||||
className="dropdown-item cursor-pointer"
|
||||
onClick={() =>
|
||||
setProcessedPayment({
|
||||
isOpen: true,
|
||||
invoiceId: row.id,
|
||||
})
|
||||
}
|
||||
>
|
||||
<i className="bx bx-check-circle me-2 text-success"></i>
|
||||
<span>Mark Payment</span>
|
||||
</a>
|
||||
</li>
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
</ul>
|
||||
</div>
|
||||
</td>
|
||||
)}
|
||||
</tr>
|
||||
))
|
||||
) : (
|
||||
|
||||
@ -227,7 +227,7 @@ const ManageCollection = ({ collectionId, onClose }) => {
|
||||
</div>
|
||||
<div className="col-12 col-md-6 mb-2">
|
||||
<Label required>Invoice Date</Label>
|
||||
<DatePicker
|
||||
<DatePicker className="w-100"
|
||||
name="invoiceDate"
|
||||
control={control}
|
||||
maxDate={new Date()}
|
||||
@ -240,7 +240,7 @@ const ManageCollection = ({ collectionId, onClose }) => {
|
||||
</div>
|
||||
<div className="col-12 col-md-6 mb-2">
|
||||
<Label required>Expected Payment Date</Label>
|
||||
<DatePicker
|
||||
<DatePicker className="w-100"
|
||||
name="exceptedPaymentDate"
|
||||
control={control}
|
||||
minDate={watch("invoiceDate")}
|
||||
@ -253,7 +253,7 @@ const ManageCollection = ({ collectionId, onClose }) => {
|
||||
</div>
|
||||
<div className="col-12 col-md-6 mb-2">
|
||||
<Label required>Submission Date (Client)</Label>
|
||||
<DatePicker
|
||||
<DatePicker className="w-100"
|
||||
name="clientSubmitedDate"
|
||||
control={control}
|
||||
maxDate={new Date()}
|
||||
|
||||
@ -29,47 +29,76 @@ const ViewCollection = ({ onClose }) => {
|
||||
return (
|
||||
<div className="container p-3">
|
||||
<p className="fs-5 fw-semibold">Collection Details</p>
|
||||
<div className="row text-start ">
|
||||
|
||||
<div className="row text-start">
|
||||
|
||||
{/* Row 0: Balance Amount + Expected Payment Date */}
|
||||
<div className="row mb-3 px-2">
|
||||
{/* Balance Amount */}
|
||||
<div className="col-md-6 d-flex align-items-center">
|
||||
<div className="fw-bold fs-6 text-dark me-2 ms-1">Balance Amount :</div>
|
||||
<div className="fw-bold fs-6 text-dark">
|
||||
{formatFigure(data?.balanceAmount, {
|
||||
type: "currency",
|
||||
currency: "INR",
|
||||
})}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Expected Payment Date */}
|
||||
<div className="col-md-6 d-flex align-items-center">
|
||||
<div className="fw-bold fs-6 text-dark me-2 ms-3">Expected Payment Date :</div>
|
||||
<div className="fw-bold fs-6 text-dark">
|
||||
{formatUTCToLocalTime(data?.exceptedPaymentDate)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
{/* Project and Status */}
|
||||
<div className="col-12 mb-3 d-flex justify-content-between">
|
||||
<div className="d-flex">
|
||||
<label
|
||||
className=" me-2 mb-0 fw-semibold"
|
||||
style={{ minWidth: "130px" }}
|
||||
className="me-2 mb-0 fw-semibold"
|
||||
style={{ minWidth: "120px" }}
|
||||
>
|
||||
Project :
|
||||
</label>
|
||||
<div className="text-muted">{data?.project?.name}</div>
|
||||
</div>
|
||||
<div>
|
||||
{" "}
|
||||
<span
|
||||
className={`badge bg-label-${
|
||||
data?.isActive ? "primary" : "danger"
|
||||
}`}
|
||||
className={`badge bg-label-${data?.markAsCompleted ? "primary" : "danger"}`}
|
||||
>
|
||||
{data?.isActive ? "Active" : "Inactive"}
|
||||
{data?.markAsCompleted ? "Active" : "Inactive"}
|
||||
</span>
|
||||
{(isAdmin || canEditCollection) &&
|
||||
!data?.receivedInvoicePayments && (
|
||||
!data?.receivedInvoicePayments &&
|
||||
!data?.markAsCompleted && (
|
||||
<span onClick={handleEdit} className="ms-2 cursor-pointer">
|
||||
<i className="bx bx-edit text-primary bx-sm"></i>
|
||||
</span>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Title */}
|
||||
<div className="col-md-6">
|
||||
<div className="row mb-2 text-wrap">
|
||||
<div className="row mb-2 text-wrap">
|
||||
<div className="col-4 fw-semibold">Title :</div>
|
||||
<div className="col-8 text-wrap">{data?.title}</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Invoice Number */}
|
||||
<div className="col-md-6">
|
||||
<div className="row mb-4 align-items-end">
|
||||
<div className="col-4 fw-semibold">Invoice Number:</div>
|
||||
<div className="col-8">{data?.invoiceNumber}</div>
|
||||
</div>
|
||||
</div>
|
||||
{/* Row 2: E-Invoice Number + Project */}
|
||||
|
||||
{/* E-Invoice Number */}
|
||||
<div className="col-md-6">
|
||||
<div className="row mb-4 align-items-end">
|
||||
<div className="col-4 fw-semibold">E-Invoice Number:</div>
|
||||
@ -77,15 +106,15 @@ const ViewCollection = ({ onClose }) => {
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Row 3: Invoice Date + Client Submitted Date */}
|
||||
{/* Invoice Date */}
|
||||
<div className="col-md-6">
|
||||
<div className="row mb-4 align-items-end">
|
||||
<div className="col-4 fw-semibold">Invoice Date:</div>
|
||||
<div className="col-8">
|
||||
{formatUTCToLocalTime(data?.invoiceDate)}
|
||||
</div>
|
||||
<div className="col-8">{formatUTCToLocalTime(data?.invoiceDate)}</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Client Submitted Date */}
|
||||
<div className="col-md-6">
|
||||
<div className="row mb-4 align-items-end">
|
||||
<div className="col-4 fw-semibold">Client Submission Date:</div>
|
||||
@ -94,17 +123,8 @@ const ViewCollection = ({ onClose }) => {
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{/* Row 4: Expected Payment Date + Mark as Completed */}
|
||||
<div className="col-md-6">
|
||||
<div className="row mb-4 align-items-end">
|
||||
<div className="col-4 fw-semibold">Expected Payment Date:</div>
|
||||
<div className="col-8">
|
||||
{formatUTCToLocalTime(data?.exceptedPaymentDate)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Row 5: Basic Amount + Tax Amount */}
|
||||
{/* Basic Amount */}
|
||||
<div className="col-md-6">
|
||||
<div className="row mb-4 align-items-end">
|
||||
<div className="col-4 fw-semibold">Basic Amount :</div>
|
||||
@ -116,6 +136,8 @@ const ViewCollection = ({ onClose }) => {
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Tax Amount */}
|
||||
<div className="col-md-6">
|
||||
<div className="row mb-4 align-items-end">
|
||||
<div className="col-4 fw-semibold">Tax Amount :</div>
|
||||
@ -127,25 +149,16 @@ const ViewCollection = ({ onClose }) => {
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{/* Row 6: Balance Amount + Created At */}
|
||||
<div className="col-md-6">
|
||||
<div className="row mb-4 align-items-end">
|
||||
<div className="col-4 fw-semibold">Balance Amount :</div>
|
||||
<div className="col-8">
|
||||
{formatFigure(data?.balanceAmount, {
|
||||
type: "currency",
|
||||
currency: "INR",
|
||||
})}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Created At */}
|
||||
<div className="col-md-6">
|
||||
<div className="row mb-4 align-items-end">
|
||||
<div className="col-4 fw-semibold">Created At :</div>
|
||||
<div className="col-8">{formatUTCToLocalTime(data?.createdAt)}</div>
|
||||
</div>
|
||||
</div>
|
||||
{/* Row 7: Created By */}
|
||||
|
||||
{/* Created By */}
|
||||
<div className="col-md-6">
|
||||
<div className="row mb-4 align-items-center">
|
||||
<div className="col-4 fw-semibold">Created By :</div>
|
||||
@ -161,23 +174,23 @@ const ViewCollection = ({ onClose }) => {
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Description */}
|
||||
<div className="col-12 my-1 mb-2">
|
||||
<div className=" me-2 mb-0 fw-semibold">Description :</div>
|
||||
<div className="me-2 mb-0 fw-semibold">Description :</div>
|
||||
<div className="text-muted">{data?.description}</div>
|
||||
</div>
|
||||
|
||||
{/* Attachments */}
|
||||
<div className="col-12 text-start">
|
||||
<label className=" me-2 mb-2 fw-semibold">Attachment :</label>
|
||||
|
||||
<label className="me-2 mb-2 fw-semibold">Attachment :</label>
|
||||
<div className="d-flex flex-wrap gap-2">
|
||||
{data?.attachments?.map((doc) => {
|
||||
const isImage = doc.contentType?.includes("image");
|
||||
|
||||
return (
|
||||
<div
|
||||
key={doc.documentId}
|
||||
className="border rounded hover-scale p-2 d-flex flex-column align-items-center"
|
||||
className="border rounded hover-scale p-2 d-flex flex-column align-items-center"
|
||||
style={{
|
||||
width: "80px",
|
||||
cursor: isImage ? "pointer" : "default",
|
||||
@ -207,14 +220,12 @@ const ViewCollection = ({ onClose }) => {
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="container px-1">
|
||||
{/* Tabs Navigation */}
|
||||
{/* Tabs Section */}
|
||||
<div className="container px-1 mt-4">
|
||||
<ul className="nav nav-tabs" role="tablist">
|
||||
<li className="nav-item">
|
||||
<button
|
||||
className={`nav-link ${
|
||||
activeTab === "payments" ? "active" : ""
|
||||
}`}
|
||||
className={`nav-link ${activeTab === "payments" ? "active" : ""}`}
|
||||
onClick={() => setActiveTab("payments")}
|
||||
type="button"
|
||||
>
|
||||
@ -223,9 +234,7 @@ const ViewCollection = ({ onClose }) => {
|
||||
</li>
|
||||
<li className="nav-item">
|
||||
<button
|
||||
className={`nav-link ${
|
||||
activeTab === "details" ? "active" : ""
|
||||
}`}
|
||||
className={`nav-link ${activeTab === "details" ? "active" : ""}`}
|
||||
onClick={() => setActiveTab("details")}
|
||||
type="button"
|
||||
>
|
||||
@ -235,7 +244,6 @@ const ViewCollection = ({ onClose }) => {
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
{/* Tab Content */}
|
||||
<div className="tab-content px-1 py-0 border-top-0">
|
||||
{activeTab === "payments" && (
|
||||
<div className="tab-pane fade show active">
|
||||
@ -252,6 +260,7 @@ const ViewCollection = ({ onClose }) => {
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
@ -178,7 +178,7 @@ export const DateRangePicker1 = ({
|
||||
<div className={`position-relative ${className} w-max `}>
|
||||
<input
|
||||
type="text"
|
||||
className="form-control form-control-sm ps-2 pe-3 me-2 cursor-pointer fw-medium"
|
||||
className="form-control form-control-sm ps-2 pe-3 me-4 cursor-pointer"
|
||||
placeholder={placeholder}
|
||||
defaultValue={formattedValue}
|
||||
ref={(el) => {
|
||||
|
||||
@ -84,6 +84,7 @@ export const useMarkedPaymentReceived = (onSuccessCallBack) => {
|
||||
await CollectionRepository.markPaymentReceived(payload),
|
||||
onSuccess: async () => {
|
||||
client.invalidateQueries({ queryKey: ["collections"] });
|
||||
client.invalidateQueries({ queryKey: ["collection"] });
|
||||
showToast("Payment Received marked Successfully", "success");
|
||||
if (onSuccessCallBack) onSuccessCallBack();
|
||||
},
|
||||
|
||||
@ -73,13 +73,13 @@ const PaymentRequestPage = () => {
|
||||
|
||||
{/* Top Bar */}
|
||||
<div className="card my-3 px-sm-4 px-0">
|
||||
<div className="card-body py-2 px-3">
|
||||
<div className="card-body py-2 px-0">
|
||||
<div className="row align-items-center">
|
||||
<div className="col-6">
|
||||
<input
|
||||
type="search"
|
||||
className="form-control form-control-sm w-auto"
|
||||
placeholder="Search Payment Req.."
|
||||
placeholder="Search Payment Request"
|
||||
value={search}
|
||||
onChange={(e) => setSearch(e.target.value)}
|
||||
/>
|
||||
|
||||
@ -47,7 +47,7 @@ const RecurringExpensePage = () => {
|
||||
<div className="container-fluid">
|
||||
{/* Breadcrumb */}
|
||||
<Breadcrumb
|
||||
data={[
|
||||
data={[
|
||||
{ label: "Home", link: "/dashboard" },
|
||||
{ label: "Recurring Expense", link: null },
|
||||
]}
|
||||
@ -56,46 +56,48 @@ const RecurringExpensePage = () => {
|
||||
{/* Top Bar */}
|
||||
<div className="card my-3 px-sm-4 px-0">
|
||||
<div className="card-body py-2 px-1">
|
||||
<div className="d-flex flex-wrap align-items-center justify-content-between">
|
||||
{/* Left side: Search + Filter */}
|
||||
<div className="d-flex align-items-center flex-wrap">
|
||||
<input
|
||||
type="search"
|
||||
className="form-control form-control-sm w-auto"
|
||||
placeholder="Search Recurring Expense..."
|
||||
value={search}
|
||||
onChange={(e) => setSearch(e.target.value)}
|
||||
/>
|
||||
<div className="row align-items-center mb-0">
|
||||
{/* Left Column: Search + Filter */}
|
||||
<div className="col-md-8 col-sm-12 mb-2 mb-md-0">
|
||||
<div className="d-flex align-items-center flex-wrap gap-0">
|
||||
<input
|
||||
type="search"
|
||||
className="form-control form-control-sm w-25"
|
||||
placeholder="Search Recurring Expense"
|
||||
value={search}
|
||||
onChange={(e) => setSearch(e.target.value)}
|
||||
/>
|
||||
|
||||
<div className="dropdown">
|
||||
<a
|
||||
className="dropdown-toggle hide-arrow cursor-pointer p-1"
|
||||
data-bs-toggle="dropdown"
|
||||
aria-expanded="false"
|
||||
title="Filter"
|
||||
>
|
||||
<i className="bx bx-slider-alt ms-1"></i>
|
||||
</a>
|
||||
<ul className="dropdown-menu p-2 text-capitalize">
|
||||
{PAYEE_RECURRING_EXPENSE.map(({ id, label }) => (
|
||||
<li key={id}>
|
||||
<div className="form-check">
|
||||
<input
|
||||
className="form-check-input"
|
||||
type="checkbox"
|
||||
checked={selectedStatuses.includes(id)}
|
||||
onChange={() => handleStatusChange(id)}
|
||||
/>
|
||||
<label className="form-check-label">{label}</label>
|
||||
</div>
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
<div className="dropdown">
|
||||
<a
|
||||
className="dropdown-toggle hide-arrow cursor-pointer p-1"
|
||||
data-bs-toggle="dropdown"
|
||||
aria-expanded="false"
|
||||
title="Filter"
|
||||
>
|
||||
<i className="bx bx-slider-alt ms-1"></i>
|
||||
</a>
|
||||
<ul className="dropdown-menu p-2 text-capitalize">
|
||||
{PAYEE_RECURRING_EXPENSE.map(({ id, label }) => (
|
||||
<li key={id}>
|
||||
<div className="form-check">
|
||||
<input
|
||||
className="form-check-input"
|
||||
type="checkbox"
|
||||
checked={selectedStatuses.includes(id)}
|
||||
onChange={() => handleStatusChange(id)}
|
||||
/>
|
||||
<label className="form-check-label">{label}</label>
|
||||
</div>
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Right side: Add Button */}
|
||||
<div className="mt-2 mt-sm-0">
|
||||
{/* Right Column: Add Button */}
|
||||
<div className="col-md-4 col-sm-12 text-md-end text-start">
|
||||
<button
|
||||
className="btn btn-sm btn-primary"
|
||||
type="button"
|
||||
@ -113,6 +115,7 @@ const RecurringExpensePage = () => {
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@ -135,7 +138,7 @@ const RecurringExpensePage = () => {
|
||||
/>
|
||||
</GlobalModel>
|
||||
)}
|
||||
{viewRecurring.view && (
|
||||
{viewRecurring.view && (
|
||||
<GlobalModel
|
||||
isOpen
|
||||
size="lg"
|
||||
@ -150,7 +153,7 @@ const RecurringExpensePage = () => {
|
||||
}
|
||||
recurringId={viewRecurring.recurringId}
|
||||
/>
|
||||
<ViewRecurringExpense/>
|
||||
<ViewRecurringExpense />
|
||||
</GlobalModel>
|
||||
)}
|
||||
|
||||
|
||||
@ -82,18 +82,18 @@ const CollectionPage = () => {
|
||||
const handleMarkedPayment = (payload) => {
|
||||
MarkedReceived(payload);
|
||||
};
|
||||
if (isAdmin === undefined ||
|
||||
canAddPayment === undefined ||
|
||||
canEditCollection === undefined ||
|
||||
canViewCollection === undefined ||
|
||||
if (isAdmin === undefined ||
|
||||
canAddPayment === undefined ||
|
||||
canEditCollection === undefined ||
|
||||
canViewCollection === undefined ||
|
||||
canCreate === undefined
|
||||
) {
|
||||
return <div className="text-center py-5">Checking access...</div>;
|
||||
}
|
||||
) {
|
||||
return <div className="text-center py-5">Checking access...</div>;
|
||||
}
|
||||
|
||||
if (!isAdmin && !canAddPayment && !canEditCollection && !canViewCollection && !canCreate) {
|
||||
return <AccessDenied data={[{ label: "Home", link: "/" }, { label: "Collection" }]} />;
|
||||
}
|
||||
if (!isAdmin && !canAddPayment && !canEditCollection && !canViewCollection && !canCreate) {
|
||||
return <AccessDenied data={[{ label: "Home", link: "/" }, { label: "Collection" }]} />;
|
||||
}
|
||||
return (
|
||||
<CollectionContext.Provider value={contextMassager}>
|
||||
<div className="container-fluid">
|
||||
@ -101,15 +101,15 @@ if (!isAdmin && !canAddPayment && !canEditCollection && !canViewCollection && !c
|
||||
data={[{ label: "Home", link: "/" }, { label: "Collection" }]}
|
||||
/>
|
||||
|
||||
<div className="card my-3 py-2 px-sm-4 px-0">
|
||||
<div className="row px-3">
|
||||
<div className="col-12 col-md-3 mb-1">
|
||||
<div className="card my-3 py-2 px-sm-4 px-2">
|
||||
<div className="row align-items-center">
|
||||
{/* Left side: Date Picker + Show Pending */}
|
||||
<div className="col-8 col-md-6 d-flex flex-wrap align-items-center gap-3">
|
||||
<FormProvider {...methods}>
|
||||
<DateRangePicker1 howManyDay={180} />
|
||||
</FormProvider>
|
||||
</div>
|
||||
<div className="col-12 col-md-3 d-flex align-items-center gap-2 ">
|
||||
<div className="form-check form-switch text-start align-items-center">
|
||||
|
||||
<div className="form-check form-switch d-flex align-items-center mb-0">
|
||||
<input
|
||||
type="checkbox"
|
||||
className="form-check-input"
|
||||
@ -119,40 +119,32 @@ if (!isAdmin && !canAddPayment && !canEditCollection && !canViewCollection && !c
|
||||
onChange={(e) => setShowPending(e.target.checked)}
|
||||
/>
|
||||
<label
|
||||
className="form-check-label ms-0"
|
||||
className="form-check-label ms-2"
|
||||
htmlFor="inactiveEmployeesCheckbox"
|
||||
>
|
||||
Show Pending
|
||||
Show Completed Collections
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="col-12 col-md-6 d-flex justify-content-end gap-4">
|
||||
<div className=" w-md-auto">
|
||||
{" "}
|
||||
{/* Right side: Search + Add Button */}
|
||||
<div className="col-4 col-md-6 d-flex justify-content-md-end align-items-center gap-3 mt-3 mt-md-0">
|
||||
<div className="w-md-auto flex-grow-1 flex-md-grow-0">
|
||||
<input
|
||||
type="search"
|
||||
value={searchText}
|
||||
onChange={(e) => setSearchText(e.target.value)}
|
||||
placeholder="search Collection"
|
||||
placeholder="Search Collection"
|
||||
className="form-control form-control-sm"
|
||||
/>
|
||||
</div>
|
||||
{ (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>
|
||||
)}
|
||||
|
||||
{(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}
|
||||
@ -209,7 +201,7 @@ if (!isAdmin && !canAddPayment && !canEditCollection && !canViewCollection && !c
|
||||
<ConfirmModal
|
||||
type="success"
|
||||
header="Payment Successful Received"
|
||||
message="Payment has been recored successfully."
|
||||
message="Payment has been recorded successfully."
|
||||
isOpen={processedPayment?.isOpen}
|
||||
loading={isPending}
|
||||
onSubmit={() => handleMarkedPayment(processedPayment?.invoiceId)}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user