Adding Date picker chips in Expense and

This commit is contained in:
Kartik Sharma 2025-12-10 15:10:52 +05:30 committed by pramod.mahajan
parent 153ffcdc3e
commit 0f43c877c4
7 changed files with 157 additions and 104 deletions

View File

@ -94,6 +94,14 @@ const ExpenseFilterPanel = forwardRef(
reset({ ...methods.getValues(), [name]: defaultFilter[name] }); reset({ ...methods.getValues(), [name]: defaultFilter[name] });
} }
}, },
// --- START FIX: Add resetDateRange method ---
resetDateRange: () => {
setValue("startDate", null);
setValue("endDate", null);
// Trigger re-render/reset of the DateRangePicker component
setResetKey((prev) => prev + 1);
},
// --- END FIX ---
getValues: methods.getValues, // optional, to read current filter state getValues: methods.getValues, // optional, to read current filter state
})); }));
@ -137,13 +145,13 @@ const ExpenseFilterPanel = forwardRef(
: dynamicDefaultFilter.projectIds || [], : dynamicDefaultFilter.projectIds || [],
startDate: dynamicDefaultFilter.startDate startDate: dynamicDefaultFilter.startDate
? moment ? moment
.utc(dynamicDefaultFilter.startDate, "DD-MM-YYYY") .utc(dynamicDefaultFilter.startDate, "DD-MM-YYYY")
.toISOString() .toISOString()
: undefined, : undefined,
endDate: dynamicDefaultFilter.endDate endDate: dynamicDefaultFilter.endDate
? moment ? moment
.utc(dynamicDefaultFilter.endDate, "DD-MM-YYYY") .utc(dynamicDefaultFilter.endDate, "DD-MM-YYYY")
.toISOString() .toISOString()
: undefined, : undefined,
}; };
@ -176,18 +184,16 @@ const ExpenseFilterPanel = forwardRef(
<div className="d-inline-flex border rounded-pill mb-1 overflow-hidden shadow-none"> <div className="d-inline-flex border rounded-pill mb-1 overflow-hidden shadow-none">
<button <button
type="button" type="button"
className={`btn px-2 py-1 rounded-0 text-tiny ${ className={`btn px-2 py-1 rounded-0 text-tiny ${isTransactionDate ? "active btn-primary text-white" : ""
isTransactionDate ? "active btn-primary text-white" : "" }`}
}`}
onClick={() => setValue("isTransactionDate", true)} onClick={() => setValue("isTransactionDate", true)}
> >
Transaction Date Transaction Date
</button> </button>
<button <button
type="button" type="button"
className={`btn px-2 py-1 rounded-0 text-tiny ${ className={`btn px-2 py-1 rounded-0 text-tiny ${!isTransactionDate ? "active btn-primary text-white" : ""
!isTransactionDate ? "active btn-primary text-white" : "" }`}
}`}
onClick={() => setValue("isTransactionDate", false)} onClick={() => setValue("isTransactionDate", false)}
> >
Submitted Date Submitted Date

View File

@ -83,64 +83,64 @@ const ExpenseList = ({
} }
}; };
const groupByField = (items, field) => { const groupByField = (items, field) => {
if (!field || field === "none") { if (!field || field === "none") {
return { return {
All: { All: {
key: "All", key: "All",
displayField: "All", displayField: "All",
items: items || [] items: items || []
}
};
}
return items.reduce((acc, item) => {
let key;
let displayField;
switch (field) {
case "transactionDate":
key = formatUTCToLocalTime(item?.transactionDate);
displayField = "Transaction Date";
break;
case "status":
key = item?.status?.displayName || "Unknown";
displayField = "Status";
break;
case "submittedBy":
key = `${item?.createdBy?.firstName ?? ""} ${item?.createdBy?.lastName ?? ""}`.trim();
displayField = "Submitted By";
break;
case "project":
key = item?.project?.name || "Unknown Project";
displayField = "Project";
break;
case "paymentMode":
key = item?.paymentMode?.name || "Unknown Mode";
displayField = "Payment Mode";
break;
case "expenseCategory":
key = item?.expenseCategory?.name || "Unknown Type";
displayField = "Expense Category";
break;
case "createdAt":
key = item?.createdAt?.split("T")[0] || "Unknown Date";
displayField = "Created Date";
break;
default:
key = "Others";
displayField = "Others";
} }
};
}
return items.reduce((acc, item) => { const groupKey = `${field}_${key}`;
let key; if (!acc[groupKey]) {
let displayField; acc[groupKey] = { key, displayField, items: [] };
}
switch (field) { acc[groupKey].items.push(item);
case "transactionDate": return acc;
key = formatUTCToLocalTime(item?.transactionDate); }, {});
displayField = "Transaction Date"; };
break;
case "status":
key = item?.status?.displayName || "Unknown";
displayField = "Status";
break;
case "submittedBy":
key = `${item?.createdBy?.firstName ?? ""} ${item?.createdBy?.lastName ?? ""}`.trim();
displayField = "Submitted By";
break;
case "project":
key = item?.project?.name || "Unknown Project";
displayField = "Project";
break;
case "paymentMode":
key = item?.paymentMode?.name || "Unknown Mode";
displayField = "Payment Mode";
break;
case "expenseCategory":
key = item?.expenseCategory?.name || "Unknown Type";
displayField = "Expense Category";
break;
case "createdAt":
key = item?.createdAt?.split("T")[0] || "Unknown Date";
displayField = "Created Date";
break;
default:
key = "Others";
displayField = "Others";
}
const groupKey = `${field}_${key}`;
if (!acc[groupKey]) {
acc[groupKey] = { key, displayField, items: [] };
}
acc[groupKey].items.push(item);
return acc;
}, {});
};
const expenseColumns = [ const expenseColumns = [
@ -167,9 +167,8 @@ const groupByField = (items, field) => {
label: "Submitted By", label: "Submitted By",
align: "text-start", align: "text-start",
getValue: (e) => getValue: (e) =>
`${e.createdBy?.firstName ?? ""} ${ `${e.createdBy?.firstName ?? ""} ${e.createdBy?.lastName ?? ""
e.createdBy?.lastName ?? "" }`.trim() || "N/A",
}`.trim() || "N/A",
customRender: (e) => ( customRender: (e) => (
<div <div
className="d-flex align-items-center cursor-pointer" className="d-flex align-items-center cursor-pointer"
@ -182,9 +181,8 @@ const groupByField = (items, field) => {
lastName={e.createdBy?.lastName} lastName={e.createdBy?.lastName}
/> />
<span className="text-truncate"> <span className="text-truncate">
{`${e.createdBy?.firstName ?? ""} ${ {`${e.createdBy?.firstName ?? ""} ${e.createdBy?.lastName ?? ""
e.createdBy?.lastName ?? "" }`.trim() || "N/A"}
}`.trim() || "N/A"}
</span> </span>
</div> </div>
), ),
@ -216,9 +214,8 @@ const groupByField = (items, field) => {
align: "text-center", align: "text-center",
getValue: (e) => ( getValue: (e) => (
<span <span
className={`badge bg-label-${ className={`badge bg-label-${getColorNameFromHex(e?.status?.color) || "secondary"
getColorNameFromHex(e?.status?.color) || "secondary" }`}
}`}
> >
{e.status?.name || "Unknown"} {e.status?.name || "Unknown"}
</span> </span>
@ -238,16 +235,16 @@ const groupByField = (items, field) => {
return <ExpenseTableSkeleton headers={headers} />; return <ExpenseTableSkeleton headers={headers} />;
if (isError) return <div>{error?.message}</div>; if (isError) return <div>{error?.message}</div>;
const isNoGrouping = !groupBy || groupBy === "none"; const isNoGrouping = !groupBy || groupBy === "none";
const grouped = isNoGrouping const grouped = isNoGrouping
? { All: { key: "All", displayField: "All", items: data?.data ?? [] } } ? { All: { key: "All", displayField: "All", items: data?.data ?? [] } }
: groupByField(data?.data ?? [], groupBy); : groupByField(data?.data ?? [], groupBy);
const IsGroupedByDate = [ const IsGroupedByDate = [
{key:"none",displayField:"None"}, { key: "none", displayField: "None" },
{ key: "transactionDate", displayField: "Transaction Date" }, { key: "transactionDate", displayField: "Transaction Date" },
{ key: "createdAt", displayField: "created Date", }, { key: "createdAt", displayField: "created Date", },
]?.includes(groupBy); ]?.includes(groupBy);
@ -343,26 +340,22 @@ const grouped = isNoGrouping
(col.isAlwaysVisible || groupBy !== col.key) && ( (col.isAlwaysVisible || groupBy !== col.key) && (
<td <td
key={col.key} key={col.key}
className={`d-table-cell ml-2 ${ className={`d-table-cell ml-2 ${col.align ?? ""
col.align ?? "" } `}
} `}
> >
<div <div
className={`d-flex px-2 ${ className={`d-flex px-2 ${col.key === "status"
col.key === "status"
? "justify-content-center" ? "justify-content-center"
: "" : ""
} }
${ ${col.key === "amount"
col.key === "amount" ? "justify-content-end"
? "justify-content-end" : ""
: "" }
} ${col.key === "submitted"
${ ? "justify-content-center"
col.key === "submitted" : ""
? "justify-content-center" }
: ""
}
`} `}
> >
{col.customRender {col.customRender
@ -445,7 +438,18 @@ const grouped = isNoGrouping
<tr> <tr>
<td colSpan={8} className="text-center border-0 "> <td colSpan={8} className="text-center border-0 ">
<div className="py-8"> <div className="py-8">
<p>No Expense Found</p> <p
className="text-center"
style={{
height: "250px",
display: "flex",
justifyContent: "center",
alignItems: "center",
}}
>
No Expense found
</p>
</div> </div>
</td> </td>
</tr> </tr>

View File

@ -1,3 +1,4 @@
import moment from "moment";
import React, { useMemo } from "react"; import React, { useMemo } from "react";
const PaymentRequestFilterChips = ({ filters, filterData, removeFilterChip, clearFilter }) => { const PaymentRequestFilterChips = ({ filters, filterData, removeFilterChip, clearFilter }) => {
@ -22,6 +23,21 @@ const PaymentRequestFilterChips = ({ filters, filterData, removeFilterChip, clea
addGroup(filters.projectIds, data.projects, "Projects", "projectIds"); addGroup(filters.projectIds, data.projects, "Projects", "projectIds");
addGroup(filters.statusIds, data.status, "Status", "statusIds"); addGroup(filters.statusIds, data.status, "Status", "statusIds");
if (filters.startDate || filters.endDate) {
const start = filters.startDate ? moment(filters.startDate).format("DD MMM YYYY") : "";
const end = filters.endDate ? moment(filters.endDate).format("DD MMM YYYY") : "";
chips.push({
key: "dateRange",
label: "Date",
items: [
{
id: "dateRange",
name: start && end ? `${start} to ${end}` : start || end,
},
],
});
}
return chips; return chips;
}, [filters, filterData]); }, [filters, filterData]);

View File

@ -76,9 +76,18 @@ const PaymentRequestFilterPanel = forwardRef(({ onApply, handleGroupBy, setFilte
if (value !== undefined) { if (value !== undefined) {
setValue(name, value); setValue(name, value);
} else { } else {
reset({ ...methods.getValues(), [name]: defaultFilter[name] }); // NOTE: Using defaultPaymentRequestFilter for clear functionality
reset({ ...methods.getValues(), [name]: defaultPaymentRequestFilter[name] });
} }
}, },
// --- START FIX: Add resetDateRange method ---
resetDateRange: () => {
setValue("startDate", null);
setValue("endDate", null);
// Trigger re-render/reset of the DateRangePicker component
setResetKey((prev) => prev + 1);
},
// --- END FIX ---
getValues: methods.getValues, // optional, to read current filter state getValues: methods.getValues, // optional, to read current filter state
})); }));
@ -94,7 +103,7 @@ const PaymentRequestFilterPanel = forwardRef(({ onApply, handleGroupBy, setFilte
startDate: moment.utc(formData.startDate, "DD-MM-YYYY").toISOString(), startDate: moment.utc(formData.startDate, "DD-MM-YYYY").toISOString(),
endDate: moment.utc(formData.endDate, "DD-MM-YYYY").toISOString(), endDate: moment.utc(formData.endDate, "DD-MM-YYYY").toISOString(),
}); });
handleGroupBy(selectedGroup.id); // handleGroupBy(selectedGroup.id);
// closePanel(); // closePanel();
}; };

View File

@ -355,8 +355,18 @@ const PaymentRequestList = ({ filters, filterData, removeFilterChip, clearFilter
) : ( ) : (
<tr> <tr>
<td colSpan={8} className="text-center border-0 "> <td colSpan={8} className="text-center border-0 ">
<div className="py-8"> <div >
<p>No Request Found</p> <p
className="text-center"
style={{
height: "250px",
display: "flex",
justifyContent: "center",
alignItems: "center",
}}
>
No data found
</p>
</div> </div>
</td> </td>
</tr> </tr>

View File

@ -106,10 +106,13 @@ const ExpensePage = () => {
updated[key] = updated[key].filter((v) => v !== id); updated[key] = updated[key].filter((v) => v !== id);
filterPanelRef.current?.resetFieldValue(key, updated[key]); filterPanelRef.current?.resetFieldValue(key, updated[key]);
} else if (key === "dateRange") { } else if (key === "dateRange") {
// --- START FIX: Use a dedicated function to reset the date range ---
updated.startDate = null; updated.startDate = null;
updated.endDate = null; updated.endDate = null;
filterPanelRef.current?.resetFieldValue("startDate", null);
filterPanelRef.current?.resetFieldValue("endDate", null); // Call the new resetDateRange method on the ref
filterPanelRef.current?.resetDateRange();
// --- END FIX ---
} }
return updated; return updated;
}); });

