Merge pull request 'Adding_Chips_DailyTask :- Adding Chips in Daily task report.' (#538) from Adding_Chips_DailyTask into Purchase_Invoice_Management

Reviewed-on: #538
merged
This commit is contained in:
pramod.mahajan 2025-12-10 11:01:16 +00:00
commit 01fc302011
19 changed files with 700 additions and 298 deletions

View File

@ -0,0 +1,95 @@
import React, { useMemo } from "react";
import { formatUTCToLocalTime } from "../../utils/dateUtils";
const TaskReportFilterChips = ({ filter, filterData, removeFilterChip, clearFilter }) => {
const data = filterData?.data || filterData || {};
const filterChips = useMemo(() => {
const chips = [];
const addGroup = (ids, list, label, key) => {
if (!ids || ids.length === 0) return;
const items = ids.map((id) => ({
id,
name: list?.find((i) => i.id === id)?.name || id,
}));
chips.push({ key, label, items });
};
// Building
addGroup(filter?.buildingIds, data?.buildings, "Building", "buildingIds");
// Floor
addGroup(filter?.floorIds, data?.floors, "Floor", "floorIds");
// Activities
addGroup(filter?.activityIds, data?.activities, "Activity", "activityIds");
// Date Range Chips
if (filter?.dateFrom || filter?.dateTo) {
chips.push({
key: "date",
label: "Date Range",
items: [
{
id: "date-range",
name: `${filter?.dateFrom ? formatUTCToLocalTime(filter.dateFrom) : ""}
${filter?.dateTo ? " to " + formatUTCToLocalTime(filter.dateTo) : ""}`,
},
],
});
}
return chips;
}, [filter, filterData]);
if (!filterChips.length) return null;
return (
<div className="d-flex flex-wrap align-items-center gap-2 mt-2">
{filterChips.map((chipGroup) => (
<div key={chipGroup.key} className="d-flex align-items-center flex-wrap">
<span className="fw-semibold me-2">{chipGroup.label}:</span>
{chipGroup.items.map((item) => (
<span
key={item.id}
className="d-flex align-items-center bg-light rounded px-2 py-1 me-1"
>
<span>{item.name}</span>
{/* If date chip → remove whole date range */}
{chipGroup.key === "date" ? (
<button
type="button"
className="btn-close btn-close-white btn-sm ms-2"
style={{
filter: "invert(1) grayscale(1)",
opacity: 0.7,
fontSize: "0.6rem",
}}
onClick={() => clearFilter()}
/>
) : (
<button
type="button"
className="btn-close btn-close-white btn-sm ms-2"
style={{
filter: "invert(1) grayscale(1)",
opacity: 0.7,
fontSize: "0.6rem",
}}
onClick={() => removeFilterChip(chipGroup.key, item.id)}
/>
)}
</span>
))}
</div>
))}
</div>
);
};
export default TaskReportFilterChips;

View File

@ -1,4 +1,4 @@
import React, { useState } from "react";
import React, { forwardRef, useEffect, useImperativeHandle, useMemo, useState } from "react";
import { useCurrentService } from "../../hooks/useProjects";
import { useSelectedProject } from "../../slices/apiDataManager";
import { FormProvider, useForm } from "react-hook-form";
@ -11,8 +11,9 @@ import { DateRangePicker1 } from "../common/DateRangePicker";
import SelectMultiple from "../common/SelectMultiple";
import { localToUtc } from "../../utils/appUtils";
import { useTaskFilter } from "../../hooks/useTasks";
import { set } from "date-fns";
const TaskReportFilterPanel = ({ handleFilter }) => {
const TaskReportFilterPanel = forwardRef(({ handleFilter, setFilterdata, clearFilter }, ref) => {
const [resetKey, setResetKey] = useState(0);
const selectedProject = useSelectedProject();
const selectedService = useCurrentService();
@ -23,10 +24,42 @@ const TaskReportFilterPanel = ({ handleFilter }) => {
defaultValues: TaskReportDefaultValue,
});
const dynamicDefaultFilter = useMemo(() => {
return {
...TaskReportDefaultValue,
buildingIds: TaskReportDefaultValue.buildingIds || [],
floorIds: TaskReportDefaultValue.floorIds || [],
activityIds: TaskReportDefaultValue.activityIds || [],
dateFrom: TaskReportDefaultValue.dateFrom,
dateTo: TaskReportDefaultValue.dateTo,
};
}, [selectedProject]);
useImperativeHandle(ref, () => ({
resetFieldValue: (name, value) => {
// Reset specific field
if (value !== undefined) {
setValue(name, value);
} else {
// Fix: Use TaskReportDefaultValue or get current values before setting new ones
// reset({ ...methods.getValues(), [name]: TaskReportDefaultValue[name] }); // Updated to use TaskReportDefaultValue
setValue(name, TaskReportDefaultValue[name]);
}
},
getValues: methods.getValues,
onClear: onClear, // 💡 EXPOSE THE ONCLEAR FUNCTION
}));
useEffect(() => {
if (data && setFilterdata) {
setFilterdata(data);
}
}, [data, setFilterdata]);
const {
register,
reset,
handleSubmit,
setValue,
formState: { errors },
} = methods;
const closePanel = () => {
@ -105,6 +138,6 @@ const TaskReportFilterPanel = ({ handleFilter }) => {
</form>
</FormProvider>
);
};
});
export default TaskReportFilterPanel;

View File

@ -17,8 +17,9 @@ import { useHasUserPermission } from "../../hooks/useHasUserPermission";
import Pagination from "../common/Pagination";
import { TaskReportListSkeleton } from "./TaskRepprtListSkeleton";
import HoverPopup from "../common/HoverPopup";
import TaskReportFilterChips from "./TaskReportFilterChips";
const TaskReportList = () => {
const TaskReportList = ({ filter, filterData, removeFilterChip, clearFilter }) => {
const [currentPage, setCurrentPage] = useState(1);
const [filters, setFilters] = useState({
selectedBuilding: "",
@ -29,7 +30,7 @@ const TaskReportList = () => {
const ApprovedTaskRights = useHasUserPermission(APPROVE_TASK);
const ReportTaskRights = useHasUserPermission(ASSIGN_REPORT_TASK);
const { service, openModal, closeModal, filter } = useDailyProgrssContext();
const { service, openModal, closeModal, filter: contextFilter } = useDailyProgrssContext();
const selectedProject = useSelectedProject();
const { projectNames } = useProjectName();
@ -37,7 +38,7 @@ const TaskReportList = () => {
selectedProject,
ITEMS_PER_PAGE,
currentPage,
service, filter
service, contextFilter
);
const ProgrssReportColumn = [
@ -193,6 +194,16 @@ const TaskReportList = () => {
if (isError) return <div>Loading....</div>;
return (
<div>
<div className="main-content">
<div className="col-12 mb-2 mt-2 px-4">
<TaskReportFilterChips
filter={filter}
filterData={filterData}
removeFilterChip={removeFilterChip}
clearFilter={clearFilter}
/>
</div>
<div className="mt-2 table-responsive text-nowrap">
<table className="table">
<thead>
@ -312,6 +323,7 @@ const TaskReportList = () => {
)
}
</div >
</div >
);
};

View File

@ -59,12 +59,18 @@ const DocumentFilterPanel = forwardRef(
useImperativeHandle(ref, () => ({
resetFieldValue: (name, value) => {
if (value !== undefined) {
setValue(name, value);
setValue(name, value, { shouldValidate: true, shouldDirty: true });
} else {
reset({ ...methods.getValues(), [name]: DocumentFilterDefaultValues[name] });
}
if ((name === "startDate" || name === "endDate") && value === null) {
setTimeout(() => {
setResetKey((prev) => prev + 1);
}, 0);
}
},
getValues: methods.getValues, // optional, to read current filter state
getValues: methods.getValues,
}));
//changes
@ -141,6 +147,7 @@ const DocumentFilterPanel = forwardRef(
defaultRange={false}
resetSignal={resetKey}
maxDate={new Date()}
className="w-100"
/>
</div>

View File

@ -129,6 +129,7 @@ const Documents = ({ Document_Entity, Entity }) => {
else if (key === "dateRange") {
updatedFilters.startDate = null;
updatedFilters.endDate = null;
// These calls correctly tell the DocumentFilterPanel to update its form state:
updatedRef.current?.resetFieldValue("startDate", null);
updatedRef.current?.resetFieldValue("endDate", null);
}
@ -143,7 +144,7 @@ const Documents = ({ Document_Entity, Entity }) => {
<DocumentContext.Provider value={contextValues}>
<div className="mt-2">
<div className="card page-min-h d-flex p-5">
<DocumentFilterChips filters={filters} filterData={filterData} removeFilterChip={removeFilterChip} />
<div className="row align-items-center">
{/* Search */}
<div className="d-flex flex-row gap-2 col-12 col-md-8 col-lg-4 mb-md-0 align-items-center mb-2">
@ -194,6 +195,9 @@ const Documents = ({ Document_Entity, Entity }) => {
)}
</div>
</div>
<div className="ms-n1">
<DocumentFilterChips filters={filters} filterData={filterData} removeFilterChip={removeFilterChip} />
</div>
<DocumentsList
Document_Entity={DocumentEntity}
Entity={Entity}

View File

@ -127,7 +127,7 @@ const ManageEmployee = ({ employeeId, onClosed }) => {
const hasAccessAplication = watch("hasApplicationAccess");
return (
<>
<form onSubmit={handleSubmit(onSubmit)} className="p-sm-0 p-2">
<form onSubmit={handleSubmit(onSubmit)} className="p-sm-2 p-2">
<div className="text-center">
<p className="fs-5 fw-semibold">
{" "}

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
}));
@ -176,8 +184,7 @@ 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)}
>
@ -185,8 +192,7 @@ const ExpenseFilterPanel = forwardRef(
</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)}
>

View File

@ -167,8 +167,7 @@ const groupByField = (items, field) => {
label: "Submitted By",
align: "text-start",
getValue: (e) =>
`${e.createdBy?.firstName ?? ""} ${
e.createdBy?.lastName ?? ""
`${e.createdBy?.firstName ?? ""} ${e.createdBy?.lastName ?? ""
}`.trim() || "N/A",
customRender: (e) => (
<div
@ -182,8 +181,7 @@ const groupByField = (items, field) => {
lastName={e.createdBy?.lastName}
/>
<span className="text-truncate">
{`${e.createdBy?.firstName ?? ""} ${
e.createdBy?.lastName ?? ""
{`${e.createdBy?.firstName ?? ""} ${e.createdBy?.lastName ?? ""
}`.trim() || "N/A"}
</span>
</div>
@ -216,8 +214,7 @@ 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"}
@ -343,23 +340,19 @@ 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"
${col.key === "amount"
? "justify-content-end"
: ""
}
${
col.key === "submitted"
${col.key === "submitted"
? "justify-content-center"
: ""
}
@ -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

@ -105,7 +105,7 @@ const ProjectCard = ({ project, isCore = true }) => {
>
{project?.shortName ? project?.shortName : project?.name}
</h5>
<div className="client-info text-body">
<div className="client-info text-body text-start">
<span>{project?.shortName ? project?.name : ""}</span>
</div>
</div>

View File

@ -0,0 +1,100 @@
import React, { useMemo } from "react";
import { TENANT_STATUS, reference } from "../../utils/constants";
import { formatUTCToLocalTime } from "../../utils/dateUtils";
const TenantFilterChips = ({ filter, filterData, removeFilterChip, clearFilter }) => {
const data = filterData || {};
const filterChips = useMemo(() => {
const chips = [];
const addGroup = (ids, list, label, key, valueKey = "id") => {
if (!ids || ids.length === 0) return;
const items = ids.map((id) => {
const found = list?.find((i) => i[valueKey] === id);
return {
id,
name: found?.name || id,
};
});
chips.push({ key, label, items });
};
// Industries
addGroup(filter?.industryIds, data, "Industries", "industryIds");
// References
addGroup(filter?.references, reference, "References", "references", "val");
// Tenant Status
addGroup(filter?.tenantStatusIds, TENANT_STATUS, "Status", "tenantStatusIds");
// Date Range Chip
if (filter?.startDate || filter?.endDate) {
chips.push({
key: "date",
label: "Date Range",
items: [
{
id: "date-range",
name: `${filter?.startDate ? formatUTCToLocalTime(filter.startDate) : ""}${
filter?.endDate ? " to " + formatUTCToLocalTime(filter.endDate) : ""
}`,
},
],
});
}
return chips;
}, [filter, filterData]);
if (!filterChips.length) return null;
return (
<div className="d-flex flex-wrap align-items-center gap-2 mt-2">
{filterChips.map((chipGroup) => (
<div key={chipGroup.key} className="d-flex align-items-center flex-wrap">
<span className="fw-semibold me-2">{chipGroup.label}:</span>
{chipGroup.items.map((item) => (
<span
key={item.id}
className="d-flex align-items-center bg-light rounded px-2 py-1 me-1"
>
<span>{item.name}</span>
{/* Remove Date Range → remove full filter */}
{chipGroup.key === "date" ? (
<button
type="button"
className="btn-close btn-close-white btn-sm ms-2"
style={{
filter: "invert(1) grayscale(1)",
opacity: 0.7,
fontSize: "0.6rem",
}}
onClick={clearFilter}
/>
) : (
<button
type="button"
className="btn-close btn-close-white btn-sm ms-2"
style={{
filter: "invert(1) grayscale(1)",
opacity: 0.7,
fontSize: "0.6rem",
}}
onClick={() => removeFilterChip(chipGroup.key, item.id)}
/>
)}
</span>
))}
</div>
))}
</div>
);
};
export default TenantFilterChips;

View File

@ -1,5 +1,5 @@
import { zodResolver } from "@hookform/resolvers/zod";
import React, { useState, useCallback, useEffect } from "react";
import React, { useState, useCallback, useEffect, useImperativeHandle, forwardRef, useMemo } from "react";
import { FormProvider, useForm, useFormContext } from "react-hook-form";
import { defaultFilterValues, filterSchema } from "./TenantSchema";
import Label from "../common/Label";
@ -10,16 +10,44 @@ import { DateRangePicker1 } from "../common/DateRangePicker";
import moment from "moment";
import { useLocation } from "react-router-dom";
const TenantFilterPanel = ({ onApply }) => {
const TenantFilterPanel = forwardRef(({ onApply, setFilterdata, clearFilter }, ref) => {
const [resetKey, setResetKey] = useState(0);
const methods = useForm({
resolver: zodResolver(filterSchema),
defaultValues: defaultFilterValues,
});
const { handleSubmit, reset, setValue } = methods;
const { data: industries, isLoading } = useIndustries();
const dynamicDefaultFilter = useMemo(() => {
return {
...defaultFilterValues,
industryIds: defaultFilterValues.industryIds || [],
tenantStatusIds: defaultFilterValues.tenantStatusIds || [],
references: defaultFilterValues.references || [],
startDate: defaultFilterValues.startDate,
endDate: defaultFilterValues.endDate,
};
}, [defaultFilterValues]);
useImperativeHandle(ref, () => ({
resetFieldValue: (name, value) => {
setValue(name, value);
},
resetFields: () => {
reset(defaultFilterValues);
setResetKey(prev => prev + 1); // reset date picker
}
}));
useEffect(() => {
if (industries && setFilterdata) {
setFilterdata(industries);
}
}, [industries, setFilterdata]);
const { handleSubmit, reset } = methods;
const { data: industries = [], isLoading } = useIndustries();
const handleClosePanel = useCallback(() => {
document.querySelector(".offcanvas.show .btn-close")?.click();
@ -32,9 +60,8 @@ const TenantFilterPanel = ({ onApply }) => {
startDate: moment.utc(formData.startDate, "DD-MM-YYYY").toISOString(),
endDate: moment.utc(formData.endDate, "DD-MM-YYYY").toISOString(),
});
handleClosePanel();
},
[onApply, handleClosePanel]
[onApply]
);
@ -65,6 +92,7 @@ const TenantFilterPanel = ({ onApply }) => {
endField="endDate"
resetSignal={resetKey}
defaultRange={false}
className="w-100"
/>
</div>
<div className="text-strat mb-2">
@ -119,6 +147,6 @@ const TenantFilterPanel = ({ onApply }) => {
</form>
</FormProvider>
);
};
});
export default TenantFilterPanel;

View File

@ -7,12 +7,14 @@ import Pagination from "../common/Pagination";
import { TenantTableSkeleton } from "./TenanatSkeleton";
import { useTenantContext } from "../../pages/Tenant/TenantPage";
import { useNavigate } from "react-router-dom";
import TenantFilterChips from "./TenantFilterChips";
const TenantsList = ({
filters,
searchText,
setIsRefetching,
setRefetchFn,
filterData, removeFilterChip, clearFilter
}) => {
const [currentPage, setCurrentPage] = useState(1);
const navigate = useNavigate();
@ -135,6 +137,16 @@ const TenantsList = ({
);
return (
<>
<div className="main-content">
<div className="col-12 mb-2 mt-2 px-4">
<TenantFilterChips
filter={filters}
filterData={filterData}
removeFilterChip={removeFilterChip}
clearFilter={clearFilter}
/>
</div>
<div className=" mt-3">
<div className=" text-nowrap table-responsive">
<table className="table border-top dataTable text-nowrap">
@ -185,6 +197,7 @@ const TenantsList = ({
)}
</div>
</div>
</div>
</>
);
};

View File

@ -1,4 +1,4 @@
import React, { createContext, useContext, useEffect, useState } from "react";
import React, { createContext, useContext, useEffect, useRef, useState } from "react";
import Breadcrumb from "../../components/common/Breadcrumb";
import { useServices } from "../../hooks/masterHook/useMaster";
import TaskReportList from "../../components/DailyProgressRport/TaskReportList";
@ -13,6 +13,7 @@ import { useSelectedProject } from "../../slices/apiDataManager";
import SelectField from "../../components/common/Forms/SelectField";
import { AppFormController } from "../../hooks/appHooks/useAppForm";
import { useForm } from "react-hook-form";
import { TaskReportDefaultValue } from "../../components/DailyProgressRport/TaskRportScheam";
const DailyProgrssContext = createContext();
export const useDailyProgrssContext = () => {
@ -30,8 +31,9 @@ const DailyProgrssReport = () => {
const [service, setService] = useState("");
const [filter, setFilter] = useState('')
const { setOffcanvasContent, setShowTrigger } = useFab();
const updatedRef = useRef();
const { data, isLoading, isError, error } = useProjectAssignedServices(selectedProject);
const [filterData, setFilterdata] = useState(null);
const [modal, setModal] = useState({ type: null, data: null });
const openModal = (type, data = null) => setModal({ type, data });
@ -49,20 +51,40 @@ const DailyProgrssReport = () => {
serviceFilter: ""
}
});
const clearFilter = () => {
updatedRef.current?.onClear();
};
const handleFilter = (filterObj) => {
setFilter(filterObj)
}
useEffect(() => {
setShowTrigger(true);
setOffcanvasContent("Report Filter", <TaskReportFilterPanel handleFilter={handleFilter} />);
setOffcanvasContent("Report Filter", <TaskReportFilterPanel handleFilter={handleFilter} ref={updatedRef}
clearFilter={clearFilter}
setFilterdata={setFilterdata} />);
return () => {
setShowTrigger(false);
setOffcanvasContent("", null);
};
}, []);
const handleRemoveChip = (key, id) => {
setFilter((prev) => {
const updated = { ...prev };
if (Array.isArray(updated[key])) {
updated[key] = updated[key].filter((v) => v !== id);
setTimeout(() => updatedRef.current?.resetFieldValue(key, updated[key]), 0);
} else {
updated[key] = null;
setTimeout(() => updatedRef.current?.resetFieldValue(key, null), 0);
}
return updated;
});
};
return (
<div className="container-fluid">
<DailyProgrssContext.Provider value={contextDispatcher}>
@ -97,7 +119,7 @@ const DailyProgrssReport = () => {
]}
/>
<div className="card card-fullscreen p-5">
<div className="card page-min-h p-5">
{data?.length > 0 && (
<div className="col-sm-4 col-md-3 col-12 text-start">
<AppFormController
@ -125,7 +147,10 @@ const DailyProgrssReport = () => {
)}
<div>
<TaskReportList />
<TaskReportList filter={filter}
filterData={filterData}
removeFilterChip={handleRemoveChip}
clearFilter={clearFilter} />
</div>
</div>

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);

View File

@ -5,6 +5,7 @@ import React, {
useContext,
useCallback,
useMemo,
useRef,
} from "react";
import { useForm } from "react-hook-form";
import { zodResolver } from "@hookform/resolvers/zod";
@ -59,6 +60,7 @@ const TenantPage = () => {
const [refetchFn, setRefetchFn] = useState(null);
const [filters, setFilters] = useState();
// ---------- Hooks ----------
const debouncedSearch = useDebounce(searchText, 500);
const { setOffcanvasContent, setShowTrigger } = useFab();
@ -66,6 +68,9 @@ const TenantPage = () => {
const isSuperTenant = useHasUserPermission(SUPPER_TENANT);
const canManageTenants = useHasUserPermission(MANAGE_TENANTS);
const isSelfTenant = useHasUserPermission(VIEW_TENANTS);
const updatedRef = useRef();
const [filterData, setFilterdata] = useState(null);
const [filter, setFilter] = useState('')
const methods = useForm({
resolver: zodResolver(filterSchema),
@ -77,8 +82,18 @@ const TenantPage = () => {
setFilters(values);
}, []);
const clearFilter = () => {
setFilters(defaultFilterValues); // update active filters
updatedRef.current?.resetFields?.(); // reset RHF fields in panel
};
const filterPanelElement = useMemo(
() => <TenantFilterPanel onApply={handleApplyFilters} />,
() => <TenantFilterPanel
onApply={handleApplyFilters}
ref={updatedRef}
clearFilter={clearFilter}
setFilterdata={setFilterdata}
/>,
[handleApplyFilters]
);
// ---------- Fab Filter Panel ----------
@ -112,6 +127,20 @@ const TenantPage = () => {
// ---------- Context Value ----------
const contextValue = {};
const handleRemoveChip = (key, id) => {
setFilters((prev) => {
const updated = { ...prev };
if (Array.isArray(updated[key])) {
updated[key] = updated[key].filter((v) => v !== id);
} else {
updated[key] = null;
}
setTimeout(() => updatedRef.current?.resetFieldValue(key, updated[key]), 0);
return updated;
});
};
return (
<TenantContext.Provider value={contextValue}>
<div className="container-fluid">
@ -121,7 +150,7 @@ const TenantPage = () => {
{ label: "Tenant", link: null },
]}
/>
<div className="card text-center my-4 p-md-5 px-1 py-3 pb-10">
<div className="card page-min-h text-center my-4 p-md-5 px-1 py-3 pb-10">
{/* Super Tenant Actions */}
{isSuperTenant && (
<div className="p-0">
@ -157,10 +186,13 @@ const TenantPage = () => {
{/* Tenant List or Access Denied */}
{isSuperTenant ? (
<TenantsList
setRefetchFn={setRefetchFn}
setIsRefetching={setIsRefetching}
filters={filters}
searchText={debouncedSearch}
setIsRefetching={setIsRefetching}
setRefetchFn={setRefetchFn}
filterData={filterData}
removeFilterChip={handleRemoveChip}
clearFilter={clearFilter}
/>
) : !isSelfTenant ? (
<div className="text-center my-4 p-2">