added updation for fllter

This commit is contained in:
pramod.mahajan 2025-09-29 11:52:11 +05:30
parent 22514b1fa0
commit 72424eee53
14 changed files with 178 additions and 148 deletions

View File

@ -1,36 +1,66 @@
import React, { useState } from 'react'
import { useCurrentService, useProjectInfra } from '../../hooks/useProjects'
import { useSelectedProject } from '../../slices/apiDataManager';
import { FormProvider, useForm } from 'react-hook-form';
import { zodResolver } from '@hookform/resolvers/zod';
import { TaskReportDefaultValue, TaskReportFilterSchema } from './TaskRportScheam';
import { DateRangePicker1 } from '../common/DateRangePicker';
import SelectMultiple from '../common/SelectMultiple';
import React, { useState } from "react";
import { useCurrentService, useProjectInfra } from "../../hooks/useProjects";
import { useSelectedProject } from "../../slices/apiDataManager";
import { FormProvider, useForm } from "react-hook-form";
import { zodResolver } from "@hookform/resolvers/zod";
import {
TaskReportDefaultValue,
TaskReportFilterSchema,
} from "./TaskRportScheam";
import { DateRangePicker1 } from "../common/DateRangePicker";
import SelectMultiple from "../common/SelectMultiple";
import { localToUtc } from "../../utils/appUtils";
const TaskReportFilterPanel = () => {
const [resetKey, setResetKey] = useState(0);
const selectedProjec = useSelectedProject()
const TaskReportFilterPanel = ({ handleFilter }) => {
const [resetKey, setResetKey] = useState(0);
const selectedProjec = useSelectedProject();
const selectedService = useCurrentService();
const {projectInfra, isLoading, error, isFetched } = useProjectInfra(selectedProjec,selectedService);
const methods = useForm({resolver:zodResolver(TaskReportFilterSchema),defaultValues:TaskReportDefaultValue})
const {register,reset,handleSubmit, formState:{errors}} = methods;
const onSubmit =(formData)=>{}
const { projectInfra, isLoading, error, isFetched } = useProjectInfra(
selectedProjec,
selectedService
);
const methods = useForm({
resolver: zodResolver(TaskReportFilterSchema),
defaultValues: TaskReportDefaultValue,
});
const {
register,
reset,
handleSubmit,
formState: { errors },
} = methods;
const onSubmit = (formData) => {
console.log(formData)
const filterPayload = {
startDate:localToUtc(formData.startDate),
endDate:localToUtc(formData.endDate)
}
handleFilter(filterPayload);
};
const onClear =()=>{
setResetKey((prev) => prev + 1);
reset(TaskReportDefaultValue)
}
return (
<FormProvider {...methods}>
<form onSubmit={handleSubmit(onSubmit)} className="p-2 text-start">
<div className="mb-3 w-100">
<FormProvider {...methods}>
<form onSubmit={handleSubmit(onSubmit)} className="p-2 text-start">
<div className="mb-3 w-100">
<label className="fw-semibold">Choose Date Range:</label>
<DateRangePicker1
placeholder="DD-MM-YYYY To DD-MM-YYYY"
startField="startDate"
endField="endDate"
resetSignal={resetKey}
defaultRange={true}
/>
</div>
<label className="fw-semibold">Choose Date Range:</label>
<DateRangePicker1
placeholder="DD-MM-YYYY To DD-MM-YYYY"
startField="startDate"
endField="endDate"
resetSignal={resetKey}
defaultRange={false}
/>
</div>
<div className="row g-2">
{/* <div className="row g-2">
<SelectMultiple
name="buildingIds"
label="Projects"
@ -47,23 +77,19 @@ const TaskReportFilterPanel = () => {
labelKey="floorName"
valueKey="id"
/>
</div>
</div> */}
<div className="d-flex justify-content-end py-3 gap-2">
<button type="button" className="btn btn-label-secondary btn-sm">
Clear
</button>
<button type="submit" className="btn btn-primary btn-sm">
Apply
</button>
</div>
</form>
</FormProvider>
);
};
<div className="d-flex justify-content-end py-3 gap-2">
<button
type="button"
className="btn btn-label-secondary btn-xs"
>
Clear
</button>
<button type="submit" className="btn btn-primary btn-xs">
Apply
</button>
</div>
</form>
</FormProvider>
)
}
export default TaskReportFilterPanel
export default TaskReportFilterPanel;

View File

