Merge branch 'upgrade_Expense' of https://git.marcoaiot.com/admin/marco.pms.web into Issues_Expense
This commit is contained in:
commit
0729723d5e
@ -1,13 +1,53 @@
|
|||||||
import React from "react";
|
import React, { useEffect, useMemo } from "react";
|
||||||
import { useExpenseTransactions } from "../../hooks/useExpense";
|
import { useExpenseTransactions } from "../../hooks/useExpense";
|
||||||
import Error from "../common/Error";
|
import Error from "../common/Error";
|
||||||
import { formatUTCToLocalTime } from "../../utils/dateUtils";
|
import { formatUTCToLocalTime } from "../../utils/dateUtils";
|
||||||
import Loader, { SpinnerLoader } from "../common/Loader";
|
import Loader, { SpinnerLoader } from "../common/Loader";
|
||||||
|
import { useForm, useFormContext } from "react-hook-form";
|
||||||
|
import { zodResolver } from "@hookform/resolvers/zod";
|
||||||
|
import { z } from "zod";
|
||||||
|
import { employee } from "../../data/masters";
|
||||||
|
import { useAdvancePaymentContext } from "../../pages/AdvancePayment/AdvancePaymentPage";
|
||||||
|
import { formatFigure } from "../../utils/appUtils";
|
||||||
|
|
||||||
const AdvancePaymentList = ({ employeeId }) => {
|
const AdvancePaymentList = ({ employeeId }) => {
|
||||||
|
const { setBalance } = useAdvancePaymentContext();
|
||||||
const { data, isError, isLoading, error, isFetching } =
|
const { data, isError, isLoading, error, isFetching } =
|
||||||
useExpenseTransactions(employeeId, { enabled: !!employeeId });
|
useExpenseTransactions(employeeId, { enabled: !!employeeId });
|
||||||
// Handle no employee selected
|
|
||||||
|
const records = Array.isArray(data) ? data : [];
|
||||||
|
|
||||||
|
let currentBalance = 0;
|
||||||
|
const rowsWithBalance = records.map((r) => {
|
||||||
|
const isCredit = r.amount > 0;
|
||||||
|
const credit = isCredit ? r.amount : 0;
|
||||||
|
const debit = !isCredit ? Math.abs(r.amount) : 0;
|
||||||
|
currentBalance += credit - debit;
|
||||||
|
return {
|
||||||
|
id: r.id,
|
||||||
|
description: r.title || "-",
|
||||||
|
projectName: r.project?.name || "-",
|
||||||
|
createdAt: r.createdAt,
|
||||||
|
credit,
|
||||||
|
debit,
|
||||||
|
financeUId: r.financeUId,
|
||||||
|
balance: currentBalance,
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (!employeeId) {
|
||||||
|
setBalance(null);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (rowsWithBalance.length > 0) {
|
||||||
|
setBalance(rowsWithBalance[rowsWithBalance.length - 1].balance);
|
||||||
|
} else {
|
||||||
|
setBalance(0);
|
||||||
|
}
|
||||||
|
}, [employeeId, data, setBalance]);
|
||||||
|
|
||||||
if (!employeeId) {
|
if (!employeeId) {
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
@ -19,7 +59,6 @@ const AdvancePaymentList = ({ employeeId }) => {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Handle loading state
|
|
||||||
if (isLoading || isFetching) {
|
if (isLoading || isFetching) {
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
@ -31,41 +70,27 @@ const AdvancePaymentList = ({ employeeId }) => {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Handle error state
|
|
||||||
if (isError) {
|
if (isError) {
|
||||||
return (
|
return (
|
||||||
<div className="text-center py-3">
|
<div className="text-center py-3">
|
||||||
{error?.status === 404 ? (
|
{error?.status === 404
|
||||||
"No advance payment transactions found."
|
? "No advance payment transactions found."
|
||||||
) : (
|
: <Error error={error} />}
|
||||||
<Error error={error} />
|
|
||||||
)}
|
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
const records = Array.isArray(data) ? data : [];
|
|
||||||
|
|
||||||
let currentBalance = 0;
|
|
||||||
const rowsWithBalance = records.map((r) => {
|
|
||||||
const isCredit = r.amount > 0;
|
|
||||||
const credit = isCredit ? r.amount : 0;
|
|
||||||
const debit = !isCredit ? Math.abs(r.amount) : 0;
|
|
||||||
currentBalance += credit - debit;
|
|
||||||
|
|
||||||
return {
|
|
||||||
id: r.id,
|
|
||||||
description: r.title || "-",
|
|
||||||
projectName: r.project?.name || "-",
|
|
||||||
createdAt: r.createdAt,
|
|
||||||
credit,
|
|
||||||
debit,
|
|
||||||
balance: currentBalance,
|
|
||||||
};
|
|
||||||
});
|
|
||||||
|
|
||||||
const columns = [
|
const columns = [
|
||||||
|
{
|
||||||
|
key: "date",
|
||||||
|
label: (
|
||||||
|
<>
|
||||||
|
Date
|
||||||
|
</>
|
||||||
|
),
|
||||||
|
align: "text-start",
|
||||||
|
},
|
||||||
{ key: "description", label: "Description", align: "text-start" },
|
{ key: "description", label: "Description", align: "text-start" },
|
||||||
|
|
||||||
{
|
{
|
||||||
key: "credit",
|
key: "credit",
|
||||||
label: (
|
label: (
|
||||||
@ -84,6 +109,7 @@ const AdvancePaymentList = ({ employeeId }) => {
|
|||||||
),
|
),
|
||||||
align: "text-end",
|
align: "text-end",
|
||||||
},
|
},
|
||||||
|
|
||||||
{
|
{
|
||||||
key: "balance",
|
key: "balance",
|
||||||
label: (
|
label: (
|
||||||
@ -103,6 +129,17 @@ const AdvancePaymentList = ({ employeeId }) => {
|
|||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
const DecideCreditOrDebit = ({ financeUId }) => {
|
||||||
|
if (!financeUId) return null;
|
||||||
|
|
||||||
|
const prefix = financeUId?.substring(0, 2).toUpperCase();
|
||||||
|
|
||||||
|
if (prefix === "PR") return <span className="text-success">+</span>;
|
||||||
|
if (prefix === "EX") return <span className="text-danger">-</span>;
|
||||||
|
|
||||||
|
return null;
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="table-responsive">
|
<div className="table-responsive">
|
||||||
<table className="table align-middle">
|
<table className="table align-middle">
|
||||||
@ -129,17 +166,25 @@ const AdvancePaymentList = ({ employeeId }) => {
|
|||||||
)
|
)
|
||||||
) : col.key === "debit" ? (
|
) : col.key === "debit" ? (
|
||||||
row.amount < 0 ? (
|
row.amount < 0 ? (
|
||||||
<span>{Math.abs(row.amount).toLocaleString("en-IN")}</span>
|
<span>
|
||||||
|
{Math.abs(row.amount).toLocaleString("en-IN")}
|
||||||
|
</span>
|
||||||
) : (
|
) : (
|
||||||
"-"
|
"-"
|
||||||
)
|
)
|
||||||
) : col.key === "balance" ? (
|
) : col.key === "balance" ? (
|
||||||
<span>{row.currentBalance?.toLocaleString("en-IN")}</span>
|
<div className="d-flex align-items-center justify-content-end">
|
||||||
|
<DecideCreditOrDebit financeUId={row?.financeUId} />
|
||||||
|
<span className="mx-2">
|
||||||
|
{formatFigure(row.currentBalance)}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
) : col.key === "date" ? (
|
||||||
|
<small className="text-muted px-1">
|
||||||
|
{formatUTCToLocalTime(row.paidAt)}
|
||||||
|
</small>
|
||||||
) : (
|
) : (
|
||||||
<div className="d-flex flex-column text-start">
|
<div className="d-flex flex-column text-start gap-1 py-1">
|
||||||
<small className="text-muted">
|
|
||||||
{formatUTCToLocalTime(row.paidAt)}
|
|
||||||
</small>
|
|
||||||
<small className="fw-semibold text-dark">
|
<small className="fw-semibold text-dark">
|
||||||
{row.project?.name || "-"}
|
{row.project?.name || "-"}
|
||||||
</small>
|
</small>
|
||||||
@ -152,21 +197,31 @@ const AdvancePaymentList = ({ employeeId }) => {
|
|||||||
))
|
))
|
||||||
) : (
|
) : (
|
||||||
<tr>
|
<tr>
|
||||||
<td colSpan={columns.length} className="text-center text-muted py-3">
|
<td
|
||||||
|
colSpan={columns.length}
|
||||||
|
className="text-center text-muted py-3"
|
||||||
|
>
|
||||||
No advance payment records found.
|
No advance payment records found.
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
)}
|
)}
|
||||||
</tbody>
|
</tbody>
|
||||||
|
|
||||||
<tfoot className="table-secondary fw-bold">
|
<tfoot className=" fw-bold">
|
||||||
<tr>
|
<tr className="tr-group text-dark py-2">
|
||||||
<td className="text-start p-3">Final Balance</td>
|
<td className="text-start">
|
||||||
<td className="text-end" colSpan="3">
|
{" "}
|
||||||
{currentBalance.toLocaleString("en-IN", {
|
<div className="d-flex align-items-center px-1 py-2">
|
||||||
style: "currency",
|
Final Balance
|
||||||
currency: "INR",
|
</div>
|
||||||
})}
|
</td>
|
||||||
|
<td className="text-end" colSpan="4">
|
||||||
|
<div className="d-flex align-items-center justify-content-end px-1 py-2">
|
||||||
|
{currentBalance.toLocaleString("en-IN", {
|
||||||
|
style: "currency",
|
||||||
|
currency: "INR",
|
||||||
|
})}
|
||||||
|
</div>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
</tfoot>
|
</tfoot>
|
||||||
|
|||||||
@ -267,7 +267,7 @@ const ExpenseList = ({ filters, groupBy = "transactionDate", searchText }) => {
|
|||||||
Object.values(grouped).map(({ key, displayField, items }) => (
|
Object.values(grouped).map(({ key, displayField, items }) => (
|
||||||
<React.Fragment key={key}>
|
<React.Fragment key={key}>
|
||||||
<tr className="tr-group text-dark">
|
<tr className="tr-group text-dark">
|
||||||
<td colSpan={8} className="text-start ">
|
<td colSpan={8} className="text-start">
|
||||||
<div className="d-flex align-items-center px-2">
|
<div className="d-flex align-items-center px-2">
|
||||||
{" "}
|
{" "}
|
||||||
<small className="fs-6 py-1">
|
<small className="fs-6 py-1">
|
||||||
|
|||||||
@ -117,7 +117,7 @@ const ViewExpense = ({ ExpenseId }) => {
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="row mb-1 ">
|
<div className="row mb-1 ">
|
||||||
<div className="col-12 col-lg-7 col-xl-8 mb-3">
|
<div className="col-12 col-lg-7 col-xl-7 mb-3">
|
||||||
<div className="row">
|
<div className="row">
|
||||||
<div className="col-12 d-flex justify-content-between text-start fw-semibold my-2">
|
<div className="col-12 d-flex justify-content-between text-start fw-semibold my-2">
|
||||||
<span>{data?.expenseUId}</span>
|
<span>{data?.expenseUId}</span>
|
||||||
@ -525,7 +525,7 @@ const ViewExpense = ({ ExpenseId }) => {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="col-12 col-lg-5 col-xl-4">
|
<div className="col-12 col-lg-5 col-xl-5">
|
||||||
<div className="d-flex align-items-center text-secondary mb-4">
|
<div className="d-flex align-items-center text-secondary mb-4">
|
||||||
<i className="bx bx-time-five me-2"></i>{" "}
|
<i className="bx bx-time-five me-2"></i>{" "}
|
||||||
<p className=" m-0">TimeLine</p>
|
<p className=" m-0">TimeLine</p>
|
||||||
|
|||||||
@ -27,31 +27,27 @@ export const PaymentRequestSchema = (expenseTypes, isItself) => {
|
|||||||
.refine((val) => /^\d+(\.\d{1,2})?$/.test(val.toString()), {
|
.refine((val) => /^\d+(\.\d{1,2})?$/.test(val.toString()), {
|
||||||
message: "Amount must have at most 2 decimal places",
|
message: "Amount must have at most 2 decimal places",
|
||||||
}),
|
}),
|
||||||
|
|
||||||
billAttachments: z
|
billAttachments: z.array(
|
||||||
.array(
|
z.object({
|
||||||
z.object({
|
fileName: z.string().min(1, { message: "Filename is required" }),
|
||||||
fileName: z.string().min(1, { message: "Filename is required" }),
|
base64Data: z.string().nullable(),
|
||||||
base64Data: z.string().nullable(),
|
contentType: z.string().refine((val) => ALLOWED_TYPES.includes(val), {
|
||||||
contentType: z
|
message: "Only PDF, PNG, JPG, or JPEG files are allowed",
|
||||||
.string()
|
}),
|
||||||
.refine((val) => ALLOWED_TYPES.includes(val), {
|
documentId: z.string().optional(),
|
||||||
message: "Only PDF, PNG, JPG, or JPEG files are allowed",
|
fileSize: z.number().max(MAX_FILE_SIZE, {
|
||||||
}),
|
message: "File size must be less than or equal to 5MB",
|
||||||
documentId: z.string().optional(),
|
}),
|
||||||
fileSize: z.number().max(MAX_FILE_SIZE, {
|
description: z.string().optional(),
|
||||||
message: "File size must be less than or equal to 5MB",
|
isActive: z.boolean().default(true),
|
||||||
}),
|
})
|
||||||
description: z.string().optional(),
|
),
|
||||||
isActive: z.boolean().default(true),
|
});
|
||||||
})
|
};
|
||||||
)
|
|
||||||
,
|
|
||||||
})
|
|
||||||
};
|
|
||||||
|
|
||||||
export const defaultPaymentRequest = {
|
export const defaultPaymentRequest = {
|
||||||
title:"",
|
title: "",
|
||||||
description: "",
|
description: "",
|
||||||
payee: "",
|
payee: "",
|
||||||
currencyId: "",
|
currencyId: "",
|
||||||
@ -63,7 +59,6 @@ export const defaultPaymentRequest = {
|
|||||||
billAttachments: [],
|
billAttachments: [],
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
export const SearchPaymentRequestSchema = z.object({
|
export const SearchPaymentRequestSchema = z.object({
|
||||||
projectIds: z.array(z.string()).optional(),
|
projectIds: z.array(z.string()).optional(),
|
||||||
statusIds: z.array(z.string()).optional(),
|
statusIds: z.array(z.string()).optional(),
|
||||||
@ -86,7 +81,6 @@ export const defaultPaymentRequestFilter = {
|
|||||||
endDate: null,
|
endDate: null,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
export const PaymentRequestActionScheam = (
|
export const PaymentRequestActionScheam = (
|
||||||
isTransaction = false,
|
isTransaction = false,
|
||||||
transactionDate
|
transactionDate
|
||||||
@ -149,9 +143,9 @@ export const defaultPRActionValues = {
|
|||||||
paidTransactionId: null,
|
paidTransactionId: null,
|
||||||
paidAt: null,
|
paidAt: null,
|
||||||
paidById: null,
|
paidById: null,
|
||||||
tdsPercentage:"0",
|
tdsPercentage: "0",
|
||||||
baseAmount: null,
|
baseAmount: null,
|
||||||
taxAmount:null,
|
taxAmount: null,
|
||||||
};
|
};
|
||||||
|
|
||||||
export const RequestedExpenseSchema = z.object({
|
export const RequestedExpenseSchema = z.object({
|
||||||
|
|||||||
@ -5,7 +5,6 @@ import Timeline from "../common/TimeLine";
|
|||||||
import moment from "moment";
|
import moment from "moment";
|
||||||
import { getColorNameFromHex } from "../../utils/appUtils";
|
import { getColorNameFromHex } from "../../utils/appUtils";
|
||||||
const PaymentStatusLogs = ({ data }) => {
|
const PaymentStatusLogs = ({ data }) => {
|
||||||
const [visibleCount, setVisibleCount] = useState(4);
|
|
||||||
|
|
||||||
const sortedLogs = useMemo(() => {
|
const sortedLogs = useMemo(() => {
|
||||||
if (!data?.updateLogs) return [];
|
if (!data?.updateLogs) return [];
|
||||||
@ -14,18 +13,16 @@ const PaymentStatusLogs = ({ data }) => {
|
|||||||
);
|
);
|
||||||
}, [data?.updateLogs]);
|
}, [data?.updateLogs]);
|
||||||
|
|
||||||
const logsToShow = useMemo(
|
|
||||||
() => sortedLogs.slice(0, visibleCount),
|
|
||||||
[sortedLogs, visibleCount]
|
|
||||||
);
|
|
||||||
|
|
||||||
const timelineData = useMemo(() => {
|
const timelineData = useMemo(() => {
|
||||||
return logsToShow.map((log, index) => ({
|
return sortedLogs.map((log, index) => ({
|
||||||
id: index + 1,
|
id: log.id,
|
||||||
title: log.nextStatus?.name || "Status Updated",
|
title: log.nextStatus?.name || "Status Updated",
|
||||||
description: log.nextStatus?.description || "",
|
description: log.nextStatus?.description || "",
|
||||||
timeAgo: log.updatedAt,
|
timeAgo: log.updatedAt,
|
||||||
color: getColorNameFromHex(log.nextStatus?.color) || "primary",
|
color: getColorNameFromHex(log.nextStatus?.color) || "primary",
|
||||||
|
userComment:log.comment,
|
||||||
users: log.updatedBy
|
users: log.updatedBy
|
||||||
? [
|
? [
|
||||||
{
|
{
|
||||||
@ -37,14 +34,13 @@ const PaymentStatusLogs = ({ data }) => {
|
|||||||
]
|
]
|
||||||
: [],
|
: [],
|
||||||
}));
|
}));
|
||||||
}, [logsToShow]);
|
}, [sortedLogs]);
|
||||||
|
|
||||||
const handleShowMore = () => {
|
const handleShowMore = () => {
|
||||||
setVisibleCount((prev) => prev + 4);
|
setVisibleCount((prev) => prev + 4);
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="page-min-h overflow-auto">
|
<div className="page-min-h overflow-auto h-56" >
|
||||||
{/* <div className="row g-2">
|
{/* <div className="row g-2">
|
||||||
{logsToShow.map((log) => (
|
{logsToShow.map((log) => (
|
||||||
<div key={log.id} className="col-12 d-flex align-items-start mb-1">
|
<div key={log.id} className="col-12 d-flex align-items-start mb-1">
|
||||||
|
|||||||
@ -403,26 +403,6 @@ function ManageRecurringExpense({ closeModal, requestToEdit = null }) {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Notify */}
|
|
||||||
{/* <div className="row my-2 text-start">
|
|
||||||
<div className="col-md-6">
|
|
||||||
<Label htmlFor="notifyTo" className="form-label" required>
|
|
||||||
Notify Employees
|
|
||||||
</Label>
|
|
||||||
<input
|
|
||||||
type="text"
|
|
||||||
id="notifyTo"
|
|
||||||
className="form-control form-control-sm"
|
|
||||||
{...register("notifyTo")}
|
|
||||||
|
|
||||||
/>
|
|
||||||
{errors.notifyTo && (
|
|
||||||
<small className="danger-text">
|
|
||||||
{errors.notifyTo.message}
|
|
||||||
</small>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
</div> */}
|
|
||||||
|
|
||||||
<div className="row my-2 text-start">
|
<div className="row my-2 text-start">
|
||||||
<div className="col-md-6">
|
<div className="col-md-6">
|
||||||
|
|||||||
@ -32,6 +32,7 @@ const EmployeeSearchInput = ({
|
|||||||
const found = employees.data.find((emp) => emp.id === value);
|
const found = employees.data.find((emp) => emp.id === value);
|
||||||
if (found && forAll) {
|
if (found && forAll) {
|
||||||
setSearch(`${found.firstName} ${found.lastName}`);
|
setSearch(`${found.firstName} ${found.lastName}`);
|
||||||
|
sessionStorage.setItem("transaction-empId",found?.id)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}, [value, employees?.data, forAll]);
|
}, [value, employees?.data, forAll]);
|
||||||
|
|||||||
@ -53,7 +53,7 @@ const MultiEmployeeSearchInput = ({
|
|||||||
}, [value, employees?.data, forAll]);
|
}, [value, employees?.data, forAll]);
|
||||||
|
|
||||||
const handleSelect = (employee) => {
|
const handleSelect = (employee) => {
|
||||||
if (!selectedEmployees.find((emp) => emp.email === employee.email)) {
|
if (!selectedEmployees.find((emp) => emp.id === employee.id)) {
|
||||||
const newSelected = [...selectedEmployees, employee];
|
const newSelected = [...selectedEmployees, employee];
|
||||||
setSelectedEmployees(newSelected);
|
setSelectedEmployees(newSelected);
|
||||||
// Store emails instead of IDs
|
// Store emails instead of IDs
|
||||||
@ -150,11 +150,11 @@ const MultiEmployeeSearchInput = ({
|
|||||||
) : (
|
) : (
|
||||||
employees?.data
|
employees?.data
|
||||||
?.filter(
|
?.filter(
|
||||||
(emp) => !selectedEmployees.find((e) => e.email === emp.email)
|
(emp) => !selectedEmployees.find((e) => e.id === emp.id)
|
||||||
)
|
)
|
||||||
.map((emp) => (
|
.map((emp) => (
|
||||||
<li
|
<li
|
||||||
key={emp.email}
|
key={emp.id}
|
||||||
className="list-group-item list-group-item-action py-1 px-2"
|
className="list-group-item list-group-item-action py-1 px-2"
|
||||||
style={{ cursor: "pointer" }}
|
style={{ cursor: "pointer" }}
|
||||||
onClick={() => handleSelect(emp)}
|
onClick={() => handleSelect(emp)}
|
||||||
|
|||||||
@ -5,6 +5,13 @@ import { formatUTCToLocalTime } from "../../utils/dateUtils";
|
|||||||
import moment from "moment";
|
import moment from "moment";
|
||||||
|
|
||||||
const Timeline = ({ items = [], transparent = true }) => {
|
const Timeline = ({ items = [], transparent = true }) => {
|
||||||
|
if(items.length === 0){
|
||||||
|
return (
|
||||||
|
<div className="d-flex justify-content-center align-item-center page-min-h">
|
||||||
|
<p>Not Action yet</p>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
return (
|
return (
|
||||||
<ul
|
<ul
|
||||||
className={`timeline ${
|
className={`timeline ${
|
||||||
@ -25,12 +32,12 @@ const Timeline = ({ items = [], transparent = true }) => {
|
|||||||
></span>
|
></span>
|
||||||
|
|
||||||
<div className="timeline-event">
|
<div className="timeline-event">
|
||||||
<div className="timeline-header mb-3 d-flex justify-content-between">
|
<div className="timeline-header mb-1 d-flex justify-content-between">
|
||||||
<h6 className="mb-0 text-body">{item.title}</h6>
|
<h6 className="mb-0 text-body">{item.title}</h6>
|
||||||
<small className="text-body-secondary"><Tooltip text={formatUTCToLocalTime(item.timeAgo,true)}>{moment.utc(item.timeAgo).local().fromNow()}</Tooltip></small>
|
<small className="text-body-secondary"><Tooltip text={formatUTCToLocalTime(item.timeAgo,true)}>{moment.utc(item.timeAgo).local().fromNow()}</Tooltip></small>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{item.description && <p className="mb-2">{item.description}</p>}
|
{item.description && <p className="mb-1">{item.description}</p>}
|
||||||
|
|
||||||
{item.attachments && item.attachments.length > 0 && (
|
{item.attachments && item.attachments.length > 0 && (
|
||||||
<div className="d-flex align-items-center mb-2">
|
<div className="d-flex align-items-center mb-2">
|
||||||
@ -54,7 +61,7 @@ const Timeline = ({ items = [], transparent = true }) => {
|
|||||||
)}
|
)}
|
||||||
|
|
||||||
{item.users && item.users.length > 0 && (
|
{item.users && item.users.length > 0 && (
|
||||||
<div className="d-flex flex-wrap align-items-center mb-2">
|
<div className="d-flex flex-wrap align-items-center ">
|
||||||
<ul className="list-unstyled users-list d-flex align-items-center avatar-group m-0">
|
<ul className="list-unstyled users-list d-flex align-items-center avatar-group m-0">
|
||||||
{item.users.map((user, i) => (
|
{item.users.map((user, i) => (
|
||||||
<li key={i} className="avatar me-1" title={user.name}>
|
<li key={i} className="avatar me-1" title={user.name}>
|
||||||
@ -82,8 +89,11 @@ const Timeline = ({ items = [], transparent = true }) => {
|
|||||||
<small>{item.users[0].role}</small>
|
<small>{item.users[0].role}</small>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
<div className="d-flex flex-wrap ms-10">{item.userComment && <p className="mb-2 ">{item.userComment}</p>}</div>
|
||||||
</div>
|
</div>
|
||||||
</li>
|
</li>
|
||||||
))}
|
))}
|
||||||
|
|||||||
@ -434,7 +434,8 @@ export const useExpenseTransactions = (employeeId)=>{
|
|||||||
const resp = await ExpenseRepository.GetTranctionList(employeeId);
|
const resp = await ExpenseRepository.GetTranctionList(employeeId);
|
||||||
return resp.data
|
return resp.data
|
||||||
},
|
},
|
||||||
enabled:!!employeeId
|
enabled:!!employeeId,
|
||||||
|
keepPreviousData:true,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
//#endregion
|
//#endregion
|
||||||
|
|||||||
@ -1,45 +1,91 @@
|
|||||||
import React from "react";
|
import React, {
|
||||||
|
createContext,
|
||||||
|
useContext,
|
||||||
|
useEffect,
|
||||||
|
useMemo,
|
||||||
|
useState,
|
||||||
|
} from "react";
|
||||||
import Breadcrumb from "../../components/common/Breadcrumb";
|
import Breadcrumb from "../../components/common/Breadcrumb";
|
||||||
import { useEmployee } from "../../hooks/useEmployees";
|
import { useEmployee } from "../../hooks/useEmployees";
|
||||||
import EmployeeSearchInput from "../../components/common/EmployeeSearchInput";
|
import EmployeeSearchInput from "../../components/common/EmployeeSearchInput";
|
||||||
import { useForm } from "react-hook-form";
|
import { useForm } from "react-hook-form";
|
||||||
import Label from "../../components/common/Label";
|
import Label from "../../components/common/Label";
|
||||||
import AdvancePaymentList from "../../components/AdvancePayment/AdvancePaymentList";
|
import AdvancePaymentList from "../../components/AdvancePayment/AdvancePaymentList";
|
||||||
|
import { employee } from "../../data/masters";
|
||||||
|
import { formatFigure } from "../../utils/appUtils";
|
||||||
|
|
||||||
|
export const AdvancePaymentContext = createContext();
|
||||||
|
export const useAdvancePaymentContext = () => {
|
||||||
|
const context = useContext(AdvancePaymentContext);
|
||||||
|
if (!context) {
|
||||||
|
throw new Error(
|
||||||
|
"useAdvancePaymentContext must be used within an AdvancePaymentProvider"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return context;
|
||||||
|
};
|
||||||
const AdvancePaymentPage = () => {
|
const AdvancePaymentPage = () => {
|
||||||
const { control, watch } = useForm({
|
const [balance, setBalance] = useState(null);
|
||||||
|
const { control, reset, watch } = useForm({
|
||||||
defaultValues: {
|
defaultValues: {
|
||||||
employeeId: "",
|
employeeId: "",
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
const selectedEmployeeId = watch("employeeId");
|
const selectedEmployeeId = watch("employeeId");
|
||||||
|
useEffect(() => {
|
||||||
|
const selectedEmpoyee = sessionStorage.getItem("transaction-empId");
|
||||||
|
reset({
|
||||||
|
employeeId: selectedEmpoyee || "",
|
||||||
|
});
|
||||||
|
}, [reset]);
|
||||||
return (
|
return (
|
||||||
<div className="container-fluid">
|
<AdvancePaymentContext.Provider value={{ setBalance }}>
|
||||||
<Breadcrumb
|
<div className="container-fluid">
|
||||||
data={[
|
<Breadcrumb
|
||||||
{ label: "Home", link: "/" },
|
data={[
|
||||||
{ label: "Finance", link: "/advance-payment" },
|
{ label: "Home", link: "/" },
|
||||||
{ label: "Advance Payment" },
|
{ label: "Finance", link: "/advance-payment" },
|
||||||
]}
|
{ label: "Advance Payment" },
|
||||||
/>
|
]}
|
||||||
<div className="card px-4 py-2 page-min-h ">
|
/>
|
||||||
<div className="row">
|
<div className="card px-4 py-2 page-min-h ">
|
||||||
<div className="col-12 col-md-4">
|
<div className="row py-1">
|
||||||
<div className="d-block text-start" >
|
<div className="col-12 col-md-4">
|
||||||
<EmployeeSearchInput
|
<div className="d-block text-start">
|
||||||
control={control}
|
<EmployeeSearchInput
|
||||||
name="employeeId"
|
control={control}
|
||||||
projectId={null}
|
name="employeeId"
|
||||||
forAll={true}
|
projectId={null}
|
||||||
placeholder={"Enter Employee Name"}
|
forAll={true}
|
||||||
/>
|
placeholder={"Enter Employee Name"}
|
||||||
</div>
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className="col-md-8 d-flex align-items-center justify-content-end">
|
||||||
|
{balance ? (
|
||||||
|
<>
|
||||||
|
<label className="fs-5 fw-semibold">Total Balance : </label>
|
||||||
|
<span
|
||||||
|
className={`${
|
||||||
|
balance > 0 ? "text-success" : "text-danger"
|
||||||
|
} fs-5 fw-bold ms-1`}
|
||||||
|
>
|
||||||
|
{formatFigure(balance, {
|
||||||
|
type: "currency",
|
||||||
|
currency: "INR",
|
||||||
|
})}
|
||||||
|
</span>
|
||||||
|
</>
|
||||||
|
) : (
|
||||||
|
<></>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<AdvancePaymentList employeeId={selectedEmployeeId} />
|
||||||
</div>
|
</div>
|
||||||
<AdvancePaymentList employeeId={selectedEmployeeId}/>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</AdvancePaymentContext.Provider>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@ -64,7 +64,7 @@ export const APPROVE_EXPENSE = "eaafdd76-8aac-45f9-a530-315589c6deca";
|
|||||||
|
|
||||||
export const PROCESS_EXPENSE = "ea5a1529-4ee8-4828-80ea-0e23c9d4dd11";
|
export const PROCESS_EXPENSE = "ea5a1529-4ee8-4828-80ea-0e23c9d4dd11";
|
||||||
|
|
||||||
export const EXPENSE_MANAGE = "ea5a1529-4ee8-4828-80ea-0e23c9d4dd11";
|
export const EXPENSE_MANAGE = "bdee29a2-b73b-402d-8dd1-c4b1f81ccbc3";
|
||||||
|
|
||||||
export const EXPENSE_REJECTEDBY = [
|
export const EXPENSE_REJECTEDBY = [
|
||||||
"965eda62-7907-4963-b4a1-657fb0b2724b",
|
"965eda62-7907-4963-b4a1-657fb0b2724b",
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user