View File

@ -71,6 +71,11 @@ const PaymentRequestPage = () => {
if (Array.isArray(updated[key])) { if (Array.isArray(updated[key])) {
updated[key] = updated[key].filter((v) => v !== id); updated[key] = updated[key].filter((v) => v !== id);
setTimeout(() => updatedRef.current?.resetFieldValue(key, updated[key]), 0); setTimeout(() => updatedRef.current?.resetFieldValue(key, updated[key]), 0);
} else if (key === "dateRange") { // Handle date range reset
updated.startDate = null;
updated.endDate = null;
// Call the new resetDateRange method on the ref
updatedRef.current?.resetDateRange();
} else { } else {
updated[key] = null; updated[key] = null;
setTimeout(() => updatedRef.current?.resetFieldValue(key, null), 0); setTimeout(() => updatedRef.current?.resetFieldValue(key, null), 0);
@ -80,9 +85,9 @@ const PaymentRequestPage = () => {
}); });
}; };
const handleExport = (type) => { const handleExport = (type) => {
HandlePaymentRequestExport(type, filters, search, tableRef, setExportLoading); HandlePaymentRequestExport(type, filters, search, tableRef, setExportLoading);
}; };
return ( return (
<PaymentRequestContext.Provider value={contextValue}> <PaymentRequestContext.Provider value={contextValue}>