added pagination and partially added filter

This commit is contained in:
pramod mahajan 2025-08-09 10:30:06 +05:30
parent fb3b55c694
commit 4bff065153
9 changed files with 304 additions and 177 deletions

View File

@ -0,0 +1,40 @@
import { zodResolver } from '@hookform/resolvers/zod'
import React from 'react'
import { FormProvider, useForm, useFormContext } from 'react-hook-form'
import { defaultFilterValues, filterSchema } from './TenantSchema'
import Label from '../common/Label'
import SelectMultiple from '../common/SelectMultiple'
import { useIndustries } from '../../hooks/useTenant'
const TenantFilterPanel = () => {
const method = useForm({
resolver:zodResolver(filterSchema),
defaultValues:defaultFilterValues
})
const {control, register, handleSubmit, reset, watch} = method;
const {data,isError,isLoading} = useIndustries()
console.log(data)
const onSubmit =()=>{
}
if(isLoading) return <div className='text-center'>Loading...</div>
return (
<FormProvider {...method}>
<form onsubmit={(handleSubmit(onSubmit))} >
<div className='text-start mb-1'>
<SelectMultiple
name="industryIds"
label="Industries :"
options={data}
labelKey="name"
valueKey="id"
/>
</div>
</form>
</FormProvider>
)
}
export default TenantFilterPanel

View File

