Remove warnings
This commit is contained in:
parent
83b6c2a307
commit
1418f84976
@ -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();
|
||||
|
||||
@ -9,12 +15,12 @@ export const ModalProvider = ({ children }) => {
|
||||
const [isOpen, setIsOpen] = useState(false);
|
||||
const [modalContent, setModalContent] = useState(null);
|
||||
const [onSubmit, setOnSubmit] = useState(null);
|
||||
const [modalSize, setModalSize] = useState('lg');
|
||||
const [modalSize, setModalSize] = useState("lg");
|
||||
|
||||
// Ref to track the modal content element
|
||||
const modalRef = useRef(null);
|
||||
|
||||
const openModal = (content, onSubmitCallback, size = 'lg') => {
|
||||
const openModal = (content, onSubmitCallback, size = "lg") => {
|
||||
setModalContent(content); // Set modal content dynamically
|
||||
setOnSubmit(() => onSubmitCallback); // Set the submit handler dynamically
|
||||
setIsOpen(true); // Open the modal
|
||||
@ -26,9 +32,20 @@ export const ModalProvider = ({ children }) => {
|
||||
setIsOpen(false); // Close the modal
|
||||
setModalContent(null); // Clear modal content
|
||||
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(() => {
|
||||
const handleClickOutside = (event) => {
|
||||
@ -43,14 +60,28 @@ export const ModalProvider = ({ children }) => {
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<ModalContext.Provider value={{ isOpen, openModal, closeModal, modalContent, modalSize, onSubmit }}>
|
||||
<ModalContext.Provider
|
||||
value={{
|
||||
isOpen,
|
||||
openModal,
|
||||
closeModal,
|
||||
modalContent,
|
||||
modalSize,
|
||||
onSubmit,
|
||||
}}
|
||||
>
|
||||
{children}
|
||||
|
||||
{isOpen && (
|
||||
<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>
|
||||
</div>
|
||||
)}
|
||||
@ -77,5 +108,5 @@ const modalStyles = {
|
||||
borderRadius: "5px",
|
||||
boxShadow: "0 4px 6px rgba(0, 0, 0, 0.1)",
|
||||
width: "90%",
|
||||
maxWidth: "800px",
|
||||
maxWidth: "800px",
|
||||
};
|
||||
|
@ -1,18 +1,18 @@
|
||||
import React, { useEffect, useState } from 'react';
|
||||
import Avatar from '../common/Avatar';
|
||||
import { convertShortTime } from '../../utils/dateUtils';
|
||||
import RenderAttendanceStatus from './RenderAttendanceStatus';
|
||||
import { useSelector, useDispatch } from 'react-redux';
|
||||
import { fetchAttendanceData } from '../../slices/apiSlice/attedanceLogsSlice';
|
||||
import React, { useEffect, useState } from "react";
|
||||
import Avatar from "../common/Avatar";
|
||||
import { convertShortTime } from "../../utils/dateUtils";
|
||||
import RenderAttendanceStatus from "./RenderAttendanceStatus";
|
||||
import { useSelector, useDispatch } from "react-redux";
|
||||
import { fetchAttendanceData } from "../../slices/apiSlice/attedanceLogsSlice";
|
||||
|
||||
const AttendanceLog = ({ attendance, handleModalData, projectId }) => {
|
||||
const [attendances, setAttendnaces] = useState([]);
|
||||
const [selectedDate, setSelectedDate] = useState('');
|
||||
const [selectedDate, setSelectedDate] = useState("");
|
||||
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
|
||||
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 date = e.target.value;
|
||||
@ -28,11 +28,15 @@ const AttendanceLog = ({ attendance, handleModalData, projectId }) => {
|
||||
setSelectedDate(currentDate); // Set default selected date to today
|
||||
}, [attendance]);
|
||||
|
||||
const renderAttendanceData = selectedDate === currentDate ? attendances : data;
|
||||
const renderAttendanceData =
|
||||
selectedDate === currentDate ? attendances : data;
|
||||
|
||||
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">
|
||||
<input
|
||||
className="form-control form-control-sm"
|
||||
@ -50,10 +54,13 @@ const AttendanceLog = ({ attendance, handleModalData, projectId }) => {
|
||||
<table className="table mb-0">
|
||||
<thead>
|
||||
<tr>
|
||||
<th className="border-top-1" colSpan={2}>Name</th>
|
||||
<th className="border-top-1" >Role</th>
|
||||
<th className="border-top-1" colSpan={2}>
|
||||
Name
|
||||
</th>
|
||||
<th className="border-top-1">Role</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>
|
||||
<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>}
|
||||
{error && <td colSpan={5}>{error}</td>}
|
||||
{selectedDate && renderAttendanceData.length === 0 && (
|
||||
<td colSpan={5}>No Data Found</td>
|
||||
<tr>
|
||||
<td colSpan={5}>No Data Found</td>
|
||||
</tr>
|
||||
)}
|
||||
|
||||
{renderAttendanceData?.map((attendance, index) => (
|
||||
<tr key={index}>
|
||||
<td colSpan={2}>
|
||||
<td colSpan={2}>
|
||||
<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">
|
||||
<a href="#" className="text-heading text-truncate">
|
||||
<span className="fw-medium">
|
||||
@ -82,9 +94,13 @@ const AttendanceLog = ({ attendance, handleModalData, projectId }) => {
|
||||
</div>
|
||||
</div>
|
||||
</td>
|
||||
<td>{ attendance.jobRoleName}</td>
|
||||
<td>{attendance.jobRoleName}</td>
|
||||
<td>{convertShortTime(attendance.checkInTime)}</td>
|
||||
<td>{attendance.checkOutTime ? convertShortTime(attendance.checkOutTime) : '--'}</td>
|
||||
<td>
|
||||
{attendance.checkOutTime
|
||||
? convertShortTime(attendance.checkOutTime)
|
||||
: "--"}
|
||||
</td>
|
||||
<td className="text-center">
|
||||
<RenderAttendanceStatus
|
||||
attendanceData={attendance}
|
||||
|
@ -1,79 +1,82 @@
|
||||
import React, { useEffect, useState } from 'react';
|
||||
import Avatar from '../common/Avatar';
|
||||
import { convertShortTime } from '../../utils/dateUtils';
|
||||
import RegularizationActions from './RegularizationActions';
|
||||
import {useSelector} from 'react-redux';
|
||||
import {useRegularizationRequests} from '../../hooks/useAttendance';
|
||||
import moment from 'moment';
|
||||
import React, { useEffect, useState } from "react";
|
||||
import Avatar from "../common/Avatar";
|
||||
import { convertShortTime } from "../../utils/dateUtils";
|
||||
import RegularizationActions from "./RegularizationActions";
|
||||
import { useSelector } from "react-redux";
|
||||
import { useRegularizationRequests } from "../../hooks/useAttendance";
|
||||
import moment from "moment";
|
||||
|
||||
const Regularization = ({ handleRequest }) => {
|
||||
var selectedProject = useSelector((store) => store.localVariables.projectId);
|
||||
const [regularizesList, setregularizedList] = useState([]);
|
||||
const { regularizes, loading, error, refetch } =
|
||||
useRegularizationRequests(selectedProject);
|
||||
|
||||
const Regularization = ( { handleRequest} ) =>
|
||||
{
|
||||
var selectedProject = useSelector((store) => store.localVariables.projectId);
|
||||
const [ regularizesList, setregularizedList ] = useState( [] )
|
||||
const { regularizes, loading,error,refetch} = useRegularizationRequests(selectedProject)
|
||||
|
||||
|
||||
useEffect(() => {
|
||||
setregularizedList(regularizes);
|
||||
}, [regularizes]);
|
||||
|
||||
useEffect(()=>{
|
||||
setregularizedList(regularizes)
|
||||
},[regularizes])
|
||||
|
||||
return (
|
||||
<div className="table-responsive text-nowrap">
|
||||
<table className="table mb-0">
|
||||
<thead>
|
||||
<tr>
|
||||
<th colSpan={2}>Name</th>
|
||||
<th>Date</th>
|
||||
<th><i className='bx bxs-down-arrow-alt text-success' ></i>Check-In</th>
|
||||
<th><i className='bx bxs-up-arrow-alt text-danger' ></i>Check-Out</th>
|
||||
<th>Action</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<div className="table-responsive text-nowrap">
|
||||
<table className="table mb-0">
|
||||
<thead>
|
||||
<tr>
|
||||
<th colSpan={2}>Name</th>
|
||||
<th>Date</th>
|
||||
<th>
|
||||
<i className="bx bxs-down-arrow-alt text-success"></i>Check-In
|
||||
</th>
|
||||
<th>
|
||||
<i className="bx bxs-up-arrow-alt text-danger"></i>Check-Out
|
||||
</th>
|
||||
<th>Action</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
|
||||
{loading &&<td colSpan={5}>Loading...</td>}
|
||||
{
|
||||
regularizes?.length > 0 ? (
|
||||
regularizes?.map((att, index) => (
|
||||
<tr key={index}>
|
||||
<td colSpan={2}>
|
||||
<div className="d-flex justify-content-start align-items-center">
|
||||
<Avatar
|
||||
firstName={att.firstName}
|
||||
lastName={att.lastName}
|
||||
></Avatar>
|
||||
<div className="d-flex flex-column">
|
||||
<a
|
||||
href="#"
|
||||
className="text-heading text-truncate"
|
||||
>
|
||||
<span className="fw-medium">
|
||||
{att.firstName} {att.lastName}
|
||||
</span>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</td>
|
||||
<td>{moment(att.checkOutTime).format("DD-MMM-YYYY")}</td>
|
||||
<td>{convertShortTime(att.checkInTime)}</td>
|
||||
<td>{att.checkOutTime ? convertShortTime(att.checkOutTime):"--"}</td>
|
||||
<td className='text-center ' >
|
||||
{/* <div className='d-flex justify-content-center align-items-center gap-3'> */}
|
||||
<RegularizationActions attendanceData={att} handleRequest={handleRequest} refresh={refetch } />
|
||||
{/* </div> */}
|
||||
</td>
|
||||
</tr>
|
||||
))
|
||||
):(
|
||||
<td colSpan={5}>No Record Found</td>
|
||||
)
|
||||
}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
{loading && <td colSpan={5}>Loading...</td>}
|
||||
{regularizes?.length > 0 ? (
|
||||
regularizes?.map((att, index) => (
|
||||
<tr key={index}>
|
||||
<td colSpan={2}>
|
||||
<div className="d-flex justify-content-start align-items-center">
|
||||
<Avatar
|
||||
firstName={att.firstName}
|
||||
lastName={att.lastName}
|
||||
></Avatar>
|
||||
<div className="d-flex flex-column">
|
||||
<a href="#" className="text-heading text-truncate">
|
||||
<span className="fw-medium">
|
||||
{att.firstName} {att.lastName}
|
||||
</span>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</td>
|
||||
<td>{moment(att.checkOutTime).format("DD-MMM-YYYY")}</td>
|
||||
<td>{convertShortTime(att.checkInTime)}</td>
|
||||
<td>
|
||||
{att.checkOutTime ? convertShortTime(att.checkOutTime) : "--"}
|
||||
</td>
|
||||
<td className="text-center ">
|
||||
{/* <div className='d-flex justify-content-center align-items-center gap-3'> */}
|
||||
<RegularizationActions
|
||||
attendanceData={att}
|
||||
handleRequest={handleRequest}
|
||||
refresh={refetch}
|
||||
/>
|
||||
{/* </div> */}
|
||||
</td>
|
||||
</tr>
|
||||
))
|
||||
) : (
|
||||
<tr>
|
||||
<td colSpan={5}>No Record Found</td>
|
||||
</tr>
|
||||
)}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default Regularization
|
||||
export default Regularization;
|
||||
|
@ -1,23 +1,29 @@
|
||||
import React from "react";
|
||||
import {useNavigate} from "react-router-dom";
|
||||
import { useNavigate } from "react-router-dom";
|
||||
|
||||
const Breadcrumb = ({ data }) => {
|
||||
const navigate = useNavigate()
|
||||
const navigate = useNavigate();
|
||||
return (
|
||||
<nav aria-label="breadcrumb">
|
||||
<ol className="breadcrumb breadcrumb-style1">
|
||||
{data.map((item,index) =>
|
||||
{data.map((item, index) =>
|
||||
item.link ? (
|
||||
<li className="breadcrumb-item cursor-pointer" key={index}>
|
||||
<a
|
||||
aria-label="pagination link link-underline-primary "
|
||||
onClick={()=>navigate(item.link)}
|
||||
onClick={() => navigate(item.link)}
|
||||
>
|
||||
{item.label}
|
||||
</a>
|
||||
</li>
|
||||
) : (
|
||||
<li className="breadcrumb-item active "> {item.label}</li>
|
||||
<li
|
||||
className="breadcrumb-item active "
|
||||
key={new Date().getMilliseconds()}
|
||||
>
|
||||
{" "}
|
||||
{item.label}
|
||||
</li>
|
||||
)
|
||||
)}
|
||||
</ol>
|
||||
|
@ -23,8 +23,8 @@ const AttendancePage = () => {
|
||||
const loginUser = getCachedProfileData();
|
||||
var selectedProject = useSelector((store) => store.localVariables.projectId);
|
||||
const { projects, loading: projectLoading } = useProjects();
|
||||
const {attendance, loading: attLoading} = useAttendace( selectedProject );
|
||||
const [ attendances, setAttendances ] = useState();
|
||||
const { attendance, loading: attLoading } = useAttendace(selectedProject);
|
||||
const [attendances, setAttendances] = useState();
|
||||
const [empRoles, setEmpRoles] = useState(null);
|
||||
const [isCreateModalOpen, setIsCreateModalOpen] = useState(false);
|
||||
const [modelConfig, setModelConfig] = useState();
|
||||
@ -32,12 +32,11 @@ const AttendancePage = () => {
|
||||
const dispatch = useDispatch();
|
||||
|
||||
const [formData, setFormData] = useState({
|
||||
markTime: "",
|
||||
description: "",
|
||||
date: new Date().toLocaleDateString(),
|
||||
});
|
||||
markTime: "",
|
||||
description: "",
|
||||
date: new Date().toLocaleDateString(),
|
||||
});
|
||||
|
||||
|
||||
const getRole = (roleId) => {
|
||||
if (!empRoles) return "Unassigned";
|
||||
if (!roleId) return "Unassigned";
|
||||
@ -49,9 +48,7 @@ const AttendancePage = () => {
|
||||
setIsCreateModalOpen(true);
|
||||
};
|
||||
|
||||
const handleModalData = ( employee ) =>
|
||||
{
|
||||
|
||||
const handleModalData = (employee) => {
|
||||
setModelConfig(employee);
|
||||
};
|
||||
|
||||
@ -66,26 +63,25 @@ const AttendancePage = () => {
|
||||
document.querySelector(".modal-backdrop").remove();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
const handleSubmit = ( formData ) =>
|
||||
{
|
||||
|
||||
dispatch( markCurrentAttendance( formData ) ).then( ( action ) =>
|
||||
{
|
||||
const updatedAttendance = attendances.map(item =>
|
||||
item.employeeId === action.payload.employeeId
|
||||
? { ...item, ...action.payload }
|
||||
: item
|
||||
);
|
||||
cacheData("Attendance", { data: updatedAttendance, projectId: selectedProject })
|
||||
setAttendances(updatedAttendance)
|
||||
showToast("Attedance Marked Successfully","success")
|
||||
})
|
||||
.catch( ( error ) =>
|
||||
{
|
||||
showToast(error.message,"error")
|
||||
});
|
||||
|
||||
const handleSubmit = (formData) => {
|
||||
dispatch(markCurrentAttendance(formData))
|
||||
.then((action) => {
|
||||
const updatedAttendance = attendances.map((item) =>
|
||||
item.employeeId === action.payload.employeeId
|
||||
? { ...item, ...action.payload }
|
||||
: item
|
||||
);
|
||||
cacheData("Attendance", {
|
||||
data: updatedAttendance,
|
||||
projectId: selectedProject,
|
||||
});
|
||||
setAttendances(updatedAttendance);
|
||||
showToast("Attedance Marked Successfully", "success");
|
||||
})
|
||||
.catch((error) => {
|
||||
showToast(error.message, "error");
|
||||
});
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
@ -94,14 +90,12 @@ const AttendancePage = () => {
|
||||
}
|
||||
}, [modelConfig, isCreateModalOpen]);
|
||||
useEffect(() => {
|
||||
setAttendances( attendance );
|
||||
setAttendances(attendance);
|
||||
}, [attendance]);
|
||||
useEffect(() => {
|
||||
dispatch(setProjectId(projects[0]?.id));
|
||||
}, [projects]);
|
||||
|
||||
|
||||
|
||||
return (
|
||||
<>
|
||||
{isCreateModalOpen && modelConfig && (
|
||||
@ -126,59 +120,71 @@ const AttendancePage = () => {
|
||||
{ label: "Home", link: "/dashboard" },
|
||||
{ label: "Attendance", link: null },
|
||||
]}
|
||||
></Breadcrumb>
|
||||
<div class="nav-align-top nav-tabs-shadow">
|
||||
<ul class="nav nav-tabs" role="tablist">
|
||||
<div
|
||||
className="dataTables_length text-start py-2 px-2"
|
||||
id="DataTables_Table_0_length"
|
||||
>
|
||||
{
|
||||
((loginUser && loginUser?.projects?.length > 1) ) && (<label>
|
||||
<select
|
||||
name="DataTables_Table_0_length"
|
||||
aria-controls="DataTables_Table_0"
|
||||
className="form-select form-select-sm"
|
||||
value={selectedProject}
|
||||
onChange={(e)=>dispatch(setProjectId(e.target.value))}
|
||||
aria-label=""
|
||||
></Breadcrumb>
|
||||
<div className="nav-align-top nav-tabs-shadow">
|
||||
<ul className="nav nav-tabs" role="tablist">
|
||||
<div
|
||||
className="dataTables_length text-start py-2 px-2"
|
||||
id="DataTables_Table_0_length"
|
||||
>
|
||||
{loginUser && loginUser?.projects?.length > 1 && (
|
||||
<label>
|
||||
<select
|
||||
name="DataTables_Table_0_length"
|
||||
aria-controls="DataTables_Table_0"
|
||||
className="form-select form-select-sm"
|
||||
value={selectedProject}
|
||||
onChange={(e) => dispatch(setProjectId(e.target.value))}
|
||||
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 =>
|
||||
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 class="nav nav-tabs" role="tablist">
|
||||
<li class="nav-item">
|
||||
<button
|
||||
type="button"
|
||||
class="nav-link active"
|
||||
role="tab"
|
||||
data-bs-toggle="tab"
|
||||
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'}`}>
|
||||
All
|
||||
</button>
|
||||
</li>
|
||||
<li className="nav-item">
|
||||
<button
|
||||
type="button"
|
||||
className="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
|
||||
type="button"
|
||||
className="nav-link "
|
||||
@ -225,10 +231,7 @@ const AttendancePage = () => {
|
||||
id="navs-top-messages"
|
||||
role="tabpanel"
|
||||
>
|
||||
<Regularization
|
||||
|
||||
handleRequest={handleSubmit}
|
||||
/>
|
||||
<Regularization handleRequest={handleSubmit} />
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
|
@ -12,9 +12,7 @@ import { MANAGE_EMPLOYEES } from "../../utils/constants";
|
||||
import { useHasUserPermission } from "../../hooks/useHasUserPermission";
|
||||
import SuspendEmp from "../../components/Employee/SuspendEmp";
|
||||
|
||||
const EmployeeList = () =>
|
||||
{
|
||||
|
||||
const EmployeeList = () => {
|
||||
const { profile: loginUser } = useProfile();
|
||||
const [selectedProject, setSelectedProject] = useState("");
|
||||
const { projects, loading: projectLoading } = useProjects();
|
||||
@ -30,7 +28,7 @@ const EmployeeList = () =>
|
||||
const [itemsPerPage] = useState(10);
|
||||
const [isCreateModalOpen, setIsCreateModalOpen] = useState(false);
|
||||
const [searchText, setSearchText] = useState("");
|
||||
const [ filteredData, setFilteredData ] = useState( [] );
|
||||
const [filteredData, setFilteredData] = useState([]);
|
||||
const [showModal, setShowModal] = useState(false);
|
||||
const navigate = useNavigate();
|
||||
|
||||
@ -59,7 +57,7 @@ const EmployeeList = () =>
|
||||
const nameB = `${b.firstName || ""}${b.lastName || ""}`.toLowerCase();
|
||||
return nameA.localeCompare(nameB);
|
||||
});
|
||||
|
||||
|
||||
setEmployeeList(sorted);
|
||||
setFilteredData(sorted);
|
||||
}
|
||||
@ -92,8 +90,8 @@ const EmployeeList = () =>
|
||||
}
|
||||
};
|
||||
const handleShow = () => setShowModal(true);
|
||||
const handleClose = () => setShowModal( false );
|
||||
|
||||
const handleClose = () => setShowModal(false);
|
||||
|
||||
const handleConfigData = (config) => {
|
||||
setModelConfig(config);
|
||||
};
|
||||
@ -109,15 +107,15 @@ const EmployeeList = () =>
|
||||
{isCreateModalOpen && (
|
||||
<ManageEmp employeeId={modelConfig} onClosed={closeModal} />
|
||||
)}
|
||||
|
||||
<div
|
||||
className={`modal fade ${showModal ? 'show' : ''}`}
|
||||
|
||||
<div
|
||||
className={`modal fade ${showModal ? "show" : ""}`}
|
||||
tabIndex="-1"
|
||||
role="dialog"
|
||||
style={{ display: showModal ? 'block' : 'none' }}
|
||||
style={{ display: showModal ? "block" : "none" }}
|
||||
aria-hidden={!showModal}
|
||||
>
|
||||
<SuspendEmp onClose={handleClose}/>
|
||||
<SuspendEmp onClose={handleClose} />
|
||||
</div>
|
||||
|
||||
<div className="container-xxl flex-grow-1 container-p-y">
|
||||
@ -329,130 +327,134 @@ const EmployeeList = () =>
|
||||
</tr>
|
||||
)}
|
||||
{!loading && employeeList?.length === 0 && (
|
||||
<td
|
||||
colSpan={8}
|
||||
style={{ paddingTop: "20px", textAlign: "center" }}
|
||||
>
|
||||
No Data Found
|
||||
</td>
|
||||
<tr>
|
||||
<td
|
||||
colSpan={8}
|
||||
style={{ paddingTop: "20px", textAlign: "center" }}
|
||||
>
|
||||
No Data Found
|
||||
</td>
|
||||
</tr>
|
||||
)}
|
||||
{!loading &&
|
||||
employeeList &&
|
||||
currentItems.length === 0 &&
|
||||
employeeList.length !== 0 && (
|
||||
<td colSpan={8}>
|
||||
<small className="muted">
|
||||
'{searchText}' employee not found
|
||||
</small>{" "}
|
||||
</td>
|
||||
<tr>
|
||||
<td colSpan={8}>
|
||||
<small className="muted">
|
||||
'{searchText}' employee not found
|
||||
</small>{" "}
|
||||
</td>
|
||||
</tr>
|
||||
)}
|
||||
|
||||
{currentItems &&
|
||||
!loading &&
|
||||
currentItems
|
||||
.map((item) => (
|
||||
<tr className="odd" key={item.id}>
|
||||
<td className="sorting_1" colSpan={2}>
|
||||
<div className="d-flex justify-content-start align-items-center user-name">
|
||||
<Avatar
|
||||
firstName={item.firstName}
|
||||
lastName={item.lastName}
|
||||
></Avatar>
|
||||
<div className="d-flex flex-column">
|
||||
<a
|
||||
currentItems.map((item) => (
|
||||
<tr className="odd" key={item.id}>
|
||||
<td className="sorting_1" colSpan={2}>
|
||||
<div className="d-flex justify-content-start align-items-center user-name">
|
||||
<Avatar
|
||||
firstName={item.firstName}
|
||||
lastName={item.lastName}
|
||||
></Avatar>
|
||||
<div className="d-flex flex-column">
|
||||
<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={() =>
|
||||
navigate(
|
||||
`/employee/${item.id}?for=account`
|
||||
)
|
||||
navigate(`/employee/${item.id}`)
|
||||
}
|
||||
className="text-heading text-truncate cursor-pointer"
|
||||
className="dropdown-item"
|
||||
>
|
||||
<span className="fw-medium">
|
||||
{item.firstName} {item.lastName}
|
||||
</span>
|
||||
</a>
|
||||
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>
|
||||
<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={() =>
|
||||
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>
|
||||
))}
|
||||
)}
|
||||
</tr>
|
||||
))}
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
|
@ -1,92 +1,96 @@
|
||||
// AppRoutes.jsx
|
||||
import React from "react";
|
||||
import { BrowserRouter as Router, Routes, Route } from "react-router-dom";
|
||||
import AuthLayout from "../layouts/AuthLayout"
|
||||
import { createBrowserRouter, RouterProvider, Outlet } from "react-router-dom";
|
||||
|
||||
// Layouts
|
||||
import AuthLayout from "../layouts/AuthLayout";
|
||||
import HomeLayout from "../layouts/HomeLayout";
|
||||
|
||||
// Authentication Pages
|
||||
import LoginPage from "../pages/authentication/LoginPage";
|
||||
import RegisterPage from "../pages/authentication/RegisterPage";
|
||||
import ForgotPasswordPage from "../pages/authentication/ForgotPasswordPage";
|
||||
import ResetPasswordPage from "../pages/authentication/ResetPasswordPage";
|
||||
|
||||
// Home & Protected Pages
|
||||
import Dashboard from "../components/Dashboard/Dashboard";
|
||||
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 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 AttendancePage from "../pages/Activities/AttendancePage";
|
||||
import DailyTask from "../pages/Activities/DailyTask";
|
||||
import TaskPlannng from "../pages/Activities/TaskPlannng";
|
||||
import Reports from "../pages/reports/Reports";
|
||||
import ImageGallary from "../pages/Gallary/ImageGallary";
|
||||
import MasterPage from "../pages/master/MasterPage";
|
||||
import Support from "../pages/support/Support";
|
||||
import Documentation from "../pages/support/Documentation";
|
||||
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 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 = () => {
|
||||
return (
|
||||
<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>
|
||||
);
|
||||
return <RouterProvider router={router} />;
|
||||
};
|
||||
|
||||
export default AppRoutes;
|
||||
|
@ -3,7 +3,7 @@ import { useNavigate } from "react-router-dom";
|
||||
import axiosRetry from "axios-retry";
|
||||
import showToast from "../services/toastService";
|
||||
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({
|
||||
baseURL: base_Url, // Your Web API URL
|
||||
withCredentials: false, // Required if the API uses cookies
|
||||
@ -31,11 +31,8 @@ axiosClient.interceptors.request.use(
|
||||
// // Response interceptor to handle responses globally (optional)
|
||||
// Add an interceptor to handle expired tokens
|
||||
axiosClient.interceptors.response.use(
|
||||
|
||||
|
||||
(response) => response,
|
||||
async (error) => {
|
||||
|
||||
const originalRequest = error.config;
|
||||
|
||||
if (!originalRequest) {
|
||||
@ -50,47 +47,47 @@ axiosClient.interceptors.response.use(
|
||||
console.error(
|
||||
"Connection refused. Please ensure the server is running."
|
||||
);
|
||||
|
||||
if ( error.config.url.indexOf( 'refresh-token' ) == -1 )
|
||||
{
|
||||
showToast("Server is unreachable. Try again later!", "error");
|
||||
}
|
||||
showToast(
|
||||
"Unable to connect to the server. Please try again later.",
|
||||
"error"
|
||||
);
|
||||
|
||||
if (error.config.url.indexOf("refresh-token") == -1) {
|
||||
//showToast("Server is unreachable. Try again later!", "error");
|
||||
console.log("1 - error fetching refresh token :", error);
|
||||
} else {
|
||||
showToast(
|
||||
"Unable to connect to the server. Please try again later.",
|
||||
"error"
|
||||
);
|
||||
}
|
||||
} else if (error.code === "ERR_NETWORK") {
|
||||
console.error( "Network error: Unable to reach the server." );
|
||||
if ( error.config.url.indexOf( 'refresh-token' ) == -1 )
|
||||
{
|
||||
showToast("Server is unreachable. Try again later!", "error");
|
||||
console.error("Network error: Unable to reach the server.");
|
||||
if (error.config.url.indexOf("refresh-token") == -1) {
|
||||
//showToast("Server is unreachable. Try again later!", "error");
|
||||
console.log("2 - error fetching refresh token :", error);
|
||||
}
|
||||
redirectToLogin();
|
||||
} else if (error.code === "ECONNABORTED") {
|
||||
console.error( "Request timed out." );
|
||||
|
||||
if ( error.config.url.indexOf( 'refresh-token' ) == -1 )
|
||||
{
|
||||
showToast("Server is unreachable. Try again later!", "error");
|
||||
}
|
||||
showToast(
|
||||
"The request took too long. Please try again later.",
|
||||
"error"
|
||||
);
|
||||
} else if ( error.response )
|
||||
{
|
||||
|
||||
if ( error.config.url.indexOf( 'refresh-token' ) == -1 )
|
||||
{
|
||||
showToast("Server is unreachable. Try again later!", "error");
|
||||
}
|
||||
showToast(error.response.data.message, "error");
|
||||
console.error("Request timed out.");
|
||||
|
||||
if (error.config.url.indexOf("refresh-token") == -1) {
|
||||
//showToast("Server is unreachable. Try again later!", "error");
|
||||
console.log("3 - error fetching refresh token :", error);
|
||||
} else {
|
||||
showToast(
|
||||
"The request took too long. Please try again later.",
|
||||
"error"
|
||||
);
|
||||
}
|
||||
} else if (error.response) {
|
||||
if (error.config.url.indexOf("refresh-token") == -1) {
|
||||
//showToast("Server is unreachable. Try again later!", "error");
|
||||
console.log("4 - error fetching refresh token :", error);
|
||||
} else {
|
||||
showToast(error.response.data.message, "error");
|
||||
}
|
||||
|
||||
if (error.response.status === 401 && !originalRequest._retry) {
|
||||
originalRequest._retry = true;
|
||||
|
||||
try {
|
||||
|
||||
// Get the refresh token from secure storage
|
||||
const refreshToken = localStorage.getItem("refreshToken");
|
||||
|
||||
@ -115,11 +112,19 @@ axiosClient.interceptors.response.use(
|
||||
// Retry the original request
|
||||
return axiosClient(originalRequest);
|
||||
} catch (err) {
|
||||
console.log(
|
||||
"5 - error fetching refresh token during refresh call :",
|
||||
error
|
||||
);
|
||||
// Redirect to login if token refresh fails
|
||||
redirectToLogin();
|
||||
return Promise.reject(err);
|
||||
}
|
||||
} 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(
|
||||
error.response.data?.message ||
|
||||
"An error occurred. Please try again.",
|
||||
|
Loading…
x
Reference in New Issue
Block a user