@ -29,7 +29,7 @@ const TaskReportList = () => {
const ApprovedTaskRights = useHasUserPermission(APPROVE_TASK);
const ReportTaskRights = useHasUserPermission(ASSIGN_REPORT_TASK);
const { service, openModal, closeModal } = useDailyProgrssContext();
const { service, openModal, closeModal,filter } = useDailyProgrssContext();
const selectedProject = useSelectedProject();
const { projectNames } = useProjectName();
@ -37,7 +37,7 @@ const TaskReportList = () => {
selectedProject,
ITEMS_PER_PAGE,
currentPage,
service
service,filter
);
const ProgrssReportColumn = [

View File

@ -1,15 +1,15 @@
import { z } from "zod";
export const TaskReportFilterSchema = z.object({
buildingIds: z.array(z.string()).optional(),
floorIds: z.array(z.string()).optional(),
// buildingIds: z.array(z.string()).optional(),
// floorIds: z.array(z.string()).optional(),
startDate: z.string().optional(),
endDate: z.string().optional(),
});
export const TaskReportDefaultValue = {
buildingIds:[],
floorIds:[],
// buildingIds:[],
// floorIds:[],
startDate:null,
endDate:null
}

View File

@ -200,12 +200,12 @@ const ExpenseFilterPanel = ({ onApply, handleGroupBy }) => {
<div className="d-flex justify-content-end py-3 gap-2">
<button
type="button"
className="btn btn-label-secondary btn-xs"
className="btn btn-label-secondary btn-sm"
onClick={onClear}
>
Clear
</button>
<button type="submit" className="btn btn-primary btn-xs">
<button type="submit" className="btn btn-primary btn-sm">
Apply
</button>
</div>

View File

@ -19,7 +19,12 @@ const ManagOrg = () => {
const { data: service, isLoading } = useGlobalServices();
const { flowType, orgData, startStep, onOpen, onClose, prevStep } =
useOrganizationModal();
const {data:organization,isLoading:organizationLoading,isError,error} = useOrganization(orgData?.id);
const {
data: organization,
isLoading: organizationLoading,
isError,
error,
} = useOrganization(orgData?.id);
const method = useForm({
resolver: zodResolver(organizationSchema),
@ -47,25 +52,27 @@ const ManagOrg = () => {
onOpen({ startStep: 1 });
onClose();
});
console.log(organization)
// Prefill form if editing
useEffect(() => {
if (orgData) {
console.log(orgData);
if (organization) {
reset({
name: orgData.name || "",
contactPerson: orgData.contactPerson || "",
contactNumber: orgData.contactNumber || "",
email: orgData.email || "",
serviceIds: orgData.services?.map((s) => s.id) || [],
address: orgData.address || "",
name: organization.name || "",
contactPerson: organization.contactPerson || "",
contactNumber: organization.contactNumber || "",
email: organization.email || "",
serviceIds: organization.services?.map((s) => s.id) || [],
address: organization.address || "",
});
}
}, [orgData, reset]);
}, [organization, reset, service?.data]);
const onSubmit = (payload) => {
if (orgData?.id) {
updateOrganization({ id: orgData.id, ...payload });
const onSubmit = (formData) => {
let payload = { ...formData };
if (organization?.id) {
updateOrganization({
orgId: organization.id,
payload: { ...payload, id: organization.id },
});
} else {
createOrganization(payload);
}
@ -144,11 +151,11 @@ console.log(organization)
<div className="mb-1 text-start">
<SelectMultiple
name="serviceIds"
label="Services"
required
label="Select Service"
options={service?.data}
labelKey="name"
valueKey="id"
options={service?.data || []}
required = {true}
IsLoading={isLoading}
/>
{errors.serviceIds && (
<span className="danger-text">{errors.serviceIds.message}</span>

View File

@ -19,7 +19,7 @@ export const organizationSchema = z.object({
.email("Invalid email address"),
serviceIds: z
.array(z.string())
.min(1, { message: "Please insert service id" }),
.min(1, { message: "Service isrequired" }),
});
export const defaultOrganizationValues = {

View File

@ -106,13 +106,13 @@ const TenantFilterPanel = ({ onApply }) => {
<div className="d-flex justify-content-end py-3 gap-2">
<button
type="button"
className="btn btn-label-secondary btn-xs"
className="btn btn-label-secondary btn-sm"
onClick={onClear}
>
Clear
</button>
<button type="submit" className="btn btn-primary btn-xs" >
<button type="submit" className="btn btn-primary btn-sm" >
Apply
</button>
</div>

View File

@ -11,22 +11,21 @@ const SelectMultiple = ({
labelKey = "name",
valueKey = "id",
placeholder = "Please select...",
IsLoading = false,
required = false
IsLoading = false,required = false
}) => {
const { setValue, watch } = useFormContext();
const selectedValues = watch(name) || [];
const { setValue, watch,register } = useFormContext();
useEffect(() => {
register(name, { value: [] });
}, [register, name]);
const selectedValues = watch(name) || [];
const [isOpen, setIsOpen] = useState(false);
const [searchText, setSearchText] = useState("");
const containerRef = useRef(null);
const dropdownRef = useRef(null);
const [dropdownStyles, setDropdownStyles] = useState({
top: 0,
left: 0,
width: 0,
});
const [dropdownStyles, setDropdownStyles] = useState({ top: 0, left: 0, width: 0 });
useEffect(() => {
const handleClickOutside = (e) => {
@ -65,10 +64,14 @@ const SelectMultiple = ({
setValue(name, updated, { shouldValidate: true });
};
const filteredOptions = options.filter((item) => {
const label = getLabel(item);
return label?.toLowerCase().includes(searchText.toLowerCase());
});
const filteredOptions = (options || []).filter((item) => {
const label = getLabel(item);
return (
typeof label === "string" &&
label.toLowerCase().includes(searchText.toLowerCase())
);
});
const dropdownElement = (
<div
@ -106,14 +109,8 @@ const SelectMultiple = ({
return (
<div
key={valueVal}
className={`multi-select-dropdown-option ${
isChecked ? "selected" : ""
}`}
style={{
display: "flex",
alignItems: "center",
padding: "4px 8px",
}}
className={`multi-select-dropdown-option ${isChecked ? "selected" : ""}`}
style={{ display: "flex", alignItems: "center", padding: "4px 8px" }}
>
<input
type="checkbox"
@ -142,13 +139,9 @@ const SelectMultiple = ({
return (
<>
<div
ref={containerRef}
className="multi-select-dropdown-container"
style={{ position: "relative" }}
>
<Label required={required}>{label}</Label>
<div ref={containerRef} className="multi-select-dropdown-container" style={{ position: "relative" }}>
<label className="form-label mb-1">{label}</label>
<Label className={name} required={required}></Label>
<div
className="multi-select-dropdown-header"
@ -157,9 +150,7 @@ const SelectMultiple = ({
>
<span
className={
selectedValues.length > 0
? "placeholder-style-selected"
: "placeholder-style"
selectedValues.length > 0 ? "placeholder-style-selected" : "placeholder-style"
}
>
<div className="selected-badges-container">
@ -168,10 +159,7 @@ const SelectMultiple = ({
const found = options.find((opt) => opt[valueKey] === val);
const label = found ? getLabel(found) : "";
return (
<span
key={val}
className="badge badge-selected-item mx-1 mb-1"
>
<span key={val} className="badge badge-selected-item mx-1 mb-1">
{label}
</span>
);

View File

@ -40,7 +40,10 @@ export const useOrganizationModal = () => {
export const useOrganization=(id)=>{
return useQuery({
queryKey:["organization",id],
queryFn:async()=> await OrganizationRepository.getOrganizaion(id),
queryFn:async()=> {
const resp = await await OrganizationRepository.getOrganizaion(id);
return resp.data
},
enabled:!!id
})
}
@ -171,7 +174,7 @@ export const useAssignOrgToTenant = (onSuccessCallback) => {
},
});
};
export const useUpdateOrganization = () => {
export const useUpdateOrganization = (onSuccessCallback) => {
const useClient = useQueryClient();
return useMutation({
mutationFn: async ({orgId,payload}) =>

View File

@ -21,7 +21,7 @@ export const useDailyProgrssContext = () => {
const DailyProgrssReport = () => {
const [service, setService] = useState("");
const [filter,setFilter] = useState('')
const { setOffcanvasContent, setShowTrigger } = useFab();
const { data, isLoading, isError, error } = useServices();
@ -30,15 +30,20 @@ const DailyProgrssReport = () => {
const openModal = (type, data = null) => setModal({ type, data });
const closeModal = () => setModal({ type: null, data: null });
const contextObj = {
const contextDispatcher = {
service,
openModal,
closeModal,
filter,
};
const handleFilter = (filterObj)=>{
setFilter(filterObj)
}
useEffect(() => {
setShowTrigger(true);
setOffcanvasContent("Report Filter", <TaskReportFilterPanel />);
setOffcanvasContent("Report Filter", <TaskReportFilterPanel handleFilter={handleFilter} />);
return () => {
setShowTrigger(false);
@ -47,7 +52,7 @@ const DailyProgrssReport = () => {
}, []);
return (
<div className="container-fluid">
<DailyProgrssContext.Provider value={contextObj}>
<DailyProgrssContext.Provider value={contextDispatcher}>
{modal.type === "report" && (
<GlobalModel isOpen size="md" closeModal={closeModal}>
<ReportTask report={modal.data} closeModal={closeModal} />

View File

@ -2,7 +2,7 @@ import { api } from "../utils/axiosClient";
const OrganizationRepository = {
createOrganization: (data) => api.post("/api/Organization/create", data),
updateOrganizaion:(id,data)=>api.put(`/api/Organization/edit/${id}`),
updateOrganizaion:(id,data)=>api.put(`/api/Organization/edit/${id}`,data),
getOrganizaion:(id)=>api.get(`/api/Organization/details/${id}`),
getOrganizationList: (pageSize, pageNumber, active, sprid, searchString) => {
return api.get(

View File

@ -12,6 +12,7 @@ export const TasksRepository = {
const payloadJsonString = encodeURIComponent(JSON.stringify(filter));
url += `&filter=${payloadJsonString}`;
}
debugger
return api.get(url);
},

View File

@ -1,31 +1,31 @@
import { useEffect, useState } from "react";
import { format, parseISO } from "date-fns";
export const formatFileSize=(bytes)=> {
export const formatFileSize = (bytes) => {
if (bytes < 1024) return bytes + " B";
else if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(2) + " KB";
else return (bytes / (1024 * 1024)).toFixed(2) + " MB";
}
};
export const AppColorconfig = {
colors: {
primary: '#696cff',
secondary: '#8592a3',
success: '#71dd37',
info: '#03c3ec',
warning: '#ffab00',
danger: '#ff3e1d',
dark: '#233446',
black: '#000',
white: '#fff',
cardColor: '#fff',
bodyBg: '#f5f5f9',
bodyColor: '#697a8d',
headingColor: '#566a7f',
textMuted: '#a1acb8',
borderColor: '#eceef1'
}
primary: "#696cff",
secondary: "#8592a3",
success: "#71dd37",
info: "#03c3ec",
warning: "#ffab00",
danger: "#ff3e1d",
dark: "#233446",
black: "#000",
white: "#fff",
cardColor: "#fff",
bodyBg: "#f5f5f9",
bodyColor: "#697a8d",
headingColor: "#566a7f",
textMuted: "#a1acb8",
borderColor: "#eceef1",
},
};
export const getColorNameFromHex = (hex) => {
const normalizedHex = hex?.replace(/'/g, '').toLowerCase();
const normalizedHex = hex?.replace(/'/g, "").toLowerCase();
const colors = AppColorconfig.colors;
for (const [name, value] of Object.entries(colors)) {
@ -62,18 +62,19 @@ export const getIconByFileType = (type = "") => {
return "bx bx-file";
};
export const normalizeAllowedContentTypes = (allowedContentType) => {
if (!allowedContentType) return [];
if (Array.isArray(allowedContentType)) return allowedContentType;
if (typeof allowedContentType === "string") return allowedContentType.split(",");
if (typeof allowedContentType === "string")
return allowedContentType.split(",");
return [];
};
export function localToUtc(localDateString) {
if (!localDateString || localDateString.trim() === "") return null; // return null instead of undefined
const date = new Date(localDateString);
if (isNaN(date.getTime())) return null; // invalid date check
return date.toISOString();
if (!localDateString || localDateString.trim() === "") return null;
const [day, month, year] = localDateString.split("-");
const date = new Date(`${year}-${month}-${day}T00:00:00`);
return isNaN(date.getTime()) ? null : date.toISOString();
}

View File

@ -16,7 +16,6 @@ export const axiosClient = axios.create({
// Auto retry failed requests (e.g., network issues)
axiosRetry(axiosClient, { retries: 3 });
debugger
// Request Interceptor Add Bearer token if required
axiosClient.interceptors.request.use(
async (config) => {