Compare commits

..

11 Commits

Author SHA1 Message Date
764d508974 Adding Services in Setting. 2025-10-13 16:21:03 +05:30
3b032b7b07 Merge pull request 'Incorrect Toggle Switch Text for Active/Inactive Employee in Project Teams' (#475) from Kartik_Bug#1455 into Issues_Oct_main_2W
Reviewed-on: #475
merged
2025-10-13 09:33:09 +00:00
b8891d403f Incorrect Toggle Switch Text for Active/Inactive Employee in Project Teams 2025-10-13 09:33:09 +00:00
01568db61c Merge pull request '“NA” Should Be Displayed When Employee Has No Email Instead of “–”' (#476) from Kartik_Bug#1451 into Issues_Oct_main_2W
Reviewed-on: #476
Merged
2025-10-13 09:32:51 +00:00
80a974e3be “NA” Should Be Displayed When Employee Has No Email Instead of “–” 2025-10-13 09:32:51 +00:00
f3e05a11d6 Merge pull request 'Adding Project and Service field in View Organization popup.' (#477) from Kartik_Task#1477 into Issues_Oct_main_2W
Reviewed-on: #477
Merged
2025-10-13 09:32:32 +00:00
222e6495a8 Adding Project and Service field in View Organization popup. 2025-10-13 09:32:32 +00:00
18a3b8a85b Merge pull request 'Filter Sidebar Should Auto-Close When Navigating to Another Page' (#478) from Kartik_Bug#1450 into Issues_Oct_main_2W
Reviewed-on: #478
merged
2025-10-13 09:32:17 +00:00
d75296ffe8 Filter Sidebar Should Auto-Close When Navigating to Another Page 2025-10-13 14:51:47 +05:30
6649cab6a2 Added cursor-not-allowed when user can delete the organization. 2025-10-13 14:16:11 +05:30
eab23389ed Correction in Projects Completion Status in this weidget data cannot be shown. 2025-10-13 12:51:42 +05:30
17 changed files with 355 additions and 147 deletions

View File

@ -280,3 +280,7 @@
.w-8-xl{ width: 2rem; } .w-8-xl{ width: 2rem; }
.w-10-xl{ width: 2.5rem; } .w-10-xl{ width: 2.5rem; }
} }
.cursor-not-allowed{
cursor: not-allowed;
}

View File

@ -126,7 +126,7 @@ const Attendance = ({ getRole, handleModalData, searchTerm, projectId, organizat
checked={ShowPending} checked={ShowPending}
onChange={(e) => setShowPending(e.target.checked)} onChange={(e) => setShowPending(e.target.checked)}
/> />
<label className="form-check-label ms-0">Show Pending</label> <label className="form-check-label ms-0">Pending Attendance</label>
</div> </div>
</div> </div>
{attLoading ? ( {attLoading ? (

View File

@ -190,7 +190,7 @@ useEffect(() => {
checked={showPending} checked={showPending}
onChange={(e) => setShowPending(e.target.checked)} onChange={(e) => setShowPending(e.target.checked)}
/> />
<label className="form-check-label ms-0">Show Pending</label> <label className="form-check-label ms-0">Pending Attendance</label>
</div> </div>
</div> </div>
</div> </div>

View File

@ -23,7 +23,7 @@ const HorizontalBarChart = ({
if (loading) { if (loading) {
return ( return (
<div className="w-full h-[380px] flex items-center justify-center bg-gray-100 rounded-xl"> <div className="w-full h-[380px] flex items-center justify-center bg-gray-100 rounded-xl">
<span className="text-gray-500 text-sm">Loading chart...</span> <span className="text-gray-500">Loading chart...</span>
{/* Replace this with a skeleton or spinner if you prefer */} {/* Replace this with a skeleton or spinner if you prefer */}
</div> </div>
); );

View File

@ -3,7 +3,8 @@ import HorizontalBarChart from "../Charts/HorizontalBarChart";
import { useProjects } from "../../hooks/useProjects"; import { useProjects } from "../../hooks/useProjects";
const ProjectCompletionChart = () => { const ProjectCompletionChart = () => {
const { projects, loading } = useProjects(); const { data: projects = [], isLoading: loading, isError, error } = useProjects();
// Bar chart logic // Bar chart logic
const projectNames = projects?.map((p) => p.name) || []; const projectNames = projects?.map((p) => p.name) || [];
@ -11,7 +12,7 @@ const ProjectCompletionChart = () => {
projects?.map((p) => { projects?.map((p) => {
const completed = p.completedWork || 0; const completed = p.completedWork || 0;
const planned = p.plannedWork || 1; const planned = p.plannedWork || 1;
const percent = (completed / planned) * 100; const percent = planned ? (completed / planned) * 100 : 0;
return Math.min(Math.round(percent), 100); return Math.min(Math.round(percent), 100);
}) || []; }) || [];

View File

@ -1,4 +1,4 @@
import React, { useState } from "react"; import React, { useEffect, useState } from "react";
import { useDocumentFilterEntities } from "../../hooks/useDocument"; import { useDocumentFilterEntities } from "../../hooks/useDocument";
import { FormProvider, useForm } from "react-hook-form"; import { FormProvider, useForm } from "react-hook-form";
import { zodResolver } from "@hookform/resolvers/zod"; import { zodResolver } from "@hookform/resolvers/zod";
@ -9,9 +9,11 @@ import {
import { DateRangePicker1 } from "../common/DateRangePicker"; import { DateRangePicker1 } from "../common/DateRangePicker";
import SelectMultiple from "../common/SelectMultiple"; import SelectMultiple from "../common/SelectMultiple";
import moment from "moment"; import moment from "moment";
import { useLocation } from "react-router-dom";
const DocumentFilterPanel = ({ entityTypeId, onApply }) => { const DocumentFilterPanel = ({ entityTypeId, onApply }) => {
const [resetKey, setResetKey] = useState(0); const [resetKey, setResetKey] = useState(0);
const location = useLocation();
const { data, isError, isLoading, error } = const { data, isError, isLoading, error } =
useDocumentFilterEntities(entityTypeId); useDocumentFilterEntities(entityTypeId);
@ -52,6 +54,13 @@ const DocumentFilterPanel = ({ entityTypeId, onApply }) => {
closePanel(); closePanel();
}; };
// Close popup when navigating to another component
useEffect(() => {
return () => {
closePanel();
};
}, []);
if (isLoading) return <div>Loading...</div>; if (isLoading) return <div>Loading...</div>;
if (isError) if (isError)
return <div>Error: {error?.message || "Something went wrong!"}</div>; return <div>Error: {error?.message || "Something went wrong!"}</div>;
@ -63,6 +72,8 @@ const DocumentFilterPanel = ({ entityTypeId, onApply }) => {
documentTag = [], documentTag = [],
} = data?.data || {}; } = data?.data || {};
return ( return (
<FormProvider {...methods}> <FormProvider {...methods}>
<form onSubmit={handleSubmit(onSubmit)}> <form onSubmit={handleSubmit(onSubmit)}>
@ -73,18 +84,16 @@ const DocumentFilterPanel = ({ entityTypeId, onApply }) => {
<div className="d-inline-flex border rounded-pill overflow-hidden shadow-none"> <div className="d-inline-flex border rounded-pill 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 ${isUploadedAt ? "active btn-secondary text-white" : ""
isUploadedAt ? "active btn-secondary text-white" : "" }`}
}`}
onClick={() => setValue("isUploadedAt", true)} onClick={() => setValue("isUploadedAt", true)}
> >
Uploaded On Uploaded On
</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 ${!isUploadedAt ? "active btn-secondary text-white" : ""
!isUploadedAt ? "active btn-secondary text-white" : "" }`}
}`}
onClick={() => setValue("isUploadedAt", false)} onClick={() => setValue("isUploadedAt", false)}
> >
Updated On Updated On

View File

@ -144,12 +144,12 @@ const Documents = ({ Document_Entity, Entity }) => {
<span className="switch-off"></span> <span className="switch-off"></span>
</span> </span>
<span className="switch-label"> <span className="switch-label">
{isActive ? "Active" : "In-Active"} {isActive ? "Active Document" : "In-Active Document"}
</span> </span>
</label> </label>
</div> </div>
<div className="col-6 col-md-6 col-lg-8 text-end"> <div className="col-12 col-md-6 col-lg-8 text-end">
{(isSelf || canUploadDocument) && ( {(isSelf || canUploadDocument) && (
<button <button
className="btn btn-sm btn-primary me-3" className="btn btn-sm btn-primary me-3"

View File

@ -51,7 +51,6 @@ const EmpAttendance = () => {
new Date(b?.checkInTime).getTime() - new Date(a?.checkInTime).getTime() new Date(b?.checkInTime).getTime() - new Date(a?.checkInTime).getTime()
); );
console.log(sorted);
const { currentPage, totalPages, currentItems, paginate } = usePagination( const { currentPage, totalPages, currentItems, paginate } = usePagination(
sorted, sorted,

View File

@ -131,7 +131,7 @@ const OrganizationsList = ({searchText}) => {
<div className="d-flex justify-content-center gap-2"> <div className="d-flex justify-content-center gap-2">
<i className="bx bx-show text-primary cursor-pointer" onClick={()=>onOpen({startStep:5,orgData:org.id,flowType:"view"})}></i> <i className="bx bx-show text-primary cursor-pointer" onClick={()=>onOpen({startStep:5,orgData:org.id,flowType:"view"})}></i>
<i className="bx bx-edit text-secondary cursor-pointer" onClick={()=>onOpen({startStep:4,orgData:org,flowType:"edit"})}></i> <i className="bx bx-edit text-secondary cursor-pointer" onClick={()=>onOpen({startStep:4,orgData:org,flowType:"edit"})}></i>
<i className="bx bx-trash text-danger cursor-pointer"></i> <i className="bx bx-trash text-danger cursor-not-allowed"></i>
</div> </div>
</td> </td>
</tr> </tr>

View File

@ -22,9 +22,8 @@ const VieworgDataanization = ({ orgId }) => {
</div> </div>
<div className="text-end"> <div className="text-end">
<span <span
className={`badge bg-label-${ className={`badge bg-label-${data?.isActive ? "primary" : "secondary"
data?.isActive ? "primary" : "secondary" } `}
} `}
> >
{data?.isActive ? "Active" : "In-Active"}{" "} {data?.isActive ? "Active" : "In-Active"}{" "}
</span> </span>
@ -105,9 +104,101 @@ const VieworgDataanization = ({ orgId }) => {
<div className="text-muted text-start">{data?.address}</div> <div className="text-muted text-start">{data?.address}</div>
</div> </div>
</div> </div>
<div className="d-flex text-secondary mb-2"> <div className="col-12 mb-3">
{" "} <div
<i className="bx bx-sm bx-briefcase me-1" /> Projects And Services className="d-flex justify-content-between align-items-center text-secondary mb-2 cursor-pointer"
data-bs-toggle="collapse"
data-bs-target="#collapse-projects-services"
aria-expanded="false"
>
<div>
<i className="bx bx-sm bx-briefcase me-1" /> Projects
</div>
<i className="bx bx-chevron-down me-2"></i>
</div>
{/* remove "show" from className */}
<div id="collapse-projects-services" className="collapse">
{data?.projects && data.projects.length > 0 ? (
data.projects
.reduce((acc, curr) => {
const projectId = curr.project.id;
if (!acc.find((p) => p.id === projectId)) {
acc.push(curr.project);
}
return acc;
}, [])
.map((project) => (
<div key={project.id} className="mb-2 rounded p-2">
<div
className="d-flex justify-content-between align-items-center cursor-pointer"
data-bs-toggle="collapse"
data-bs-target={`#collapse-${project.id}`}
aria-expanded="false"
>
<label className="form-label fw-semibold">
<i className="bx bx-buildings me-2"></i>
{project.name}
</label>
<i className="bx bx-chevron-down"></i>
</div>
<div id={`collapse-${project.id}`} className="collapse mt-2 ps-5">
{data.projects
.filter((p) => p.project.id === project.id)
.map((p) => (
<div key={p.service.id} className="mb-1 text-muted">
<i className="bx bx-wrench me-2"></i>
{p.service.name}
</div>
))}
</div>
</div>
))
) : (
<div className="text-muted fst-italic ps-2">No projects available</div>
)}
</div>
</div>
{/* Services Section */}
<div className="col-12 mb-3">
<div
className="d-flex justify-content-between align-items-center text-secondary mb-2 cursor-pointer"
data-bs-toggle="collapse"
data-bs-target="#collapse-services"
aria-expanded="false"
>
<div>
<i className="bx bx-sm bx-cog me-1" /> Services
</div>
<i className="bx bx-chevron-down me-2"></i>
</div>
{/* collapse is closed initially */}
<div id="collapse-services" className="collapse">
{data?.services && data.services.length > 0 ? (
<div className="row">
{data.services.map((service) => (
<div key={service.id} className="col-md-12 mb-3">
<div className="card h-100 shadow-sm border-0">
<div className="card-body">
<h6 className="fw-semibold mb-1">
<i className="bx bx-wrench me-1"></i>
{service.name}
</h6>
<p className="text-muted small mb-0">
{service.description || "No description available."}
</p>
</div>
</div>
</div>
))}
</div>
) : (
<div className="text-muted fst-italic ps-2">No services available</div>
)}
</div>
</div> </div>
</div> </div>
); );

View File

@ -1,6 +1,8 @@
import React, { useState } from "react"; import React, { useState } from "react";
import { ComingSoonPage } from "../../pages/Misc/ComingSoonPage"; import { ComingSoonPage } from "../../pages/Misc/ComingSoonPage";
import ProjectPermission from "./ProjectPermission"; import ProjectPermission from "./ProjectPermission";
import ListViewContact_1 from "./services/Services";
import ServiceListView from "./services/Services";
const ProjectSetting = () => { const ProjectSetting = () => {
const [activePill, setActivePill] = useState("Permissions") const [activePill, setActivePill] = useState("Permissions")
@ -9,7 +11,7 @@ const ProjectSetting = () => {
// }); // });
const projectSettingTab = [ const projectSettingTab = [
{ key: "Permissions", label: "Permissions" }, { key: "Permissions", label: "Permissions" },
{ key: "Notification", label: "Notification" }, { key: "services", label: "Services" },
{ key: "SeparatedLink", label: "Separated link", isButton: true }, { key: "SeparatedLink", label: "Separated link", isButton: true },
]; ];
const handlePillClick = (pillKey) => { const handlePillClick = (pillKey) => {
@ -22,8 +24,8 @@ const ProjectSetting = () => {
case "Permissions": case "Permissions":
return <ProjectPermission />; return <ProjectPermission />;
case "Notification": case "services":
return <ComingSoonPage />; return <ServiceListView />;
default: default:
return <ComingSoonPage />; return <ComingSoonPage />;
@ -33,7 +35,7 @@ const ProjectSetting = () => {
return ( return (
<div className="w-100"> <div className="w-100">
<div className="card py-2 px-5"> <div className="card py-2 px-5">
{/* <div className="col-12"> <div className="col-12">
<div className="dropdown text-end"> <div className="dropdown text-end">
<button <button
className="btn btn-sm btn-outline-primary dropdown-toggle" className="btn btn-sm btn-outline-primary dropdown-toggle"
@ -64,7 +66,7 @@ const ProjectSetting = () => {
)} )}
</ul> </ul>
</div> </div>
</div> */} </div>
<div className="mt-3">{renderContent()}</div> <div className="mt-3">{renderContent()}</div>
</div> </div>

View File

@ -201,7 +201,7 @@ const Teams = () => {
className="form-check-label ms-2" className="form-check-label ms-2"
htmlFor="activeEmployeeSwitch" htmlFor="activeEmployeeSwitch"
> >
{activeEmployee ? "Active Employees" : "Include Inactive Employees"} {activeEmployee ? "Active Employees" : "In-active Employees"}
</label> </label>
</div> </div>
</div> </div>

View File

@ -0,0 +1,105 @@
import React from "react";
import { useProjectAssignedServices } from "../../../hooks/useProjects";
import { useSelectedProject } from "../../../slices/apiDataManager";
const ServiceListView = () => {
const projectId = useSelectedProject();
const { data, isLoading, error } = useProjectAssignedServices(projectId);
const serviceColumns = [
{
key: "name",
label: "Service Name",
getValue: (service) => (
<span
className="text-truncate d-inline-block"
style={{ maxWidth: "200px" }}
>
{service?.name || "N/A"}
</span>
),
align: "text-start",
},
{
key: "description",
label: "Description",
getValue: (service) => (
<span
className="text-truncate d-inline-block"
style={{ maxWidth: "400px" }}
title={service?.description}
>
{service?.description || "N/A"}
</span>
),
align: "text-start",
},
{
key: "isActive",
label: "Status",
getValue: (service) => (
<span
className={`badge ${service?.isActive ? "bg-success" : "bg-secondary"
}`}
>
{service?.isActive ? "Active" : "Inactive"}
</span>
),
align: "text-center",
},
];
if (isLoading)
return <div className="p-4 text-center">Loading services...</div>;
if (error)
return (
<div className="p-4 text-center text-danger">
Failed to load services: {error.message}
</div>
);
const services = data || [];
return (
<div className="card-datatable table-responsive">
<div className="dataTables_wrapper no-footer mx-5 pb-2">
<table className="table dataTable text-nowrap">
<thead>
<tr className="table_header_border">
{serviceColumns.map((col) => (
<th key={col.key} className={col.align}>
{col.label}
</th>
))}
</tr>
</thead>
<tbody>
{Array.isArray(services) && services.length > 0 ? (
services.map((row, i) => (
<tr key={i}>
{serviceColumns.map((col) => (
<td key={col.key} className={col.align}>
{col.getValue(row)}
</td>
))}
</tr>
))
) : (
<tr style={{ height: "200px" }}>
<td
colSpan={serviceColumns.length}
className="text-center border-0 align-middle"
>
No services found
</td>
</tr>
)}
</tbody>
</table>
</div>
</div>
);
};
export default ServiceListView;

View File

@ -1,5 +1,5 @@
import { zodResolver } from "@hookform/resolvers/zod"; import { zodResolver } from "@hookform/resolvers/zod";
import React from "react"; import React, { useEffect } from "react";
import { FormProvider, useForm } from "react-hook-form"; import { FormProvider, useForm } from "react-hook-form";
import { import {
contactsFilter, contactsFilter,
@ -8,11 +8,14 @@ import {
import { useContactFilter } from "../../hooks/useDirectory"; import { useContactFilter } from "../../hooks/useDirectory";
import { ExpenseFilterSkeleton } from "../../components/Expenses/ExpenseSkeleton"; import { ExpenseFilterSkeleton } from "../../components/Expenses/ExpenseSkeleton";
import SelectMultiple from "../../components/common/SelectMultiple"; import SelectMultiple from "../../components/common/SelectMultiple";
import { useLocation } from "react-router-dom";
const ContactFilterPanel = ({ onApply, clearFilter }) => { const ContactFilterPanel = ({ onApply, clearFilter }) => {
const { data, isError, isLoading, error, isFetched, isFetching } = const { data, isError, isLoading, error, isFetched, isFetching } =
useContactFilter(); useContactFilter();
const location = useLocation();
const methods = useForm({ const methods = useForm({
resolver: zodResolver(contactsFilter), resolver: zodResolver(contactsFilter),
defaultValues: defaultContactFilter, defaultValues: defaultContactFilter,
@ -30,14 +33,24 @@ const ContactFilterPanel = ({ onApply, clearFilter }) => {
}; };
const handleClose = () => { const handleClose = () => {
reset(defaultContactFilter); reset(defaultContactFilter);
onApply(defaultContactFilter); onApply(defaultContactFilter);
closePanel(); closePanel();
}; };
useEffect(() => {
return () => {
closePanel();
};
}, []);
if (isLoading || isFetching) return <ExpenseFilterSkeleton />; if (isLoading || isFetching) return <ExpenseFilterSkeleton />;
if (isError && isFetched) if (isError && isFetched)
return <div>Something went wrong Here- {error.message} </div>; return <div>Something went wrong Here- {error.message} </div>;
return ( return (
<FormProvider {...methods}> <FormProvider {...methods}>
<form onSubmit={handleSubmit(onSubmit)} className="p-2 text-start"> <form onSubmit={handleSubmit(onSubmit)} className="p-2 text-start">

View File

@ -139,9 +139,8 @@ export default function DirectoryPage({ IsPage = true, projectId = null }) {
<ul className="nav nav-tabs"> <ul className="nav nav-tabs">
<li className="nav-item cursor-pointer"> <li className="nav-item cursor-pointer">
<a <a
className={`nav-link ${ className={`nav-link ${activeTab === "notes" ? "active" : ""
activeTab === "notes" ? "active" : "" } fs-6`}
} fs-6`}
onClick={(e) => handleTabClick("notes", e)} onClick={(e) => handleTabClick("notes", e)}
> >
<i className="bx bx-notepad bx-sm me-1_5"></i> <i className="bx bx-notepad bx-sm me-1_5"></i>
@ -150,9 +149,8 @@ export default function DirectoryPage({ IsPage = true, projectId = null }) {
</li> </li>
<li className="nav-item cursor-pointer"> <li className="nav-item cursor-pointer">
<a <a
className={`nav-link ${ className={`nav-link ${activeTab === "contacts" ? "active" : ""
activeTab === "contacts" ? "active" : "" } fs-6`}
} fs-6`}
onClick={(e) => handleTabClick("contacts", e)} onClick={(e) => handleTabClick("contacts", e)}
> >
<i className="bx bxs-contact bx-sm me-1_5"></i> <i className="bx bxs-contact bx-sm me-1_5"></i>
@ -168,105 +166,84 @@ export default function DirectoryPage({ IsPage = true, projectId = null }) {
{activeTab === "notes" && ( {activeTab === "notes" && (
<div className="col-8 col-md-3"> <div className="col-8 col-md-3">
<input <input
type="search" type="search"
className="form-control form-control-sm" className="form-control form-control-sm"
placeholder="Search notes..." placeholder="Search notes..."
value={searchNote} value={searchNote}
onChange={(e) => setSearchNote(e.target.value)} onChange={(e) => setSearchNote(e.target.value)}
/> />
</div> </div>
)} )}
{activeTab === "contacts" && ( {activeTab === "contacts" && (
<div className="d-flex align-items-center gap-3"> <div className="d-flex align-items-center gap-3">
<div className="col-12 col-md-8 d-flex flex-row gap-2"> <div className="col-12 col-md-8 d-flex flex-row gap-2">
<div className="col-7 col-md-4"> <div className="col-7 col-md-4">
<input <input
type="search" type="search"
className="form-control form-control-sm" className="form-control form-control-sm"
placeholder="Search contacts..." placeholder="Search contacts..."
value={searchContact} value={searchContact}
onChange={(e) => setsearchContact(e.target.value)} onChange={(e) => setsearchContact(e.target.value)}
/> />
</div> </div>
<button <button
className={`btn btn-sm p-1 ${ className={`btn btn-sm p-1 ${gridView ? " btn-primary" : " btn-outline-primary"
!gridView ? "btn-primary" : "btn-outline-primary" }`}
}`}
onClick={() => setGridView(false)}
>
<i className="bx bx-list-ul"></i>
</button>
<button
className={`btn btn-sm p-1 ${
gridView ? " btn-primary" : " btn-outline-primary"
}`}
onClick={() => setGridView(true)} onClick={() => setGridView(true)}
> >
<i className="bx bx-grid-alt"></i> <i className="bx bx-grid-alt"></i>
</button> </button>
<div className="form-check form-switch d-flex align-items-center d-none d-md-flex"> <button
<input className={`btn btn-sm p-1 ${!gridView ? "btn-primary" : "btn-outline-primary"
type="checkbox" }`}
className="form-check-input" onClick={() => setGridView(false)}
role="switch"
id="inactiveEmployeesCheckbox"
checked={showActive}
onChange={(e) => setShowActive(e.target.checked)}
/>
<label
className="form-check-label ms-2"
htmlFor="inactiveEmployeesCheckbox"
> >
{showActive ? "Active" : "Inactive"} Contacts <i className="bx bx-list-ul"></i>
</label> </button>
<div className="form-check form-switch d-flex align-items-end d-none d-md-flex">
<input
type="checkbox"
className="form-check-input"
role="switch"
id="inactiveEmployeesCheckbox"
checked={showActive}
onChange={(e) => setShowActive(e.target.checked)}
/>
<label
className="form-check-label ms-2"
htmlFor="inactiveEmployeesCheckbox"
>
{showActive ? "Active" : "In-active"} Contacts
</label>
</div>
</div> </div>
</div>
</div> </div>
)} )}
</div> </div>
<div className="col-12 col-md-2 d-flex justify-content-end align-items-center gap-2"> <div className="col-12 col-md-2 d-flex justify-content-end align-items-center gap-2">
<div className={`form-check form-switch d-flex align-items-center ${activeTab === "contacts" ? " d-flex d-md-none m-0":"d-none" }`}> <div className=" btn-group">
<input <button
type="checkbox" className="btn btn-sm btn-label-secondary dropdown-toggle"
className="form-check-input" type="button"
role="switch" data-bs-toggle="dropdown"
id="inactiveEmployeesCheckbox" aria-expanded="false"
checked={showActive} >
onChange={(e) => setShowActive(e.target.checked)} <i className="bx bx-export me-2 bx-sm"></i>Export
/> </button>
<label <ul className="dropdown-menu">
className="form-check-label ms-2" <li>
htmlFor="inactiveEmployeesCheckbox" <a
className="dropdown-item cursor-pointer"
onClick={() => handleExport("csv")}
> >
{showActive ? "Active" : "Inactive"} Contacts <i className="bx bx-file me-1"></i> CSV
</label> </a>
</div> </li>
<div className=" btn-group"> </ul>
<button </div>
className="btn btn-sm btn-label-secondary dropdown-toggle"
type="button"
data-bs-toggle="dropdown"
aria-expanded="false"
>
<i className="bx bx-export me-2 bx-sm"></i>Export
</button>
<ul className="dropdown-menu">
<li>
<a
className="dropdown-item cursor-pointer"
onClick={() => handleExport("csv")}
>
<i className="bx bx-file me-1"></i> CSV
</a>
</li>
</ul>
</div> </div>
</div>
</div> </div>
</div> </div>
</div> </div>

View File

@ -1,5 +1,5 @@
import { zodResolver } from "@hookform/resolvers/zod"; import { zodResolver } from "@hookform/resolvers/zod";
import React from "react"; import React, { useEffect } from "react";
import { FormProvider, useForm } from "react-hook-form"; import { FormProvider, useForm } from "react-hook-form";
import { import {
defaultNotesFilter, defaultNotesFilter,
@ -8,11 +8,18 @@ import {
import { useContactFilter, useNoteFilter } from "../../hooks/useDirectory"; import { useContactFilter, useNoteFilter } from "../../hooks/useDirectory";
import { ExpenseFilterSkeleton } from "../../components/Expenses/ExpenseSkeleton"; import { ExpenseFilterSkeleton } from "../../components/Expenses/ExpenseSkeleton";
import SelectMultiple from "../../components/common/SelectMultiple"; import SelectMultiple from "../../components/common/SelectMultiple";
import { useLocation } from "react-router-dom";
const NoteFilterPanel = ({ onApply, clearFilter }) => { const NoteFilterPanel = ({ onApply, clearFilter }) => {
const { data, isError, isLoading, error, isFetched, isFetching } = const { data, isError, isLoading, error, isFetched, isFetching } =
useNoteFilter(); useNoteFilter();
useEffect(() => {
return () => {
closePanel();
};
}, []);
const methods = useForm({ const methods = useForm({
resolver: zodResolver(notesFilter), resolver: zodResolver(notesFilter),
defaultValues: defaultNotesFilter, defaultValues: defaultNotesFilter,
@ -31,7 +38,7 @@ const NoteFilterPanel = ({ onApply, clearFilter }) => {
const handleClose = () => { const handleClose = () => {
reset(defaultNotesFilter); reset(defaultNotesFilter);
onApply(defaultNotesFilter); onApply(defaultNotesFilter);
closePanel(); closePanel();
}; };

View File

@ -176,12 +176,10 @@ const EmployeeList = () => {
useEffect(() => { useEffect(() => {
if (!loading && Array.isArray(employees)) { if (!loading && Array.isArray(employees)) {
const sorted = [...employees].sort((a, b) => { const sorted = [...employees].sort((a, b) => {
const nameA = `${a.firstName || ""}${a.middleName || ""}${ const nameA = `${a.firstName || ""}${a.middleName || ""}${a.lastName || ""
a.lastName || "" }`.toLowerCase();
}`.toLowerCase(); const nameB = `${b.firstName || ""}${b.middleName || ""}${b.lastName || ""
const nameB = `${b.firstName || ""}${b.middleName || ""}${ }`.toLowerCase();
b.lastName || ""
}`.toLowerCase();
return nameA?.localeCompare(nameB); return nameA?.localeCompare(nameB);
}); });
@ -258,9 +256,8 @@ const EmployeeList = () => {
? "Suspend Employee" ? "Suspend Employee"
: "Reactivate Employee" : "Reactivate Employee"
} }
message={`Are you sure you want to ${ message={`Are you sure you want to ${selectedEmpFordelete?.isActive ? "suspend" : "reactivate"
selectedEmpFordelete?.isActive ? "suspend" : "reactivate" } this employee?`}
} this employee?`}
onSubmit={(id) => onSubmit={(id) =>
suspendEmployee({ suspendEmployee({
employeeId: id, employeeId: id,
@ -309,7 +306,7 @@ const EmployeeList = () => {
className="form-check-label ms-0" className="form-check-label ms-0"
htmlFor="inactiveEmployeesCheckbox" htmlFor="inactiveEmployeesCheckbox"
> >
Show Inactive Employees In-active Employees
</label> </label>
</div> </div>
</div> </div>
@ -471,9 +468,8 @@ const EmployeeList = () => {
Status Status
</th> </th>
<th <th
className={`sorting_disabled ${ className={`sorting_disabled ${!Manage_Employee && "d-none"
!Manage_Employee && "d-none" }`}
}`}
rowSpan="1" rowSpan="1"
colSpan="1" colSpan="1"
style={{ width: "50px" }} style={{ width: "50px" }}
@ -493,20 +489,20 @@ const EmployeeList = () => {
)} )}
{!loading && {!loading &&
displayData?.length === 0 && displayData?.length === 0 &&
(!searchText ) ? ( (!searchText) ? (
<tr> <tr>
<td colSpan={8} className="border-0 py-3"> <td colSpan={8} className="border-0 py-3">
<div className="py-4"> <div className="py-4">
No Data Found No Data Found
</div> </div>
</td> </td>
</tr> </tr>
) : null} ) : null}
{!loading && {!loading &&
displayData?.length === 0 && displayData?.length === 0 &&
(searchText ) ? ( (searchText) ? (
<tr> <tr>
<td colSpan={8} className="border-0 py-3"> <td colSpan={8} className="border-0 py-3">
<div className="py-4"> <div className="py-4">
@ -542,18 +538,17 @@ const EmployeeList = () => {
</div> </div>
</div> </div>
</td> </td>
<td className="text-start d-none d-sm-table-cell"> <td className="text-start d-none d-sm-table-cell">
{item.email ? ( {item.email ? (
<span className="text-truncate"> <span className="text-truncate">
<i className="bx bxs-envelope text-primary me-2"></i> <i className="bx bxs-envelope text-primary me-2"></i>
{item.email} {item.email}
</span> </span>
) : ( ) : (
<span className="text-truncate text-italic"> <span className="d-block text-start text-muted fst-italic">NA</span>
-
</span>
)} )}
</td> </td>
<td className="text-start d-none d-sm-table-cell"> <td className="text-start d-none d-sm-table-cell">
<span className="text-truncate"> <span className="text-truncate">
<i className="bx bxs-phone-call text-primary me-2"></i> <i className="bx bxs-phone-call text-primary me-2"></i>
@ -567,9 +562,14 @@ const EmployeeList = () => {
</span> </span>
</td> </td>
<td className=" d-none d-md-table-cell"> <td className="d-none d-md-table-cell">
{moment(item.joiningDate)?.format("DD-MMM-YYYY")} {item.joiningDate ? (
moment(item.joiningDate).format("DD-MMM-YYYY")
) : (
<span className="d-block text-center text-muted fst-italic">NA</span>
)}
</td> </td>
<td> <td>
{showInactive ? ( {showInactive ? (
<span <span