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] });
}
},
// --- 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
}));
@ -137,13 +145,13 @@ const ExpenseFilterPanel = forwardRef(
: dynamicDefaultFilter.projectIds || [],
startDate: dynamicDefaultFilter.startDate
? moment
.utc(dynamicDefaultFilter.startDate, "DD-MM-YYYY")
.toISOString()
.utc(dynamicDefaultFilter.startDate, "DD-MM-YYYY")
.toISOString()
: undefined,
endDate: dynamicDefaultFilter.endDate
? moment
.utc(dynamicDefaultFilter.endDate, "DD-MM-YYYY")
.toISOString()
.utc(dynamicDefaultFilter.endDate, "DD-MM-YYYY")
.toISOString()
: undefined,
};
@ -176,18 +184,16 @@ const ExpenseFilterPanel = forwardRef(
<div className="d-inline-flex border rounded-pill mb-1 overflow-hidden shadow-none">
<button
type="button"
className={`btn px-2 py-1 rounded-0 text-tiny ${
isTransactionDate ? "active btn-primary text-white" : ""
}`}
className={`btn px-2 py-1 rounded-0 text-tiny ${isTransactionDate ? "active btn-primary text-white" : ""
}`}
onClick={() => setValue("isTransactionDate", true)}
>
Transaction Date
</button>
<button
type="button"
className={`btn px-2 py-1 rounded-0 text-tiny ${
!isTransactionDate ? "active btn-primary text-white" : ""
}`}
className={`btn px-2 py-1 rounded-0 text-tiny ${!isTransactionDate ? "active btn-primary text-white" : ""
}`}
onClick={() => setValue("isTransactionDate", false)}
>
Submitted Date

View File

@ -83,64 +83,64 @@ const ExpenseList = ({
}
};
const groupByField = (items, field) => {
if (!field || field === "none") {
return {
All: {
key: "All",
displayField: "All",
items: items || []
const groupByField = (items, field) => {
if (!field || field === "none") {
return {
All: {
key: "All",
displayField: "All",
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) => {
let key;
let displayField;
const groupKey = `${field}_${key}`;
if (!acc[groupKey]) {
acc[groupKey] = { key, displayField, items: [] };
}
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";
}
const groupKey = `${field}_${key}`;
if (!acc[groupKey]) {
acc[groupKey] = { key, displayField, items: [] };
}
acc[groupKey].items.push(item);
return acc;
}, {});
};
acc[groupKey].items.push(item);
return acc;
}, {});
};
const expenseColumns = [
@ -167,9 +167,8 @@ const groupByField = (items, field) => {
label: "Submitted By",
align: "text-start",
getValue: (e) =>
`${e.createdBy?.firstName ?? ""} ${
e.createdBy?.lastName ?? ""
}`.trim() || "N/A",
`${e.createdBy?.firstName ?? ""} ${e.createdBy?.lastName ?? ""
}`.trim() || "N/A",
customRender: (e) => (
<div
className="d-flex align-items-center cursor-pointer"
@ -182,9 +181,8 @@ const groupByField = (items, field) => {
lastName={e.createdBy?.lastName}
/>
<span className="text-truncate">
{`${e.createdBy?.firstName ?? ""} ${
e.createdBy?.lastName ?? ""
}`.trim() || "N/A"}
{`${e.createdBy?.firstName ?? ""} ${e.createdBy?.lastName ?? ""
}`.trim() || "N/A"}
</span>
</div>
),
@ -216,9 +214,8 @@ const groupByField = (items, field) => {
align: "text-center",
getValue: (e) => (
<span
className={`badge bg-label-${
getColorNameFromHex(e?.status?.color) || "secondary"
}`}
className={`badge bg-label-${getColorNameFromHex(e?.status?.color) || "secondary"
}`}
>
{e.status?.name || "Unknown"}
</span>
@ -238,16 +235,16 @@ const groupByField = (items, field) => {
return <ExpenseTableSkeleton headers={headers} />;
if (isError) return <div>{error?.message}</div>;
const isNoGrouping = !groupBy || groupBy === "none";
const grouped = isNoGrouping
? { All: { key: "All", displayField: "All", items: data?.data ?? [] } }
: groupByField(data?.data ?? [], groupBy);
const isNoGrouping = !groupBy || groupBy === "none";
const grouped = isNoGrouping
? { All: { key: "All", displayField: "All", items: data?.data ?? [] } }
: groupByField(data?.data ?? [], groupBy);
const IsGroupedByDate = [
{key:"none",displayField:"None"},
{ key: "none", displayField: "None" },
{ key: "transactionDate", displayField: "Transaction Date" },
{ key: "createdAt", displayField: "created Date", },
]?.includes(groupBy);
@ -343,26 +340,22 @@ const grouped = isNoGrouping
(col.isAlwaysVisible || groupBy !== col.key) && (
<td
key={col.key}
className={`d-table-cell ml-2 ${
col.align ?? ""
} `}
className={`d-table-cell ml-2 ${col.align ?? ""
} `}
>
<div
className={`d-flex px-2 ${
col.key === "status"
className={`d-flex px-2 ${col.key === "status"
? "justify-content-center"
: ""
}
${
col.key === "amount"
? "justify-content-end"
: ""
}
${
col.key === "submitted"
? "justify-content-center"
: ""
}
}
${col.key === "amount"
? "justify-content-end"
: ""
}
${col.key === "submitted"
? "justify-content-center"
: ""
}
`}
>
{col.customRender
@ -445,7 +438,18 @@ const grouped = isNoGrouping
<tr>
<td colSpan={8} className="text-center border-0 ">
<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>
</td>
</tr>

View File

@ -1,3 +1,4 @@
import moment from "moment";
import React, { useMemo } from "react";
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.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;
}, [filters, filterData]);

View File

@ -76,9 +76,18 @@ const PaymentRequestFilterPanel = forwardRef(({ onApply, handleGroupBy, setFilte
if (value !== undefined) {
setValue(name, value);
} 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
}));
@ -94,7 +103,7 @@ const PaymentRequestFilterPanel = forwardRef(({ onApply, handleGroupBy, setFilte
startDate: moment.utc(formData.startDate, "DD-MM-YYYY").toISOString(),
endDate: moment.utc(formData.endDate, "DD-MM-YYYY").toISOString(),
});
handleGroupBy(selectedGroup.id);
// handleGroupBy(selectedGroup.id);
// closePanel();
};

View File

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

View File

@ -106,10 +106,13 @@ const ExpensePage = () => {
updated[key] = updated[key].filter((v) => v !== id);
filterPanelRef.current?.resetFieldValue(key, updated[key]);
} else if (key === "dateRange") {
// --- START FIX: Use a dedicated function to reset the date range ---
updated.startDate = 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;
});

View File

@ -71,6 +71,11 @@ const PaymentRequestPage = () => {
if (Array.isArray(updated[key])) {
updated[key] = updated[key].filter((v) => v !== id);
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 {
updated[key] = null;
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);
};
};
return (
<PaymentRequestContext.Provider value={contextValue}>