Remove warnings

This commit is contained in:
Vikas Nale 2025-04-17 17:29:18 +05:30
parent 83b6c2a307
commit 1418f84976
8 changed files with 487 additions and 417 deletions

View File

@ -1,4 +1,10 @@
import React, { createContext, useContext, useState, useEffect, useRef } from "react"; import React, {
createContext,
useContext,
useState,
useEffect,
useRef,
} from "react";
const ModalContext = createContext(); const ModalContext = createContext();
@ -9,12 +15,12 @@ export const ModalProvider = ({ children }) => {
const [isOpen, setIsOpen] = useState(false); const [isOpen, setIsOpen] = useState(false);
const [modalContent, setModalContent] = useState(null); const [modalContent, setModalContent] = useState(null);
const [onSubmit, setOnSubmit] = useState(null); const [onSubmit, setOnSubmit] = useState(null);
const [modalSize, setModalSize] = useState('lg'); const [modalSize, setModalSize] = useState("lg");
// Ref to track the modal content element // Ref to track the modal content element
const modalRef = useRef(null); const modalRef = useRef(null);
const openModal = (content, onSubmitCallback, size = 'lg') => { const openModal = (content, onSubmitCallback, size = "lg") => {
setModalContent(content); // Set modal content dynamically setModalContent(content); // Set modal content dynamically
setOnSubmit(() => onSubmitCallback); // Set the submit handler dynamically setOnSubmit(() => onSubmitCallback); // Set the submit handler dynamically
setIsOpen(true); // Open the modal setIsOpen(true); // Open the modal
@ -26,9 +32,20 @@ export const ModalProvider = ({ children }) => {
setIsOpen(false); // Close the modal setIsOpen(false); // Close the modal
setModalContent(null); // Clear modal content setModalContent(null); // Clear modal content
setOnSubmit(null); // Clear the submit callback setOnSubmit(null); // Clear the submit callback
setModalSize('lg'); // Reset modal size setModalSize("lg"); // Reset modal size
}; };
useEffect(() => {
const handleEscape = (event) => {
if (event.key === "Escape") {
closeModal();
}
};
document.addEventListener("keydown", handleEscape);
return () => {
document.removeEventListener("keydown", handleEscape);
};
}, []);
useEffect(() => { useEffect(() => {
const handleClickOutside = (event) => { const handleClickOutside = (event) => {
@ -43,14 +60,28 @@ export const ModalProvider = ({ children }) => {
}, []); }, []);
return ( return (
<ModalContext.Provider value={{ isOpen, openModal, closeModal, modalContent, modalSize, onSubmit }}> <ModalContext.Provider
value={{
isOpen,
openModal,
closeModal,
modalContent,
modalSize,
onSubmit,
}}
>
{children} {children}
{isOpen && ( {isOpen && (
<div style={overlayStyles}> <div style={overlayStyles}>
<div ref={modalRef} style={{ ...modalStyles, maxWidth: modalSize === 'sm' ? '400px' : '800px' }}> <div
ref={modalRef}
style={{
...modalStyles,
maxWidth: modalSize === "sm" ? "400px" : "800px",
}}
>
<div>{modalContent}</div> <div>{modalContent}</div>
</div> </div>
</div> </div>
)} )}

View File

@ -1,18 +1,18 @@
import React, { useEffect, useState } from 'react'; import React, { useEffect, useState } from "react";
import Avatar from '../common/Avatar'; import Avatar from "../common/Avatar";
import { convertShortTime } from '../../utils/dateUtils'; import { convertShortTime } from "../../utils/dateUtils";
import RenderAttendanceStatus from './RenderAttendanceStatus'; import RenderAttendanceStatus from "./RenderAttendanceStatus";
import { useSelector, useDispatch } from 'react-redux'; import { useSelector, useDispatch } from "react-redux";
import { fetchAttendanceData } from '../../slices/apiSlice/attedanceLogsSlice'; import { fetchAttendanceData } from "../../slices/apiSlice/attedanceLogsSlice";
const AttendanceLog = ({ attendance, handleModalData, projectId }) => { const AttendanceLog = ({ attendance, handleModalData, projectId }) => {
const [attendances, setAttendnaces] = useState([]); const [attendances, setAttendnaces] = useState([]);
const [selectedDate, setSelectedDate] = useState(''); const [selectedDate, setSelectedDate] = useState("");
const dispatch = useDispatch(); const dispatch = useDispatch();
const { data, loading, error } = useSelector((store) => store.attendanceLogs); const { data, loading, error } = useSelector((store) => store.attendanceLogs);
// Set the default selected date to the current date // Set the default selected date to the current date
const currentDate = new Date().toISOString().split('T')[0]; // "YYYY-MM-DD" const currentDate = new Date().toISOString().split("T")[0]; // "YYYY-MM-DD"
const handleDateChange = (e) => { const handleDateChange = (e) => {
const date = e.target.value; const date = e.target.value;
@ -28,11 +28,15 @@ const AttendanceLog = ({ attendance, handleModalData, projectId }) => {
setSelectedDate(currentDate); // Set default selected date to today setSelectedDate(currentDate); // Set default selected date to today
}, [attendance]); }, [attendance]);
const renderAttendanceData = selectedDate === currentDate ? attendances : data; const renderAttendanceData =
selectedDate === currentDate ? attendances : data;
return ( return (
<> <>
<div className="dataTables_length text-start py-2" id="DataTables_Table_0_length"> <div
className="dataTables_length text-start py-2"
id="DataTables_Table_0_length"
>
<div className="col-md-3"> <div className="col-md-3">
<input <input
className="form-control form-control-sm" className="form-control form-control-sm"
@ -50,10 +54,13 @@ const AttendanceLog = ({ attendance, handleModalData, projectId }) => {
<table className="table mb-0"> <table className="table mb-0">
<thead> <thead>
<tr> <tr>
<th className="border-top-1" colSpan={2}>Name</th> <th className="border-top-1" colSpan={2}>
<th className="border-top-1" >Role</th> Name
</th>
<th className="border-top-1">Role</th>
<th> <th>
<i className="bx bxs-down-arrow-alt text-success"></i> Check-In <i className="bx bxs-down-arrow-alt text-success"></i>{" "}
Check-In
</th> </th>
<th> <th>
<i className="bx bxs-up-arrow-alt text-danger"></i> Check-Out <i className="bx bxs-up-arrow-alt text-danger"></i> Check-Out
@ -65,14 +72,19 @@ const AttendanceLog = ({ attendance, handleModalData, projectId }) => {
{loading && <td colSpan={5}>Loading...</td>} {loading && <td colSpan={5}>Loading...</td>}
{error && <td colSpan={5}>{error}</td>} {error && <td colSpan={5}>{error}</td>}
{selectedDate && renderAttendanceData.length === 0 && ( {selectedDate && renderAttendanceData.length === 0 && (
<td colSpan={5}>No Data Found</td> <tr>
<td colSpan={5}>No Data Found</td>
</tr>
)} )}
{renderAttendanceData?.map((attendance, index) => ( {renderAttendanceData?.map((attendance, index) => (
<tr key={index}> <tr key={index}>
<td colSpan={2}> <td colSpan={2}>
<div className="d-flex justify-content-start align-items-center"> <div className="d-flex justify-content-start align-items-center">
<Avatar firstName={attendance.firstName} lastName={attendance.lastName} /> <Avatar
firstName={attendance.firstName}
lastName={attendance.lastName}
/>
<div className="d-flex flex-column"> <div className="d-flex flex-column">
<a href="#" className="text-heading text-truncate"> <a href="#" className="text-heading text-truncate">
<span className="fw-medium"> <span className="fw-medium">
@ -82,9 +94,13 @@ const AttendanceLog = ({ attendance, handleModalData, projectId }) => {
</div> </div>
</div> </div>
</td> </td>
<td>{ attendance.jobRoleName}</td> <td>{attendance.jobRoleName}</td>
<td>{convertShortTime(attendance.checkInTime)}</td> <td>{convertShortTime(attendance.checkInTime)}</td>
<td>{attendance.checkOutTime ? convertShortTime(attendance.checkOutTime) : '--'}</td> <td>
{attendance.checkOutTime
? convertShortTime(attendance.checkOutTime)
: "--"}
</td>
<td className="text-center"> <td className="text-center">
<RenderAttendanceStatus <RenderAttendanceStatus
attendanceData={attendance} attendanceData={attendance}

View File

@ -1,79 +1,82 @@
import React, { useEffect, useState } from 'react'; import React, { useEffect, useState } from "react";
import Avatar from '../common/Avatar'; import Avatar from "../common/Avatar";
import { convertShortTime } from '../../utils/dateUtils'; import { convertShortTime } from "../../utils/dateUtils";
import RegularizationActions from './RegularizationActions'; import RegularizationActions from "./RegularizationActions";
import {useSelector} from 'react-redux'; import { useSelector } from "react-redux";
import {useRegularizationRequests} from '../../hooks/useAttendance'; import { useRegularizationRequests } from "../../hooks/useAttendance";
import moment from 'moment'; import moment from "moment";
const Regularization = ({ handleRequest }) => {
const Regularization = ( { handleRequest} ) =>
{
var selectedProject = useSelector((store) => store.localVariables.projectId); var selectedProject = useSelector((store) => store.localVariables.projectId);
const [ regularizesList, setregularizedList ] = useState( [] ) const [regularizesList, setregularizedList] = useState([]);
const { regularizes, loading,error,refetch} = useRegularizationRequests(selectedProject) const { regularizes, loading, error, refetch } =
useRegularizationRequests(selectedProject);
useEffect(() => {
setregularizedList(regularizes);
useEffect(()=>{ }, [regularizes]);
setregularizedList(regularizes)
},[regularizes])
return ( return (
<div className="table-responsive text-nowrap"> <div className="table-responsive text-nowrap">
<table className="table mb-0"> <table className="table mb-0">
<thead> <thead>
<tr> <tr>
<th colSpan={2}>Name</th> <th colSpan={2}>Name</th>
<th>Date</th> <th>Date</th>
<th><i className='bx bxs-down-arrow-alt text-success' ></i>Check-In</th> <th>
<th><i className='bx bxs-up-arrow-alt text-danger' ></i>Check-Out</th> <i className="bx bxs-down-arrow-alt text-success"></i>Check-In
<th>Action</th> </th>
</tr> <th>
</thead> <i className="bx bxs-up-arrow-alt text-danger"></i>Check-Out
</th>
<th>Action</th>
</tr>
</thead>
<tbody> <tbody>
{loading && <td colSpan={5}>Loading...</td>}
{loading &&<td colSpan={5}>Loading...</td>} {regularizes?.length > 0 ? (
{ regularizes?.map((att, index) => (
regularizes?.length > 0 ? ( <tr key={index}>
regularizes?.map((att, index) => ( <td colSpan={2}>
<tr key={index}> <div className="d-flex justify-content-start align-items-center">
<td colSpan={2}> <Avatar
<div className="d-flex justify-content-start align-items-center"> firstName={att.firstName}
<Avatar lastName={att.lastName}
firstName={att.firstName} ></Avatar>
lastName={att.lastName} <div className="d-flex flex-column">
></Avatar> <a href="#" className="text-heading text-truncate">
<div className="d-flex flex-column"> <span className="fw-medium">
<a {att.firstName} {att.lastName}
href="#" </span>
className="text-heading text-truncate" </a>
> </div>
<span className="fw-medium"> </div>
{att.firstName} {att.lastName} </td>
</span> <td>{moment(att.checkOutTime).format("DD-MMM-YYYY")}</td>
</a> <td>{convertShortTime(att.checkInTime)}</td>
</div> <td>
</div> {att.checkOutTime ? convertShortTime(att.checkOutTime) : "--"}
</td> </td>
<td>{moment(att.checkOutTime).format("DD-MMM-YYYY")}</td> <td className="text-center ">
<td>{convertShortTime(att.checkInTime)}</td> {/* <div className='d-flex justify-content-center align-items-center gap-3'> */}
<td>{att.checkOutTime ? convertShortTime(att.checkOutTime):"--"}</td> <RegularizationActions
<td className='text-center ' > attendanceData={att}
{/* <div className='d-flex justify-content-center align-items-center gap-3'> */} handleRequest={handleRequest}
<RegularizationActions attendanceData={att} handleRequest={handleRequest} refresh={refetch } /> refresh={refetch}
{/* </div> */} />
</td> {/* </div> */}
</tr> </td>
)) </tr>
):( ))
<td colSpan={5}>No Record Found</td> ) : (
) <tr>
} <td colSpan={5}>No Record Found</td>
</tbody> </tr>
</table> )}
</div> </tbody>
</table>
</div>
); );
}; };
export default Regularization export default Regularization;

View File

@ -1,23 +1,29 @@
import React from "react"; import React from "react";
import {useNavigate} from "react-router-dom"; import { useNavigate } from "react-router-dom";
const Breadcrumb = ({ data }) => { const Breadcrumb = ({ data }) => {
const navigate = useNavigate() const navigate = useNavigate();
return ( return (
<nav aria-label="breadcrumb"> <nav aria-label="breadcrumb">
<ol className="breadcrumb breadcrumb-style1"> <ol className="breadcrumb breadcrumb-style1">
{data.map((item,index) => {data.map((item, index) =>
item.link ? ( item.link ? (
<li className="breadcrumb-item cursor-pointer" key={index}> <li className="breadcrumb-item cursor-pointer" key={index}>
<a <a
aria-label="pagination link link-underline-primary " aria-label="pagination link link-underline-primary "
onClick={()=>navigate(item.link)} onClick={() => navigate(item.link)}
> >
{item.label} {item.label}
</a> </a>
</li> </li>
) : ( ) : (
<li className="breadcrumb-item active "> {item.label}</li> <li
className="breadcrumb-item active "
key={new Date().getMilliseconds()}
>
{" "}
{item.label}
</li>
) )
)} )}
</ol> </ol>

View File

@ -23,8 +23,8 @@ const AttendancePage = () => {
const loginUser = getCachedProfileData(); const loginUser = getCachedProfileData();
var selectedProject = useSelector((store) => store.localVariables.projectId); var selectedProject = useSelector((store) => store.localVariables.projectId);
const { projects, loading: projectLoading } = useProjects(); const { projects, loading: projectLoading } = useProjects();
const {attendance, loading: attLoading} = useAttendace( selectedProject ); const { attendance, loading: attLoading } = useAttendace(selectedProject);
const [ attendances, setAttendances ] = useState(); const [attendances, setAttendances] = useState();
const [empRoles, setEmpRoles] = useState(null); const [empRoles, setEmpRoles] = useState(null);
const [isCreateModalOpen, setIsCreateModalOpen] = useState(false); const [isCreateModalOpen, setIsCreateModalOpen] = useState(false);
const [modelConfig, setModelConfig] = useState(); const [modelConfig, setModelConfig] = useState();
@ -32,11 +32,10 @@ const AttendancePage = () => {
const dispatch = useDispatch(); const dispatch = useDispatch();
const [formData, setFormData] = useState({ const [formData, setFormData] = useState({
markTime: "", markTime: "",
description: "", description: "",
date: new Date().toLocaleDateString(), date: new Date().toLocaleDateString(),
}); });
const getRole = (roleId) => { const getRole = (roleId) => {
if (!empRoles) return "Unassigned"; if (!empRoles) return "Unassigned";
@ -49,9 +48,7 @@ const AttendancePage = () => {
setIsCreateModalOpen(true); setIsCreateModalOpen(true);
}; };
const handleModalData = ( employee ) => const handleModalData = (employee) => {
{
setModelConfig(employee); setModelConfig(employee);
}; };
@ -67,25 +64,24 @@ const AttendancePage = () => {
} }
}; };
const handleSubmit = (formData) => {
const handleSubmit = ( formData ) => dispatch(markCurrentAttendance(formData))
{ .then((action) => {
const updatedAttendance = attendances.map((item) =>
dispatch( markCurrentAttendance( formData ) ).then( ( action ) => item.employeeId === action.payload.employeeId
{ ? { ...item, ...action.payload }
const updatedAttendance = attendances.map(item => : item
item.employeeId === action.payload.employeeId );
? { ...item, ...action.payload } cacheData("Attendance", {
: item data: updatedAttendance,
); projectId: selectedProject,
cacheData("Attendance", { data: updatedAttendance, projectId: selectedProject }) });
setAttendances(updatedAttendance) setAttendances(updatedAttendance);
showToast("Attedance Marked Successfully","success") showToast("Attedance Marked Successfully", "success");
}) })
.catch( ( error ) => .catch((error) => {
{ showToast(error.message, "error");
showToast(error.message,"error") });
});
}; };
useEffect(() => { useEffect(() => {
@ -94,14 +90,12 @@ const AttendancePage = () => {
} }
}, [modelConfig, isCreateModalOpen]); }, [modelConfig, isCreateModalOpen]);
useEffect(() => { useEffect(() => {
setAttendances( attendance ); setAttendances(attendance);
}, [attendance]); }, [attendance]);
useEffect(() => { useEffect(() => {
dispatch(setProjectId(projects[0]?.id)); dispatch(setProjectId(projects[0]?.id));
}, [projects]); }, [projects]);
return ( return (
<> <>
{isCreateModalOpen && modelConfig && ( {isCreateModalOpen && modelConfig && (
@ -126,59 +120,71 @@ const AttendancePage = () => {
{ label: "Home", link: "/dashboard" }, { label: "Home", link: "/dashboard" },
{ label: "Attendance", link: null }, { label: "Attendance", link: null },
]} ]}
></Breadcrumb> ></Breadcrumb>
<div class="nav-align-top nav-tabs-shadow"> <div className="nav-align-top nav-tabs-shadow">
<ul class="nav nav-tabs" role="tablist"> <ul className="nav nav-tabs" role="tablist">
<div <div
className="dataTables_length text-start py-2 px-2" className="dataTables_length text-start py-2 px-2"
id="DataTables_Table_0_length" id="DataTables_Table_0_length"
> >
{ {loginUser && loginUser?.projects?.length > 1 && (
((loginUser && loginUser?.projects?.length > 1) ) && (<label> <label>
<select <select
name="DataTables_Table_0_length" name="DataTables_Table_0_length"
aria-controls="DataTables_Table_0" aria-controls="DataTables_Table_0"
className="form-select form-select-sm" className="form-select form-select-sm"
value={selectedProject} value={selectedProject}
onChange={(e)=>dispatch(setProjectId(e.target.value))} onChange={(e) => dispatch(setProjectId(e.target.value))}
aria-label="" aria-label=""
>
{!projectLoading &&
projects
?.filter((project) =>
loginUser?.projects?.map(Number).includes(project.id)
)
.map((project) => (
<option value={project.id} key={project.id}>
{project.name}
</option>
))}
{projectLoading && (
<option value="Loading..." disabled>
Loading...
</option>
)}
</select>
</label>
)}
</div>
</ul>
<ul className="nav nav-tabs" role="tablist">
<li className="nav-item">
<button
type="button"
className="nav-link active"
role="tab"
data-bs-toggle="tab"
data-bs-target="#navs-top-home"
aria-controls="navs-top-home"
aria-selected="true"
> >
{!projectLoading && projects?.filter(project => All
loginUser?.projects?.map(Number).includes(project.id)).map((project)=>( </button>
<option value={project.id} key={project.id}>{project.name}</option> </li>
))} <li className="nav-item">
{projectLoading && <option value="Loading..." disabled>Loading...</option> } <button
</select> type="button"
</label>) className="nav-link"
} role="tab"
</div> data-bs-toggle="tab"
</ul> data-bs-target="#navs-top-profile"
<ul class="nav nav-tabs" role="tablist"> aria-controls="navs-top-profile"
<li class="nav-item"> aria-selected="false"
<button >
type="button" Logs
class="nav-link active" </button>
role="tab" </li>
data-bs-toggle="tab" <li className={`nav-item ${!DoRegularized && "d-none"}`}>
data-bs-target="#navs-top-home"
aria-controls="navs-top-home"
aria-selected="true">
All
</button>
</li>
<li class="nav-item">
<button
type="button"
class="nav-link"
role="tab"
data-bs-toggle="tab"
data-bs-target="#navs-top-profile"
aria-controls="navs-top-profile"
aria-selected="false">
Logs
</button>
</li>
<li className={`nav-item ${!DoRegularized && 'd-none'}`}>
<button <button
type="button" type="button"
className="nav-link " className="nav-link "
@ -225,10 +231,7 @@ const AttendancePage = () => {
id="navs-top-messages" id="navs-top-messages"
role="tabpanel" role="tabpanel"
> >
<Regularization <Regularization handleRequest={handleSubmit} />
handleRequest={handleSubmit}
/>
</div> </div>
</> </>
)} )}

View File

@ -12,9 +12,7 @@ import { MANAGE_EMPLOYEES } from "../../utils/constants";
import { useHasUserPermission } from "../../hooks/useHasUserPermission"; import { useHasUserPermission } from "../../hooks/useHasUserPermission";
import SuspendEmp from "../../components/Employee/SuspendEmp"; import SuspendEmp from "../../components/Employee/SuspendEmp";
const EmployeeList = () => const EmployeeList = () => {
{
const { profile: loginUser } = useProfile(); const { profile: loginUser } = useProfile();
const [selectedProject, setSelectedProject] = useState(""); const [selectedProject, setSelectedProject] = useState("");
const { projects, loading: projectLoading } = useProjects(); const { projects, loading: projectLoading } = useProjects();
@ -30,7 +28,7 @@ const EmployeeList = () =>
const [itemsPerPage] = useState(10); const [itemsPerPage] = useState(10);
const [isCreateModalOpen, setIsCreateModalOpen] = useState(false); const [isCreateModalOpen, setIsCreateModalOpen] = useState(false);
const [searchText, setSearchText] = useState(""); const [searchText, setSearchText] = useState("");
const [ filteredData, setFilteredData ] = useState( [] ); const [filteredData, setFilteredData] = useState([]);
const [showModal, setShowModal] = useState(false); const [showModal, setShowModal] = useState(false);
const navigate = useNavigate(); const navigate = useNavigate();
@ -92,7 +90,7 @@ const EmployeeList = () =>
} }
}; };
const handleShow = () => setShowModal(true); const handleShow = () => setShowModal(true);
const handleClose = () => setShowModal( false ); const handleClose = () => setShowModal(false);
const handleConfigData = (config) => { const handleConfigData = (config) => {
setModelConfig(config); setModelConfig(config);
@ -110,14 +108,14 @@ const EmployeeList = () =>
<ManageEmp employeeId={modelConfig} onClosed={closeModal} /> <ManageEmp employeeId={modelConfig} onClosed={closeModal} />
)} )}
<div <div
className={`modal fade ${showModal ? 'show' : ''}`} className={`modal fade ${showModal ? "show" : ""}`}
tabIndex="-1" tabIndex="-1"
role="dialog" role="dialog"
style={{ display: showModal ? 'block' : 'none' }} style={{ display: showModal ? "block" : "none" }}
aria-hidden={!showModal} aria-hidden={!showModal}
> >
<SuspendEmp onClose={handleClose}/> <SuspendEmp onClose={handleClose} />
</div> </div>
<div className="container-xxl flex-grow-1 container-p-y"> <div className="container-xxl flex-grow-1 container-p-y">
@ -329,130 +327,134 @@ const EmployeeList = () =>
</tr> </tr>
)} )}
{!loading && employeeList?.length === 0 && ( {!loading && employeeList?.length === 0 && (
<td <tr>
colSpan={8} <td
style={{ paddingTop: "20px", textAlign: "center" }} colSpan={8}
> style={{ paddingTop: "20px", textAlign: "center" }}
No Data Found >
</td> No Data Found
</td>
</tr>
)} )}
{!loading && {!loading &&
employeeList && employeeList &&
currentItems.length === 0 && currentItems.length === 0 &&
employeeList.length !== 0 && ( employeeList.length !== 0 && (
<td colSpan={8}> <tr>
<small className="muted"> <td colSpan={8}>
'{searchText}' employee not found <small className="muted">
</small>{" "} '{searchText}' employee not found
</td> </small>{" "}
</td>
</tr>
)} )}
{currentItems && {currentItems &&
!loading && !loading &&
currentItems currentItems.map((item) => (
.map((item) => ( <tr className="odd" key={item.id}>
<tr className="odd" key={item.id}> <td className="sorting_1" colSpan={2}>
<td className="sorting_1" colSpan={2}> <div className="d-flex justify-content-start align-items-center user-name">
<div className="d-flex justify-content-start align-items-center user-name"> <Avatar
<Avatar firstName={item.firstName}
firstName={item.firstName} lastName={item.lastName}
lastName={item.lastName} ></Avatar>
></Avatar> <div className="d-flex flex-column">
<div className="d-flex flex-column"> <a
<a onClick={() =>
navigate(`/employee/${item.id}?for=account`)
}
className="text-heading text-truncate cursor-pointer"
>
<span className="fw-medium">
{item.firstName} {item.lastName}
</span>
</a>
</div>
</div>
</td>
<td className="text-start d-none d-sm-table-cell">
{item.email ? (
<span className="text-truncate">
<i className="bx bxs-envelope text-primary me-2"></i>
{item.email}
</span>
) : (
<span className="text-truncate text-italic">
NA
</span>
)}
</td>
<td className="text-start d-none d-sm-table-cell">
<span className="text-truncate">
<i className="bx bxs-phone-call text-primary me-2"></i>
{item.phoneNumber}
</span>
</td>
<td className=" d-none d-sm-table-cell text-start">
<span className="text-truncate">
<i className="bx bxs-wrench text-success me-2"></i>
{item.jobRole || "Not Assign Yet"}
</span>
</td>
<td className=" d-none d-md-table-cell">
{moment(item.joiningDate).format("DD-MMM-YYYY")}
</td>
<td>
<span
className="badge bg-label-success"
text-capitalized=""
>
Active
</span>
</td>
{ManageEmployee && (
<td className="text-end">
<div className="dropdown">
<button
className="btn btn-icon dropdown-toggle hide-arrow"
data-bs-toggle="dropdown"
>
<i className="bx bx-dots-vertical-rounded bx-md"></i>
</button>
<div className="dropdown-menu dropdown-menu-end">
<button
onClick={() => onClick={() =>
navigate( navigate(`/employee/${item.id}`)
`/employee/${item.id}?for=account`
)
} }
className="text-heading text-truncate cursor-pointer" className="dropdown-item"
> >
<span className="fw-medium"> View
{item.firstName} {item.lastName} </button>
</span> <Link
</a> to={`/employee/manage/${item.id}`}
className="dropdown-item"
>
Edit
</Link>
<button
className="dropdown-item"
onClick={handleShow}
>
Suspend
</button>
<button
className="dropdown-item"
type="button"
data-bs-toggle="modal"
data-bs-target="#managerole-modal"
onClick={() => handleConfigData(item.id)}
>
Manage Role
</button>
</div> </div>
</div> </div>
</td> </td>
<td className="text-start d-none d-sm-table-cell"> )}
{item.email ? ( </tr>
<span className="text-truncate"> ))}
<i className="bx bxs-envelope text-primary me-2"></i>
{item.email}
</span>
) : (
<span className="text-truncate text-italic">
NA
</span>
)}
</td>
<td className="text-start d-none d-sm-table-cell">
<span className="text-truncate">
<i className="bx bxs-phone-call text-primary me-2"></i>
{item.phoneNumber}
</span>
</td>
<td className=" d-none d-sm-table-cell text-start">
<span className="text-truncate">
<i className="bx bxs-wrench text-success me-2"></i>
{item.jobRole || "Not Assign Yet"}
</span>
</td>
<td className=" d-none d-md-table-cell">
{moment(item.joiningDate).format("DD-MMM-YYYY")}
</td>
<td>
<span
className="badge bg-label-success"
text-capitalized=""
>
Active
</span>
</td>
{ManageEmployee && (
<td className="text-end">
<div className="dropdown">
<button
className="btn btn-icon dropdown-toggle hide-arrow"
data-bs-toggle="dropdown"
>
<i className="bx bx-dots-vertical-rounded bx-md"></i>
</button>
<div className="dropdown-menu dropdown-menu-end">
<button
onClick={() =>
navigate(`/employee/${item.id}`)
}
className="dropdown-item"
>
View
</button>
<Link
to={`/employee/manage/${item.id}`}
className="dropdown-item"
>
Edit
</Link>
<button className="dropdown-item" onClick={handleShow}>
Suspend
</button>
<button
className="dropdown-item"
type="button"
data-bs-toggle="modal"
data-bs-target="#managerole-modal"
onClick={() => handleConfigData(item.id)}
>
Manage Role
</button>
</div>
</div>
</td>
)}
</tr>
))}
</tbody> </tbody>
</table> </table>

View File

@ -1,92 +1,96 @@
// AppRoutes.jsx
import React from "react"; import React from "react";
import { BrowserRouter as Router, Routes, Route } from "react-router-dom"; import { createBrowserRouter, RouterProvider, Outlet } from "react-router-dom";
import AuthLayout from "../layouts/AuthLayout"
// Layouts
import AuthLayout from "../layouts/AuthLayout";
import HomeLayout from "../layouts/HomeLayout"; import HomeLayout from "../layouts/HomeLayout";
// Authentication Pages
import LoginPage from "../pages/authentication/LoginPage"; import LoginPage from "../pages/authentication/LoginPage";
import RegisterPage from "../pages/authentication/RegisterPage"; import RegisterPage from "../pages/authentication/RegisterPage";
import ForgotPasswordPage from "../pages/authentication/ForgotPasswordPage"; import ForgotPasswordPage from "../pages/authentication/ForgotPasswordPage";
import ResetPasswordPage from "../pages/authentication/ResetPasswordPage"; import ResetPasswordPage from "../pages/authentication/ResetPasswordPage";
// Home & Protected Pages
import Dashboard from "../components/Dashboard/Dashboard"; import Dashboard from "../components/Dashboard/Dashboard";
import ProjectList from "../pages/project/ProjectList"; import ProjectList from "../pages/project/ProjectList";
import EmployeeList from "../pages/employee/EmployeeList";
import NotFound from "../pages/Home/NotFound";
import ProtectedRoute from "./ProtectedRoute";
import ProjectDetails from "../pages/project/ProjectDetails"; import ProjectDetails from "../pages/project/ProjectDetails";
import ManageProject from "../components/Project/ManageProject";
import EmployeeList from "../pages/employee/EmployeeList";
import ManageEmp from "../pages/employee/ManageEmp";
import EmployeeProfile from "../pages/employee/EmployeeProfile";
import Inventory from "../pages/project/Inventory"; import Inventory from "../pages/project/Inventory";
import AttendancePage from "../pages/Activities/AttendancePage";
import DailyTask from "../pages/Activities/DailyTask";
import TaskPlannng from "../pages/Activities/TaskPlannng"; import TaskPlannng from "../pages/Activities/TaskPlannng";
import Reports from "../pages/reports/Reports"; import Reports from "../pages/reports/Reports";
import ImageGallary from "../pages/Gallary/ImageGallary"; import ImageGallary from "../pages/Gallary/ImageGallary";
import MasterPage from "../pages/master/MasterPage";
import Support from "../pages/support/Support"; import Support from "../pages/support/Support";
import Documentation from "../pages/support/Documentation"; import Documentation from "../pages/support/Documentation";
import Connect from "../pages/support/Connect"; import Connect from "../pages/support/Connect";
import ManageProject from "../components/Project/ManageProject";
import ManageEmp from "../pages/employee/ManageEmp";
import EmployeeProfile from "../pages/employee/EmployeeProfile";
import { ErrorPage } from "../pages/support/ErrorPage"; import { ErrorPage } from "../pages/support/ErrorPage";
import MasterPage from "../pages/master/MasterPage";
import DailyTask from "../pages/Activities/DailyTask";
import AttendancePage from "../pages/Activities/AttendancePage";
// Protected Route Wrapper
import ProtectedRoute from "./ProtectedRoute";
const router = createBrowserRouter(
[
{
element: <AuthLayout />,
children: [
{ path: "/auth/login", element: <LoginPage /> },
{ path: "/auth/reqest/demo", element: <RegisterPage /> },
{ path: "/auth/forgot-password", element: <ForgotPasswordPage /> },
{ path: "/reset-password", element: <ResetPasswordPage /> },
],
},
{
element: <ProtectedRoute />,
children: [
{
element: <HomeLayout />,
children: [
{ path: "/", element: <Dashboard /> },
{ path: "/dashboard", element: <Dashboard /> },
{ path: "/projects", element: <ProjectList /> },
{ path: "/projects/:projectId", element: <ProjectDetails /> },
{ path: "/project/manage/:projectId", element: <ManageProject /> },
{ path: "/employees", element: <EmployeeList /> },
{ path: "/employee/:employeeId", element: <EmployeeProfile /> },
{ path: "/employee/manage", element: <ManageEmp /> },
{ path: "/employee/manage/:employeeId", element: <ManageEmp /> },
{ path: "/inventory", element: <Inventory /> },
{ path: "/activities/attendance", element: <AttendancePage /> },
{ path: "/activities/records", element: <DailyTask /> },
{ path: "/activities/task", element: <TaskPlannng /> },
{ path: "/activities/reports", element: <Reports /> },
{ path: "/activities/gallary", element: <ImageGallary /> },
{ path: "/masters", element: <MasterPage /> },
{ path: "/help/support", element: <Support /> },
{ path: "/help/docs", element: <Documentation /> },
{ path: "/help/connect", element: <Connect /> },
],
},
],
},
{
path: "*",
element: <ErrorPage />,
},
],
{
// Enables the v7 splat path resolution behavior
future: {
v7_relativeSplatPath: true,
v7_startTransition: true,
},
}
);
const AppRoutes = () => { const AppRoutes = () => {
return ( return <RouterProvider router={router} />;
<Router>
<Routes>
{/* Authentication Routes */}
<Route element={<AuthLayout />}>
<Route path="/auth/login" element={<LoginPage />} />
<Route path="/auth/reqest/demo" element={<RegisterPage />} />
<Route
path="/auth/forgot-password"
element={<ForgotPasswordPage />}
/>
<Route path="/reset-password" element={<ResetPasswordPage />} />
</Route>
{/* Protected Routes */}
<Route element={<ProtectedRoute />}>
<Route element={<HomeLayout />}>
<Route path="/" element={<Dashboard />} />
<Route path="/dashboard" element={<Dashboard />} />
<Route path="/projects" element={<ProjectList />} />
<Route path="/projects/:projectId" element={<ProjectDetails />} />
<Route
path="/project/manage/:projectId"
element={<ManageProject />}
/>
<Route path="/employees" element={<EmployeeList />} />
<Route path="/employee/:employeeId" element={<EmployeeProfile />} />
<Route path="/employee/manage" element={<ManageEmp />} />
<Route
path="/employee/manage/:employeeId"
element={<ManageEmp />}
/>
<Route path="/inventory" element={<Inventory />} />
<Route path="/activities/attendance" element={<AttendancePage />} />
<Route path="/activities/records" element={<DailyTask />} />
<Route path="/activities/task" element={<TaskPlannng />} />
<Route path="/activities/reports" element={<Reports />} />
<Route path="/activities/gallary" element={<ImageGallary />} />
<Route path="/masters" element={<MasterPage />} />
<Route path="/help/support" element={<Support />} />
<Route path="/help/docs" element={<Documentation />} />
<Route path="/help/connect" element={<Connect />} />
</Route>
</Route>
{/* Fallback Route */}
<Route path="*" element={<ErrorPage />} />
</Routes>
</Router>
);
}; };
export default AppRoutes; export default AppRoutes;

View File

@ -3,7 +3,7 @@ import { useNavigate } from "react-router-dom";
import axiosRetry from "axios-retry"; import axiosRetry from "axios-retry";
import showToast from "../services/toastService"; import showToast from "../services/toastService";
const base_Url = process.env.VITE_BASE_URL; const base_Url = process.env.VITE_BASE_URL;
// const base_Url = https://api.marcoaiot.com; // const base_Url = "https://api.marcoaiot.com";
export const axiosClient = axios.create({ export const axiosClient = axios.create({
baseURL: base_Url, // Your Web API URL baseURL: base_Url, // Your Web API URL
withCredentials: false, // Required if the API uses cookies withCredentials: false, // Required if the API uses cookies
@ -31,11 +31,8 @@ axiosClient.interceptors.request.use(
// // Response interceptor to handle responses globally (optional) // // Response interceptor to handle responses globally (optional)
// Add an interceptor to handle expired tokens // Add an interceptor to handle expired tokens
axiosClient.interceptors.response.use( axiosClient.interceptors.response.use(
(response) => response, (response) => response,
async (error) => { async (error) => {
const originalRequest = error.config; const originalRequest = error.config;
if (!originalRequest) { if (!originalRequest) {
@ -51,46 +48,46 @@ axiosClient.interceptors.response.use(
"Connection refused. Please ensure the server is running." "Connection refused. Please ensure the server is running."
); );
if ( error.config.url.indexOf( 'refresh-token' ) == -1 ) if (error.config.url.indexOf("refresh-token") == -1) {
{ //showToast("Server is unreachable. Try again later!", "error");
showToast("Server is unreachable. Try again later!", "error"); console.log("1 - error fetching refresh token :", error);
} } else {
showToast( showToast(
"Unable to connect to the server. Please try again later.", "Unable to connect to the server. Please try again later.",
"error" "error"
); );
}
} else if (error.code === "ERR_NETWORK") { } else if (error.code === "ERR_NETWORK") {
console.error( "Network error: Unable to reach the server." ); console.error("Network error: Unable to reach the server.");
if ( error.config.url.indexOf( 'refresh-token' ) == -1 ) if (error.config.url.indexOf("refresh-token") == -1) {
{ //showToast("Server is unreachable. Try again later!", "error");
showToast("Server is unreachable. Try again later!", "error"); console.log("2 - error fetching refresh token :", error);
} }
redirectToLogin(); redirectToLogin();
} else if (error.code === "ECONNABORTED") { } else if (error.code === "ECONNABORTED") {
console.error( "Request timed out." ); console.error("Request timed out.");
if ( error.config.url.indexOf( 'refresh-token' ) == -1 ) if (error.config.url.indexOf("refresh-token") == -1) {
{ //showToast("Server is unreachable. Try again later!", "error");
showToast("Server is unreachable. Try again later!", "error"); console.log("3 - error fetching refresh token :", error);
} } else {
showToast( showToast(
"The request took too long. Please try again later.", "The request took too long. Please try again later.",
"error" "error"
); );
} else if ( error.response ) }
{ } else if (error.response) {
if (error.config.url.indexOf("refresh-token") == -1) {
if ( error.config.url.indexOf( 'refresh-token' ) == -1 ) //showToast("Server is unreachable. Try again later!", "error");
{ console.log("4 - error fetching refresh token :", error);
showToast("Server is unreachable. Try again later!", "error"); } else {
} showToast(error.response.data.message, "error");
showToast(error.response.data.message, "error"); }
if (error.response.status === 401 && !originalRequest._retry) { if (error.response.status === 401 && !originalRequest._retry) {
originalRequest._retry = true; originalRequest._retry = true;
try { try {
// Get the refresh token from secure storage // Get the refresh token from secure storage
const refreshToken = localStorage.getItem("refreshToken"); const refreshToken = localStorage.getItem("refreshToken");
@ -115,11 +112,19 @@ axiosClient.interceptors.response.use(
// Retry the original request // Retry the original request
return axiosClient(originalRequest); return axiosClient(originalRequest);
} catch (err) { } catch (err) {
console.log(
"5 - error fetching refresh token during refresh call :",
error
);
// Redirect to login if token refresh fails // Redirect to login if token refresh fails
redirectToLogin(); redirectToLogin();
return Promise.reject(err); return Promise.reject(err);
} }
} else { } else {
if (error.config.url.indexOf("refresh-token") == -1) {
//showToast("Server is unreachable. Try again later!", "error");
console.log("6 - error fetching refresh token :", error);
}
showToast( showToast(
error.response.data?.message || error.response.data?.message ||
"An error occurred. Please try again.", "An error occurred. Please try again.",