@ -64,6 +64,24 @@ export const subscriptionDefaultValues = {
autoRenew: false, autoRenew: false,
}; };
export const filterSchema = z.object({
industryIds: z.array(z.string()).optional(),
createdByIds: z.array(z.string()).optional(),
tenantStatusIds: z.array(z.string()).optional(),
references: z.array(z.string()).optional(),
startDate: z.string().optional(),
endDate: z.string().optional(),
});
export const defaultFilterValues = {
industryIds: [],
createdByIds: [],
tenantStatusIds: [],
references: [],
startDate: "YYYY-MM-DDTHH:mm:ssZ",
endDate: "YYYY-MM-DDTHH:mm:ssZ",
};
export const getStepFields = (stepIndex) => { export const getStepFields = (stepIndex) => {
const stepFieldMap = { const stepFieldMap = {
0: [ 0: [

View File

@ -3,12 +3,14 @@ import { useTenants } from "../../hooks/useTenant";
import { ITEMS_PER_PAGE } from "../../utils/constants"; import { ITEMS_PER_PAGE } from "../../utils/constants";
import { getTenantStatus } from "../../utils/dateUtils"; import { getTenantStatus } from "../../utils/dateUtils";
import IconButton from "../common/IconButton"; import IconButton from "../common/IconButton";
import Pagination from "../common/Pagination";
const TenantsList = ({searchText}) => { const TenantsList = ({searchText}) => {
const [currentPage, setCurrentPage] = useState(1); const [currentPage, setCurrentPage] = useState(1);
const { data, isLoading, isError, isInitialLoading, error } = useTenants( const { data, isLoading, isError, isInitialLoading, error } = useTenants(
ITEMS_PER_PAGE, currentPage,
currentPage {},
searchText,
); );
const paginate = (page) => { const paginate = (page) => {
@ -131,6 +133,13 @@ const TenantsList = ({searchText}) => {
)} )}
</tbody> </tbody>
</table> </table>
{data?.data?.length > 0 && (
<Pagination
currentPage={currentPage}
totalPages={data.totalPages}
onPageChange={paginate}
/>
)}
</div> </div>
</div> </div>
</> </>

View File

@ -1,118 +1,124 @@
[ [
{ {
"header": "", "header": "",
"items": [ "items": [
{ {
"text": "Dashboard", "text": "Dashboard",
"icon": "bx bx-home", "icon": "bx bx-home",
"available": true, "available": true,
"link": "/dashboard" "link": "/dashboard"
}, },
{ {
"text": "Projects", "text": "Projects",
"icon": "bx bx-building-house", "icon": "bx bx-building-house",
"available": true, "available": true,
"link": "/projects" "link": "/projects"
}, },
{ {
"text": "Employees", "text": "Employees",
"icon": "bx bx-user", "icon": "bx bx-user",
"available": true, "available": true,
"link": "/employees" "link": "/employees"
}, },
{ {
"text": "Activities", "text": "Activities",
"icon": "bx bx-list-ul", "icon": "bx bx-list-ul",
"available": true, "available": true,
"link": "", "link": "",
"submenu": [ "submenu": [
{ {
"text": "Attendance", "text": "Attendance",
"available": true, "available": true,
"link": "/activities/Attendance" "link": "/activities/Attendance"
}, },
{ {
"text": "Daily Task Planning", "text": "Daily Task Planning",
"available": true, "available": true,
"link": "/activities/task" "link": "/activities/task"
}, },
{ {
"text": "Daily Progress Report", "text": "Daily Progress Report",
"available": true, "available": true,
"link": "/activities/records" "link": "/activities/records"
}, },
{ {
"text": "Project Report", "text": "Project Report",
"available": true, "available": true,
"link": "/activities/reports" "link": "/activities/reports"
}, },
{ {
"text": "Daily Expenses", "text": "Daily Expenses",
"available": true, "available": true,
"link": "/activities/reports" "link": "/activities/reports"
} }
]
},
{
"text": "Directory",
"icon": "bx bx-group",
"available": true,
"link": "/directory"
},
{
"text": "Image Gallary",
"icon": "bx bx-images",
"available": true,
"link": "/gallary"
},
{
"text": "Administration",
"icon": "bx bx-box",
"available": true,
"link": "",
"submenu": [
{
"text": "Users",
"available": true,
"link": "/employees/"
},
{
"text": "Masters",
"available": true,
"link": "/masters"
}
]
},
{
"text": "Inventory",
"icon": "bx bx-store",
"available": true,
"link": "/inventory"
}
] ]
}, },
{ {
"header": "", "text": "Directory",
"items": [ "icon": "bx bx-group",
{ "available": true,
"text": "Support", "link": "/directory"
"icon": "bx bx-copy", },
"available": true, {
"link": "/help/support" "text": "Expense",
}, "icon": "bx bx-receipt",
{ "available": true,
"text": "Documentation", "link": "/expenses"
"available": true, },
"icon": "bx bx-book-reader", {
"link": "/help/docs" "text": "Image Gallary",
}, "icon": "bx bx-images",
{ "available": true,
"text": "Help Desk", "link": "/gallary"
"available": true, },
"link": "/help/connect", {
"icon": "bx bx-question-mark" "text": "Administration",
} "icon": "bx bx-box",
"available": true,
"link": "",
"submenu": [
{
"text": "Tenant",
"available": true,
"link": "/tenants/"
},
{
"text": "Masters",
"available": true,
"link": "/masters"
}
] ]
} },
{
"text": "Inventory",
"icon": "bx bx-store",
"available": true,
"link": "/inventory"
}
]
},
{
"header": "",
"items": [
{
"text": "Support",
"icon": "bx bx-copy",
"available": true,
"link": "/help/support"
},
{
"text": "Documentation",
"available": true,
"icon": "bx bx-book-reader",
"link": "/help/docs"
},
{
"text": "Help Desk",
"available": true,
"link": "/help/connect",
"icon": "bx bx-question-mark"
}
]
}
] ]

View File

@ -4,23 +4,22 @@ import { MarketRepository } from "../repositories/MarketRepository";
import showToast from "../services/toastService"; import showToast from "../services/toastService";
import { useDispatch } from "react-redux"; import { useDispatch } from "react-redux";
import { setCurrentTenant } from "../slices/globalVariablesSlice"; import { setCurrentTenant } from "../slices/globalVariablesSlice";
import { ITEMS_PER_PAGE } from "../utils/constants";
export const useTenants = ( export const useTenants = (pageNumber, filter = {}, searchString = "") => {
pageSize,
pageNumber,
filter,
searchString = ""
) => {
return useQuery({ return useQuery({
queryKey: ["Tenants", pageNumber, pageSize], queryKey: ["Tenants", pageNumber, JSON.stringify(filter), searchString],
queryFn: async () => { queryFn: async () => {
const response = await TenantRepository.getTenantList( const response = await TenantRepository.getTenantList(
pageSize, ITEMS_PER_PAGE,
pageNumber, pageNumber,
filter,
searchString
); );
return response.data; return response.data;
}, },
keepPreviousData: true, keepPreviousData: true,
staleTime: 60_000
}); });
}; };

View File

@ -48,11 +48,13 @@ const DailyTask = () => {
dateRange?.endDate || null dateRange?.endDate || null
); );
useEffect(() => { useEffect(() => {
if(selectedProject == null){ if (!selectedProject?.id && projectNames.length > 0) {
dispatch(setProjectId(projectNames[0]?.id)); dispatch(setProjectId(projectNames[0].id));
} }
},[])
}, [selectedProject, projectNames, dispatch]);
const [TaskLists, setTaskLists] = useState([]); const [TaskLists, setTaskLists] = useState([]);
const [dates, setDates] = useState([]); const [dates, setDates] = useState([]);
const popoverRefs = useRef([]); const popoverRefs = useRef([]);

View File

@ -1,9 +1,19 @@
import React, { useState,createContext } from "react"; import React, { useState, createContext, useEffect } from "react";
import { useForm } from "react-hook-form";
import { zodResolver } from "@hookform/resolvers/zod";
// ------Components-------
import Breadcrumb from "../../components/common/Breadcrumb"; import Breadcrumb from "../../components/common/Breadcrumb";
import TenantsList from "../../components/Tenanat/TenantsList"; import TenantsList from "../../components/Tenanat/TenantsList";
import { useNavigate } from "react-router-dom"; import { useNavigate } from "react-router-dom";
import { useDebounce } from "../../utils/appUtils";
import { useFab } from "../../Context/FabContext";
//---------- Schema and defaultValues----
import { defaultFilterValues, filterSchema } from "../../components/Tenanat/TenantSchema";
import TenantFilterPanel from "../../components/Tenanat/TenantFilterPanel";
// This is context that wrapping all components tenant releated , but must pass inside 'TenantContext.Provider'
export const TenantContext = createContext(); export const TenantContext = createContext();
export const useTenantContext = () => { export const useTenantContext = () => {
const context = useContext(TenantContext); const context = useContext(TenantContext);
@ -12,52 +22,72 @@ export const useTenantContext = () => {
} }
return context; return context;
}; };
const TenantPage = () => { const TenantPage = () => {
const [searchText, setSearchText] = useState(""); const [searchText, setSearchText] = useState("");
const debouncedSearch = useDebounce(searchText, 500);
const contextValue = {};
const navigate = useNavigate(); const navigate = useNavigate();
const contextValue = { const { setOffcanvasContent, setShowTrigger } = useFab();
};
return (
<TenantContext.Provider value={contextValue}>
<div className="container-fluid">
<Breadcrumb
data={[
{ label: "Home", link: "/dashboard" },
{ label: "Tenant", link: null },
]}
/>
<div className="card d-flex p-3">
<div className="row align-items-center">
<div className="col-6 col-md-6 col-lg-3 mb-md-0">
<input
type="search"
className="form-control form-control-sm"
placeholder="Search..."
/>
</div>
<div className="col-6 col-md-6 col-lg-9 text-end">
<button // This Hook allow us to right-side bar for filter Tenants
type="button"
data-bs-toggle="tooltip" useEffect(() => {
data-bs-offset="0,8" setShowTrigger(true);
data-bs-placement="top" setOffcanvasContent(
data-bs-custom-class="tooltip" "Expense Filters",
title="Add New Tenant" <TenantFilterPanel/>
className="p-1 bg-primary rounded-circle" );
onClick={() => navigate("/tenants/new-tenant")} return () => {
> setShowTrigger(false);
<i className="bx bx-plus fs-4 text-white"></i> setOffcanvasContent("", null);
</button> };
}, []);
return (
<TenantContext.Provider value={contextValue}>
<div className="container-fluid">
<Breadcrumb
data={[
{ label: "Home", link: "/dashboard" },
{ label: "Tenant", link: null },
]}
/>
<div className="card d-flex p-2">
<div className="row align-items-center">
<div className="col-6 col-md-6 col-lg-3 mb-md-0">
<input
type="search"
value={searchText}
onChange={(e) => setSearchText(e.target.value)}
className="form-control form-control-sm"
placeholder="Search..."
/>
</div>
<div className="col-6 col-md-6 col-lg-9 text-end">
<button
type="button"
data-bs-toggle="tooltip"
data-bs-offset="0,8"
data-bs-placement="top"
data-bs-custom-class="tooltip"
title="Add New Tenant"
className="p-1 bg-primary rounded-circle"
onClick={() => navigate("/tenants/new-tenant")}
>
<i className="bx bx-plus fs-4 text-white"></i>
</button>
</div>
</div> </div>
</div> </div>
</div>
<TenantsList searchText ={searchText} /> <TenantsList searchText={debouncedSearch} />
</div> </div>
</TenantContext.Provider> </TenantContext.Provider>
); );
}; };

View File

@ -40,6 +40,7 @@ import Directory from "../pages/Directory/Directory";
import LoginWithOtp from "../pages/authentication/LoginWithOtp"; import LoginWithOtp from "../pages/authentication/LoginWithOtp";
import TenantPage from "../pages/Tenant/TenantPage"; import TenantPage from "../pages/Tenant/TenantPage";
import CreateTenant from "../pages/Tenant/CreateTenant"; import CreateTenant from "../pages/Tenant/CreateTenant";
import ExpensePage from "../pages/Expense/ExpensePage";
const router = createBrowserRouter( const router = createBrowserRouter(
[ [

View File

@ -1,6 +1,6 @@
export const THRESH_HOLD = 48; // hours export const THRESH_HOLD = 48; // hours
export const DURATION_TIME = 10; // minutes export const DURATION_TIME = 20; // minutes
export const ITEMS_PER_PAGE = 20; export const ITEMS_PER_PAGE = 10;
export const OTP_EXPIRY_SECONDS = 600 // OTP time export const OTP_EXPIRY_SECONDS = 600 // OTP time
export const MANAGE_MASTER = "588a8824-f924-4955-82d8-fc51956cf323"; export const MANAGE_MASTER = "588a8824-f924-4955-82d8-fc51956cf323";
@ -41,14 +41,36 @@ export const DIRECTORY_MANAGER = "62668630-13ce-4f52-a0f0-db38af2230c5"
export const DIRECTORY_USER = "0f919170-92d4-4337-abd3-49b66fc871bb" export const DIRECTORY_USER = "0f919170-92d4-4337-abd3-49b66fc871bb"
export const BASIC_PLAN = "08ddd43e-ca62-4cf4-8d7b-569a364307f4" export const VIEW_SELF_EXPENSE = "385be49f-8fde-440e-bdbc-3dffeb8dd116"
export const VIEW_ALL_EXPNESE = "01e06444-9ca7-4df4-b900-8c3fa051b92f";
export const CREATE_EXEPENSE = "0f57885d-bcb2-4711-ac95-d841ace6d5a7";
export const REVIEW_EXPENSE = "1f4bda08-1873-449a-bb66-3e8222bd871b";
export const APPROVE_EXPENSE = "eaafdd76-8aac-45f9-a530-315589c6deca";
export const PROCESS_EXPENSE = "ea5a1529-4ee8-4828-80ea-0e23c9d4dd11"
export const EXPENSE_MANAGE = "ea5a1529-4ee8-4828-80ea-0e23c9d4dd11"
export const EXPENSE_REJECTEDBY = ["d1ee5eec-24b6-4364-8673-a8f859c60729","965eda62-7907-4963-b4a1-657fb0b2724b"]
export const EXPENSE_DRAFT = "297e0d8f-f668-41b5-bfea-e03b354251c8"
export const ActiveTenant = "297e0d8f-f668-41b5-bfea-e03b354251c8"
// -------------------Application Role------------------------------
// 1 - Expense Manage
export const EXPENSE_MANAGEMENT = "a4e25142-449b-4334-a6e5-22f70e4732d7"
export const CONSTANT_TEXT = {
}
export const BASE_URL = process.env.VITE_BASE_URL; export const BASE_URL = process.env.VITE_BASE_URL;
export const ActiveTenant = "62b05792-5115-4f99-8ff5-e8374859b191"
// export const BASE_URL = "https://api.marcoaiot.com"; // export const BASE_URL = "https://api.marcoaiot.com";
export const CONSTANT_TEXT = {
RenewsubscriptionLabel : " This option; if checked, will renew your productive subscription, if the current plan expires."
}