display all time lien from darft

This commit is contained in:
pramod.mahajan 2025-11-06 15:48:53 +05:30
parent 1278e32da9
commit 72e5cf0bbe
6 changed files with 95 additions and 91 deletions

View File

@ -1,8 +1,5 @@
import React, { useEffect, useMemo } from "react"; import React, { useEffect, useMemo } from "react";
import { import { useExpenseTransactions } from "../../hooks/useExpense";
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";
@ -13,48 +10,10 @@ import { employee } from "../../data/masters";
import { useAdvancePaymentContext } from "../../pages/AdvancePayment/AdvancePaymentPage"; import { useAdvancePaymentContext } from "../../pages/AdvancePayment/AdvancePaymentPage";
import { formatFigure } from "../../utils/appUtils"; import { formatFigure } from "../../utils/appUtils";
const AdvancePaymentList = ({ employeeId }) => { const AdvancePaymentList = ({ employeeId }) => {
const { setBalance} = useAdvancePaymentContext() const { setBalance } = useAdvancePaymentContext();
const { data, isError, isLoading, error, isFetching } = const { data, isError, isLoading, error, isFetching } =
useExpenseTransactions(employeeId, { enabled: !!employeeId }); useExpenseTransactions(employeeId, { enabled: !!employeeId });
if (!employeeId) {
return (
<div
className="d-flex justify-content-center align-items-center"
style={{ height: "200px" }}
>
<p className="text-muted m-0">Please select an employee</p>
</div>
);
}
// Handle loading state
if (isLoading || isFetching) {
return (
<div
className="d-flex justify-content-center align-items-center"
style={{ height: "200px" }}
>
<SpinnerLoader />
</div>
);
}
// Handle error state
if (isError) {
return (
<div className="text-center py-3">
{error?.status === 404 ? (
"No advance payment transactions found."
) : (
<Error error={error} />
)}
</div>
);
}
const records = Array.isArray(data) ? data : []; const records = Array.isArray(data) ? data : [];
@ -64,7 +23,6 @@ const AdvancePaymentList = ({ employeeId }) => {
const credit = isCredit ? r.amount : 0; const credit = isCredit ? r.amount : 0;
const debit = !isCredit ? Math.abs(r.amount) : 0; const debit = !isCredit ? Math.abs(r.amount) : 0;
currentBalance += credit - debit; currentBalance += credit - debit;
setBalance(currentBalance);
return { return {
id: r.id, id: r.id,
description: r.title || "-", description: r.title || "-",
@ -77,12 +35,56 @@ const AdvancePaymentList = ({ employeeId }) => {
}; };
}); });
useEffect(() => {
if (!employeeId) {
setBalance(null);
return;
}
if (rowsWithBalance.length > 0) {
setBalance(rowsWithBalance[rowsWithBalance.length - 1].balance);
} else {
setBalance(0);
}
}, [employeeId, data, setBalance]);
if (!employeeId) {
return (
<div
className="d-flex justify-content-center align-items-center"
style={{ height: "200px" }}
>
<p className="text-muted m-0">Please select an employee</p>
</div>
);
}
if (isLoading || isFetching) {
return (
<div
className="d-flex justify-content-center align-items-center"
style={{ height: "200px" }}
>
<SpinnerLoader />
</div>
);
}
if (isError) {
return (
<div className="text-center py-3">
{error?.status === 404
? "No advance payment transactions found."
: <Error error={error} />}
</div>
);
}
const columns = [ const columns = [
{ {
key: "date", key: "date",
label: ( label: (
<> <>
Date <i className="bx bx-rupee text-danger"></i> Date
</> </>
), ),
align: "text-start", align: "text-start",
@ -138,7 +140,6 @@ const AdvancePaymentList = ({ employeeId }) => {
return null; return null;
}; };
return ( return (
<div className="table-responsive"> <div className="table-responsive">
<table className="table align-middle"> <table className="table align-middle">
@ -173,7 +174,10 @@ const AdvancePaymentList = ({ employeeId }) => {
) )
) : col.key === "balance" ? ( ) : col.key === "balance" ? (
<div className="d-flex align-items-center justify-content-end"> <div className="d-flex align-items-center justify-content-end">
<DecideCreditOrDebit financeUId={row?.financeUId}/><span className="mx-2">{formatFigure(row.currentBalance)}</span> <DecideCreditOrDebit financeUId={row?.financeUId} />
<span className="mx-2">
{formatFigure(row.currentBalance)}
</span>
</div> </div>
) : col.key === "date" ? ( ) : col.key === "date" ? (
<small className="text-muted px-1"> <small className="text-muted px-1">

View File

@ -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>

View File

@ -28,14 +28,11 @@ export const PaymentRequestSchema = (expenseTypes, isItself) => {
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 contentType: z.string().refine((val) => ALLOWED_TYPES.includes(val), {
.string()
.refine((val) => ALLOWED_TYPES.includes(val), {
message: "Only PDF, PNG, JPG, or JPEG files are allowed", message: "Only PDF, PNG, JPG, or JPEG files are allowed",
}), }),
documentId: z.string().optional(), documentId: z.string().optional(),
@ -45,9 +42,8 @@ export const PaymentRequestSchema = (expenseTypes, isItself) => {
description: z.string().optional(), description: z.string().optional(),
isActive: z.boolean().default(true), isActive: z.boolean().default(true),
}) })
) ),
, });
})
}; };
export const defaultPaymentRequest = { export const defaultPaymentRequest = {
@ -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

View File

@ -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">

View File

@ -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>
))} ))}

View File

@ -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",